From 07a58f56ea0eccfd236bd49326a4d3dfeb6a9ad4 Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Thu, 23 May 2024 18:29:48 +0000 Subject: [PATCH] test: Add property-based tests Following the discussion started on https://github.com/chaijs/loupe/pull/79. I'm opening this PR as an opened question and suggestion to better cover the library and its edge-cases. First, what is property-based testing? It's a technic coming from functional world and aiming to help devs into detecting edge cases without having them to think of them too much. Why, property-based testing? Well, in order to reduce the risks of bugs and potentially regressions on key libraries. Could it found problems? Well, probably. I tried another property but I'm not sure whether or not the failure is considered as ok or not. As such I'm not sure of what to expect from truncate so I was not able to make a decision. ```js it('produces strings with at most characters', () => { fc.assert( fc.property( fc.anything({ withBigInt: true, withBoxedValues: true, withDate: true, withMap: true, withNullPrototype: true, withObjectString: true, withSet: true, withSparseArray: true, withTypedArray: true, withUnicodeString: true, }), fc.nat(), (source, truncate) => { const output = inspect(source, { truncate }) expect(output).to.have.lengthOf.at.most(truncate) } ) ) }) ``` Who am I? I'm the author of fast-check, the library added by this PR. It's the leading property-based testing library today. --- package-lock.json | 39 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + test/property.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 test/property.js diff --git a/package-lock.json b/package-lock.json index 529de81..61dc299 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "eslint-config-strict": "^14.0.1", "eslint-plugin-filenames": "^1.3.2", "eslint-plugin-prettier": "^3.3.1", + "fast-check": "^3.19.0", "husky": "^4.3.8", "mocha": "^10.2.0", "nyc": "^15.1.0", @@ -5235,6 +5236,28 @@ "@types/yauzl": "^2.9.1" } }, + "node_modules/fast-check": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.19.0.tgz", + "integrity": "sha512-CO2JX/8/PT9bDGO1iXa5h5ey1skaKI1dvecERyhH4pp3PGjwd3KIjMAXEg79Ps9nclsdt4oPbfqiAnLU0EwrAQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -13658,6 +13681,22 @@ } } }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", diff --git a/package.json b/package.json index 83a9e6f..ef8ea38 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "eslint-config-strict": "^14.0.1", "eslint-plugin-filenames": "^1.3.2", "eslint-plugin-prettier": "^3.3.1", + "fast-check": "^3.19.0", "husky": "^4.3.8", "mocha": "^10.2.0", "nyc": "^15.1.0", diff --git a/test/property.js b/test/property.js new file mode 100644 index 0000000..4e9e2a2 --- /dev/null +++ b/test/property.js @@ -0,0 +1,28 @@ +import inspect from '../lib/index.js' +import { expect } from 'chai' +import fc from 'fast-check' + +describe('property', () => { + it('produces valid UTF-16 strings whatever the source', () => { + fc.assert( + fc.property( + fc.anything({ + withBigInt: true, + withBoxedValues: true, + withDate: true, + withMap: true, + withNullPrototype: true, + withObjectString: true, + withSet: true, + withSparseArray: true, + withTypedArray: true, + withUnicodeString: true, + }), + fc.option(fc.nat(), { nil: undefined }), + (source, truncate) => { + expect(() => encodeURI(inspect(source, { truncate }))).not.to.throw() + } + ) + ) + }) +})