Skip to content

Commit ccdd947

Browse files
committed
GP-145 Additional HashTable tests
* calculateIndex returns the same index for the same key * remove deletes element when it's in the middle of the list * remove deletes element when it's in the end of the list
1 parent 07042c0 commit ccdd947

File tree

1 file changed

+85
-26
lines changed
  • 2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs

1 file changed

+85
-26
lines changed

2-0-data-structures-and-algorithms/2-2-7-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import java.util.Arrays;
1010
import java.util.Objects;
1111
import java.util.Optional;
12+
import java.util.concurrent.ThreadLocalRandom;
1213
import java.util.stream.Collectors;
1314
import java.util.stream.Stream;
1415

1516
import static java.lang.reflect.Modifier.isStatic;
1617
import static org.assertj.core.api.Assertions.assertThat;
1718
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1819
import static org.junit.jupiter.api.Assertions.*;
19-
import static org.mockito.Mockito.atLeastOnce;
20-
import static org.mockito.Mockito.verify;
20+
import static org.mockito.Mockito.*;
2121

2222
/**
2323
* A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used
@@ -200,31 +200,49 @@ void constructorWithTableCapacityWhenArgumentIsNegative() {
200200
class HashFunctionTest {
201201
@Test
202202
@Order(1)
203-
@DisplayName("calculateIndex uses hashCode to compute an index for a given key")
204-
void calculateIndexReturnDifferentValues() {
205-
var key = Mockito.spy(new Object());
206-
207-
HashTable.calculateIndex(key, 8);
203+
@DisplayName("calculateIndex returns the same value for the same key")
204+
void calculateIndexReturnTheSameValueWhenKeyIsTheSame() {
205+
var indexSet = Stream.generate(() -> "ASDFDFSD34234234")
206+
.limit(10)
207+
.map(key -> HashTable.calculateIndex(key, 8))
208+
.collect(Collectors.toSet());
208209

209-
verify(key, atLeastOnce()).hashCode();
210+
assertThat(indexSet).hasSize(1);
210211
}
211212

212213
@Test
213214
@Order(2)
214-
@DisplayName("calculateIndex returns different values in array bounds")
215-
void calculateIndexReturnIndexInArrayBounds() {
215+
@DisplayName("calculateIndex returns different values for different keys")
216+
void calculateIndexReturnDifferentValuesWheKeysAreDifferent() {
216217
var arrayCapacity = 8;
217218
var indexSet = Stream.of("A", "Aa", "AaB", "4234", "2234fasdf", "ASDFDFSD34234234", "afsd-fdfd-ae43-5gd3")
218219
.map(str -> HashTable.calculateIndex(str, arrayCapacity))
219220
.collect(Collectors.toSet());
220221

221222
assertThat(indexSet)
222-
.hasSizeGreaterThan(1)
223+
.hasSizeGreaterThan(1);
224+
}
225+
226+
@Test
227+
@Order(3)
228+
@DisplayName("calculateIndex returns values in array bounds")
229+
void calculateIndexReturnIndexInArrayBounds() {
230+
var arrayCapacity = 8;
231+
var keys = Stream.generate(() -> ThreadLocalRandom.current().nextLong())
232+
.limit(100)
233+
.toList();
234+
235+
var indexes = keys.stream()
236+
.map(key -> HashTable.calculateIndex(key, arrayCapacity))
237+
.toList();
238+
239+
assertThat(indexes)
240+
.isNotEmpty()
223241
.allMatch(i -> i >= 0 && i < arrayCapacity);
224242
}
225243

226244
@Test
227-
@Order(3)
245+
@Order(4)
228246
@DisplayName("calculateIndex return non-negative value when hashCode is negative")
229247
void calculateIndexReturnPositiveIndexWhenHashCodeIsNegative() {
230248
var key = Long.MAX_VALUE;
@@ -248,7 +266,7 @@ class HashTableMethodsTest {
248266
void putWhenTableIsEmpty() {
249267
var previousValue = hashTable.put("madmax", 833);
250268

251-
var keyValueExists = checkKeyValueMappingExists("madmax", 833);
269+
var keyValueExists = checkKeyValueExists("madmax", 833);
252270

253271
assertNull(previousValue);
254272
assertTrue(keyValueExists);
@@ -262,8 +280,8 @@ void putTwoElementsWithTheSameHashCode() {
262280
var table = getInternalTable(hashTable);
263281
var prevValueA = hashTable.put("AaAa", 123);
264282
var prevValueB = hashTable.put("BBBB", 456);
265-
var containsKeyValueA = checkKeyValueMappingExists("AaAa", 123);
266-
var containsKeyValueB = checkKeyValueMappingExists("BBBB", 456);
283+
var containsKeyValueA = checkKeyValueExists("AaAa", 123);
284+
var containsKeyValueB = checkKeyValueExists("BBBB", 456);
267285
var bucketIndexA = HashTable.calculateIndex("AaAa", table.length);
268286
var bucketIndexB = HashTable.calculateIndex("BBBB", table.length);
269287

@@ -283,7 +301,7 @@ void putElementWithTheSameKey() {
283301

284302
var previousValue = hashTable.put("madmax", 876);
285303
System.out.println(hashTable);
286-
var containsNewValueByKey = checkKeyValueMappingExists("madmax", 876);
304+
var containsNewValueByKey = checkKeyValueExists("madmax", 876);
287305

288306
assertThat(previousValue).isEqualTo(833);
289307
assertTrue(containsNewValueByKey);
@@ -419,7 +437,7 @@ void remove() {
419437
var result = hashTable.remove("madmax");
420438

421439
assertThat(result).isEqualTo(833);
422-
assertFalse(checkKeyValueMappingExists("madmaxx", 833));
440+
assertFalse(checkKeyValueExists("madmaxx", 833));
423441
}
424442

425443
@Test
@@ -430,6 +448,38 @@ void removeWhenKeyDoesNotExists() {
430448

431449
assertNull(result);
432450
}
451+
452+
@Test
453+
@Order(15)
454+
@DisplayName("remove deletes the element when it's in the middle of the list")
455+
void removeFromTheMiddleOfTheList() {
456+
addToTable("AaAa", 843);
457+
addToTable("BBBB", 434);
458+
addToTable("AaBB", 587);
459+
460+
var removedValue = hashTable.remove("BBBB");
461+
462+
assertTrue(checkKeyValueExists("AaAa", 843));
463+
assertFalse(checkKeyExists("BBBB"));
464+
assertTrue(checkKeyValueExists("AaBB", 587));
465+
assertThat(removedValue).isEqualTo(434);
466+
}
467+
468+
@Test
469+
@Order(16)
470+
@DisplayName("remove deletes the element when it's in the end of the list")
471+
void removeFromTheEndOfTheList() {
472+
addToTable("AaAa", 843);
473+
addToTable("BBBB", 434);
474+
addToTable("AaBB", 587);
475+
476+
var removedValue = hashTable.remove("AaBB");
477+
478+
assertTrue(checkKeyValueExists("AaAa", 843));
479+
assertTrue(checkKeyValueExists("BBBB", 434));
480+
assertFalse(checkKeyExists("AaBB"));
481+
assertThat(removedValue).isEqualTo(587);
482+
}
433483
}
434484

435485
@Nested
@@ -452,10 +502,10 @@ void resizeTable() {
452502
hashTable.resizeTable(16);
453503

454504
assertThat(getInternalTable(hashTable)).hasSize(16);
455-
assertTrue(checkKeyValueMappingExists("madmax", 833));
456-
assertTrue(checkKeyValueMappingExists("altea", 553));
457-
assertTrue(checkKeyValueMappingExists("AaAa", 123));
458-
assertTrue(checkKeyValueMappingExists("BBBB", 456));
505+
assertTrue(checkKeyValueExists("madmax", 833));
506+
assertTrue(checkKeyValueExists("altea", 553));
507+
assertTrue(checkKeyValueExists("AaAa", 123));
508+
assertTrue(checkKeyValueExists("BBBB", 456));
459509
}
460510

461511
@Test
@@ -502,21 +552,30 @@ private void addToTable(String key, Integer value) {
502552
}
503553
}
504554

505-
@SneakyThrows
506-
private boolean checkKeyValueMappingExists(Object key, Object value) {
555+
private NodeProxy getNodeByKey(Object key) {
507556
var table = getInternalTable(hashTable);
508557
for (var head : table) {
509558
if (head != null) {
510559
var current = new NodeProxy(head);
511560
while (current != null) {
512-
if (current.key().equals(key) && current.value().equals(value)) {
513-
return true;
561+
if (current.key().equals(key)) {
562+
return current;
514563
}
515564
current = current.next();
516565
}
517566
}
518567
}
519-
return false;
568+
return null;
569+
}
570+
571+
private boolean checkKeyValueExists(Object key, Object value) {
572+
var node = getNodeByKey(key);
573+
return node != null && node.value().equals(value);
574+
}
575+
576+
private boolean checkKeyExists(Object key) {
577+
var node = getNodeByKey(key);
578+
return node != null;
520579
}
521580

522581
@SneakyThrows

0 commit comments

Comments
 (0)