UNPKG

12.2 kBJavaScriptView Raw
1import test from 'ava'
2import Chance from '../chance.js'
3import _ from 'lodash'
4
5const chance = new Chance()
6
7const timeout = (seconds) => {
8 new Promise((resolve, reject) => {
9 setTimeout(() => resolve(), seconds)
10 })
11}
12
13test('bool() returns a random boolean', t => {
14 let bool = chance.bool()
15 t.is(typeof bool, 'boolean')
16})
17
18test('bool() is within the bounds of what we would call random', t => {
19 let trueCount = 0;
20 _.times(1000, () => {
21 if (chance.bool()) {
22 trueCount++
23 }
24 })
25
26 // The probability of this test failing is approximately 4.09e-86.
27 // So, in theory, it could give a false negative, but the sun will
28 // probably die long before that happens.
29
30 t.true((trueCount > 200) && (trueCount < 800))
31})
32
33test('bool() takes and obeys likelihood', t => {
34 let trueCount = 0
35 _.times(1000, () => {
36 if (chance.bool({ likelihood: 30 })) {
37 trueCount++
38 }
39 })
40
41 // Expect it to average around 300
42 t.true((trueCount > 200) && (trueCount < 400))
43
44 trueCount = 0
45 _.times(1000, () => {
46 if (chance.bool({ likelihood: 99 })) {
47 trueCount++
48 }
49 })
50
51 // Expect it to average at 990
52 t.true(trueCount > 900)
53})
54
55test('bool() throws an error if likelihood < 0 or > 100', t => {
56 const fn1 = () => chance.bool({likelihood: -23})
57 t.throws(fn1, RangeError)
58 const fn2 = () => chance.bool({likelihood: 7933})
59 t.throws(fn2, RangeError)
60})
61
62test('Chance() null works', async t => {
63 t.plan(1)
64
65 let chance1 = Chance(null)
66 // Wait 5 ms before creating chance2 else sometimes they happen on the same
67 // tick and end up with the same seed!
68 await timeout(5)
69 let chance2 = Chance(null)
70 t.not(chance1.random(), chance2.random())
71})
72
73test('Chance() does return differing results if differing seeds provided', t => {
74 let chance1 = new Chance(12345)
75 let chance2 = new Chance(54321)
76 t.not(chance1.random(), chance2.random())
77})
78
79test('Chance() does not return repeatable results if no seed provided', async t => {
80 t.plan(1000)
81 let chance1 = new Chance()
82 await timeout(5)
83 let chance2 = new Chance()
84 _.times(1000, () => {
85 t.not(chance1.random(), chance2.random())
86 })
87})
88
89test('Chance() returns repeatable results if seed provided on the Chance object', t => {
90 let seed = new Date().getTime()
91 let chance1 = new Chance(seed)
92 let chance2 = new Chance(seed)
93
94 _.times(1000, () => {
95 t.is(chance1.random(), chance2.random())
96 })
97})
98
99test('Chance() returns repeatable results if a string is provided as a seed', t => {
100 let seed = "foo"
101 let chance1 = new Chance(seed)
102 let chance2 = new Chance(seed)
103
104 _.times(1000, () => {
105 t.is(chance1.random(), chance2.random())
106 })
107})
108
109test('Chance() returns different results if two different strings are provided', t => {
110 let chance1 = new Chance("foo")
111 let chance2 = new Chance("baz")
112
113 _.times(1000, () => {
114 t.not(chance1.random(), chance2.random())
115 })
116})
117
118test('Chance() returns different results if two different strings are provided redux', t => {
119 // Credit to @dan-tilley for noticing this flaw in the old seed
120 let chance1 = new Chance("abe")
121 let chance2 = new Chance("acc")
122
123 _.times(1000, () => {
124 t.not(chance1.random(), chance2.random())
125 })
126})
127
128test('Chance() returns different results if multiple arguments are provided', t => {
129 let seed = new Date().getTime()
130 let chance1 = new Chance(seed, "foo")
131 let chance2 = new Chance(seed, "bar")
132
133 _.times(1000, () => {
134 t.not(chance1.random(), chance2.random())
135 })
136})
137
138test('Chance() will take an arbitrary function for the seed and use it', t => {
139 let chance = new Chance(() => 123)
140
141 _.times(1000, () => {
142 t.is(chance.random(), 123)
143 })
144})
145
146test('character() returns a character', t => {
147 let char = chance.character()
148 t.is(typeof char, 'string')
149 t.is(char.length, 1)
150})
151
152test('character() pulls only from pool, when specified', t => {
153 _.times(1000, () => {
154 let char = chance.character({ pool: 'abcde' })
155 t.true(/[abcde]/.test(char))
156 })
157})
158
159test('character() allows only alpha', t => {
160 _.times(1000, () => {
161 let char = chance.character({ alpha: true })
162 t.true(/[a-zA-Z]/.test(char))
163 })
164})
165
166test('character() throws when specifying both alpha and symbols', t => {
167 const fn = () => chance.character({alpha: true, symbols: true})
168 t.throws(fn, 'Chance: Cannot specify both alpha and symbols.')
169})
170
171test('character() obeys upper case', t => {
172 _.times(1000, () => {
173 let char = chance.character({ alpha: true, casing: 'upper' })
174 t.true(/[A-Z]/.test(char))
175 })
176})
177
178test('character() obeys lower case', t => {
179 _.times(1000, () => {
180 let char = chance.character({ alpha: true, casing: 'lower' })
181 t.true(/[a-z]/.test(char))
182 })
183})
184
185test('floating() returns a random floating', t => {
186 t.is(typeof chance.floating(), 'number')
187})
188
189test('floating() can take both a max and min and obey them both', t => {
190 _.times(1000, () => {
191 let floating = chance.floating({ min: 90, max: 100 })
192 t.true(floating > 89)
193 t.true(floating < 101)
194 })
195})
196
197test('floating() will not take fixed + min that would be out of range', t => {
198 const fn = () => chance.floating({ fixed: 13, min: -9007199254740992 })
199 t.throws(fn, "Chance: Min specified is out of range with fixed. Min should be, at least, -900.7199254740992")
200})
201
202test('floating() will not take fixed + max that would be out of range', t => {
203 const fn = () => chance.floating({ fixed: 13, max: 9007199254740992 })
204 t.throws(fn, "Chance: Max specified is out of range with fixed. Max should be, at most, 900.7199254740992")
205})
206
207test('floating() obeys the fixed parameter, when present', t => {
208 _.times(1000, () => {
209 let floating = chance.floating({ fixed: 4 })
210 let decimals = floating.toString().split('.')[1] ? floating.toString().split('.')[1] : ''
211 t.true(decimals.length < 5)
212 })
213})
214
215test('floating() can take fixed and obey it', t => {
216 _.times(1000, () => {
217 let floating = chance.floating({ fixed: 3 })
218 let parsed = parseFloat(floating.toFixed(3))
219 t.is(floating, parsed)
220 })
221})
222
223test('floating() will not take both fixed and precision', t => {
224 const fn = () => chance.floating({fixed: 2, precision: 8})
225 t.throws(fn, 'Chance: Cannot specify both fixed and precision.')
226})
227
228test('get() works as expected', t => {
229 let data = chance.get('lastNames')
230 t.true(typeof data === 'object')
231})
232
233test('hex() works as expected', t => {
234 _.times(1000, () => {
235 t.true(/[0-9a-f]/.test(chance.hex()))
236 })
237})
238
239test('hex() can take Upper and obey it', t => {
240 _.times(1000, () => {
241 t.true(/[0-9A-F]/.test(chance.hex({ casing: 'upper' })))
242 })
243})
244
245test('integer() returns a random integer', t => {
246 t.is(typeof chance.integer(), 'number')
247})
248
249test('integer() is sometimes negative, sometimes positive', t => {
250 let positiveCount = 0
251 _.times(1000, () => {
252 if (chance.integer() > 0) {
253 positiveCount++
254 }
255 })
256
257 // Note: In very extreme circumstances this test may fail as, by its
258 // nature it's random. But it's a low enough percentage that I'm
259 // willing to accept it.
260 t.true((positiveCount > 200) && (positiveCount < 800))
261})
262
263test('integer() can take a zero min and obey it', t => {
264 _.times(1000, () => {
265 t.true(chance.integer({ min: 0 }) > 0)
266 })
267})
268
269test('integer() can take a negative min and obey it', t => {
270 _.times(1000, () => {
271 t.true(chance.integer({ min: -25 }) > -26)
272 })
273})
274
275test('integer() can take a negative min and max and obey both', t => {
276 _.times(1000, () => {
277 let integer = chance.integer({ min: -25, max: -1 })
278 t.true((integer > -26) && integer < 0)
279 })
280})
281
282test('integer() can take a min with absolute value less than max and return in range above', t => {
283 let count = 0
284 _.times(1000, () => {
285 // With a range this large we'd expect most values to be
286 // greater than 1 if this works correctly.
287 if (Math.abs(chance.integer({ min: -1, max: 1000000 })) < 2) {
288 count++
289 }
290 })
291 t.true(count < 900)
292})
293
294test('integer() throws an error when min > max', t => {
295 const fn = () => chance.integer({ min: 1000, max: 500 })
296 t.throws(fn, 'Chance: Min cannot be greater than Max.')
297})
298
299test('letter() returns a letter', t => {
300 _.times(1000, () => {
301 let letter = chance.letter()
302 t.is(typeof letter, 'string')
303 t.is(letter.length, 1)
304 t.true(letter.match(/[a-z]/) !== null)
305 })
306})
307
308test('letter() can take upper case', t => {
309 _.times(1000, () => {
310 let letter = chance.letter({ casing: 'upper' })
311 t.is(typeof letter, 'string')
312 t.is(letter.length, 1)
313 t.true(letter.match(/[A-Z]/) !== null)
314 })
315})
316
317test('natural() returns a random natural', t => {
318 t.is(typeof chance.natural(), 'number')
319})
320
321test('natural() throws an error if min < 0', t => {
322 const fn = () => chance.natural({ min: -23 })
323 t.throws(fn, 'Chance: Min cannot be less than zero.')
324})
325
326test('natural() is always positive or zero', t => {
327 let positiveCount = 0
328 _.times(1000, () => {
329 if (chance.natural() >= 0) {
330 positiveCount++
331 }
332 })
333 t.is(positiveCount, 1000)
334})
335
336test('natural() can take just a min and obey it', t => {
337 _.times(1000, () => {
338 t.true(chance.natural({ min: 9007199254740991 }) > 9007199254740990)
339 })
340})
341
342test('natural() can take just a max and obey it', t => {
343 _.times(1000, () => {
344 t.true(chance.natural({ max: 100 }) < 101)
345 })
346})
347
348test('natural() can take both a max and min and obey them both', t => {
349 _.times(1000, () => {
350 let natural = chance.natural({ min: 90, max: 100 })
351 t.true(natural > 89)
352 t.true(natural < 101)
353 })
354})
355
356test('natural() works with both bounds 0', t => {
357 _.times(1000, () => {
358 t.is(chance.natural({ min: 0, max: 0 }), 0)
359 })
360})
361
362test('natural() respects numerals', t => {
363 _.times(1000, () => {
364 let natural = chance.natural({ numerals: 2 })
365 t.true(natural <= 99)
366 t.true(natural >= 10)
367 })
368})
369
370test('natural() throws an error if min > max', t => {
371 const fn = () => chance.natural({ min: 1000, max: 500 })
372 t.throws(fn, 'Chance: Min cannot be greater than Max.')
373})
374
375test('natural() throws an error if numerals is less than 1', t => {
376 const fn = () => chance.natural({ numerals: 0 })
377 t.throws(fn, 'Chance: Numerals cannot be less than one.')
378})
379
380test('set() works as expected', t => {
381 let cData = { lastNames: ['customName', 'testLast'] }
382 chance.set(cData)
383 let data = chance.get('lastNames')
384 t.true(_.isArray(data))
385 t.is(data.length, 2)
386})
387
388test('string() returns a string', t => {
389 t.is(typeof chance.string(), 'string')
390})
391
392test('string() obeys length, when specified', t => {
393 _.times(1000, () => {
394 let length = chance.natural({ min: 1, max: 25 })
395 t.is(chance.string({ length: length }).length, length)
396 })
397})
398
399test('string() throws error if length < 0', t => {
400 const fn = () => chance.string({ length: -23 })
401 t.throws(fn, 'Chance: Length cannot be less than zero.')
402})
403
404test('string() returns only letters with alpha', t => {
405 _.times(1000, () => {
406 let str = chance.string({ alpha: true })
407 t.true(/[a-zA-Z]+/.test(str))
408 })
409})
410
411test('string() obeys upper case', t => {
412 _.times(1000, () => {
413 let str = chance.string({ alpha: true, casing: 'upper' })
414 t.true(/[A-Z]+/.test(str))
415 })
416})
417
418test('string() obeys lower case', t => {
419 _.times(1000, () => {
420 let str = chance.string({ alpha: true, casing: 'lower' })
421 t.true(/[a-z]+/.test(str))
422 })
423})
424
425test('string() obeys symbol', t => {
426 _.times(1000, () => {
427 let str = chance.string({ symbols: true })
428 t.true(/[\!\@\#\$\%\^\&\*\(\)\[\]]+/.test(str))
429 })
430})