@@ -8,17 +8,13 @@ describe("RandomUtil", () => {
8
8
let mockLogger : any ;
9
9
10
10
beforeEach ( ( ) => {
11
- // Mock dependencies
12
11
mockCloner = {
13
12
clone : vi . fn ( ( obj ) => JSON . parse ( JSON . stringify ( obj ) ) ) ,
14
13
} ;
15
-
16
14
mockLogger = {
17
15
warning : vi . fn ( ) ,
18
16
info : vi . fn ( ) ,
19
17
} ;
20
-
21
- // Instantiate RandomUtil with mocked dependencies
22
18
randomUtil = new RandomUtil ( mockCloner , mockLogger ) ;
23
19
} ) ;
24
20
@@ -74,18 +70,6 @@ describe("RandomUtil", () => {
74
70
expect ( result ) . toBeLessThanOrEqual ( Math . floor ( max ) ) ;
75
71
expect ( Number . isInteger ( result ) ) . toBe ( true ) ;
76
72
} ) ;
77
-
78
- it ( "should return predictable result when Math.random is mocked" , ( ) => {
79
- // Mock Math.random to always return 0.5
80
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.5 ) ;
81
-
82
- const min = 1 ;
83
- const max = 5 ;
84
- const expected = Math . floor ( 0.5 * ( Math . floor ( max ) - Math . ceil ( min ) + 1 ) + Math . ceil ( min ) ) ;
85
- const result = randomUtil . getInt ( min , max ) ;
86
-
87
- expect ( result ) . toBe ( expected ) ;
88
- } ) ;
89
73
} ) ;
90
74
91
75
describe ( "getIntEx" , ( ) => {
@@ -112,28 +96,6 @@ describe("RandomUtil", () => {
112
96
113
97
expect ( result ) . toBe ( 1 ) ;
114
98
} ) ;
115
-
116
- it ( "should return predictable result when Math.random is mocked" , ( ) => {
117
- // Mock Math.random to always return 0.5
118
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.5 ) ;
119
-
120
- const max = 10 ;
121
- // Expected calculation: Math.floor(0.5 * (10 - 2) + 1) = Math.floor(0.5 * 8 + 1) = Math.floor(5) = 5
122
- const expected = 5 ;
123
- const result = randomUtil . getIntEx ( max ) ;
124
-
125
- expect ( result ) . toBe ( expected ) ;
126
- } ) ;
127
-
128
- it ( "should return 1 when max is 2 (edge case with Math.random mocked)" , ( ) => {
129
- // Mock Math.random to always return 0.99
130
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.99 ) ;
131
-
132
- const max = 2 ;
133
- const result = randomUtil . getIntEx ( max ) ;
134
-
135
- expect ( result ) . toBe ( 1 ) ;
136
- } ) ;
137
99
} ) ;
138
100
139
101
describe ( "getFloat" , ( ) => {
@@ -162,17 +124,6 @@ describe("RandomUtil", () => {
162
124
163
125
expect ( result ) . toBe ( min ) ;
164
126
} ) ;
165
-
166
- it ( "should return a predictable value when Math.random is mocked" , ( ) => {
167
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.5 ) ;
168
-
169
- const min = 2.0 ;
170
- const max = 4.0 ;
171
- const expected = 3.0 ;
172
- const result = randomUtil . getFloat ( min , max ) ;
173
-
174
- expect ( result ) . toBe ( expected ) ;
175
- } ) ;
176
127
} ) ;
177
128
178
129
describe ( "getBool" , ( ) => {
@@ -182,13 +133,13 @@ describe("RandomUtil", () => {
182
133
} ) ;
183
134
184
135
it ( "should return true when Math.random is less than 0.5" , ( ) => {
185
- vi . spyOn ( Math , "random " ) . mockReturnValue ( 0.3 ) ;
136
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockReturnValue ( 0.4 ) ;
186
137
const result = randomUtil . getBool ( ) ;
187
138
expect ( result ) . toBe ( true ) ;
188
139
} ) ;
189
140
190
- it ( "should return false when Math.random is greater than or equal to 0.5" , ( ) => {
191
- vi . spyOn ( Math , "random " ) . mockReturnValue ( 0.5 ) ;
141
+ it ( "should return false when getSecureRandomNumber returns 0.5" , ( ) => {
142
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockReturnValue ( 0.5 ) ;
192
143
const result = randomUtil . getBool ( ) ;
193
144
expect ( result ) . toBe ( false ) ;
194
145
} ) ;
@@ -332,6 +283,20 @@ describe("RandomUtil", () => {
332
283
expect ( result ) . toBe ( "onlyKey" ) ;
333
284
} ) ;
334
285
286
+ it ( "should handle empty objects" , ( ) => {
287
+ const obj = { } ;
288
+ const result = randomUtil . getKey ( obj ) ;
289
+
290
+ expect ( result ) . toBeUndefined ( ) ;
291
+ } ) ;
292
+
293
+ it ( "should handle objects with integer keys" , ( ) => {
294
+ const obj = { 1 : "a" , 2 : "b" , 3 : "c" } ;
295
+ const result = randomUtil . getKey ( obj ) ;
296
+
297
+ expect ( Object . keys ( obj ) ) . toContain ( result ) ;
298
+ } ) ;
299
+
335
300
it ( "should return predictable key when getArrayValue is mocked" , ( ) => {
336
301
vi . spyOn ( randomUtil , "getArrayValue" ) . mockReturnValue ( "b" ) ;
337
302
@@ -382,7 +347,7 @@ describe("RandomUtil", () => {
382
347
383
348
it ( "should handle high attempt counts" , ( ) => {
384
349
let callCount = 0 ;
385
- vi . spyOn ( Math , "random " ) . mockImplementation ( ( ) => {
350
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockImplementation ( ( ) => {
386
351
callCount ++ ;
387
352
// Alternate between u and v
388
353
if ( callCount % 2 === 1 ) {
@@ -410,7 +375,7 @@ describe("RandomUtil", () => {
410
375
411
376
it ( "should return a fallback value after many attempts" , ( ) => {
412
377
let callCount = 0 ;
413
- vi . spyOn ( Math , "random " ) . mockImplementation ( ( ) => {
378
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockImplementation ( ( ) => {
414
379
// Alternate between u and v
415
380
const value = callCount % 2 === 0 ? 0.0000001 : 0.5 ;
416
381
callCount ++ ;
@@ -456,16 +421,6 @@ describe("RandomUtil", () => {
456
421
expect ( result ) . toBeGreaterThanOrEqual ( low ) ;
457
422
expect ( result ) . toBeLessThan ( high ) ;
458
423
} ) ;
459
-
460
- it ( "should return predictable result when Math.random is mocked" , ( ) => {
461
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.5 ) ;
462
-
463
- const low = 0 ;
464
- const high = 10 ;
465
- const result = randomUtil . randInt ( low , high ) ;
466
-
467
- expect ( result ) . toBe ( 5 ) ;
468
- } ) ;
469
424
} ) ;
470
425
471
426
describe ( "drawRandomFromList" , ( ) => {
@@ -541,6 +496,26 @@ describe("RandomUtil", () => {
541
496
expect ( new Set ( result ) . size ) . toBe ( count ) ;
542
497
} ) ;
543
498
499
+ it ( "should handle single-key dictionaries" , ( ) => {
500
+ const dict = { onlyKey : 1 } ;
501
+ const count = 2 ;
502
+ const result = randomUtil . drawRandomFromDict ( dict , count , false ) ;
503
+
504
+ expect ( result . length ) . toBe ( 1 ) ;
505
+ expect ( result ) . toEqual ( [ "onlyKey" ] ) ;
506
+ } ) ;
507
+
508
+ it ( "should handle dictionaries with integer keys" , ( ) => {
509
+ const dict = { 1 : "a" , 2 : "b" , 3 : "c" } ;
510
+ const count = 2 ;
511
+ const result = randomUtil . drawRandomFromDict ( dict , count , false ) ;
512
+
513
+ expect ( result . length ) . toBe ( count ) ;
514
+ for ( const key of result ) {
515
+ expect ( Object . keys ( dict ) ) . toContain ( key ) ;
516
+ }
517
+ } ) ;
518
+
544
519
it ( "should handle count greater than number of keys without replacement" , ( ) => {
545
520
const dict = { a : 1 , b : 2 } ;
546
521
const count = 3 ;
@@ -599,13 +574,24 @@ describe("RandomUtil", () => {
599
574
expect ( mockLogger . info ) . toHaveBeenCalledWith ( `min -> ${ min } ; max -> ${ max } ; shift -> ${ shift } ` ) ;
600
575
} ) ;
601
576
602
- it ( "should return predictable result when gaussianRandom is mocked" , ( ) => {
603
- vi . spyOn ( Math , "random " ) . mockReturnValue ( 0.5 ) ;
577
+ it ( "should return predictable result when getSecureRandomNumber is mocked" , ( ) => {
578
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockReturnValue ( 0.5 ) ;
604
579
605
580
const min = 1 ;
606
581
const max = 10 ;
607
582
const shift = 0 ;
608
- const n = 1 ;
583
+ const n = 2 ; // n affects how many times getSecureRandomNumber is summed/averaged
584
+
585
+ // With getSecureRandomNumber always returning 0.5,
586
+ // gaussianRandom(n) = 0.5 no matter what
587
+ // boundedGaussian(start, end, n) = round(start + 0.5 * (end - start + 1))
588
+
589
+ // For shift = 0:
590
+ // biasedMin = min = 1
591
+ // biasedMax = max = 10
592
+ // boundedGaussian(1, 10, 2) = round(1 + 0.5*(10 - 1 + 1)) = round(1 + 0.5*10) = round(1+5) = 6
593
+
594
+ // The loop ensures num is within [min, max], and since 6 is within [1,10], it returns 6 immediately.
609
595
const result = randomUtil . getBiasedRandomNumber ( min , max , shift , n ) ;
610
596
611
597
expect ( result ) . toBe ( 6 ) ;
@@ -635,44 +621,41 @@ describe("RandomUtil", () => {
635
621
636
622
expect ( shuffled ) . toEqual ( [ 1 ] ) ;
637
623
} ) ;
638
-
639
- it ( "should produce predictable shuffle when Math.random is mocked" , ( ) => {
640
- const array = [ 1 , 2 , 3 , 4 , 5 ] ;
641
- vi . spyOn ( Math , "random" ) . mockReturnValue ( 0.5 ) ;
642
-
643
- const shuffled = randomUtil . shuffle ( [ ...array ] ) ;
644
-
645
- expect ( shuffled ) . toEqual ( [ 1 , 4 , 2 , 5 , 3 ] ) ;
646
- } ) ;
647
624
} ) ;
648
625
649
626
describe ( "rollForChanceProbability" , ( ) => {
650
627
it ( "should return true when rolled chance is less than or equal to probabilityChance" , ( ) => {
651
- vi . spyOn ( randomUtil , "getInt " ) . mockReturnValue ( 4999 ) ;
628
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockReturnValue ( 0.5 ) ;
652
629
653
- const probabilityChance = 0.5 ;
630
+ const probabilityChance = 0.6 ;
654
631
const result = randomUtil . rollForChanceProbability ( probabilityChance ) ;
655
632
656
633
expect ( result ) . toBe ( true ) ;
657
634
} ) ;
658
635
659
636
it ( "should return false when rolled chance is greater than probabilityChance" , ( ) => {
660
- vi . spyOn ( randomUtil , "getInt " ) . mockReturnValue ( 5001 ) ;
637
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber " ) . mockReturnValue ( 0.7 ) ;
661
638
662
- const probabilityChance = 0.5 ;
639
+ const probabilityChance = 0.6 ;
663
640
const result = randomUtil . rollForChanceProbability ( probabilityChance ) ;
664
641
665
642
expect ( result ) . toBe ( false ) ;
666
643
} ) ;
667
644
668
645
it ( "should handle probabilityChance of 0" , ( ) => {
669
- const result = randomUtil . rollForChanceProbability ( 0 ) ;
646
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber" ) . mockReturnValue ( 0.1 ) ;
647
+
648
+ const probabilityChance = 0 ;
649
+ const result = randomUtil . rollForChanceProbability ( probabilityChance ) ;
670
650
671
651
expect ( result ) . toBe ( false ) ;
672
652
} ) ;
673
653
674
654
it ( "should handle probabilityChance of 1" , ( ) => {
675
- const result = randomUtil . rollForChanceProbability ( 1 ) ;
655
+ vi . spyOn ( randomUtil as any , "getSecureRandomNumber" ) . mockReturnValue ( 0.99 ) ;
656
+
657
+ const probabilityChance = 1 ;
658
+ const result = randomUtil . rollForChanceProbability ( probabilityChance ) ;
676
659
677
660
expect ( result ) . toBe ( true ) ;
678
661
} ) ;
0 commit comments