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
29
* A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used
28
34
@ TestClassOrder (OrderAnnotation .class )
29
35
@ DisplayName ("HashTable Test" )
30
36
class HashTableTest {
37
+
31
38
private HashTable <String , Integer > hashTable = new HashTable <>();
32
39
33
40
@ Nested
@@ -126,6 +133,7 @@ void nodeConstructorAcceptKeyValue() {
126
133
@ DisplayName ("2. HashTable fields Test" )
127
134
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
128
135
class HashTableFieldsTest {
136
+
129
137
@ Test
130
138
@ Order (1 )
131
139
@ DisplayName ("HastTable has a field 'table' which is an array of nodes" )
@@ -155,6 +163,7 @@ void sizeFieldExists() {
155
163
@ DisplayName ("3. HashTable constructors Test" )
156
164
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
157
165
class HashTableConstructorsTest {
166
+
158
167
@ Test
159
168
@ Order (1 )
160
169
@ SneakyThrows
@@ -198,6 +207,7 @@ void constructorWithTableCapacityWhenArgumentIsNegative() {
198
207
@ DisplayName ("4. Hash Function Test" )
199
208
@ TestMethodOrder (MethodOrderer .OrderAnnotation .class )
200
209
class HashFunctionTest {
210
+
201
211
@ Test
202
212
@ Order (1 )
203
213
@ DisplayName ("calculateIndex returns the same value for the same key" )
@@ -221,8 +231,8 @@ void calculateIndexReturnDifferentValuesWheKeysAreDifferent() {
221
231
222
232
assertThat (indexSet )
223
233
.hasSizeGreaterThan (1 );
224
- }
225
-
234
+ }
235
+
226
236
@ Test
227
237
@ Order (3 )
228
238
@ DisplayName ("calculateIndex returns values in array bounds" )
@@ -235,7 +245,7 @@ void calculateIndexReturnIndexInArrayBounds() {
235
245
var indexes = keys .stream ()
236
246
.map (key -> HashTable .calculateIndex (key , arrayCapacity ))
237
247
.toList ();
238
-
248
+
239
249
assertThat (indexes )
240
250
.isNotEmpty ()
241
251
.allMatch (i -> i >= 0 && i < arrayCapacity );
@@ -262,19 +272,20 @@ class HashTableMethodsTest {
262
272
@ Test
263
273
@ SneakyThrows
264
274
@ Order (1 )
265
- @ DisplayName ("put creates new entry and returns null when the table is empty" )
275
+ @ DisplayName ("put creates new entry and returns null when the table is empty, should increase the table size " )
266
276
void putWhenTableIsEmpty () {
267
277
var previousValue = hashTable .put ("madmax" , 833 );
268
278
269
279
var keyValueExists = checkKeyValueExists ("madmax" , 833 );
270
280
271
281
assertNull (previousValue );
272
282
assertTrue (keyValueExists );
283
+ assertEquals (1 , getSize ());
273
284
}
274
285
275
286
@ Test
276
287
@ Order (2 )
277
- @ DisplayName ("put elements adds entry to to the same bucket when the hash code is the same" )
288
+ @ DisplayName ("put elements adds entry to the same bucket and increases table size when the hash code is the same" )
278
289
@ SneakyThrows
279
290
void putTwoElementsWithTheSameHashCode () {
280
291
var table = getInternalTable (hashTable );
@@ -290,11 +301,13 @@ void putTwoElementsWithTheSameHashCode() {
290
301
assertTrue (containsKeyValueA );
291
302
assertTrue (containsKeyValueB );
292
303
assertThat (bucketIndexA ).isEqualTo (bucketIndexB );
304
+ assertEquals (2 , getSize ());
293
305
}
294
306
295
307
@ Test
296
308
@ Order (3 )
297
- @ DisplayName ("put element updates the value and returns the previous one when key is the same" )
309
+ @ DisplayName (
310
+ "put element updates the value and returns the previous one when key is the same, should not increase table size" )
298
311
void putElementWithTheSameKey () {
299
312
hashTable .put ("madmax" , 833 );
300
313
System .out .println (hashTable );
@@ -305,6 +318,7 @@ void putElementWithTheSameKey() {
305
318
306
319
assertThat (previousValue ).isEqualTo (833 );
307
320
assertTrue (containsNewValueByKey );
321
+ assertEquals (1 , getSize ());
308
322
}
309
323
310
324
@ Test
@@ -430,14 +444,15 @@ void isEmptyWhenThereIsNoElements() {
430
444
431
445
@ Test
432
446
@ Order (13 )
433
- @ DisplayName ("remove deletes the entry and returns a value" )
447
+ @ DisplayName ("remove deletes the entry, decreases table size and returns a value" )
434
448
void remove () {
435
449
addToTable ("madmax" , 833 );
436
-
450
+ setSize ( 1 );
437
451
var result = hashTable .remove ("madmax" );
438
452
439
453
assertThat (result ).isEqualTo (833 );
440
454
assertFalse (checkKeyValueExists ("madmaxx" , 833 ));
455
+ assertEquals (0 , getSize ());
441
456
}
442
457
443
458
@ Test
@@ -451,34 +466,40 @@ void removeWhenKeyDoesNotExists() {
451
466
452
467
@ Test
453
468
@ Order (15 )
454
- @ DisplayName ("remove deletes the element when it's in the middle of the list" )
469
+ @ DisplayName ("remove deletes the element when it's in the middle of the list and decreases the size of table " )
455
470
void removeFromTheMiddleOfTheList () {
456
471
addToTable ("AaAa" , 843 );
457
472
addToTable ("BBBB" , 434 );
458
473
addToTable ("AaBB" , 587 );
459
474
475
+ var size = 3 ;
476
+ setSize (size );
460
477
var removedValue = hashTable .remove ("BBBB" );
461
478
462
479
assertTrue (checkKeyValueExists ("AaAa" , 843 ));
463
480
assertFalse (checkKeyExists ("BBBB" ));
464
481
assertTrue (checkKeyValueExists ("AaBB" , 587 ));
465
482
assertThat (removedValue ).isEqualTo (434 );
466
- }
467
-
483
+ assertEquals (size - 1 , getSize ());
484
+ }
485
+
468
486
@ Test
469
487
@ Order (16 )
470
- @ DisplayName ("remove deletes the element when it's in the end of the list" )
488
+ @ DisplayName ("remove deletes the element when it's in the end of the list and decreases the size of table " )
471
489
void removeFromTheEndOfTheList () {
472
490
addToTable ("AaAa" , 843 );
473
491
addToTable ("BBBB" , 434 );
474
492
addToTable ("AaBB" , 587 );
493
+ var size = 3 ;
494
+ setSize (size );
475
495
476
496
var removedValue = hashTable .remove ("AaBB" );
477
497
478
498
assertTrue (checkKeyValueExists ("AaAa" , 843 ));
479
499
assertTrue (checkKeyValueExists ("BBBB" , 434 ));
480
500
assertFalse (checkKeyExists ("AaBB" ));
481
501
assertThat (removedValue ).isEqualTo (587 );
502
+ assertEquals (2 , getSize ());
482
503
}
483
504
}
484
505
@@ -585,6 +606,13 @@ private void setSize(int size) {
585
606
sizeField .set (hashTable , size );
586
607
}
587
608
609
+ @ SneakyThrows
610
+ private int getSize () {
611
+ var sizeField = HashTable .class .getDeclaredField ("size" );
612
+ sizeField .setAccessible (true );
613
+ return sizeField .getInt (hashTable );
614
+ }
615
+
588
616
private String tableToString (Object [] table ) {
589
617
StringBuilder result = new StringBuilder ();
590
618
var n = table .length ;
0 commit comments