@flemist/test-variants 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ [![NPM Version][npm-image]][npm-url]
2
+ [![NPM Downloads][downloads-image]][downloads-url]
3
+ [![Build Status][github-image]][github-url]
4
+ [![Test Coverage][coveralls-image]][coveralls-url]
5
+
6
+ Runs a test function with all possible combinations of its parameters.
7
+
8
+ # Usage
9
+
10
+ ## Sync only
11
+ ```ts
12
+ const result = []
13
+ const testVariants = createTestVariantsSync(({a, b, c}: { a: number, b: string, c: boolean }) => {
14
+ result.push([a, b, c])
15
+ })
16
+ const count = testVariants({
17
+ a: [1, 2],
18
+ b: ['3', '4'],
19
+ c: [true, false],
20
+ })
21
+
22
+ // result == [
23
+ // [1, '3', true],
24
+ // [1, '3', false],
25
+ // [1, '4', true],
26
+ // [1, '4', false],
27
+ // [2, '3', true],
28
+ // [2, '3', false],
29
+ // [2, '4', true],
30
+ // [2, '4', false],
31
+ // ]
32
+ // count == 8
33
+ ```
34
+
35
+ ## Sync or Async
36
+ ```ts
37
+ const result = []
38
+ const testVariants = createTestVariants(async ({a, b, c}: { a: number, b: string, c: boolean }) => {
39
+ await delay(10)
40
+ result.push([a, b, c])
41
+ })
42
+ const count = await testVariants({
43
+ a: [1, 2],
44
+ b: ['3', '4'],
45
+ c: [true, false],
46
+ })
47
+ ```
48
+
49
+ ## Calculable variants
50
+ ```ts
51
+ const result = []
52
+ const testVariants = createTestVariants(async ({a, b, c}: { a: number, b: number, c: number }) => {
53
+ await delay(10)
54
+ result.push([a, b, c])
55
+ })
56
+ const count = await testVariants({
57
+ a: [1, 2],
58
+ b: ({a}) => [ a + 1, a + 2 ], // you can use 'a', but you can't use 'c' because it will initialize after 'b'
59
+ c: ({a, b}) => [ a, b, a + b ],
60
+ })
61
+ ```
62
+
63
+ [npm-image]: https://img.shields.io/npm/v/@flemist/test-variants.svg
64
+ [npm-url]: https://npmjs.org/package/@flemist/test-variants
65
+ [downloads-image]: https://img.shields.io/npm/dm/@flemist/test-variants.svg
66
+ [downloads-url]: https://npmjs.org/package/@flemist/test-variants
67
+ [github-image]: https://github.com/NikolayMakhonin/test-variants/actions/workflows/test.yml/badge.svg
68
+ [github-url]: https://github.com/NikolayMakhonin/test-variants/actions
69
+ [coveralls-image]: https://coveralls.io/repos/github/NikolayMakhonin/test-variants/badge.svg
70
+ [coveralls-url]: https://coveralls.io/github/NikolayMakhonin/test-variants
@@ -0,0 +1,24 @@
1
+ !function(r){"use strict";function t(r,t){
2
+ return function(n){
3
+ var e=Object.keys(n),o=Object.values(n),c=e.length,f={}
4
+ ;function u(r){var t=o[r]
5
+ ;return"function"==typeof t&&(t=t(f)),t}
6
+ for(var a=[],i=[],s=0;s<c;s++)a[s]=-1,i[s]=[]
7
+ ;function v(){for(var r=c-1;r>=0;r--){var t=a[r]+1
8
+ ;if(t<i[r].length){
9
+ for(a[r]=t,f[e[r]]=i[r][t],r++;r<c;r++){var n=u(r)
10
+ ;if(0===n.length)break;a[r]=0,i[r]=n,f[e[r]]=n[0]}
11
+ if(r>=c)return!0}}return!1}i[0]=u(0);var l=0
12
+ ;function h(t){
13
+ console.error(JSON.stringify(f,null,2)),console.error(t)
14
+ ;var n=Date.now()
15
+ ;if(Date.now()-n>5)for(var e=0;e<5;e++)try{r(f)
16
+ }catch(r){}throw t}return function n(){
17
+ for(;v();)try{l++;var e=r(f)
18
+ ;if(e&&"function"==typeof e.then)return t&&h(new Error("Unexpected Promise result for sync test function")),
19
+ e.then(n).catch(h)}catch(r){h(r)}return l}()}}
20
+ r.createTestVariants=function(r){return t(r,!1)
21
+ },r.createTestVariantsSync=function(r){
22
+ return t(r,!0)
23
+ },Object.defineProperty(r,"__esModule",{value:!0})
24
+ }({});
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var testVariants_createTestVariants = require('./test-variants/createTestVariants.cjs');
6
+
7
+
8
+
9
+ exports.createTestVariants = testVariants_createTestVariants.createTestVariants;
10
+ exports.createTestVariantsSync = testVariants_createTestVariants.createTestVariantsSync;
@@ -0,0 +1 @@
1
+ export { createTestVariantsSync, createTestVariants, } from './test-variants/createTestVariants';
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /* eslint-disable @typescript-eslint/no-shadow */
6
+ function _createTestVariants(test, sync) {
7
+ return function _testVariants(args) {
8
+ const argsKeys = Object.keys(args);
9
+ const argsValues = Object.values(args);
10
+ const argsLength = argsKeys.length;
11
+ const variantArgs = {};
12
+ function getArgValues(nArg) {
13
+ let argValues = argsValues[nArg];
14
+ if (typeof argValues === 'function') {
15
+ argValues = argValues(variantArgs);
16
+ }
17
+ return argValues;
18
+ }
19
+ const indexes = [];
20
+ const values = [];
21
+ for (let nArg = 0; nArg < argsLength; nArg++) {
22
+ indexes[nArg] = -1;
23
+ values[nArg] = [];
24
+ }
25
+ values[0] = getArgValues(0);
26
+ function nextVariant() {
27
+ for (let nArg = argsLength - 1; nArg >= 0; nArg--) {
28
+ const index = indexes[nArg] + 1;
29
+ if (index < values[nArg].length) {
30
+ indexes[nArg] = index;
31
+ variantArgs[argsKeys[nArg]] = values[nArg][index];
32
+ for (nArg++; nArg < argsLength; nArg++) {
33
+ const argValues = getArgValues(nArg);
34
+ if (argValues.length === 0) {
35
+ break;
36
+ }
37
+ indexes[nArg] = 0;
38
+ values[nArg] = argValues;
39
+ variantArgs[argsKeys[nArg]] = argValues[0];
40
+ }
41
+ if (nArg >= argsLength) {
42
+ return true;
43
+ }
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ let iteration = 0;
49
+ function onError(err) {
50
+ console.error(JSON.stringify(variantArgs, null, 2));
51
+ console.error(err);
52
+ // rerun failed variant 5 times for debug
53
+ const time0 = Date.now();
54
+ // eslint-disable-next-line no-debugger
55
+ debugger;
56
+ if (Date.now() - time0 > 5) {
57
+ for (let i = 0; i < 5; i++) {
58
+ try {
59
+ test(variantArgs);
60
+ }
61
+ catch (_a) {
62
+ // eslint-disable-next-line no-debugger
63
+ debugger;
64
+ }
65
+ }
66
+ }
67
+ throw err;
68
+ }
69
+ const next = function next() {
70
+ while (nextVariant()) {
71
+ try {
72
+ iteration++;
73
+ const promise = test(variantArgs);
74
+ if (promise && typeof promise.then === 'function') {
75
+ if (sync) {
76
+ onError(new Error('Unexpected Promise result for sync test function'));
77
+ }
78
+ return promise.then(next).catch(onError);
79
+ }
80
+ }
81
+ catch (err) {
82
+ onError(err);
83
+ }
84
+ }
85
+ return iteration;
86
+ };
87
+ return next();
88
+ };
89
+ }
90
+ function createTestVariantsSync(test) {
91
+ return _createTestVariants(test, true);
92
+ }
93
+ function createTestVariants(test) {
94
+ return _createTestVariants(test, false);
95
+ }
96
+
97
+ exports.createTestVariants = createTestVariants;
98
+ exports.createTestVariantsSync = createTestVariantsSync;
@@ -0,0 +1,11 @@
1
+ declare type VariantsArgs<TArgs> = {
2
+ [key in keyof TArgs]: TArgs[key][] | ((args: TArgs) => TArgs[key][]);
3
+ };
4
+ declare type TestVariantsFunc<TArgs, TResult> = <TAdditionalArgs>(args: VariantsArgs<{
5
+ [key in (keyof TAdditionalArgs | keyof TArgs)]: key extends keyof TArgs ? TArgs[key] : key extends keyof TAdditionalArgs ? TAdditionalArgs[key] : never;
6
+ }>) => TResult;
7
+ export declare type TestVariantsFuncSync<TArgs> = TestVariantsFunc<TArgs, number>;
8
+ export declare type TestVariantsFuncAsync<TArgs> = TestVariantsFunc<TArgs, Promise<number> | number>;
9
+ export declare function createTestVariantsSync<TArgs extends object>(test: (args: TArgs) => void): TestVariantsFuncSync<TArgs>;
10
+ export declare function createTestVariants<TArgs extends object>(test: (args: TArgs) => Promise<void> | void): TestVariantsFuncAsync<TArgs>;
11
+ export {};
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var rdtsc = require('rdtsc');
4
+ var testVariants_createTestVariants = require('./createTestVariants.cjs');
5
+
6
+ describe('test > testVariants perf', function () {
7
+ this.timeout(300000);
8
+ it('sync/async', function () {
9
+ const testVariantsAsync = testVariants_createTestVariants.createTestVariants(({ a, b, c }) => {
10
+ });
11
+ const testVariantsSync = testVariants_createTestVariants.createTestVariantsSync(({ a, b, c }) => {
12
+ });
13
+ const args = {
14
+ a: [1, 2],
15
+ b: ['3', '4'],
16
+ c: [true, false],
17
+ };
18
+ const result = rdtsc.calcPerformance(10000, () => {
19
+ }, () => {
20
+ testVariantsSync(args);
21
+ }, () => {
22
+ testVariantsAsync(args);
23
+ });
24
+ const count = testVariantsSync(args);
25
+ result.absoluteDiff = result.absoluteDiff.map(o => o / count);
26
+ console.log('testVariants perf:', result);
27
+ });
28
+ });
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@flemist/test-variants",
3
+ "version": "0.0.0",
4
+ "description": "Runs a test function with all possible combinations of its parameters.",
5
+ "main": "dist/node/index.cjs",
6
+ "types": "dist/node/index.d.ts",
7
+ "engines": {
8
+ "yarn": "^1.22"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/NikolayMakhonin/test-variants.git"
13
+ },
14
+ "keywords": [
15
+ "test",
16
+ "variants",
17
+ "combinations",
18
+ "enumeration",
19
+ "helper"
20
+ ],
21
+ "author": "NikolayMakhonin",
22
+ "license": "ISC",
23
+ "bugs": {
24
+ "url": "https://github.com/NikolayMakhonin/test-variants/issues"
25
+ },
26
+ "homepage": "https://github.com/NikolayMakhonin/test-variants#readme",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "prepublishOnly": "yarn build && yarn run test:mocha:ci && yarn run test:karma",
32
+ "lint": "eslint \"./src/**/*.{ts,js,cjs,mjs}\"",
33
+ "lint:fix": "eslint --fix \"./src/**/*.{ts,js,cjs,mjs}\"",
34
+ "build:js": "rollup -c && cpy \"**/assets/**\" \"../dist/\" --parents --cwd=src",
35
+ "build:types": "tsc --outDir dist/node --declaration",
36
+ "build": "rimraf dist && yarn run build:js && yarn run build:types",
37
+ "coverage:merge": "rimraf tmp/coverage/{all,merge} && cp-flat \"tmp/coverage/*/json/**/*.json\" \"tmp/coverage/merge\" && nyc report -r lcov --report-dir tmp/coverage/all/lcov --temp-dir \"tmp/coverage/merge/\"",
38
+ "coverage:check": "yarn run coverage:merge && nyc check-coverage --report-dir tmp/coverage/all/lcov --lines 50 --functions 50 --branches 50 --statements 50",
39
+ "test:mocha": "mocha ./src/**/*.test.ts",
40
+ "test:mocha:coverage": "rimraf tmp/coverage/mocha && nyc --all mocha ./src/**/*.test.ts",
41
+ "test:mocha:watch": "mocha --watch ./src/**/*.test.ts",
42
+ "test:karma": "rimraf tmp/coverage/karma && karma start --single-run --log-level debug",
43
+ "test:mocha:ci": "rimraf tmp/coverage/mocha && nyc --all mocha ./src/**/*.test.ts ./dist/**/*.test.cjs",
44
+ "coveralls": "yarn run coverage:check && nyc report --reporter=text-lcov --temp-dir \"tmp/coverage/merge/\" | coveralls"
45
+ },
46
+ "devDependencies": {
47
+ "@babel/core": "^7.18.0",
48
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
49
+ "@babel/plugin-transform-classes": "^7.17.12",
50
+ "@babel/plugin-transform-runtime": "^7.18.0",
51
+ "@babel/preset-env": "^7.18.0",
52
+ "@babel/runtime-corejs3": "^7.18.0",
53
+ "@flemist/copy-glob-flat": "^0.0.5",
54
+ "@flemist/karma-custom-launcher": "^0.0.0",
55
+ "@rollup/plugin-alias": "^3.1.9",
56
+ "@rollup/plugin-babel": "^5.3.1",
57
+ "@rollup/plugin-commonjs": "^21.0.3",
58
+ "@rollup/plugin-inject": "^4.0.4",
59
+ "@rollup/plugin-json": "^4.1.0",
60
+ "@rollup/plugin-multi-entry": "^4.1.0",
61
+ "@rollup/plugin-node-resolve": "^13.1.3",
62
+ "@rollup/plugin-replace": "^4.0.0",
63
+ "@rollup/plugin-typescript": "^8.3.1",
64
+ "@types/assert": "^1.5.6",
65
+ "@types/fs-extra": "^9.0.13",
66
+ "@types/mocha": "^9.1.0",
67
+ "@types/node": "^17.0.23",
68
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
69
+ "@typescript-eslint/parser": "^5.17.0",
70
+ "cpy-cli": "^3.1.1",
71
+ "eslint": "^8.12.0",
72
+ "eslint-config-pro": "^2.1.1",
73
+ "fs-extra": "^10.0.1",
74
+ "globby": "^11.1.0",
75
+ "karma": "^6.3.20",
76
+ "karma-chrome-launcher": "^3.1.1",
77
+ "karma-coverage": "^2.2.0",
78
+ "karma-firefox-launcher": "^2.1.2",
79
+ "karma-mocha": "^2.0.1",
80
+ "karma-safari-launcher": "^1.0.0",
81
+ "mocha": "^9.2.2",
82
+ "nodemon": "^2.0.15",
83
+ "nyc": "^15.1.0",
84
+ "rdtsc": "^2.0.0",
85
+ "rimraf": "^3.0.2",
86
+ "rollup": "^2.70.1",
87
+ "rollup-plugin-delete": "^2.0.0",
88
+ "rollup-plugin-istanbul": "^3.0.0",
89
+ "rollup-plugin-multi-input": "^1.3.1",
90
+ "rollup-plugin-node-polyfills": "^0.2.1",
91
+ "rollup-plugin-terser": "^7.0.2",
92
+ "ts-node": "^10.7.0",
93
+ "tsconfig-paths": "^3.14.1",
94
+ "typescript": "^4.6.4"
95
+ },
96
+ "dependencies": {
97
+ "tslib": "^2.3.1"
98
+ }
99
+ }