From 03041201c21ad599bbe1874c375f4f41b94961ba Mon Sep 17 00:00:00 2001 From: Piotr Kuczynski Date: Thu, 31 Mar 2022 19:48:24 +0200 Subject: [PATCH] fix: datatype.number when min = max + precision, throw when max > min (#664) --- src/address.ts | 4 ++-- src/datatype.ts | 34 +++++++++++------------------- src/random.ts | 8 ++++++-- test/address.spec.ts | 2 +- test/datatype.spec.ts | 23 +++++++++++++++------ test/system.spec.ts | 20 ++++++++++-------- test/word.spec.ts | 48 +++++++++++++++++++++---------------------- 7 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/address.ts b/src/address.ts index 5a130cb20a2..264b02817fc 100644 --- a/src/address.ts +++ b/src/address.ts @@ -407,8 +407,8 @@ export class Address { latitude(max: number = 90, min: number = -90, precision: number = 4): string { return this.faker.datatype .number({ - max: max, - min: min, + min, + max, precision: parseFloat((0.0).toPrecision(precision) + '1'), }) .toFixed(precision); diff --git a/src/datatype.ts b/src/datatype.ts index ad37c3daf5e..79b0b61c1c1 100644 --- a/src/datatype.ts +++ b/src/datatype.ts @@ -20,9 +20,11 @@ export class Datatype { * * @param options Maximum value or options object. * @param options.min Lower bound for generated number. Defaults to `0`. - * @param options.max Upper bound for generated number. Defaults to `99999`. + * @param options.max Upper bound for generated number. Defaults to `min + 99999`. * @param options.precision Precision of the generated number. Defaults to `1`. * + * @throws When options define `max < min` + * * @example * faker.datatype.number() // 55422 * faker.datatype.number(100) // 52 @@ -34,25 +36,14 @@ export class Datatype { number( options?: number | { min?: number; max?: number; precision?: number } ): number { - if (typeof options === 'number') { - options = { max: options }; - } + const opts = typeof options === 'number' ? { max: options } : options ?? {}; - options = options ?? {}; - - let max = 99999; - let min = 0; - let precision = 1; - if (typeof options.min === 'number') { - min = options.min; - } - - if (typeof options.max === 'number') { - max = options.max; - } + const min = typeof opts.min === 'number' ? opts.min : 0; + let max = typeof opts.max === 'number' ? opts.max : min + 99999; + const precision = typeof opts.precision === 'number' ? opts.precision : 1; - if (typeof options.precision === 'number') { - precision = options.precision; + if (max < min) { + throw new Error(`Max ${max} should be larger then min ${min}`); } // Make the range inclusive of the max value @@ -60,13 +51,12 @@ export class Datatype { max += precision; } - let randomNumber = Math.floor( + const randomNumber = Math.floor( this.faker.mersenne.rand(max / precision, min / precision) ); - // Workaround problem in Float point arithmetics for e.g. 6681493 / 0.01 - randomNumber = randomNumber / (1 / precision); - return randomNumber; + // Workaround problem in float point arithmetics for e.g. 6681493 / 0.01 + return randomNumber / (1 / precision); } /** diff --git a/src/random.ts b/src/random.ts index 0a3b3c5ecaf..f41a67fa36d 100644 --- a/src/random.ts +++ b/src/random.ts @@ -107,8 +107,12 @@ export class Random { arrayElement( array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray ): T { - const r = this.faker.datatype.number({ max: array.length - 1 }); - return array[r]; + const index = + array.length > 1 + ? this.faker.datatype.number({ max: array.length - 1 }) + : 0; + + return array[index]; } /** diff --git a/test/address.spec.ts b/test/address.spec.ts index 729d9190b0f..5929f4628cb 100644 --- a/test/address.spec.ts +++ b/test/address.spec.ts @@ -411,7 +411,7 @@ describe('address', () => { it('returns latitude with min and max and default precision', () => { for (let i = 0; i < 100; i++) { - const latitude = faker.address.latitude(-5, 5); + const latitude = faker.address.latitude(5, -5); expect(latitude).toBeTypeOf('string'); expect( diff --git a/test/datatype.spec.ts b/test/datatype.spec.ts index 902cf9ba706..e4d69fe69b2 100644 --- a/test/datatype.spec.ts +++ b/test/datatype.spec.ts @@ -8,7 +8,7 @@ const seededRuns = [ number: { noArgs: 37454, numbers: [2, 5, 6, 1, 5], - withMin: 37427, + withMin: 37412, withMinAndMax: -1, withMax: 26, withMinAndMaxAndPrecision: -0.43, @@ -16,7 +16,7 @@ const seededRuns = [ float: { noArgs: 37453.64, numbers: [37452, 79656, 95076, 18342, 73200], - withMin: 37427.37, + withMin: 37411.64, withMinAndMax: -0.43, withMax: 25.84, withMinAndMaxAndPrecision: -0.4261, @@ -80,7 +80,7 @@ const seededRuns = [ number: { noArgs: 26202, numbers: [1, 3, 1, 1, 1], - withMin: 26171, + withMin: 26160, withMinAndMax: -13, withMax: 18, withMinAndMaxAndPrecision: -12.92, @@ -88,7 +88,7 @@ const seededRuns = [ float: { noArgs: 26202.2, numbers: [26202, 56052, 15864, 21258, 27810], - withMin: 26171.21, + withMin: 26160.2, withMinAndMax: -12.92, withMax: 18.08, withMinAndMaxAndPrecision: -12.9153, @@ -152,7 +152,7 @@ const seededRuns = [ number: { noArgs: 92852, numbers: [6, 3, 6, 5, 1], - withMin: 92849, + withMin: 92810, withMinAndMax: 61, withMax: 64, withMinAndMaxAndPrecision: 61.07, @@ -160,7 +160,7 @@ const seededRuns = [ float: { noArgs: 92851.09, numbers: [92856, 45900, 89346, 77826, 22554], - withMin: 92848.09, + withMin: 92809.09, withMinAndMax: 61.07, withMax: 64.07, withMinAndMaxAndPrecision: 61.0658, @@ -288,6 +288,17 @@ describe('datatype', () => { }); expect(actual).toEqual(expectations.number.withMinAndMaxAndPrecision); }); + + it('should throw when min > max', () => { + const min = 10; + const max = 9; + + faker.seed(seed); + + expect(() => { + faker.datatype.number({ min, max }); + }).toThrowError(`Max ${max} should be larger then min ${min}`); + }); }); describe('float', () => { diff --git a/test/system.spec.ts b/test/system.spec.ts index e9eee5060ec..e3e7f692adf 100644 --- a/test/system.spec.ts +++ b/test/system.spec.ts @@ -7,45 +7,45 @@ const seededRuns = [ { seed: 42, expectations: { - fileName: 'mobile_application.wad', - commonFileName: 'mobile_application.gif', + fileName: 'mobile_fish.gif', + commonFileName: 'mobile_fish.mpe', mimeType: 'application/vnd.marlin.drm.license+xml', commonFileType: 'audio', commonFileExt: 'png', fileType: 'image', fileExt: 'chm', directoryPath: '/opt/bin', - filePath: '/opt/bin/directives_savings_computer.qwd', + filePath: '/opt/bin/directives_application_home.paw', semver: '3.7.9', }, }, { seed: 1337, expectations: { - fileName: 'delaware.vcg', - commonFileName: 'delaware.wav', + fileName: 'delaware.uvvt', + commonFileName: 'delaware.mp2', mimeType: 'application/vnd.dxr', commonFileType: 'audio', commonFileExt: 'wav', fileType: 'font', fileExt: 'gxt', directoryPath: '/Library', - filePath: '/Library/bike_kiribati.kpr', + filePath: '/Library/bike_interactive.qwt', semver: '2.5.1', }, }, { seed: 1211, expectations: { - fileName: 'turnpike_supervisor_chicken.mka', - commonFileName: 'turnpike_supervisor_chicken.mp4v', + fileName: 'turnpike_frozen_handcrafted.mka', + commonFileName: 'turnpike_frozen_handcrafted.mp4v', mimeType: 'text/vnd.fmi.flexstor', commonFileType: 'application', commonFileExt: 'htm', fileType: 'x-shader', fileExt: 'opml', directoryPath: '/var/log', - filePath: '/var/log/forward_frozen.swf', + filePath: '/var/log/forward_supervisor.swf', semver: '9.4.8', }, }, @@ -101,6 +101,8 @@ describe('system', () => { 'jpeg', 'm2a', 'm2v', + 'mp2', + 'mp3', 'mp4', 'mp4v', 'mpeg', diff --git a/test/word.spec.ts b/test/word.spec.ts index ac40c8a5e01..d236f564a0c 100644 --- a/test/word.spec.ts +++ b/test/word.spec.ts @@ -8,37 +8,37 @@ const seededRuns = [ adjective: { noArgs: 'harmonious', length10: 'gregarious', - length20: 'stable', + length20: 'harmonious', }, adverb: { noArgs: 'jealously', length10: 'generously', - length20: 'swiftly', + length20: 'jealously', }, conjunction: { noArgs: 'however', length10: 'as much as', - length20: 'since', + length20: 'however', }, interjection: { noArgs: 'yahoo', - length10: 'ack', - length20: 'ack', + length10: 'yahoo', + length20: 'yahoo', }, noun: { noArgs: 'gale', length10: 'exposition', - length20: 'shift', + length20: 'gale', }, preposition: { noArgs: 'concerning', length10: 'throughout', - length20: 'than', + length20: 'concerning', }, verb: { noArgs: 'function', length10: 'exasperate', - length20: 'shred', + length20: 'function', }, }, }, @@ -48,37 +48,37 @@ const seededRuns = [ adjective: { noArgs: 'fabulous', length10: 'enchanting', - length20: 'neat', + length20: 'fabulous', }, adverb: { noArgs: 'frankly', length10: 'enormously', - length20: 'overconfidently', + length20: 'frankly', }, conjunction: { noArgs: 'even if', length10: 'as long as', - length20: 'instead', + length20: 'even if', }, interjection: { noArgs: 'ew', - length10: 'yippee', - length20: 'yippee', + length10: 'ew', + length20: 'ew', }, noun: { noArgs: 'digit', length10: 'depressive', - length20: 'might', + length20: 'digit', }, preposition: { noArgs: 'barring', length10: 'concerning', - length20: 'midst', + length20: 'barring', }, verb: { noArgs: 'dispense', length10: 'demoralize', - length20: 'nearest', + length20: 'dispense', }, }, }, @@ -88,37 +88,37 @@ const seededRuns = [ adjective: { noArgs: 'verifiable', length10: 'unfinished', - length20: 'joyous', + length20: 'verifiable', }, adverb: { noArgs: 'viciously', length10: 'unbearably', - length20: 'loudly', + length20: 'viciously', }, conjunction: { noArgs: 'whereas', length10: 'as soon as', - length20: 'in addition', + length20: 'whereas', }, interjection: { noArgs: 'er', - length10: 'gah', - length20: 'gah', + length10: 'er', + length20: 'er', }, noun: { noArgs: 'trick', length10: 'trafficker', - length20: 'infection', + length20: 'trick', }, preposition: { noArgs: 'upon', length10: 'underneath', - length20: 'for', + length20: 'upon', }, verb: { noArgs: 'trick', length10: 'trampoline', - length20: 'intercede', + length20: 'trick', }, }, },