Skip to content

Commit c706566

Browse files
committed
added tests for size change HashTableTest,
added decrement of size when removing element
1 parent 3acaf11 commit c706566

File tree

2 files changed

+57
-29
lines changed

2 files changed

+57
-29
lines changed

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.bobocode.cs;
22

3-
import lombok.ToString;
4-
53
import static java.util.Objects.requireNonNull;
64

5+
import lombok.ToString;
6+
77
/**
88
* {@link HashTable} is a simple Hashtable-based implementation of {@link Map} interface with some additional methods.
99
* It is based on the array of {@link Node} objects. Both {@link HashTable} and {@link Node} have two type parameters:
@@ -198,12 +198,14 @@ public V remove(K key) {
198198
if (current.key.equals(key)) {
199199
var value = current.value;
200200
table[index] = current.next;
201+
size--;
201202
return value;
202203
}
203204
while (current.next != null) {
204205
if (current.next.key.equals(key)) {
205206
var value = current.next.value;
206207
current.next = current.next.next;
208+
size--;
207209
return value;
208210
}
209211
current = current.next;

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

+53-27
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.bobocode.cs;
22

3-
import lombok.SneakyThrows;
4-
import org.junit.jupiter.api.ClassOrderer.OrderAnnotation;
5-
import org.junit.jupiter.api.*;
6-
import org.mockito.Mockito;
3+
import static java.lang.reflect.Modifier.isStatic;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
import static org.junit.jupiter.api.Assertions.assertFalse;
8+
import static org.junit.jupiter.api.Assertions.assertNull;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
710

811
import java.lang.reflect.Field;
912
import java.util.Arrays;
@@ -12,22 +15,24 @@
1215
import java.util.concurrent.ThreadLocalRandom;
1316
import java.util.stream.Collectors;
1417
import java.util.stream.Stream;
15-
16-
import static java.lang.reflect.Modifier.isStatic;
17-
import static org.assertj.core.api.Assertions.assertThat;
18-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
19-
import static org.junit.jupiter.api.Assertions.*;
20-
import static org.mockito.Mockito.*;
18+
import lombok.SneakyThrows;
19+
import org.junit.jupiter.api.ClassOrderer.OrderAnnotation;
20+
import org.junit.jupiter.api.DisplayName;
21+
import org.junit.jupiter.api.MethodOrderer;
22+
import org.junit.jupiter.api.Nested;
23+
import org.junit.jupiter.api.Order;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.TestClassOrder;
26+
import org.junit.jupiter.api.TestMethodOrder;
2127

2228
/**
23-
* A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used
24-
* for testing a production code. We use it for learning purposes only!
25-
*
26-
* @author Taras Boychuk
27-
*/
29+
A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used for testing a
30+
production code. We use it for learning purposes only!
31+
@author Taras Boychuk */
2832
@TestClassOrder(OrderAnnotation.class)
2933
@DisplayName("HashTable Test")
3034
class HashTableTest {
35+
3136
private HashTable<String, Integer> hashTable = new HashTable<>();
3237

3338
@Nested
@@ -126,6 +131,7 @@ void nodeConstructorAcceptKeyValue() {
126131
@DisplayName("2. HashTable fields Test")
127132
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
128133
class HashTableFieldsTest {
134+
129135
@Test
130136
@Order(1)
131137
@DisplayName("HastTable has a field 'table' which is an array of nodes")
@@ -155,6 +161,7 @@ void sizeFieldExists() {
155161
@DisplayName("3. HashTable constructors Test")
156162
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
157163
class HashTableConstructorsTest {
164+
158165
@Test
159166
@Order(1)
160167
@SneakyThrows
@@ -198,6 +205,7 @@ void constructorWithTableCapacityWhenArgumentIsNegative() {
198205
@DisplayName("4. Hash Function Test")
199206
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
200207
class HashFunctionTest {
208+
201209
@Test
202210
@Order(1)
203211
@DisplayName("calculateIndex returns the same value for the same key")
@@ -221,8 +229,8 @@ void calculateIndexReturnDifferentValuesWheKeysAreDifferent() {
221229

222230
assertThat(indexSet)
223231
.hasSizeGreaterThan(1);
224-
}
225-
232+
}
233+
226234
@Test
227235
@Order(3)
228236
@DisplayName("calculateIndex returns values in array bounds")
@@ -235,7 +243,7 @@ void calculateIndexReturnIndexInArrayBounds() {
235243
var indexes = keys.stream()
236244
.map(key -> HashTable.calculateIndex(key, arrayCapacity))
237245
.toList();
238-
246+
239247
assertThat(indexes)
240248
.isNotEmpty()
241249
.allMatch(i -> i >= 0 && i < arrayCapacity);
@@ -262,19 +270,20 @@ class HashTableMethodsTest {
262270
@Test
263271
@SneakyThrows
264272
@Order(1)
265-
@DisplayName("put creates new entry and returns null when the table is empty")
273+
@DisplayName("put creates new entry and returns null when the table is empty, should increase the table size")
266274
void putWhenTableIsEmpty() {
267275
var previousValue = hashTable.put("madmax", 833);
268276

269277
var keyValueExists = checkKeyValueExists("madmax", 833);
270278

271279
assertNull(previousValue);
272280
assertTrue(keyValueExists);
281+
assertEquals(1, getSize());
273282
}
274283

275284
@Test
276285
@Order(2)
277-
@DisplayName("put elements adds entry to to the same bucket when the hash code is the same")
286+
@DisplayName("put elements adds entry to the same bucket and increases table size when the hash code is the same")
278287
@SneakyThrows
279288
void putTwoElementsWithTheSameHashCode() {
280289
var table = getInternalTable(hashTable);
@@ -290,11 +299,13 @@ void putTwoElementsWithTheSameHashCode() {
290299
assertTrue(containsKeyValueA);
291300
assertTrue(containsKeyValueB);
292301
assertThat(bucketIndexA).isEqualTo(bucketIndexB);
302+
assertEquals(2, getSize());
293303
}
294304

295305
@Test
296306
@Order(3)
297-
@DisplayName("put element updates the value and returns the previous one when key is the same")
307+
@DisplayName(
308+
"put element updates the value and returns the previous one when key is the same, should not increase table size")
298309
void putElementWithTheSameKey() {
299310
hashTable.put("madmax", 833);
300311
System.out.println(hashTable);
@@ -305,6 +316,7 @@ void putElementWithTheSameKey() {
305316

306317
assertThat(previousValue).isEqualTo(833);
307318
assertTrue(containsNewValueByKey);
319+
assertEquals(1, getSize());
308320
}
309321

310322
@Test
@@ -430,14 +442,15 @@ void isEmptyWhenThereIsNoElements() {
430442

431443
@Test
432444
@Order(13)
433-
@DisplayName("remove deletes the entry and returns a value")
445+
@DisplayName("remove deletes the entry, decreases table size and returns a value")
434446
void remove() {
435447
addToTable("madmax", 833);
436-
448+
setSize(1);
437449
var result = hashTable.remove("madmax");
438450

439451
assertThat(result).isEqualTo(833);
440452
assertFalse(checkKeyValueExists("madmaxx", 833));
453+
assertEquals(0, getSize());
441454
}
442455

443456
@Test
@@ -451,34 +464,40 @@ void removeWhenKeyDoesNotExists() {
451464

452465
@Test
453466
@Order(15)
454-
@DisplayName("remove deletes the element when it's in the middle of the list")
467+
@DisplayName("remove deletes the element when it's in the middle of the list and decreases the size of table")
455468
void removeFromTheMiddleOfTheList() {
456469
addToTable("AaAa", 843);
457470
addToTable("BBBB", 434);
458471
addToTable("AaBB", 587);
459472

473+
var size = 3;
474+
setSize(size);
460475
var removedValue = hashTable.remove("BBBB");
461476

462477
assertTrue(checkKeyValueExists("AaAa", 843));
463478
assertFalse(checkKeyExists("BBBB"));
464479
assertTrue(checkKeyValueExists("AaBB", 587));
465480
assertThat(removedValue).isEqualTo(434);
466-
}
467-
481+
assertEquals(size - 1, getSize());
482+
}
483+
468484
@Test
469485
@Order(16)
470-
@DisplayName("remove deletes the element when it's in the end of the list")
486+
@DisplayName("remove deletes the element when it's in the end of the list and decreases the size of table")
471487
void removeFromTheEndOfTheList() {
472488
addToTable("AaAa", 843);
473489
addToTable("BBBB", 434);
474490
addToTable("AaBB", 587);
491+
var size = 3;
492+
setSize(size);
475493

476494
var removedValue = hashTable.remove("AaBB");
477495

478496
assertTrue(checkKeyValueExists("AaAa", 843));
479497
assertTrue(checkKeyValueExists("BBBB", 434));
480498
assertFalse(checkKeyExists("AaBB"));
481499
assertThat(removedValue).isEqualTo(587);
500+
assertEquals(2, getSize());
482501
}
483502
}
484503

@@ -585,6 +604,13 @@ private void setSize(int size) {
585604
sizeField.set(hashTable, size);
586605
}
587606

607+
@SneakyThrows
608+
private int getSize() {
609+
var sizeField = HashTable.class.getDeclaredField("size");
610+
sizeField.setAccessible(true);
611+
return sizeField.getInt(hashTable);
612+
}
613+
588614
private String tableToString(Object[] table) {
589615
StringBuilder result = new StringBuilder();
590616
var n = table.length;

0 commit comments

Comments
 (0)