Skip to content

Commit

Permalink
🐛 Add findOrUndefined function. (#583)
Browse files Browse the repository at this point in the history
This allows us to avoid using Array.prototype.find,
which is not available on Internet Explorer 11.
  • Loading branch information
tinydylan committed Apr 25, 2020
1 parent d4a01c6 commit 8d572d1
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/check/arbitrary/ConstantArbitrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { stream } from '../../stream/Stream';
import { cloneMethod, hasCloneMethod } from '../symbols';
import { Arbitrary } from './definition/Arbitrary';
import { Shrinkable } from './definition/Shrinkable';
import { findOrUndefined } from './helpers/ArrayHelper';

/** @hidden */
class ConstantArbitrary<T> extends Arbitrary<T> {
Expand Down Expand Up @@ -56,7 +57,7 @@ function constantFrom<T>(...values: T[]): Arbitrary<T> {
if (values.length === 0) {
throw new Error('fc.constantFrom expects at least one parameter');
}
if (values.find(v => hasCloneMethod(v)) != null) {
if (findOrUndefined(values, v => hasCloneMethod(v)) != undefined) {
throw new Error('fc.constantFrom does not accept cloneable values, not supported for the moment');
}
return new ConstantArbitrary<T>([...values]);
Expand Down
12 changes: 12 additions & 0 deletions src/check/arbitrary/helpers/ArrayHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @hidden
* Find first element matching the predicate in the array, or null if none match
* Equivalent to Array.prototype.find, but works on Internet Explorer 11.
*/
export function findOrUndefined<T>(ts: ArrayLike<T>, f: (t: T) => boolean): T | undefined {
for (let i = 0; i < ts.length; i++) {
const t = ts[i];
if (f(t)) return t;
}
return undefined;
}
46 changes: 46 additions & 0 deletions test/unit/check/arbitrary/helpers/ArrayHelper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as fc from '../../../../../lib/fast-check';
import { findOrUndefined } from '../../../../../src/check/arbitrary/helpers/ArrayHelper';

describe('ArrayHelper', () => {
describe('findOrUndefined', () => {
it('should return undefined for empty array', () => {
expect(
findOrUndefined<number>([], () => {
throw new Error('⊥');
})
).toBe(undefined);
});
it('should return a matching element', () => {
fc.assert(
fc.property(fc.array(fc.integer()), fc.integer(), fc.array(fc.integer()), (prefix, e, suffix) => {
expect(findOrUndefined<number>([...prefix, e, ...suffix], x => x === e)).toBe(e);
})
);
});
it('should return undefined when not present', () => {
fc.assert(
fc.property(
fc.array(fc.integer(0, 100)),
fc.integer(-100, -1),
fc.array(fc.integer(0, 100)),
(prefix, e, suffix) => {
expect(findOrUndefined<number>([...prefix, ...suffix], x => x === e)).toBe(undefined);
}
)
);
});
it('should pass some simple examples', () => {
expect(findOrUndefined<number>([7, 8, 2, 1], x => x < 3)).toBe(2);
expect(findOrUndefined<number>([12, 8, -1], x => x < 3)).toBe(-1);
expect(findOrUndefined<number>([3], x => x > 10)).toBe(undefined);
expect(findOrUndefined<number>([], x => x > 10)).toBe(undefined);
});
it('should be consistent with Array.prototype.indexOf', () => {
fc.assert(
fc.property(fc.array(fc.integer(1, 200)), fc.integer(1, 200), (xs, x) => {
expect(findOrUndefined<number>(xs, a => a === x) === undefined).toBe(xs.indexOf(x) === -1);
})
);
});
});
});

0 comments on commit 8d572d1

Please sign in to comment.