Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

💥 Include invalid dates by default #4490

Merged
merged 3 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/fast-check/src/arbitrary/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface DateConstraints {
max?: Date;
/**
* When set to true, no more "Invalid Date" can be generated.
* @defaultValue true
* @defaultValue false
* @remarks Since 3.13.0
*/
noInvalidDate?: boolean;
Expand All @@ -48,7 +48,7 @@ export function date(constraints: DateConstraints = {}): Arbitrary<Date> {
// Date min and max in ECMAScript specification : https://stackoverflow.com/a/11526569/3707828
const intMin = constraints.min !== undefined ? safeGetTime(constraints.min) : -8640000000000000;
const intMax = constraints.max !== undefined ? safeGetTime(constraints.max) : 8640000000000000;
const noInvalidDate = constraints.noInvalidDate === undefined || constraints.noInvalidDate;
const noInvalidDate = constraints.noInvalidDate;
if (safeNumberIsNaN(intMin)) throw new Error('fc.date min must be valid instance of Date');
if (safeNumberIsNaN(intMax)) throw new Error('fc.date max must be valid instance of Date');
if (intMin > intMax) throw new Error('fc.date max must be greater or equal to min');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
describe('timeToDateUnmapper', () => {
it('should be able to revert any mapped date correctly even invalid ones', () => {
fc.assert(
fc.property(fc.date({ noInvalidDate: false }), (d) => {
fc.property(fc.date(), (d) => {
// Arrange / Act
const rev = timeToDateUnmapper(d);
const revRev = timeToDateMapper(rev);
Expand All @@ -21,26 +21,22 @@ describe('timeToDateUnmapper', () => {
});
});

describe('timeToDateUnmapperWithNane', () => {
describe('timeToDateUnmapperWithNaN', () => {
it('should be able to revert any mapped date correctly even invalid once', () => {
fc.assert(
fc.property(
fc.date({ noInvalidDate: false }),
fc.integer({ min: -8640000000000000, max: 8640000000000001 }),
(d, nanValue) => {
// Arrange / Act
const rev = timeToDateUnmapperWithNaN(nanValue)(d);
const revRev = timeToDateMapperWithNaN(nanValue)(rev);
fc.property(fc.date(), fc.integer({ min: -8640000000000000, max: 8640000000000001 }), (d, nanValue) => {
// Arrange / Act
const rev = timeToDateUnmapperWithNaN(nanValue)(d);
const revRev = timeToDateMapperWithNaN(nanValue)(rev);

// Assert
if (d.getTime() === nanValue) {
expect(rev).toBe(nanValue);
expect(revRev.getTime()).toEqual(Number.NaN);
} else {
expect(revRev.getTime()).toEqual(d.getTime());
}
},
),
// Assert
if (d.getTime() === nanValue) {
expect(rev).toBe(nanValue);
expect(revRev.getTime()).toEqual(Number.NaN);
} else {
expect(revRev.getTime()).toEqual(d.getTime());
}
}),
);
});
});
20 changes: 15 additions & 5 deletions packages/fast-check/test/unit/arbitrary/date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('date', () => {
fc.assert(
fc.property(constraintsArb(), (constraints) => {
// Arrange
const withInvalidDates = constraints.noInvalidDate === false;
const withInvalidDates = !constraints.noInvalidDate;
const { instance, map } = fakeArbitrary<number>();
const { instance: mappedInstance } = fakeArbitrary<Date>();
const integer = jest.spyOn(IntegerMock, 'integer');
Expand Down Expand Up @@ -118,7 +118,7 @@ describe('date', () => {
const d = mapper(rangeMin! + (mod % (rangeMax! - rangeMin! + 1))) as Date;

// Assert
if (constraints.noInvalidDate !== false || !Number.isNaN(d.getTime())) {
if (constraints.noInvalidDate || !Number.isNaN(d.getTime())) {
expect(d.getTime()).not.toBe(Number.NaN);
if (constraints.min) expect(d.getTime()).toBeGreaterThanOrEqual(constraints.min.getTime());
if (constraints.max) expect(d.getTime()).toBeLessThanOrEqual(constraints.max.getTime());
Expand Down Expand Up @@ -156,7 +156,7 @@ describe('date (integration)', () => {
const extraParameters: fc.Arbitrary<Extra> = constraintsArb();

const isCorrect = (d: Date, extra: Extra) => {
if (extra.noInvalidDate || extra.noInvalidDate === undefined) {
if (extra.noInvalidDate) {
expect(d.getTime()).not.toBe(Number.NaN);
} else if (Number.isNaN(d.getTime())) {
return;
Expand Down Expand Up @@ -206,7 +206,13 @@ describe('date (integration)', () => {

function constraintsArb() {
return fc
.tuple(fc.date(), fc.date(), fc.boolean(), fc.boolean(), fc.option(fc.boolean(), { nil: undefined }))
.tuple(
fc.date({ noInvalidDate: true }),
fc.date({ noInvalidDate: true }),
fc.boolean(),
fc.boolean(),
fc.option(fc.boolean(), { nil: undefined }),
)
.map(([d1, d2, withMin, withMax, noInvalidDate]) => {
const min = d1 < d2 ? d1 : d2;
const max = d1 < d2 ? d2 : d1;
Expand All @@ -216,7 +222,11 @@ function constraintsArb() {

function invalidRangeConstraintsArb() {
return fc
.tuple(fc.date(), fc.date(), fc.option(fc.boolean(), { nil: undefined }))
.tuple(
fc.date({ noInvalidDate: true }),
fc.date({ noInvalidDate: true }),
fc.option(fc.boolean(), { nil: undefined }),
)
.filter(([d1, d2]) => +d1 !== +d2)
.map(([d1, d2, noInvalidDate]) => {
const min = d1 < d2 ? d1 : d2;
Expand Down
4 changes: 2 additions & 2 deletions website/docs/core-blocks/arbitraries/composites/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ fc.record(
);
// Note: All keys except 'id' will be optional values. id has been marked as required.
// Examples of generated values:
// • {"id":"46045be9-0009-4000-8000-0008ffffffed","name":"Karen","age":11,"birthday":new Date("2100-12-31T23:59:59.996Z")}
// • {"id":"46045be9-0009-4000-8000-0008ffffffed","name":"Karen","age":11,"birthday":new Date("2100-12-31T23:59:59.997Z")}
// • {"id":"fffffffe-0015-4000-95a0-f8e9ffffffe7","name":"Karen","birthday":new Date("1970-01-01T00:00:00.018Z")}
// • {"id":"e2b066ec-000b-4000-bfff-ffe7ccb1828d","name":"Karen","age":17}
// • {"id":"43b7d8e5-d043-42ef-8000-001a00000005","age":16,"birthday":new Date("2004-10-16T22:01:09.416Z")}
// • {"id":"00000007-2008-452e-8000-00133ed36be7","name":"Karen","age":6,"birthday":new Date("2100-12-31T23:59:59.981Z")}
// • {"id":"00000007-2008-452e-8000-00133ed36be7","name":"Karen","age":6,"birthday":new Date("2100-12-31T23:59:59.982Z")}
// • …

fc.record(
Expand Down
15 changes: 12 additions & 3 deletions website/docs/core-blocks/arbitraries/primitives/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Generate any possible dates in the specified range. Both the lower bound and upp

- `min?` — default: `new Date(-8640000000000000)` — _lower bound of the range (included)_
- `max?` — default: `new Date(8640000000000000)` — _upper bound of the range (included)_
- `noInvalidDate?` — default: `true` — _when `true` the Date "Invalid Date" will never be defined_
- `noInvalidDate?` — default: `false` — _when `true` the Date "Invalid Date" will never be defined_

**Usages:**

Expand All @@ -41,7 +41,7 @@ fc.date({ min: new Date('2000-01-01T00:00:00.000Z') });
// • new Date("2000-01-01T00:00:00.039Z")
// • new Date("2000-01-01T00:00:00.047Z")
// • new Date("2000-01-01T00:00:00.003Z")
// • new Date("+275760-09-12T23:59:59.981Z")
// • new Date("+275760-09-12T23:59:59.982Z")
// • …

fc.date({ max: new Date('2000-01-01T00:00:00.000Z') });
Expand All @@ -58,9 +58,18 @@ fc.date({ min: new Date('2000-01-01T00:00:00.000Z'), max: new Date('2000-12-31T2
// • new Date("2000-05-15T03:02:40.263Z")
// • new Date("2000-10-22T03:00:45.936Z")
// • new Date("2000-02-25T19:00:10.679Z")
// • new Date("2000-12-31T23:59:59.996Z")
// • new Date("2000-12-31T23:59:59.997Z")
// • new Date("2000-01-04T14:12:03.484Z")
// • …

fc.date({ noInvalidDate: true });
// Examples of generated values:
// • new Date("-043663-07-08T11:17:34.486Z")
// • new Date("-169183-12-11T00:28:46.358Z")
// • new Date("1969-12-31T23:59:59.988Z")
// • new Date("1969-12-31T23:59:59.984Z")
// • new Date("-271821-04-20T00:00:00.033Z")
// • …
```

Resources: [API reference](https://fast-check.dev/api-reference/functions/date.html).
Expand Down
Loading