Created
April 14, 2021 19:36
-
-
Save dubzzz/c26b20d2695410eb871177decd197d87 to your computer and use it in GitHub Desktop.
pbt.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fc from 'fast-check'; | |
| |
// Characteristics independent of the inputs | |
| |
test('for any floating point number d, Math.floor(d) is an integer', () => { | |
fc.assert(fc.property(fc.double(), (d) => Number.isInteger(Math.floor(d)))); | |
}); | |
| |
test('for any floating point number d, Math.abs(d) ≥ 0', () => { | |
fc.assert(fc.property(fc.double(), (d) => Math.abs(d) >= 0)); | |
}); | |
| |
// Characteristics derived from the inputs | |
| |
test('for any a and b integers, the average of a and b is between a and b', () => { | |
fc.assert( | |
fc.property(fc.integer(), fc.integer(), (a, b) => { | |
const r = average(a, b); | |
if (a <= b) return a <= r && r <= b; | |
else return b <= r && r <= a; | |
}) | |
); | |
}); | |
| |
test("for any n positive integer, its square root multiplied by itself 'is' n", () => { | |
fc.assert( | |
fc.property(fc.nat(), (n) => { | |
const s = Math.sqrt(n); | |
const nNew = s * s; | |
return n - n * Number.EPSILON <= nNew && nNew <= n + n * Number.EPSILON; | |
}) | |
); | |
}); | |
| |
test('for any n, the product of all numbers in the prime factor decomposition of n equals n', () => { | |
fc.assert( | |
fc.property(fc.nat(), (n) => { | |
let acc = 1; | |
for (const d of decompPrime(n)) { | |
acc *= d; | |
} | |
return acc === n; | |
}) | |
); | |
}); | |
| |
test('for any n, the decomposition in prime factors of its own prime factors are themselves', () => { | |
fc.assert( | |
fc.property(fc.nat(), (n) => { | |
for (const d of decompPrime(n)) { | |
expect(decompPrime(d)).toEqual([d]); | |
} | |
}) | |
); | |
}); | |
| |
test('for any a and b, such as n = a * b, the decomposition in prime factors be the merge of primes of a and primes of b', () => { | |
fc.assert( | |
fc.property(fc.integer({ min: 2, max: 10000 }), fc.integer({ min: 2, max: 10000 }), (a, b) => { | |
const decompA = decompPrime(a); | |
const decompB = decompPrime(b); | |
const decompN = decompPrime(a * b); | |
expect(sort(decompN)).toEqual(sort([...decompA, ...decompB])); | |
}) | |
); | |
}); | |
| |
test('for any tab array of integers, the sorted tab is sorted', () => { | |
fc.assert( | |
fc.property(fc.array(fc.integer()), (tab) => { | |
const sorted = sort(tab); | |
for (let idx = 1; idx < sorted.length; ++idx) { | |
expect(sorted[idx - 1]).toBeLessThanOrEqual(sorted[idx]); | |
} | |
}) | |
); | |
}); | |
| |
test('for any tab arrays of integers, the sorted tab contains the same elements as tab', () => { | |
fc.assert( | |
fc.property(fc.array(fc.integer()), (tab) => { | |
const sorted = sort(tab); | |
for (const item of new Set(sorted)) { | |
expect(sorted.filter((v) => v == item).length).toBe(tab.filter((v) => v == item).length); | |
} | |
for (const item of new Set(tab)) { | |
expect(sorted.filter((v) => v == item).length).toBe(tab.filter((v) => v == item).length); | |
} | |
}) | |
); | |
}); | |
| |
// Restricted set of inputs with useful characteristics | |
| |
test('for any array data without duplicates, the result of removing duplicates from data is data itself', () => { | |
fc.assert( | |
fc.property(fc.set(fc.integer()), (tab) => { | |
expect(noDuplicates(tab)).toEqual(tab); | |
}) | |
); | |
}); | |
| |
test('for any a, b and c strings, the concatenation of a, b and c always contains b', () => { | |
fc.assert(fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => contains(b, a + b + c))); | |
}); | |
| |
// Characteristics on combination of functions | |
| |
test('for any JSON object, parsing its string representation results in a clone of itself', () => { | |
fc.assert( | |
fc.property(fc.jsonObject(), (obj) => { | |
expect(JSON.parse(JSON.stringify(obj))).toEqual(obj); | |
}) | |
); | |
}); | |
| |
// Comparison with a simpler implementation | |
| |
// Helpers | |
| |
const average = (a: number, b: number) => (a + b) / 2; | |
| |
const decompPrime = (n: number): number[] => { | |
const decomp: number[] = []; | |
| |
let current = n; | |
let currentLimit = Math.floor(Math.sqrt(current)); | |
for (let dividerCandidate = 2; dividerCandidate <= currentLimit; ++dividerCandidate) { | |
if (current % dividerCandidate === 0) { | |
current = current / dividerCandidate; | |
currentLimit = Math.floor(Math.sqrt(current)); | |
decomp.push(dividerCandidate); | |
--dividerCandidate; // otherwise we will fail to have n = m^3 | |
} | |
} | |
| |
return [...decomp, current]; | |
}; | |
| |
const sort = (tab: number[]): number[] => { | |
return [...tab].sort((a, b) => a - b); | |
}; | |
| |
const noDuplicates = (tab: number[]): number[] => { | |
return [...new Set(tab)]; | |
}; | |
| |
const contains = (pattern: string, text: string): boolean => { | |
return text.includes(pattern); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment