@@ -113,6 +113,18 @@ public void Add_IncreasesCount_WhenValueAlreadyExists()
113
113
Assert . That ( hashTable . Count , Is . EqualTo ( 2 ) ) ;
114
114
}
115
115
116
+ [ Test ]
117
+ public void Add_ThrowsException_OnCollision ( )
118
+ {
119
+ // Arrange
120
+ var hashTable = new HashTable < Collider , int > ( ) ;
121
+ hashTable . Add ( new Collider ( 1 ) , 1 ) ;
122
+
123
+
124
+ // Act & Assert
125
+ Assert . Throws < ArgumentException > ( ( ) => hashTable . Add ( new Collider ( 1 ) , 2 ) ) ;
126
+ }
127
+
116
128
[ Test ]
117
129
public void Remove_ThrowsException_WhenKeyIsNull ( )
118
130
{
@@ -154,12 +166,45 @@ public void Remove_DecreasesCount_WhenKeyExists()
154
166
public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist ( )
155
167
{
156
168
var hashTable = new HashTable < string , int > ( ) ;
157
-
158
169
hashTable . Remove ( "a" ) ;
159
170
160
171
Assert . That ( hashTable . Count , Is . EqualTo ( 0 ) ) ;
161
172
}
162
173
174
+ [ Test ]
175
+ public void Remove_TriggersResizeDown ( )
176
+ {
177
+ var hashTable = new HashTable < int , string > ( 4 ) ;
178
+ for ( var i = 1 ; i <= 50 ; i ++ )
179
+ {
180
+ hashTable . Add ( i , $ "Value{ i } ") ;
181
+ }
182
+
183
+ for ( var i = 1 ; i <= 40 ; i ++ )
184
+ {
185
+ hashTable . Remove ( i ) ;
186
+ }
187
+
188
+ Assert . That ( hashTable . Capacity , Is . EqualTo ( 40 ) ) ;
189
+ }
190
+
191
+ [ Test ]
192
+ public void Remove_TriggersResizeDown_MinimumOfDefaultCapacity ( )
193
+ {
194
+ var hashTable = new HashTable < int , string > ( 4 ) ;
195
+ for ( var i = 1 ; i <= 50 ; i ++ )
196
+ {
197
+ hashTable . Add ( i , $ "Value{ i } ") ;
198
+ }
199
+
200
+ for ( var i = 1 ; i <= 48 ; i ++ )
201
+ {
202
+ hashTable . Remove ( i ) ;
203
+ }
204
+
205
+ Assert . That ( hashTable . Capacity , Is . EqualTo ( 16 ) ) ;
206
+ }
207
+
163
208
[ Test ]
164
209
public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist ( )
165
210
{
@@ -234,6 +279,17 @@ public void Clear_RemovesAllElements()
234
279
Assert . That ( hashTable . ContainsKey ( "a" ) , Is . False ) ;
235
280
}
236
281
282
+ [ Test ]
283
+ public void Clear_ResetsTable ( )
284
+ {
285
+ var hashTable = new HashTable < int , string > ( ) ;
286
+ hashTable . Add ( 1 , "A" ) ;
287
+ hashTable . Clear ( ) ;
288
+ hashTable . Add ( 2 , "B" ) ;
289
+ Assert . That ( hashTable . Count , Is . EqualTo ( 1 ) ) ;
290
+ Assert . That ( hashTable [ 2 ] , Is . EqualTo ( "B" ) ) ;
291
+ }
292
+
237
293
[ Test ]
238
294
public void Resize_IncreasesCapacity ( )
239
295
{
@@ -313,6 +369,13 @@ public void Constructor_ThrowsException_WhenLoadFactorIsGreaterThanOne()
313
369
Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new HashTable < string , int > ( 4 , 2 ) ) ;
314
370
}
315
371
372
+ [ Test ]
373
+ public void Constructor_RoundsCapacityToPrime ( )
374
+ {
375
+ var hashTable = new HashTable < int , string > ( 17 ) ;
376
+ Assert . That ( hashTable . Capacity , Is . EqualTo ( 19 ) ) ;
377
+ }
378
+
316
379
[ Test ]
317
380
public void GetIndex_ThrowsException_WhenKeyIsNull ( )
318
381
{
@@ -388,6 +451,23 @@ public void Test_NegativeHashKey_ReturnsCorrectValue()
388
451
Assert . That ( hashTable [ new NegativeHashKey ( 1 ) ] , Is . EqualTo ( 1 ) ) ;
389
452
}
390
453
454
+ [ Test ]
455
+ public void Resize_HandlesNegativeHashCodeCorrectly ( )
456
+ {
457
+ // Arrange
458
+ var hashTable = new HashTable < NegativeHashKey , string > ( 2 ) ;
459
+
460
+ // Act
461
+ hashTable . Add ( new NegativeHashKey ( 1 ) , "A" ) ;
462
+ hashTable . Add ( new NegativeHashKey ( 2 ) , "B" ) ;
463
+ hashTable . Add ( new NegativeHashKey ( 3 ) , "C" ) ;
464
+
465
+ // Assert
466
+ Assert . That ( hashTable [ new NegativeHashKey ( 1 ) ] , Is . EqualTo ( "A" ) ) ;
467
+ Assert . That ( hashTable [ new NegativeHashKey ( 2 ) ] , Is . EqualTo ( "B" ) ) ;
468
+ Assert . That ( hashTable [ new NegativeHashKey ( 3 ) ] , Is . EqualTo ( "C" ) ) ;
469
+ }
470
+
391
471
[ Test ]
392
472
public void Add_ShouldTriggerResize_WhenThresholdExceeded ( )
393
473
{
@@ -396,14 +476,14 @@ public void Add_ShouldTriggerResize_WhenThresholdExceeded()
396
476
var hashTable = new HashTable < int , string > ( initialCapacity ) ;
397
477
398
478
// Act
399
- for ( int i = 1 ; i <= 4 ; i ++ ) // Start keys from 1 to avoid default(TKey) = 0 issue
479
+ for ( var i = 1 ; i <= 32 ; i ++ )
400
480
{
401
481
hashTable . Add ( i , $ "Value{ i } ") ;
402
482
}
403
483
404
484
// Assert
405
- hashTable . Capacity . Should ( ) . BeGreaterThan ( initialCapacity ) ; // Ensure resizing occurred
406
- hashTable . Count . Should ( ) . Be ( 4 ) ; // Verify count reflects number of added items
485
+ hashTable . Capacity . Should ( ) . BeGreaterThan ( initialCapacity ) ;
486
+ hashTable . Count . Should ( ) . Be ( 32 ) ;
407
487
}
408
488
409
489
@@ -473,23 +553,28 @@ public void Capacity_Increases_WhenResizeOccurs()
473
553
var initialCapacity = 4 ;
474
554
var hashTable = new HashTable < int , string > ( initialCapacity ) ;
475
555
476
- for ( int i = 1 ; i <= 5 ; i ++ )
556
+ for ( var i = 1 ; i <= 5 ; i ++ )
477
557
{
478
558
hashTable . Add ( i , $ "Value{ i } ") ;
479
559
}
480
560
481
561
hashTable . Capacity . Should ( ) . BeGreaterThan ( initialCapacity ) ;
482
562
}
483
- }
484
-
485
- public class NegativeHashKey
486
- {
487
- private readonly int id ;
488
563
489
- public NegativeHashKey ( int id )
564
+ [ Test ]
565
+ public void IndexerSet_Throws_KeyNotFound ( )
490
566
{
491
- this . id = id ;
567
+ // Arrange
568
+ var hashTable = new HashTable < int , string > ( ) ;
569
+
570
+ // Act & Assert
571
+ Assert . Throws < KeyNotFoundException > ( ( ) => hashTable [ 1 ] = "A" ) ;
492
572
}
573
+ }
574
+
575
+ public class NegativeHashKey ( int id )
576
+ {
577
+ private readonly int id = id ;
493
578
494
579
public override int GetHashCode ( )
495
580
{
@@ -506,3 +591,14 @@ public override bool Equals(object? obj)
506
591
return false ;
507
592
}
508
593
}
594
+
595
+ /// <summary>
596
+ /// Class to simulate hash collisions
597
+ /// </summary>
598
+ /// <param name="id">Id of this object</param>
599
+ public class Collider ( int id )
600
+ {
601
+ private readonly int id = id ;
602
+ public override int GetHashCode ( ) => 42 ; // Force all instances to collide
603
+ public override bool Equals ( object ? obj ) => obj is Collider other && other . id == id ;
604
+ }
0 commit comments