diff --git a/package.json b/package.json index dcf9185cb..47521fda6 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "eslint-plugin-prettier": "4.2.1", "eslint-plugin-promise": "6.1.1", "eslint-plugin-sonarjs": "0.16.0", + "fast-check": "3.6.3", "husky": "8.0.1", "jest": "28.1.3", "jest-watch-typeahead": "1.1.0", diff --git a/packages/core/etc/core.api.md b/packages/core/etc/core.api.md index eac1d1b5c..47a8aea91 100644 --- a/packages/core/etc/core.api.md +++ b/packages/core/etc/core.api.md @@ -102,7 +102,7 @@ export type DineroSnapshot = { // @public (undocumented) export type DivideOperation = (amount: TAmount, factor: TAmount, calculator: Calculator) => TAmount; -// @public (undocumented) +// @public export const down: DivideOperation; // @public (undocumented) @@ -132,22 +132,22 @@ dineroObject: Dinero, comparator: Dinero ]; -// @public (undocumented) +// @public export const halfAwayFromZero: DivideOperation; -// @public (undocumented) +// @public export const halfDown: DivideOperation; -// @public (undocumented) +// @public export const halfEven: DivideOperation; -// @public (undocumented) +// @public export const halfOdd: DivideOperation; -// @public (undocumented) +// @public export const halfTowardsZero: DivideOperation; -// @public (undocumented) +// @public export const halfUp: DivideOperation; // @public (undocumented) @@ -346,7 +346,7 @@ export const UNEQUAL_CURRENCIES_MESSAGE = "Objects must have the same currency." // @public (undocumented) export const UNEQUAL_SCALES_MESSAGE = "Objects must have the same scale."; -// @public (undocumented) +// @public export const up: DivideOperation; // (No @packageDocumentation comment for this package) diff --git a/packages/core/src/divide/__tests__/down.test.ts b/packages/core/src/divide/__tests__/down.test.ts index 066d70529..f46831580 100644 --- a/packages/core/src/divide/__tests__/down.test.ts +++ b/packages/core/src/divide/__tests__/down.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { down } from '../down'; describe('down', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(down(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(down(20, 10, calculator)).toBe(2); }); - it('rounds down with a negative quotient below half', () => { - expect(down(-14, 10, calculator)).toBe(-2); + it('does not round with a negative integer quotient', () => { + expect(down(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(down(0, 10, calculator)).toBe(0); }); it('rounds down with a positive half quotient', () => { expect(down(15, 10, calculator)).toBe(1); @@ -16,19 +20,30 @@ describe('down', () => { it('rounds down with a negative half quotient', () => { expect(down(-15, 10, calculator)).toBe(-2); }); - it('rounds down with a positive quotient above half', () => { - expect(down(16, 10, calculator)).toBe(1); + it('rounds down with any positive float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 9 }), (a) => { + expect(down(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(down(-16, 10, calculator)).toBe(-2); + it('rounds down with any negative float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -1 }), (a) => { + expect(down(a, 10, calculator)).toBe(-1); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(down(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(down(20, 5, calculator)).toBe(4); + }); + it('does not round with a negative integer quotient', () => { + expect(down(-20, 5, calculator)).toBe(-4); }); - it('rounds down with a negative quotient below half', () => { - expect(down(-22, 5, calculator)).toBe(-5); + it('does not round with a zero quotient', () => { + expect(down(0, 5, calculator)).toBe(0); }); it('rounds down with a positive half quotient', () => { expect(down(3, 2, calculator)).toBe(1); @@ -36,11 +51,19 @@ describe('down', () => { it('rounds down with a negative half quotient', () => { expect(down(-3, 2, calculator)).toBe(-2); }); - it('rounds down with a positive quotient above half', () => { - expect(down(24, 5, calculator)).toBe(4); + it('rounds down with any positive float', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(down(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(down(-24, 5, calculator)).toBe(-5); + it('rounds down with any negative float', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(down(a, 5, calculator)).toBe(-1); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/halfAwayFromZero.test.ts b/packages/core/src/divide/__tests__/halfAwayFromZero.test.ts index 23a1c8e2b..dcd2f70b2 100644 --- a/packages/core/src/divide/__tests__/halfAwayFromZero.test.ts +++ b/packages/core/src/divide/__tests__/halfAwayFromZero.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfAwayFromZero } from '../halfAwayFromZero'; describe('halfAwayFromZero', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfAwayFromZero(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfAwayFromZero(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(halfAwayFromZero(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfAwayFromZero(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfAwayFromZero(0, 10, calculator)).toBe(0); }); it('rounds to the nearest integer away from zero with a positive half quotient', () => { expect(halfAwayFromZero(15, 10, calculator)).toBe(2); @@ -16,19 +20,44 @@ describe('halfAwayFromZero', () => { it('rounds to the nearest integer away from zero with a negative half quotient', () => { expect(halfAwayFromZero(-25, 10, calculator)).toBe(-3); }); - it('rounds up with a positive quotient above half', () => { - expect(halfAwayFromZero(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfAwayFromZero(a, 10, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfAwayFromZero(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfAwayFromZero(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfAwayFromZero(-16, 10, calculator)).toBe(-2); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfAwayFromZero(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfAwayFromZero(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(halfAwayFromZero(20, 5, calculator)).toBe(4); }); - it('rounds up with a negative quotient below half', () => { - expect(halfAwayFromZero(-22, 5, calculator)).toBe(-4); + it('does not round with a negative integer quotient', () => { + expect(halfAwayFromZero(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfAwayFromZero(0, 5, calculator)).toBe(0); }); it('rounds to the nearest integer away from zero with a positive half quotient', () => { expect(halfAwayFromZero(3, 2, calculator)).toBe(2); @@ -36,11 +65,33 @@ describe('halfAwayFromZero', () => { it('rounds to the nearest integer away from zero with a negative half quotient', () => { expect(halfAwayFromZero(-5, 2, calculator)).toBe(-3); }); - it('rounds up with a positive quotient above half', () => { - expect(halfAwayFromZero(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfAwayFromZero(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfAwayFromZero(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfAwayFromZero(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfAwayFromZero(-24, 5, calculator)).toBe(-5); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfAwayFromZero(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/halfDown.test.ts b/packages/core/src/divide/__tests__/halfDown.test.ts index b9f5511e4..6018e6007 100644 --- a/packages/core/src/divide/__tests__/halfDown.test.ts +++ b/packages/core/src/divide/__tests__/halfDown.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfDown } from '../halfDown'; describe('halfDown', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfDown(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfDown(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(halfDown(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfDown(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfDown(0, 10, calculator)).toBe(0); }); it('rounds down with a positive half quotient', () => { expect(halfDown(15, 10, calculator)).toBe(1); @@ -16,14 +20,45 @@ describe('halfDown', () => { it('rounds down with a negative half quotient', () => { expect(halfDown(-15, 10, calculator)).toBe(-2); }); - it('rounds up with a positive quotient above half', () => { - expect(halfDown(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfDown(a, 10, calculator)).toBe(1); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfDown(-16, 10, calculator)).toBe(-2); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfDown(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfDown(a, 10, calculator)).toBe(0); + }) + ); + }); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfDown(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { + it('does not round with a positive integer quotient', () => { + expect(halfDown(20, 5, calculator)).toBe(4); + }); + it('does not round with a negative integer quotient', () => { + expect(halfDown(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfDown(0, 5, calculator)).toBe(0); + }); it('rounds down with a positive quotient below half', () => { expect(halfDown(22, 5, calculator)).toBe(4); }); @@ -42,5 +77,33 @@ describe('halfDown', () => { it('rounds down with a negative quotient above half', () => { expect(halfDown(-24, 5, calculator)).toBe(-5); }); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfDown(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfDown(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfDown(a, 5, calculator)).toBe(0); + }) + ); + }); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfDown(a, 5, calculator)).toBe(-0); + }) + ); + }); }); }); diff --git a/packages/core/src/divide/__tests__/halfEven.test.ts b/packages/core/src/divide/__tests__/halfEven.test.ts index 2e83c4aa6..9521be6d5 100644 --- a/packages/core/src/divide/__tests__/halfEven.test.ts +++ b/packages/core/src/divide/__tests__/halfEven.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfEven } from '../halfEven'; describe('halfEven', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfEven(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfEven(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(halfEven(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfEven(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfEven(0, 10, calculator)).toBe(0); }); it('rounds to nearest even integer with a positive half quotient rounding to an even integer', () => { expect(halfEven(15, 10, calculator)).toBe(2); @@ -19,19 +23,44 @@ describe('halfEven', () => { it('rounds to nearest even integer with a negative half quotient', () => { expect(halfEven(-25, 10, calculator)).toBe(-2); }); - it('rounds up with a positive quotient above half', () => { - expect(halfEven(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfEven(a, 10, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfEven(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfEven(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfEven(-16, 10, calculator)).toBe(-2); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfEven(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfEven(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(halfEven(20, 5, calculator)).toBe(4); }); - it('rounds up with a negative quotient below half', () => { - expect(halfEven(-22, 5, calculator)).toBe(-4); + it('does not round with a negative integer quotient', () => { + expect(halfEven(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfEven(0, 5, calculator)).toBe(0); }); it('rounds to nearest even integer with a positive half quotient rounding to an even integer', () => { expect(halfEven(3, 2, calculator)).toBe(2); @@ -42,11 +71,33 @@ describe('halfEven', () => { it('rounds to nearest even integer with a negative half quotient', () => { expect(halfEven(-5, 2, calculator)).toBe(-2); }); - it('rounds up with a positive quotient above half', () => { - expect(halfEven(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfEven(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfEven(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfEven(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfEven(-24, 5, calculator)).toBe(-5); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfEven(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/halfOdd.test.ts b/packages/core/src/divide/__tests__/halfOdd.test.ts index ed1c3d23a..c733e8f40 100644 --- a/packages/core/src/divide/__tests__/halfOdd.test.ts +++ b/packages/core/src/divide/__tests__/halfOdd.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfOdd } from '../halfOdd'; describe('halfOdd', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfOdd(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfOdd(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(halfOdd(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfOdd(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfOdd(0, 10, calculator)).toBe(0); }); it('rounds to nearest odd integer with a positive half quotient rounding to an even integer', () => { expect(halfOdd(15, 10, calculator)).toBe(1); @@ -19,19 +23,44 @@ describe('halfOdd', () => { it('rounds to nearest odd integer with a negative half quotient', () => { expect(halfOdd(-25, 10, calculator)).toBe(-3); }); - it('rounds up with a positive quotient above half', () => { - expect(halfOdd(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfOdd(a, 10, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfOdd(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfOdd(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfOdd(-16, 10, calculator)).toBe(-2); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfOdd(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfOdd(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(halfOdd(20, 5, calculator)).toBe(4); }); - it('rounds up with a negative quotient below half', () => { - expect(halfOdd(-22, 5, calculator)).toBe(-4); + it('does not round with a negative integer quotient', () => { + expect(halfOdd(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfOdd(0, 5, calculator)).toBe(0); }); it('rounds to nearest odd integer with a positive half quotient rounding to an even integer', () => { expect(halfOdd(3, 2, calculator)).toBe(1); @@ -42,11 +71,33 @@ describe('halfOdd', () => { it('rounds to nearest odd integer with a negative half quotient', () => { expect(halfOdd(-5, 2, calculator)).toBe(-3); }); - it('rounds up with a positive quotient above half', () => { - expect(halfOdd(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfOdd(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfOdd(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfOdd(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfOdd(-24, 5, calculator)).toBe(-5); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfOdd(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/halfTowardsZero.test.ts b/packages/core/src/divide/__tests__/halfTowardsZero.test.ts index a8eb70034..4adfc1f68 100644 --- a/packages/core/src/divide/__tests__/halfTowardsZero.test.ts +++ b/packages/core/src/divide/__tests__/halfTowardsZero.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfTowardsZero } from '../halfTowardsZero'; describe('halfTowardsZero', () => { describe('decimal factors', () => { - it('rounds down with a positive float below half', () => { - expect(halfTowardsZero(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfTowardsZero(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative float below half', () => { - expect(halfTowardsZero(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfTowardsZero(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfTowardsZero(0, 10, calculator)).toBe(0); }); it('rounds to the nearest integer towards zero with a positive half float', () => { expect(halfTowardsZero(15, 10, calculator)).toBe(1); @@ -16,19 +20,44 @@ describe('halfTowardsZero', () => { it('rounds to the nearest integer towards zero with a negative half float', () => { expect(halfTowardsZero(-25, 10, calculator)).toBe(-2); }); - it('rounds up with a positive float above half', () => { - expect(halfTowardsZero(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfTowardsZero(a, 10, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfTowardsZero(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfTowardsZero(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative float above half', () => { - expect(halfTowardsZero(-16, 10, calculator)).toBe(-2); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfTowardsZero(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive float below half', () => { - expect(halfTowardsZero(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(halfTowardsZero(20, 5, calculator)).toBe(4); }); - it('rounds up with a negative float below half', () => { - expect(halfTowardsZero(-22, 5, calculator)).toBe(-4); + it('does not round with a negative integer quotient', () => { + expect(halfTowardsZero(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfTowardsZero(0, 5, calculator)).toBe(0); }); it('rounds to the nearest integer towards zero with a positive half float', () => { expect(halfTowardsZero(3, 2, calculator)).toBe(1); @@ -36,11 +65,33 @@ describe('halfTowardsZero', () => { it('rounds to the nearest integer towards zero with a negative half float', () => { expect(halfTowardsZero(-5, 2, calculator)).toBe(-2); }); - it('rounds up with a positive float above half', () => { - expect(halfTowardsZero(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfTowardsZero(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfTowardsZero(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfTowardsZero(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative float above half', () => { - expect(halfTowardsZero(-24, 5, calculator)).toBe(-5); + it('rounds up with any negative quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfTowardsZero(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/halfUp.test.ts b/packages/core/src/divide/__tests__/halfUp.test.ts index bc2555e12..70f5c7e0a 100644 --- a/packages/core/src/divide/__tests__/halfUp.test.ts +++ b/packages/core/src/divide/__tests__/halfUp.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { halfUp } from '../halfUp'; describe('halfUp', () => { describe('decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfUp(14, 10, calculator)).toBe(1); + it('does not round with a positive integer quotient', () => { + expect(halfUp(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(halfUp(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(halfUp(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(halfUp(0, 10, calculator)).toBe(0); }); it('rounds up with a positive half quotient', () => { expect(halfUp(15, 10, calculator)).toBe(2); @@ -16,19 +20,44 @@ describe('halfUp', () => { it('rounds up with a negative half quotient', () => { expect(halfUp(-15, 10, calculator)).toBe(-1); }); - it('rounds up with a positive quotient above half', () => { - expect(halfUp(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 6, max: 9 }), (a) => { + expect(halfUp(a, 10, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -6 }), (a) => { + expect(halfUp(a, 10, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(halfUp(a, 10, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfUp(-16, 10, calculator)).toBe(-2); + it('rounds up with any negative float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(halfUp(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds down with a positive quotient below half', () => { - expect(halfUp(22, 5, calculator)).toBe(4); + it('does not round with a positive integer quotient', () => { + expect(halfUp(20, 5, calculator)).toBe(4); }); - it('rounds up with a negative quotient below half', () => { - expect(halfUp(-22, 5, calculator)).toBe(-4); + it('does not round with a negative integer quotient', () => { + expect(halfUp(-20, 5, calculator)).toBe(-4); + }); + it('does not round with a zero quotient', () => { + expect(halfUp(0, 5, calculator)).toBe(0); }); it('rounds up with a positive half quotient', () => { expect(halfUp(3, 2, calculator)).toBe(2); @@ -36,11 +65,33 @@ describe('halfUp', () => { it('rounds up with a negative half quotient', () => { expect(halfUp(-3, 2, calculator)).toBe(-1); }); - it('rounds up with a positive quotient above half', () => { - expect(halfUp(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: 3, max: 4 }), (a) => { + expect(halfUp(a, 5, calculator)).toBe(1); + }) + ); + }); + it('rounds down with any negative float quotient above half', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -3 }), (a) => { + expect(halfUp(a, 5, calculator)).toBe(-1); + }) + ); + }); + it('rounds down with any positive float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 2 }), (a) => { + expect(halfUp(a, 5, calculator)).toBe(0); + }) + ); }); - it('rounds down with a negative quotient above half', () => { - expect(halfUp(-24, 5, calculator)).toBe(-5); + it('rounds up with any negative float quotient below half', () => { + fc.assert( + fc.property(fc.integer({ min: -2, max: -1 }), (a) => { + expect(halfUp(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/__tests__/up.test.ts b/packages/core/src/divide/__tests__/up.test.ts index 03ebb0a20..c59f6ed92 100644 --- a/packages/core/src/divide/__tests__/up.test.ts +++ b/packages/core/src/divide/__tests__/up.test.ts @@ -1,14 +1,18 @@ import { calculator } from '@dinero.js/calculator-number'; +import * as fc from 'fast-check'; import { up } from '../up'; describe('up', () => { describe('decimal factors', () => { - it('rounds up with a positive quotient below half', () => { - expect(up(14, 10, calculator)).toBe(2); + it('does not round with a positive integer quotient', () => { + expect(up(20, 10, calculator)).toBe(2); }); - it('rounds up with a negative quotient below half', () => { - expect(up(-14, 10, calculator)).toBe(-1); + it('does not round with a negative integer quotient', () => { + expect(up(-20, 10, calculator)).toBe(-2); + }); + it('does not round with a zero quotient', () => { + expect(up(0, 10, calculator)).toBe(0); }); it('rounds up with a positive half quotient', () => { expect(up(15, 10, calculator)).toBe(2); @@ -16,19 +20,30 @@ describe('up', () => { it('rounds up with a negative half quotient', () => { expect(up(-15, 10, calculator)).toBe(-1); }); - it('rounds up with a positive quotient above half', () => { - expect(up(16, 10, calculator)).toBe(2); + it('rounds up with any positive float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 9 }), (a) => { + expect(up(a, 10, calculator)).toBe(1); + }) + ); }); - it('rounds up with a negative quotient above half', () => { - expect(up(-16, 10, calculator)).toBe(-1); + it('rounds up with any negative float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: -9, max: -1 }), (a) => { + expect(up(a, 10, calculator)).toBe(-0); + }) + ); }); }); describe('non-decimal factors', () => { - it('rounds up with a positive quotient below half', () => { - expect(up(22, 5, calculator)).toBe(5); + it('does not round with a positive integer quotient', () => { + expect(up(20, 5, calculator)).toBe(4); + }); + it('does not round with a negative integer quotient', () => { + expect(up(-20, 5, calculator)).toBe(-4); }); - it('rounds up with a negative quotient below half', () => { - expect(up(-22, 5, calculator)).toBe(-4); + it('does not round with a zero quotient', () => { + expect(up(0, 5, calculator)).toBe(0); }); it('rounds up with a positive half quotient', () => { expect(up(3, 2, calculator)).toBe(2); @@ -36,11 +51,19 @@ describe('up', () => { it('rounds up with a negative half quotient', () => { expect(up(-3, 2, calculator)).toBe(-1); }); - it('rounds up with a positive quotient above half', () => { - expect(up(24, 5, calculator)).toBe(5); + it('rounds up with any positive float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: 1, max: 4 }), (a) => { + expect(up(a, 5, calculator)).toBe(1); + }) + ); }); - it('rounds up with a negative quotient above half', () => { - expect(up(-24, 5, calculator)).toBe(-4); + it('rounds up with any negative float quotient', () => { + fc.assert( + fc.property(fc.integer({ min: -4, max: -1 }), (a) => { + expect(up(a, 5, calculator)).toBe(-0); + }) + ); }); }); }); diff --git a/packages/core/src/divide/down.ts b/packages/core/src/divide/down.ts index 725b9aec8..13a7a58eb 100644 --- a/packages/core/src/divide/down.ts +++ b/packages/core/src/divide/down.ts @@ -1,14 +1,28 @@ import type { DivideOperation } from '..'; -import { greaterThanOrEqual } from '../utils'; +import { equal, greaterThan } from '../utils'; +/** + * Divide and round down. + * + * Rounding down happens whenever the quotient is not an integer. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const down: DivideOperation = (amount, factor, calculator) => { - const greaterThanOrEqualFn = greaterThanOrEqual(calculator); + const greaterThanFn = greaterThan(calculator); + const equalFn = equal(calculator); const zero = calculator.zero(); - const isPositive = greaterThanOrEqualFn(amount, zero); + const isPositive = greaterThanFn(amount, zero); const quotient = calculator.integerDivide(amount, factor); + const remainder = calculator.modulo(amount, factor); + const isInteger = equalFn(remainder, zero); - if (isPositive) { + if (isPositive || isInteger) { return quotient; } diff --git a/packages/core/src/divide/halfAwayFromZero.ts b/packages/core/src/divide/halfAwayFromZero.ts index 71936ca47..612122430 100644 --- a/packages/core/src/divide/halfAwayFromZero.ts +++ b/packages/core/src/divide/halfAwayFromZero.ts @@ -3,6 +3,16 @@ import { sign, isHalf, absolute } from '../utils'; import { halfUp, up } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round away from zero. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfAwayFromZero: DivideOperation = ( amount, factor, diff --git a/packages/core/src/divide/halfDown.ts b/packages/core/src/divide/halfDown.ts index 20d0947e8..e5610e647 100644 --- a/packages/core/src/divide/halfDown.ts +++ b/packages/core/src/divide/halfDown.ts @@ -3,6 +3,21 @@ import { isHalf } from '../utils'; import { down, halfUp } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round down. + * + * Rounding down happens when: + * - The quotient is half (e.g., -1.5, 1.5). + * - The quotient is positive and less than half (e.g., 1.4). + * - The quotient is negative and greater than half (e.g., -1.6). + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfDown: DivideOperation = (amount, factor, calculator) => { const isHalfFn = isHalf(calculator); diff --git a/packages/core/src/divide/halfEven.ts b/packages/core/src/divide/halfEven.ts index 5881f7daa..2ea788d9f 100644 --- a/packages/core/src/divide/halfEven.ts +++ b/packages/core/src/divide/halfEven.ts @@ -3,6 +3,16 @@ import { isEven, isHalf } from '../utils'; import { halfUp } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round to the nearest even integer. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfEven: DivideOperation = (amount, factor, calculator) => { const isEvenFn = isEven(calculator); const isHalfFn = isHalf(calculator); diff --git a/packages/core/src/divide/halfOdd.ts b/packages/core/src/divide/halfOdd.ts index b6b30fa14..1244fdd05 100644 --- a/packages/core/src/divide/halfOdd.ts +++ b/packages/core/src/divide/halfOdd.ts @@ -3,6 +3,16 @@ import { isEven, isHalf } from '../utils'; import { halfUp } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round to the nearest odd integer. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfOdd: DivideOperation = (amount, factor, calculator) => { const isEvenFn = isEven(calculator); const isHalfFn = isHalf(calculator); diff --git a/packages/core/src/divide/halfTowardsZero.ts b/packages/core/src/divide/halfTowardsZero.ts index 65b7b90d0..496db6385 100644 --- a/packages/core/src/divide/halfTowardsZero.ts +++ b/packages/core/src/divide/halfTowardsZero.ts @@ -3,6 +3,16 @@ import { sign, isHalf, absolute } from '../utils'; import { halfUp, down } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round towards zero. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfTowardsZero: DivideOperation = ( amount, factor, diff --git a/packages/core/src/divide/halfUp.ts b/packages/core/src/divide/halfUp.ts index 6bbecb4eb..539914db1 100644 --- a/packages/core/src/divide/halfUp.ts +++ b/packages/core/src/divide/halfUp.ts @@ -1,8 +1,23 @@ import type { DivideOperation } from '..'; -import { greaterThan, isHalf, absolute } from '../utils'; +import { absolute, greaterThan, isHalf } from '../utils'; import { down, up } from '.'; +/** + * Divide and round towards "nearest neighbor" unless both neighbors are + * equidistant, in which case round up. + * + * Rounding up happens when: + * - The quotient is half (e.g., -1.5, 1.5). + * - The quotient is positive and greater than half (e.g., 1.6). + * - The quotient is negative and less than half (e.g., -1.4). + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const halfUp: DivideOperation = (amount, factor, calculator) => { const greaterThanFn = greaterThan(calculator); const isHalfFn = isHalf(calculator); @@ -12,12 +27,12 @@ export const halfUp: DivideOperation = (amount, factor, calculator) => { const remainder = absoluteFn(calculator.modulo(amount, factor)); const difference = calculator.subtract(factor, remainder); const isLessThanHalf = greaterThanFn(difference, remainder); - const isPositive = greaterThanFn(amount, calculator.increment(zero)); + const isPositive = greaterThanFn(amount, zero); if ( isHalfFn(amount, factor) || - (isLessThanHalf && !isPositive) || - (!isLessThanHalf && isPositive) + (isPositive && !isLessThanHalf) || + (!isPositive && isLessThanHalf) ) { return up(amount, factor, calculator); } diff --git a/packages/core/src/divide/up.ts b/packages/core/src/divide/up.ts index c2705c55f..3204e22d0 100644 --- a/packages/core/src/divide/up.ts +++ b/packages/core/src/divide/up.ts @@ -1,14 +1,28 @@ import type { DivideOperation } from '..'; -import { greaterThanOrEqual } from '../utils'; +import { equal, greaterThan } from '../utils'; +/** + * Divide and round up. + * + * Rounding up happens whenever the quotient is not an integer. + * + * @param amount - The amount to divide. + * @param factor - The factor to divide by. + * @param calculator - The calculator to use. + * + * @returns The rounded amount. + */ export const up: DivideOperation = (amount, factor, calculator) => { - const greaterThanOrEqualFn = greaterThanOrEqual(calculator); + const greaterThanFn = greaterThan(calculator); + const equalFn = equal(calculator); const zero = calculator.zero(); - const isPositive = greaterThanOrEqualFn(amount, zero); + const isPositive = greaterThanFn(amount, zero); const quotient = calculator.integerDivide(amount, factor); + const remainder = calculator.modulo(amount, factor); + const isInteger = equalFn(remainder, zero); - if (isPositive) { + if (!isInteger && isPositive) { return calculator.increment(quotient); } diff --git a/packages/dinero.js/src/api/__tests__/multiply.test.ts b/packages/dinero.js/src/api/__tests__/multiply.test.ts index 2058214ba..75dbef426 100644 --- a/packages/dinero.js/src/api/__tests__/multiply.test.ts +++ b/packages/dinero.js/src/api/__tests__/multiply.test.ts @@ -17,13 +17,30 @@ describe('multiply', () => { it('multiplies positive Dinero objects', () => { const d = dinero({ amount: 400, currency: USD }); - const snapshot = toSnapshot(multiply(d, 4)); - - expect(snapshot).toEqual({ + expect(toSnapshot(multiply(d, 4))).toEqual({ amount: 1600, scale: 2, currency: USD, }); + expect(toSnapshot(multiply(d, -1))).toEqual({ + amount: -400, + scale: 2, + currency: USD, + }); + }); + it('multiplies negative Dinero objects', () => { + const d = dinero({ amount: -400, currency: USD }); + + expect(toSnapshot(multiply(d, 4))).toEqual({ + amount: -1600, + scale: 2, + currency: USD, + }); + expect(toSnapshot(multiply(d, 1))).toEqual({ + amount: -400, + scale: 2, + currency: USD, + }); }); it('converts the multiplied amount to the safest scale', () => { const d = dinero({ amount: 401, currency: USD }); @@ -44,13 +61,30 @@ describe('multiply', () => { it('multiplies positive Dinero objects', () => { const d = dinero({ amount: 400n, currency: bigintUSD }); - const snapshot = toSnapshot(multiply(d, 4n)); - - expect(snapshot).toEqual({ + expect(toSnapshot(multiply(d, 4n))).toEqual({ amount: 1600n, scale: 2n, currency: bigintUSD, }); + expect(toSnapshot(multiply(d, -1n))).toEqual({ + amount: -400n, + scale: 2n, + currency: bigintUSD, + }); + }); + it('multiplies negative Dinero objects', () => { + const d = dinero({ amount: -400n, currency: bigintUSD }); + + expect(toSnapshot(multiply(d, 4n))).toEqual({ + amount: -1600n, + scale: 2n, + currency: bigintUSD, + }); + expect(toSnapshot(multiply(d, 1n))).toEqual({ + amount: -400n, + scale: 2n, + currency: bigintUSD, + }); }); it('converts the multiplied amount to the safest scale', () => { const d = dinero({ amount: 401n, currency: bigintUSD }); @@ -71,13 +105,30 @@ describe('multiply', () => { it('multiplies positive Dinero objects', () => { const d = dinero({ amount: new Big(400), currency: bigjsUSD }); - const snapshot = toSnapshot(multiply(d, new Big(4))); - - expect(snapshot).toEqual({ + expect(toSnapshot(multiply(d, new Big(4)))).toEqual({ amount: new Big(1600), scale: new Big(2), currency: bigjsUSD, }); + expect(toSnapshot(multiply(d, new Big(-1)))).toEqual({ + amount: new Big(-400), + scale: new Big(2), + currency: bigjsUSD, + }); + }); + it('multiplies negative Dinero objects', () => { + const d = dinero({ amount: new Big(-400), currency: bigjsUSD }); + + expect(toSnapshot(multiply(d, new Big(4)))).toEqual({ + amount: new Big(-1600), + scale: new Big(2), + currency: bigjsUSD, + }); + expect(toSnapshot(multiply(d, new Big(1)))).toEqual({ + amount: new Big(-400), + scale: new Big(2), + currency: bigjsUSD, + }); }); it('converts the multiplied amount to the safest scale', () => { const d = dinero({ amount: new Big(401), currency: bigjsUSD }); diff --git a/yarn.lock b/yarn.lock index 99d96d1ca..0f6ae05a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4928,6 +4928,13 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +fast-check@3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.6.3.tgz#9adb8161390c4a6a84c0f3ed333b15e1c7292f8a" + integrity sha512-5+ovrjQLUa+F9RbRcW7A++K+olKy2mNgYNfFmXSzQOAQ/Fuit12F1UI8z5Bic9YgRkUAQqXSkFUAAs7xohbvvg== + dependencies: + pure-rand "^6.0.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -8424,6 +8431,11 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.0.tgz#701996ceefa253507923a0e864c17ab421c04a7c" + integrity sha512-rLSBxJjP+4DQOgcJAx6RZHT2he2pkhQdSnofG5VWyVl6GRq/K02ISOuOLcsMOrtKDIJb8JN2zm3FFzWNbezdPw== + purgecss@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-3.1.3.tgz#26987ec09d12eeadc318e22f6e5a9eb0be094f41"