1
1
package com .bobocode .cs ;
2
2
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 ;
7
10
8
11
import java .lang .reflect .Field ;
9
12
import java .util .Arrays ;
12
15
import java .util .concurrent .ThreadLocalRandom ;
13
16
import java .util .stream .Collectors ;
14
17
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 ;
21
27
22
28
/**
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 */
28
32
@ TestClassOrder (OrderAnnotation .class )
29
33
@ DisplayName ("HashTable Test" )
30
34
class HashTableTest {
35
+
31
36
private HashTable <String , Integer > hashTable = new HashTable <>();
32
37
33
38
@ Nested
@@ -126,6 +131,7 @@ void nodeConstructorAcceptKeyValue() {
126
131
@ DisplayName ("2. HashTable fields Test" )
127
132
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
128
133
class HashTableFieldsTest {
134
+
129
135
@ Test
130
136
@ Order (1 )
131
137
@ DisplayName ("HastTable has a field 'table' which is an array of nodes" )
@@ -155,6 +161,7 @@ void sizeFieldExists() {
155
161
@ DisplayName ("3. HashTable constructors Test" )
156
162
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
157
163
class HashTableConstructorsTest {
164
+
158
165
@ Test
159
166
@ Order (1 )
160
167
@ SneakyThrows
@@ -198,6 +205,7 @@ void constructorWithTableCapacityWhenArgumentIsNegative() {
198
205
@ DisplayName ("4. Hash Function Test" )
199
206
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
200
207
class HashFunctionTest {
208
+
201
209
@ Test
202
210
@ Order (1 )
203
211
@ DisplayName ("calculateIndex returns the same value for the same key" )
@@ -221,8 +229,8 @@ void calculateIndexReturnDifferentValuesWheKeysAreDifferent() {
221
229
222
230
assertThat (indexSet )
223
231
.hasSizeGreaterThan (1 );
224
- }
225
-
232
+ }
233
+
226
234
@ Test
227
235
@ Order (3 )
228
236
@ DisplayName ("calculateIndex returns values in array bounds" )
@@ -235,7 +243,7 @@ void calculateIndexReturnIndexInArrayBounds() {
235
243
var indexes = keys .stream ()
236
244
.map (key -> HashTable .calculateIndex (key , arrayCapacity ))
237
245
.toList ();
238
-
246
+
239
247
assertThat (indexes )
240
248
.isNotEmpty ()
241
249
.allMatch (i -> i >= 0 && i < arrayCapacity );
@@ -262,19 +270,20 @@ class HashTableMethodsTest {
262
270
@ Test
263
271
@ SneakyThrows
264
272
@ 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 " )
266
274
void putWhenTableIsEmpty () {
267
275
var previousValue = hashTable .put ("madmax" , 833 );
268
276
269
277
var keyValueExists = checkKeyValueExists ("madmax" , 833 );
270
278
271
279
assertNull (previousValue );
272
280
assertTrue (keyValueExists );
281
+ assertEquals (1 , getSize ());
273
282
}
274
283
275
284
@ Test
276
285
@ 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" )
278
287
@ SneakyThrows
279
288
void putTwoElementsWithTheSameHashCode () {
280
289
var table = getInternalTable (hashTable );
@@ -290,11 +299,13 @@ void putTwoElementsWithTheSameHashCode() {
290
299
assertTrue (containsKeyValueA );
291
300
assertTrue (containsKeyValueB );
292
301
assertThat (bucketIndexA ).isEqualTo (bucketIndexB );
302
+ assertEquals (2 , getSize ());
293
303
}
294
304
295
305
@ Test
296
306
@ 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" )
298
309
void putElementWithTheSameKey () {
299
310
hashTable .put ("madmax" , 833 );
300
311
System .out .println (hashTable );
@@ -305,6 +316,7 @@ void putElementWithTheSameKey() {
305
316
306
317
assertThat (previousValue ).isEqualTo (833 );
307
318
assertTrue (containsNewValueByKey );
319
+ assertEquals (1 , getSize ());
308
320
}
309
321
310
322
@ Test
@@ -430,14 +442,15 @@ void isEmptyWhenThereIsNoElements() {
430
442
431
443
@ Test
432
444
@ 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" )
434
446
void remove () {
435
447
addToTable ("madmax" , 833 );
436
-
448
+ setSize ( 1 );
437
449
var result = hashTable .remove ("madmax" );
438
450
439
451
assertThat (result ).isEqualTo (833 );
440
452
assertFalse (checkKeyValueExists ("madmaxx" , 833 ));
453
+ assertEquals (0 , getSize ());
441
454
}
442
455
443
456
@ Test
@@ -451,34 +464,40 @@ void removeWhenKeyDoesNotExists() {
451
464
452
465
@ Test
453
466
@ 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 " )
455
468
void removeFromTheMiddleOfTheList () {
456
469
addToTable ("AaAa" , 843 );
457
470
addToTable ("BBBB" , 434 );
458
471
addToTable ("AaBB" , 587 );
459
472
473
+ var size = 3 ;
474
+ setSize (size );
460
475
var removedValue = hashTable .remove ("BBBB" );
461
476
462
477
assertTrue (checkKeyValueExists ("AaAa" , 843 ));
463
478
assertFalse (checkKeyExists ("BBBB" ));
464
479
assertTrue (checkKeyValueExists ("AaBB" , 587 ));
465
480
assertThat (removedValue ).isEqualTo (434 );
466
- }
467
-
481
+ assertEquals (size - 1 , getSize ());
482
+ }
483
+
468
484
@ Test
469
485
@ 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 " )
471
487
void removeFromTheEndOfTheList () {
472
488
addToTable ("AaAa" , 843 );
473
489
addToTable ("BBBB" , 434 );
474
490
addToTable ("AaBB" , 587 );
491
+ var size = 3 ;
492
+ setSize (size );
475
493
476
494
var removedValue = hashTable .remove ("AaBB" );
477
495
478
496
assertTrue (checkKeyValueExists ("AaAa" , 843 ));
479
497
assertTrue (checkKeyValueExists ("BBBB" , 434 ));
480
498
assertFalse (checkKeyExists ("AaBB" ));
481
499
assertThat (removedValue ).isEqualTo (587 );
500
+ assertEquals (2 , getSize ());
482
501
}
483
502
}
484
503
@@ -585,6 +604,13 @@ private void setSize(int size) {
585
604
sizeField .set (hashTable , size );
586
605
}
587
606
607
+ @ SneakyThrows
608
+ private int getSize () {
609
+ var sizeField = HashTable .class .getDeclaredField ("size" );
610
+ sizeField .setAccessible (true );
611
+ return sizeField .getInt (hashTable );
612
+ }
613
+
588
614
private String tableToString (Object [] table ) {
589
615
StringBuilder result = new StringBuilder ();
590
616
var n = table .length ;
0 commit comments