1 | import test from 'ava'
|
2 | import Chance from '../chance.js'
|
3 | import _ from 'lodash'
|
4 |
|
5 | const chance = new Chance()
|
6 |
|
7 | const timeout = (seconds) => {
|
8 | new Promise((resolve, reject) => {
|
9 | setTimeout(() => resolve(), seconds)
|
10 | })
|
11 | }
|
12 |
|
13 | test('bool() returns a random boolean', t => {
|
14 | let bool = chance.bool()
|
15 | t.is(typeof bool, 'boolean')
|
16 | })
|
17 |
|
18 | test('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 |
|
27 |
|
28 |
|
29 |
|
30 | t.true((trueCount > 200) && (trueCount < 800))
|
31 | })
|
32 |
|
33 | test('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 |
|
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 |
|
52 | t.true(trueCount > 900)
|
53 | })
|
54 |
|
55 | test('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 |
|
62 | test('Chance() null works', async t => {
|
63 | t.plan(1)
|
64 |
|
65 | let chance1 = Chance(null)
|
66 |
|
67 |
|
68 | await timeout(5)
|
69 | let chance2 = Chance(null)
|
70 | t.not(chance1.random(), chance2.random())
|
71 | })
|
72 |
|
73 | test('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 |
|
79 | test('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 |
|
89 | test('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 |
|
99 | test('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 |
|
109 | test('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 |
|
118 | test('Chance() returns different results if two different strings are provided redux', t => {
|
119 |
|
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 |
|
128 | test('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 |
|
138 | test('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 |
|
146 | test('character() returns a character', t => {
|
147 | let char = chance.character()
|
148 | t.is(typeof char, 'string')
|
149 | t.is(char.length, 1)
|
150 | })
|
151 |
|
152 | test('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 |
|
159 | test('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 |
|
166 | test('character() allows only alphanumeric', t => {
|
167 | _.times(1000, () => {
|
168 | let char = chance.character({ alpha: true, numeric: true })
|
169 | t.true(/[a-zA-Z0-9]/.test(char))
|
170 | })
|
171 | })
|
172 |
|
173 | test('character() obeys upper case', t => {
|
174 | _.times(1000, () => {
|
175 | let char = chance.character({ alpha: true, casing: 'upper' })
|
176 | t.true(/[A-Z]/.test(char))
|
177 | })
|
178 | })
|
179 |
|
180 | test('character() obeys lower case', t => {
|
181 | _.times(1000, () => {
|
182 | let char = chance.character({ alpha: true, casing: 'lower' })
|
183 | t.true(/[a-z]/.test(char))
|
184 | })
|
185 | })
|
186 |
|
187 | test('floating() returns a random floating', t => {
|
188 | t.is(typeof chance.floating(), 'number')
|
189 | })
|
190 |
|
191 | test('floating() can take both a max and min and obey them both', t => {
|
192 | _.times(1000, () => {
|
193 | let floating = chance.floating({ min: 90, max: 100 })
|
194 | t.true(floating > 89)
|
195 | t.true(floating < 101)
|
196 | })
|
197 | })
|
198 |
|
199 | test('floating() will not take fixed + min that would be out of range', t => {
|
200 | const fn = () => chance.floating({ fixed: 13, min: -9007199254740992 })
|
201 | t.throws(fn, "Chance: Min specified is out of range with fixed. Min should be, at least, -900.7199254740992")
|
202 | })
|
203 |
|
204 | test('floating() will not take fixed + max that would be out of range', t => {
|
205 | const fn = () => chance.floating({ fixed: 13, max: 9007199254740992 })
|
206 | t.throws(fn, "Chance: Max specified is out of range with fixed. Max should be, at most, 900.7199254740992")
|
207 | })
|
208 |
|
209 | test('floating() obeys the fixed parameter, when present', t => {
|
210 | _.times(1000, () => {
|
211 | let floating = chance.floating({ fixed: 4 })
|
212 | let decimals = floating.toString().split('.')[1] ? floating.toString().split('.')[1] : ''
|
213 | t.true(decimals.length < 5)
|
214 | })
|
215 | })
|
216 |
|
217 | test('floating() can take fixed and obey it', t => {
|
218 | _.times(1000, () => {
|
219 | let floating = chance.floating({ fixed: 3 })
|
220 | let parsed = parseFloat(floating.toFixed(3))
|
221 | t.is(floating, parsed)
|
222 | })
|
223 | })
|
224 |
|
225 | test('floating() will not take both fixed and precision', t => {
|
226 | const fn = () => chance.floating({fixed: 2, precision: 8})
|
227 | t.throws(fn, 'Chance: Cannot specify both fixed and precision.')
|
228 | })
|
229 |
|
230 | test('get() works as expected', t => {
|
231 | let data = chance.get('lastNames')
|
232 | t.true(typeof data === 'object')
|
233 | })
|
234 |
|
235 | test('hex() works as expected', t => {
|
236 | _.times(1000, () => {
|
237 | t.true(/[0-9a-f]/.test(chance.hex()))
|
238 | })
|
239 | })
|
240 |
|
241 | test('hex() can take Upper and obey it', t => {
|
242 | _.times(1000, () => {
|
243 | t.true(/[0-9A-F]/.test(chance.hex({ casing: 'upper' })))
|
244 | })
|
245 | })
|
246 |
|
247 | test('integer() returns a random integer', t => {
|
248 | t.is(typeof chance.integer(), 'number')
|
249 | })
|
250 |
|
251 | test('integer() is sometimes negative, sometimes positive', t => {
|
252 | let positiveCount = 0
|
253 | _.times(1000, () => {
|
254 | if (chance.integer() > 0) {
|
255 | positiveCount++
|
256 | }
|
257 | })
|
258 |
|
259 |
|
260 |
|
261 |
|
262 | t.true((positiveCount > 200) && (positiveCount < 800))
|
263 | })
|
264 |
|
265 | test('integer() can take a zero min and obey it', t => {
|
266 | _.times(1000, () => {
|
267 | t.true(chance.integer({ min: 0 }) > 0)
|
268 | })
|
269 | })
|
270 |
|
271 | test('integer() can take a negative min and obey it', t => {
|
272 | _.times(1000, () => {
|
273 | t.true(chance.integer({ min: -25 }) > -26)
|
274 | })
|
275 | })
|
276 |
|
277 | test('integer() can take a negative min and max and obey both', t => {
|
278 | _.times(1000, () => {
|
279 | let integer = chance.integer({ min: -25, max: -1 })
|
280 | t.true((integer > -26) && integer < 0)
|
281 | })
|
282 | })
|
283 |
|
284 | test('integer() can take a min with absolute value less than max and return in range above', t => {
|
285 | let count = 0
|
286 | _.times(1000, () => {
|
287 |
|
288 |
|
289 | if (Math.abs(chance.integer({ min: -1, max: 1000000 })) < 2) {
|
290 | count++
|
291 | }
|
292 | })
|
293 | t.true(count < 900)
|
294 | })
|
295 |
|
296 | test('integer() throws an error when min > max', t => {
|
297 | const fn = () => chance.integer({ min: 1000, max: 500 })
|
298 | t.throws(fn, 'Chance: Min cannot be greater than Max.')
|
299 | })
|
300 |
|
301 | test('letter() returns a letter', t => {
|
302 | _.times(1000, () => {
|
303 | let letter = chance.letter()
|
304 | t.is(typeof letter, 'string')
|
305 | t.is(letter.length, 1)
|
306 | t.true(letter.match(/[a-z]/) !== null)
|
307 | })
|
308 | })
|
309 |
|
310 | test('letter() can take upper case', t => {
|
311 | _.times(1000, () => {
|
312 | let letter = chance.letter({ casing: 'upper' })
|
313 | t.is(typeof letter, 'string')
|
314 | t.is(letter.length, 1)
|
315 | t.true(letter.match(/[A-Z]/) !== null)
|
316 | })
|
317 | })
|
318 |
|
319 | test('natural() returns a random natural', t => {
|
320 | t.is(typeof chance.natural(), 'number')
|
321 | })
|
322 |
|
323 | test('natural() throws an error if min < 0', t => {
|
324 | const fn = () => chance.natural({ min: -23 })
|
325 | t.throws(fn, 'Chance: Min cannot be less than zero.')
|
326 | })
|
327 |
|
328 | test('natural() is always positive or zero', t => {
|
329 | let positiveCount = 0
|
330 | _.times(1000, () => {
|
331 | if (chance.natural() >= 0) {
|
332 | positiveCount++
|
333 | }
|
334 | })
|
335 | t.is(positiveCount, 1000)
|
336 | })
|
337 |
|
338 | test('natural() can take just a min and obey it', t => {
|
339 | _.times(1000, () => {
|
340 | t.true(chance.natural({ min: 9007199254740991 }) > 9007199254740990)
|
341 | })
|
342 | })
|
343 |
|
344 | test('natural() can take just a max and obey it', t => {
|
345 | _.times(1000, () => {
|
346 | t.true(chance.natural({ max: 100 }) < 101)
|
347 | })
|
348 | })
|
349 |
|
350 | test('natural() can take both a max and min and obey them both', t => {
|
351 | _.times(1000, () => {
|
352 | let natural = chance.natural({ min: 90, max: 100 })
|
353 | t.true(natural > 89)
|
354 | t.true(natural < 101)
|
355 | })
|
356 | })
|
357 |
|
358 | test('natural() works with both bounds 0', t => {
|
359 | _.times(1000, () => {
|
360 | t.is(chance.natural({ min: 0, max: 0 }), 0)
|
361 | })
|
362 | })
|
363 |
|
364 | test('natural() respects numerals', t => {
|
365 | _.times(1000, () => {
|
366 | let natural = chance.natural({ numerals: 2 })
|
367 | t.true(natural <= 99)
|
368 | t.true(natural >= 10)
|
369 | })
|
370 | })
|
371 |
|
372 | test('natural() works with excluded numbers', t => {
|
373 | _.times(1000, () => {
|
374 | let natural = chance.natural({ min: 1, max: 5, exclude: [1, 3] })
|
375 | t.true(natural <= 5)
|
376 | t.true(natural >= 1)
|
377 | t.true(natural !== 1)
|
378 | t.true(natural !== 3)
|
379 | })
|
380 | })
|
381 |
|
382 | test('natural() works within empty exclude option', t => {
|
383 | _.times(1000, () => {
|
384 | let natural = chance.natural({ min: 1, max: 5, exclude: [] })
|
385 | t.true(natural <= 5)
|
386 | t.true(natural >= 1)
|
387 | })
|
388 | })
|
389 |
|
390 | test('natural() throws an error if exclude is not an array', t => {
|
391 | const fn = () => chance.natural({ min: 1, max: 5, exclude: "foo" })
|
392 | t.throws(fn, 'Chance: exclude must be an array.')
|
393 | })
|
394 |
|
395 | test('natural() throws an error if exclude is not an array', t => {
|
396 | const fn = () => chance.natural({ min: 1, max: 5, exclude: ["puppies", 1] })
|
397 | t.throws(fn, 'Chance: exclude must be numbers.')
|
398 | })
|
399 |
|
400 | test('natural() throws an error if min > max', t => {
|
401 | const fn = () => chance.natural({ min: 1000, max: 500 })
|
402 | t.throws(fn, 'Chance: Min cannot be greater than Max.')
|
403 | })
|
404 |
|
405 | test('natural() throws an error if numerals is less than 1', t => {
|
406 | const fn = () => chance.natural({ numerals: 0 })
|
407 | t.throws(fn, 'Chance: Numerals cannot be less than one.')
|
408 | })
|
409 |
|
410 | test('prime() returns a number', t => {
|
411 | t.is(typeof chance.prime(), 'number')
|
412 | })
|
413 |
|
414 | test('prime() throws an error if min < 0', t => {
|
415 | const fn = () => chance.prime({ min: -23 })
|
416 | t.throws(fn, 'Chance: Min cannot be less than zero.')
|
417 | })
|
418 |
|
419 | test('prime() throws an error if min > max', t => {
|
420 | const fn = () => chance.prime({ min: 1000, max: 500 })
|
421 | t.throws(fn, 'Chance: Min cannot be greater than Max.')
|
422 | })
|
423 |
|
424 | test('prime() is always positive and odd (or 2)', t => {
|
425 | let positiveCount = 0
|
426 | _.times(1000, () => {
|
427 | const prime = chance.prime()
|
428 | if (prime > 0 && (prime % 2 === 1 || prime === 2)) {
|
429 | positiveCount++
|
430 | }
|
431 | })
|
432 | t.is(positiveCount, 1000)
|
433 | })
|
434 |
|
435 | test('prime() can take just a min and obey it', t => {
|
436 | _.times(1000, () => {
|
437 | t.true(chance.prime({ min: 5000 }) >= 5000)
|
438 | })
|
439 | })
|
440 |
|
441 | test('prime() can take just a max and obey it', t => {
|
442 | _.times(1000, () => {
|
443 | t.true(chance.prime({ max: 20000 }) <= 20000)
|
444 | })
|
445 | })
|
446 |
|
447 | test('prime() can take both a max and min and obey them both', t => {
|
448 | _.times(1000, () => {
|
449 | const prime = chance.prime({ min: 90, max: 100 })
|
450 | t.true(prime >= 90)
|
451 | t.true(prime <= 100)
|
452 | })
|
453 | })
|
454 |
|
455 | test('set() works as expected', t => {
|
456 | let cData = { lastNames: ['customName', 'testLast'] }
|
457 | chance.set(cData)
|
458 | let data = chance.get('lastNames')
|
459 | t.true(_.isArray(data))
|
460 | t.is(data.length, 2)
|
461 | })
|
462 |
|
463 | test('string() returns a string', t => {
|
464 | t.is(typeof chance.string(), 'string')
|
465 | })
|
466 |
|
467 | test('string() obeys length, when specified', t => {
|
468 | _.times(1000, () => {
|
469 | let length = chance.natural({ min: 1, max: 25 })
|
470 | t.is(chance.string({ length: length }).length, length)
|
471 | })
|
472 | })
|
473 |
|
474 | test('string() throws error if length < 0', t => {
|
475 | const fn = () => chance.string({ length: -23 })
|
476 | t.throws(fn, 'Chance: Length cannot be less than zero.')
|
477 | })
|
478 |
|
479 | test('string() returns only letters with alpha', t => {
|
480 | _.times(1000, () => {
|
481 | let str = chance.string({ alpha: true })
|
482 | t.true(/[a-zA-Z]+/.test(str))
|
483 | })
|
484 | })
|
485 |
|
486 | test('string() obeys upper case', t => {
|
487 | _.times(1000, () => {
|
488 | let str = chance.string({ alpha: true, casing: 'upper' })
|
489 | t.true(/[A-Z]+/.test(str))
|
490 | })
|
491 | })
|
492 |
|
493 | test('string() obeys lower case', t => {
|
494 | _.times(1000, () => {
|
495 | let str = chance.string({ alpha: true, casing: 'lower' })
|
496 | t.true(/[a-z]+/.test(str))
|
497 | })
|
498 | })
|
499 |
|
500 | test('string() obeys symbol', t => {
|
501 | _.times(1000, () => {
|
502 | let str = chance.string({ symbols: true })
|
503 | t.true(/[\!\@\#\$\%\^\&\*\(\)\[\]]+/.test(str))
|
504 | })
|
505 | })
|
506 |
|
507 | test('string() can take just a min and obey it', t => {
|
508 | _.times(1000, () => {
|
509 | t.true(chance.string({ min: 6 }).length >= 6)
|
510 | })
|
511 | })
|
512 |
|
513 | test('string() can take just a max and obey it', t => {
|
514 | _.times(1000, () => {
|
515 | t.true(chance.string({ max: 20 }).length <= 20)
|
516 | })
|
517 | })
|
518 |
|
519 | test('string() returns an empty string with zero length', t => {
|
520 | t.is(chance.string({length: 0}), '')
|
521 | })
|
522 |
|
523 | test('falsy() should return a falsy value', t => {
|
524 | _.times(1000, () => {
|
525 | const value = chance.falsy()
|
526 | t.falsy(value)
|
527 | })
|
528 | })
|
529 |
|
530 | test('falsy() should return a falsy value using a pool data', t => {
|
531 | _.times(1000, () => {
|
532 | const value = chance.falsy({pool: [null, undefined]})
|
533 | t.falsy(value)
|
534 | })
|
535 | })
|
536 |
|
537 | test('template() returns alpha numeric substituted', t => {
|
538 | _.times(1000, () => {
|
539 | let str = chance.template('ID-{Aa}-{##}')
|
540 | t.regex(str, /^ID-[A-Z][a-z]-[0-9][0-9]$/)
|
541 | })
|
542 | })
|
543 |
|
544 | test('template() rejects unknown tokens', t => {
|
545 | t.throws(() => chance.template('{Aa-}'), 'Invalid replacement character: "-".')
|
546 | t.throws(() => chance.template('{Aa{}'), 'Invalid replacement character: "{".')
|
547 | t.throws(() => chance.template('{Aab}'), 'Invalid replacement character: "b".')
|
548 | })
|
549 |
|
550 | test('template() allows escape sequnce', t => {
|
551 | t.is(chance.template('\\\\ID-\\{Aa\\}'), '\\ID-{Aa}')
|
552 | })
|
553 |
|
554 | test('template() rejects invalid escape sequnce', t => {
|
555 | t.throws(() => chance.template('ID-\\Aa'), 'Invalid escape sequence: "\\A".')
|
556 | })
|
557 |
|
558 | test('template() cannot be undefined', t => {
|
559 | t.throws(() => chance.template(), 'Template string is required')
|
560 | })
|
561 |
|
562 | test('template() cannot be empty', t => {
|
563 | t.throws(() => chance.template(''), 'Template string is required')
|
564 | })
|