Skip to content

Commit

Permalink
🐛 Better interrupt between multiple versions (#4981)
Browse files Browse the repository at this point in the history
fast-check was badly behaving on cloning method, custom toString and
assertions linked to pre when several versions of it were running at the
same time.

One of the case for that issue is ES module and CommonJS being mixed in
the same test and leading fast-check to be loaded once in ESM and once
in CJS.

Another case is that user relies on two versions of fast-check due to a
dependency forcing a version that is not the same as the one requested
by the user or by another dependency (not the same meaning not
compatible semver ranges).

Fixes #4845

<!-- Context of the PR: short description and potentially linked issues
-->

<!-- ...a few words to describe the content of this PR... -->
<!-- ... -->

<!-- Type of PR: [ ] unchecked / [ ] checked -->

**_Category:_**

- [ ] ✨ Introduce new features
- [ ] 📝 Add or update documentation
- [ ] ✅ Add or update tests
- [ ] 🐛 Fix a bug
- [ ] 🏷️ Add or update types
- [ ] ⚡️ Improve performance
- [ ] _Other(s):_ ...
  <!-- Don't forget to add the gitmoji icon in the name of the PR -->
  <!-- See: https://gitmoji.dev/                                  -->

<!-- Fixing bugs, adding features... may impact existing ones -->
<!-- in order to track potential issues that could be related to your PR
-->
<!-- please check the impacts and describe more precisely what to expect
-->

**_Potential impacts:_**

<!-- Generated values: Can your change impact any of the existing
generators in terms of generated values, if so which ones? when? -->
<!-- Shrink values: Can your change impact any of the existing
generators in terms of shrink values, if so which ones? when? -->
<!-- Performance: Can it require some typings changes on user side?
Please give more details -->
<!-- Typings: Is there a potential performance impact? In which cases?
-->

- [ ] Generated values
- [ ] Shrink values
- [ ] Performance
- [ ] Typings
- [ ] _Other(s):_ ...
  • Loading branch information
dubzzz authored May 14, 2024
1 parent 5a699ae commit e70aea4
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 14 deletions.
8 changes: 8 additions & 0 deletions .yarn/versions/eac5c04e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
releases:
fast-check: patch

declined:
- "@fast-check/ava"
- "@fast-check/jest"
- "@fast-check/vitest"
- "@fast-check/worker"
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
export class PreconditionFailure extends Error {
/** @internal */
private static readonly SharedFootPrint: symbol = Symbol('fast-check/PreconditionFailure');
private static readonly SharedFootPrint: symbol = Symbol.for('fast-check/PreconditionFailure');
/** @internal */
private readonly footprint: symbol;
constructor(readonly interruptExecution: boolean = false) {
Expand Down
2 changes: 1 addition & 1 deletion packages/fast-check/src/check/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* @remarks Since 1.8.0
* @public
*/
export const cloneMethod = Symbol('fast-check/cloneMethod');
export const cloneMethod = Symbol.for('fast-check/cloneMethod');

/**
* Object instance that should be cloned from one generation/shrink to another
Expand Down
4 changes: 2 additions & 2 deletions packages/fast-check/src/utils/stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const safePositiveInfinity = Number.POSITIVE_INFINITY;
* @remarks Since 2.17.0
* @public
*/
export const toStringMethod = Symbol('fast-check/toStringMethod');
export const toStringMethod = Symbol.for('fast-check/toStringMethod');
/**
* Interface to implement for {@link toStringMethod}
*
Expand Down Expand Up @@ -62,7 +62,7 @@ export function hasToStringMethod<T>(instance: T): instance is T & WithToStringM
* @remarks Since 2.17.0
* @public
*/
export const asyncToStringMethod = Symbol('fast-check/asyncToStringMethod');
export const asyncToStringMethod = Symbol.for('fast-check/asyncToStringMethod');
/**
* Interface to implement for {@link asyncToStringMethod}
*
Expand Down
4 changes: 2 additions & 2 deletions packages/fast-check/test/unit/check/precondition/Pre.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ describe('pre', () => {
}
expect(failed).toBe(true);
});
it('should not understand PreconditionFailure thrown by other instances', () => {
it('should understand PreconditionFailure thrown by another instance of fast-check', () => {
let failed = false;
try {
fc.pre(false);
} catch (err) {
failed = true;
expect(PreconditionFailure.isFailure(err)).toBe(false);
expect(PreconditionFailure.isFailure(err)).toBe(true);
}
expect(failed).toBe(true);
});
Expand Down
4 changes: 2 additions & 2 deletions packages/fast-check/test/unit/check/symbols.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { cloneMethod, hasCloneMethod } from '../../../src/check/symbols';
import * as fc from 'fast-check';

describe('symbols', () => {
it('should declare distinct cloneMethod for distinct libraries', () => {
expect(cloneMethod).not.toBe(fc.cloneMethod);
it('should declare identical cloneMethod for distinct instances of fast-check', () => {
expect(cloneMethod).toBe(fc.cloneMethod);
});
});

Expand Down
12 changes: 6 additions & 6 deletions packages/fast-check/test/unit/utils/stringify.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ describe('stringify', () => {
const instance3 = { [toStringMethod]: () => { throw new Error('hello3'); } };
const stringified3 = stringify(instance3);
expect(stringified3.replace(/[\s\n]+/g, ' ')).toEqual(
'{[Symbol("fast-check/toStringMethod")]:() => { throw new Error("hello3"); }}',
'{[Symbol.for("fast-check/toStringMethod")]:() => { throw new Error("hello3"); }}',
); // fallbacking to default

class InProto {
Expand All @@ -435,11 +435,11 @@ describe('stringify', () => {
expect(stringify(instance4)).toEqual('hello4');

const instance5 = { [toStringMethod]: 1 }; // not callable
expect(stringify(instance5)).toEqual('{[Symbol("fast-check/toStringMethod")]:1}');
expect(stringify(instance5)).toEqual('{[Symbol.for("fast-check/toStringMethod")]:1}');
});
it('Should not be able to rely on the output of [asyncToStringMethod] in sync mode', () => {
const instance1 = { [asyncToStringMethod]: () => 'hello1' }; // not even async there
expect(stringify(instance1)).toEqual('{[Symbol("fast-check/asyncToStringMethod")]:() => "hello1"}'); // fallbacking to default
expect(stringify(instance1)).toEqual('{[Symbol.for("fast-check/asyncToStringMethod")]:() => "hello1"}'); // fallbacking to default

const instance2 = { [asyncToStringMethod]: () => 'hello2', [toStringMethod]: () => 'world' };
expect(stringify(instance2)).toEqual('world'); // fallbacking to [toStringMethod]
Expand Down Expand Up @@ -560,7 +560,7 @@ describe('asyncStringify', () => {
const instance4 = { [asyncToStringMethod]: async () => { throw new Error('hello4'); } };
const stringified4 = await asyncStringify(instance4);
expect(stringified4.replace(/[\s\n]+/g, ' ')).toEqual(
'{[Symbol("fast-check/asyncToStringMethod")]:async () => { throw new Error("hello4"); }}',
'{[Symbol.for("fast-check/asyncToStringMethod")]:async () => { throw new Error("hello4"); }}',
); // fallbacking to default

// prettier-ignore
Expand All @@ -571,7 +571,7 @@ describe('asyncStringify', () => {
const instance6 = { [asyncToStringMethod]: () => { throw new Error('hello6'); } }; // throw is sync
const stringified6 = await asyncStringify(instance6);
expect(stringified6.replace(/[\s\n]+/g, ' ')).toEqual(
'{[Symbol("fast-check/asyncToStringMethod")]:() => { throw new Error("hello6"); }}',
'{[Symbol.for("fast-check/asyncToStringMethod")]:() => { throw new Error("hello6"); }}',
); // fallbacking to default

class InProto {
Expand All @@ -583,7 +583,7 @@ describe('asyncStringify', () => {
expect(await asyncStringify(instance7)).toEqual('hello7');

const instance8 = { [asyncToStringMethod]: 1 }; // not callable
expect(await asyncStringify(instance8)).toEqual('{[Symbol("fast-check/asyncToStringMethod")]:1}');
expect(await asyncStringify(instance8)).toEqual('{[Symbol.for("fast-check/asyncToStringMethod")]:1}');

const instance9 = {
[asyncToStringMethod]: async () => {
Expand Down

0 comments on commit e70aea4

Please sign in to comment.