Repository: dubzzz/fast-check
Pull request #1750 (2021-04-15 20:41:47)

✨ Add support for cloneable instances in `fc.constant` and `fc.constantFrom`
<!-- Why is this PR for? -->
<!-- Describe the reason why you opened this PR or give a link towards the associated issue. -->

## In a nutshell

✔️ New feature
❌ Fix an issue
❌ Documentation improvement
❌ Other: *please explain*

(✔️: yes, ❌: no)

## Potential impacts

`fc.constant` and `fc.constantFrom` accept cloneables

codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/dubzzz/fast-check/pr/1750/builds/120301) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e791dbb38c462ec90c23beff69b829540c3edc81:

|Sandbox| Source |
|--|--|
|[Vanilla](https://codesandbox.io/s/vanilla-c3dtr)| Configuration |
|[fast-check-examples](https://codesandbox.io/s/fast-check-examples-1huqr)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> Merging [#1750](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (c2c3ea2) into [main](https://codecov.io/gh/dubzzz/fast-check/commit/b7eac30bbd841d5fd29ed75a0c7f8c36fffff65e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (b7eac30) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1750/graphs/tree.svg?width=650&height=150&src=pr&token=fRi2fJN730&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)

```diff
@@            Coverage Diff             @@
##             main    #1750      +/-   ##
==========================================
+ Coverage   96.97%   96.99%   +0.01%     
==========================================
  Files         115      115              
  Lines        3609     3597      -12     
  Branches      714      711       -3     
==========================================
- Hits         3500     3489      -11     
+ Misses        105      104       -1     
  Partials        4        4              
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `96.99% <100.00%> (+0.01%)` | :arrow_up: |
| unit-tests-10.x-Linux | `?` | |
| unit-tests-12.x-Linux | `96.99% <100.00%> (+0.01%)` | :arrow_up: |
| unit-tests-14.x-Linux | `?` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | Coverage Δ | |
|---|---|---|
| [src/arbitrary/constant.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9jb25zdGFudC50cw==) | `100.00% <ø> (ø)` | |
| [src/arbitrary/constantFrom.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9jb25zdGFudEZyb20udHM=) | `100.00% <ø> (ø)` | |
| [src/arbitrary/clonedConstant.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9jbG9uZWRDb25zdGFudC50cw==) | `100.00% <100.00%> (+12.50%)` | :arrow_up: |
| [src/arbitrary/context.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9jb250ZXh0LnRz) | `100.00% <100.00%> (ø)` | |
| [src/check/arbitrary/StreamArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1750/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9TdHJlYW1BcmJpdHJhcnkudHM=) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [b7eac30...c2c3ea2](https://codecov.io/gh/dubzzz/fast-check/pull/1750?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).


Patch:
diff --git a/documentation/Arbitraries.md b/documentation/Arbitraries.md
index 7ec6a692..f3115518 100644
--- a/documentation/Arbitraries.md
+++ b/documentation/Arbitraries.md
@@ -1979,8 +1979,6 @@ fc.float64Array({minLength: 1})
 *&#8195;Description*
 
 > Always produce the same value
->
-> ⚠️ The value will not be cloned by the arbitrary
 
 *&#8195;Signatures*
 
@@ -2009,8 +2007,6 @@ fc.constant({})
 > One of the values specified as argument
 >
 > Randomly chooses among the provided values. It considers the first value as the default value so that in case of failure it will shrink to it. It expects a minimum of one value and throws whether it receives no value as parameters. It can easily be used on arrays with `fc.constantFrom(...myArray)`.
->
-> ⚠️ The values will not be cloned by the arbitrary
 
 *&#8195;Signatures*
 
@@ -2042,7 +2038,7 @@ fc.constantFrom(1, 'string', {})
 
 *&#8195;Signatures*
 
-- `fc.clonedConstant(value)`
+- _`fc.clonedConstant(value)`_ — _deprecated since v2.15.0, prefer `fc.constant`_
 
 *&#8195;with:*
 
diff --git a/src/arbitrary/clonedConstant.ts b/src/arbitrary/clonedConstant.ts
index b977d702..489c15ce 100644
--- a/src/arbitrary/clonedConstant.ts
+++ b/src/arbitrary/clonedConstant.ts
@@ -1,18 +1,10 @@
-import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
-import { convertFromNext } from '../check/arbitrary/definition/Converters';
-import { cloneMethod, hasCloneMethod } from '../check/symbols';
-import { ConstantArbitrary } from './_internals/ConstantArbitrary';
+import { constant } from './constant';
 
 /**
  * For `value`
  * @param value - The value to produce
  * @remarks Since 1.8.0
+ * @deprecated Switch to {@link constant} instead
  * @public
  */
-export function clonedConstant<T>(value: T): Arbitrary<T> {
-  if (hasCloneMethod(value)) {
-    const producer = () => value[cloneMethod]();
-    return convertFromNext(new ConstantArbitrary([producer]).map((c) => c()));
-  }
-  return convertFromNext(new ConstantArbitrary([value]));
-}
+export const clonedConstant = constant;
diff --git a/src/arbitrary/constant.ts b/src/arbitrary/constant.ts
index bb9d3bbe..c31951a8 100644
--- a/src/arbitrary/constant.ts
+++ b/src/arbitrary/constant.ts
@@ -1,6 +1,5 @@
 import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
 import { convertFromNext } from '../check/arbitrary/definition/Converters';
-import { hasCloneMethod } from '../check/symbols';
 import { ConstantArbitrary } from './_internals/ConstantArbitrary';
 
 /**
@@ -10,8 +9,5 @@ import { ConstantArbitrary } from './_internals/ConstantArbitrary';
  * @public
  */
 export function constant<T>(value: T): Arbitrary<T> {
-  if (hasCloneMethod(value)) {
-    throw new Error('fc.constant does not accept cloneable values, use fc.clonedConstant instead');
-  }
   return convertFromNext(new ConstantArbitrary([value]));
 }
diff --git a/src/arbitrary/constantFrom.ts b/src/arbitrary/constantFrom.ts
index 78cc2695..ad2ee564 100644
--- a/src/arbitrary/constantFrom.ts
+++ b/src/arbitrary/constantFrom.ts
@@ -1,6 +1,5 @@
 import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
 import { convertFromNext } from '../check/arbitrary/definition/Converters';
-import { hasCloneMethod } from '../check/symbols';
 import { ConstantArbitrary } from './_internals/ConstantArbitrary';
 
 /**
@@ -17,8 +16,5 @@ export function constantFrom<TArgs extends any[] | [any]>(...values: TArgs): Arb
   if (values.length === 0) {
     throw new Error('fc.constantFrom expects at least one parameter');
   }
-  if (values.find((v) => hasCloneMethod(v)) != undefined) {
-    throw new Error('fc.constantFrom does not accept cloneable values, not supported for the moment');
-  }
   return convertFromNext(new ConstantArbitrary(values));
 }
diff --git a/src/arbitrary/context.ts b/src/arbitrary/context.ts
index 1341304a..46222ea3 100644
--- a/src/arbitrary/context.ts
+++ b/src/arbitrary/context.ts
@@ -1,6 +1,6 @@
 import { cloneMethod } from '../check/symbols';
 import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
-import { clonedConstant } from './clonedConstant';
+import { constant } from './constant';
 
 /**
  * Execution context attached to one predicate run
@@ -48,5 +48,5 @@ class ContextImplem implements ContextValue {
  * @public
  */
 export function context(): Arbitrary<ContextValue> {
-  return clonedConstant(new ContextImplem());
+  return constant(new ContextImplem());
 }


Test patch:
diff --git a/test/unit/arbitrary/ConstantArbitrary.spec.ts b/test/unit/arbitrary/ConstantArbitrary.spec.ts
index b92c81ee..7cde4dfc 100644
--- a/test/unit/arbitrary/ConstantArbitrary.spec.ts
+++ b/test/unit/arbitrary/ConstantArbitrary.spec.ts
@@ -24,8 +24,8 @@ describe('ConstantArbitrary', () => {
       instance.push('world');
       expect(g).toEqual(['hello', 'world']);
     });
-    it('Should throw on cloneable instance', () => {
-      expect(() => constant(cloneable)).toThrowError();
+    it('Should not throw on cloneable instance', () => {
+      expect(() => constant(cloneable)).not.toThrowError();
     });
   });
   describe('constantFrom', () => {
@@ -52,8 +52,8 @@ describe('ConstantArbitrary', () => {
           return false;
         })
       ));
-    it('Should throw on cloneable instance', () => {
-      expect(() => constantFrom(cloneable)).toThrowError();
+    it('Should not throw on cloneable instance', () => {
+      expect(() => constantFrom(cloneable)).not.toThrowError();
     });
     it('Should shrink any of the constants towards the first one', () =>
       fc.assert(
@@ -66,7 +66,7 @@ describe('ConstantArbitrary', () => {
       ));
   });
   describe('clonedConstant', () => {
-    it('Should throw on cloneable instance with flag enabled', () => {
+    it('Should not throw on cloneable instance with flag enabled', () => {
       expect(() => clonedConstant(cloneable)).not.toThrow();
     });
     it('Should clone cloneable on generate', () => {