@flemist/test-variants 3.0.2 → 5.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.
Files changed (118) hide show
  1. package/README.md +283 -49
  2. package/build/browser/index.cjs +1 -0
  3. package/build/browser/index.d.ts +1 -0
  4. package/build/browser/index.mjs +4 -0
  5. package/build/common/-test/freezeProps.d.ts +2 -0
  6. package/build/common/garbage-collect/garbageCollect.d.ts +5 -0
  7. package/build/common/helpers/log.d.ts +5 -0
  8. package/build/common/index.cjs +1 -0
  9. package/build/common/index.d.ts +2 -0
  10. package/build/common/index.mjs +4 -0
  11. package/build/common/test-variants/-test/caches.d.ts +1 -0
  12. package/build/common/test-variants/-test/constants.d.ts +8 -0
  13. package/build/common/test-variants/-test/estimations/estimateCallCount.d.ts +4 -0
  14. package/build/common/test-variants/-test/estimations/estimateModeChanges.d.ts +4 -0
  15. package/build/common/test-variants/-test/generators/findBestError.d.ts +4 -0
  16. package/build/common/test-variants/-test/generators/primitives.d.ts +16 -0
  17. package/build/common/test-variants/-test/generators/run.d.ts +9 -0
  18. package/build/common/test-variants/-test/generators/template.d.ts +3 -0
  19. package/build/common/test-variants/-test/generators/testFunc.d.ts +3 -0
  20. package/build/common/test-variants/-test/helpers/CallController.d.ts +28 -0
  21. package/build/common/test-variants/-test/helpers/ErrorVariantController.d.ts +17 -0
  22. package/build/common/test-variants/-test/helpers/TestError.d.ts +2 -0
  23. package/build/common/test-variants/-test/helpers/deepEqualJsonLikeWithoutSeed.d.ts +1 -0
  24. package/build/common/test-variants/-test/helpers/deepFreezeJsonLike.d.ts +1 -0
  25. package/build/common/test-variants/-test/helpers/forEachVariant.d.ts +4 -0
  26. package/build/common/test-variants/-test/helpers/getMaxAttemptsPerVariant.d.ts +2 -0
  27. package/build/common/test-variants/-test/helpers/getParallelLimit.d.ts +7 -0
  28. package/build/common/test-variants/-test/helpers/getVariantArgs.d.ts +12 -0
  29. package/build/common/test-variants/-test/helpers/runWithTimeController.d.ts +7 -0
  30. package/build/common/test-variants/-test/invariants/CallCountInvariant.d.ts +18 -0
  31. package/build/common/test-variants/-test/invariants/CallOptionsInvariant.d.ts +32 -0
  32. package/build/common/test-variants/-test/invariants/ErrorBehaviorInvariant.d.ts +32 -0
  33. package/build/common/test-variants/-test/invariants/FindBestErrorInvariant.d.ts +37 -0
  34. package/build/common/test-variants/-test/invariants/IterationsInvariant.d.ts +21 -0
  35. package/build/common/test-variants/-test/invariants/LimitTimeInvariant.d.ts +26 -0
  36. package/build/common/test-variants/-test/invariants/LogInvariant.d.ts +126 -0
  37. package/build/common/test-variants/-test/invariants/OnErrorInvariant.d.ts +38 -0
  38. package/build/common/test-variants/-test/invariants/OnModeChangeInvariant.d.ts +32 -0
  39. package/build/common/test-variants/-test/invariants/ParallelInvariant.d.ts +25 -0
  40. package/build/common/test-variants/-test/log.d.ts +3 -0
  41. package/build/common/test-variants/-test/types.d.ts +34 -0
  42. package/build/common/test-variants/-test/variants.d.ts +3 -0
  43. package/build/common/test-variants/createTestRun.d.ts +3 -0
  44. package/build/common/test-variants/createTestVariants.d.ts +4 -0
  45. package/build/common/test-variants/iterator/createVariantsIterator.d.ts +4 -0
  46. package/build/common/test-variants/iterator/helpers/findValueIndex.d.ts +2 -0
  47. package/build/common/test-variants/iterator/helpers/mode.d.ts +3 -0
  48. package/build/common/test-variants/iterator/helpers/template.d.ts +7 -0
  49. package/build/common/test-variants/iterator/types.d.ts +102 -0
  50. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/caches.d.ts +1 -0
  51. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/check.d.ts +2 -0
  52. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/create.d.ts +3 -0
  53. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/format.d.ts +6 -0
  54. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/parse.d.ts +8 -0
  55. package/build/common/test-variants/iterator/variant-navigation/-test/helpers/variants.d.ts +12 -0
  56. package/build/common/test-variants/iterator/variant-navigation/variantNavigation.d.ts +28 -0
  57. package/build/common/test-variants/log/format.d.ts +7 -0
  58. package/build/common/test-variants/log/getMemoryUsage.d.ts +2 -0
  59. package/build/common/test-variants/log/logOptions.d.ts +8 -0
  60. package/build/common/test-variants/run/AbortErrorSilent.d.ts +3 -0
  61. package/build/common/test-variants/run/RunContext.d.ts +21 -0
  62. package/build/common/test-variants/run/createRunResult.d.ts +6 -0
  63. package/build/common/test-variants/run/createRunState.d.ts +23 -0
  64. package/build/common/test-variants/run/errorHandlers.d.ts +20 -0
  65. package/build/common/test-variants/run/gcManager.d.ts +6 -0
  66. package/build/common/test-variants/run/resolveRunOptions.d.ts +23 -0
  67. package/build/common/test-variants/run/runIterationLoop.d.ts +9 -0
  68. package/build/common/test-variants/run/runLogger.d.ts +9 -0
  69. package/build/common/test-variants/run/types.d.ts +57 -0
  70. package/build/common/test-variants/testVariantsRun.d.ts +6 -0
  71. package/build/common/test-variants/types.d.ts +183 -0
  72. package/build/createTestVariants-BL9wiuRD.mjs +1014 -0
  73. package/build/createTestVariants-CpzwjKTs.js +4 -0
  74. package/build/node/index.cjs +1 -0
  75. package/build/node/index.d.ts +8 -0
  76. package/build/node/index.mjs +102 -0
  77. package/build/node/test-variants/createSaveErrorVariantsStore.d.ts +5 -0
  78. package/{dist/lib → build/node}/test-variants/saveErrorVariants.d.ts +4 -3
  79. package/package.json +109 -68
  80. package/dist/bundle/browser.js +0 -650
  81. package/dist/lib/garbage-collect/garbageCollect.cjs +0 -30
  82. package/dist/lib/garbage-collect/garbageCollect.d.ts +0 -2
  83. package/dist/lib/garbage-collect/garbageCollect.mjs +0 -26
  84. package/dist/lib/index.cjs +0 -23
  85. package/dist/lib/index.d.ts +0 -7
  86. package/dist/lib/index.mjs +0 -13
  87. package/dist/lib/test-variants/argsToString.cjs +0 -17
  88. package/dist/lib/test-variants/argsToString.d.ts +0 -2
  89. package/dist/lib/test-variants/argsToString.mjs +0 -13
  90. package/dist/lib/test-variants/createTestVariants.cjs +0 -91
  91. package/dist/lib/test-variants/createTestVariants.d.ts +0 -8
  92. package/dist/lib/test-variants/createTestVariants.mjs +0 -87
  93. package/dist/lib/test-variants/createTestVariants.perf.cjs +0 -44
  94. package/dist/lib/test-variants/createTestVariants.perf.d.ts +0 -1
  95. package/dist/lib/test-variants/createTestVariants.perf.mjs +0 -42
  96. package/dist/lib/test-variants/prime.cjs +0 -65
  97. package/dist/lib/test-variants/prime.d.ts +0 -3
  98. package/dist/lib/test-variants/prime.mjs +0 -59
  99. package/dist/lib/test-variants/prime.perf.cjs +0 -30
  100. package/dist/lib/test-variants/prime.perf.d.ts +0 -1
  101. package/dist/lib/test-variants/prime.perf.mjs +0 -28
  102. package/dist/lib/test-variants/saveErrorVariants.cjs +0 -97
  103. package/dist/lib/test-variants/saveErrorVariants.mjs +0 -69
  104. package/dist/lib/test-variants/testVariantsCreateTestRun.cjs +0 -80
  105. package/dist/lib/test-variants/testVariantsCreateTestRun.d.ts +0 -22
  106. package/dist/lib/test-variants/testVariantsCreateTestRun.mjs +0 -76
  107. package/dist/lib/test-variants/testVariantsIterable.cjs +0 -70
  108. package/dist/lib/test-variants/testVariantsIterable.d.ts +0 -15
  109. package/dist/lib/test-variants/testVariantsIterable.mjs +0 -66
  110. package/dist/lib/test-variants/testVariantsIterator.cjs +0 -359
  111. package/dist/lib/test-variants/testVariantsIterator.d.ts +0 -67
  112. package/dist/lib/test-variants/testVariantsIterator.mjs +0 -355
  113. package/dist/lib/test-variants/testVariantsRun.cjs +0 -289
  114. package/dist/lib/test-variants/testVariantsRun.d.ts +0 -50
  115. package/dist/lib/test-variants/testVariantsRun.mjs +0 -265
  116. package/dist/lib/test-variants/types.cjs +0 -2
  117. package/dist/lib/test-variants/types.d.ts +0 -20
  118. package/dist/lib/test-variants/types.mjs +0 -1
@@ -1,355 +0,0 @@
1
- /** Find last index of value in array; uses custom equals or strict equality */
2
- function findLastIndex(values, value, equals) {
3
- if (equals) {
4
- for (let i = values.length - 1; i >= 0; i--) {
5
- if (equals(values[i], value)) {
6
- return i;
7
- }
8
- }
9
- return -1;
10
- }
11
- for (let i = values.length - 1; i >= 0; i--) {
12
- if (values[i] === value) {
13
- return i;
14
- }
15
- }
16
- return -1;
17
- }
18
- /** Calculate template values for given key index */
19
- function calcTemplateValues(templates, args, keyIndex) {
20
- const template = templates[keyIndex];
21
- if (typeof template === 'function') {
22
- return template(args);
23
- }
24
- return template;
25
- }
26
- /** Reset iterator state for new cycle */
27
- function resetIteratorState(state, templates, keysCount) {
28
- state.index = -1;
29
- state.repeatIndex = 0;
30
- for (let i = 0; i < keysCount; i++) {
31
- state.indexes[i] = -1;
32
- state.variants[i] = [];
33
- }
34
- if (keysCount > 0) {
35
- state.variants[0] = calcTemplateValues(templates, state.args, 0);
36
- }
37
- }
38
- /** Get effective max index for an arg (considering argLimit) */
39
- function getMaxIndex(state, keyIndex) {
40
- const variantsLen = state.variants[keyIndex].length;
41
- const argLimit = state.argLimits[keyIndex];
42
- if (argLimit == null) {
43
- return variantsLen;
44
- }
45
- return argLimit < variantsLen ? argLimit : variantsLen;
46
- }
47
- /** Advance to next variant in cartesian product; returns true if successful */
48
- function advanceVariant(state, templates, keys, keysCount) {
49
- var _a;
50
- for (let keyIndex = keysCount - 1; keyIndex >= 0; keyIndex--) {
51
- const valueIndex = state.indexes[keyIndex] + 1;
52
- const maxIndex = getMaxIndex(state, keyIndex);
53
- if (valueIndex < maxIndex) {
54
- const key = keys[keyIndex];
55
- const value = state.variants[keyIndex][valueIndex];
56
- state.indexes[keyIndex] = valueIndex;
57
- state.args[key] = value;
58
- for (keyIndex++; keyIndex < keysCount; keyIndex++) {
59
- const keyVariants = calcTemplateValues(templates, state.args, keyIndex);
60
- const keyMaxIndex = (_a = state.argLimits[keyIndex]) !== null && _a !== void 0 ? _a : keyVariants.length;
61
- if (keyVariants.length === 0 || keyMaxIndex <= 0) {
62
- break;
63
- }
64
- state.indexes[keyIndex] = 0;
65
- state.variants[keyIndex] = keyVariants;
66
- const key = keys[keyIndex];
67
- const value = keyVariants[0];
68
- state.args[key] = value;
69
- }
70
- if (keyIndex >= keysCount) {
71
- return true;
72
- }
73
- }
74
- }
75
- return false;
76
- }
77
- /** Validate saved args keys match iterator's arg names (ignoring "seed" key) */
78
- function validateArgsKeys(savedArgs, keysSet, keysCount) {
79
- const savedKeys = Object.keys(savedArgs).filter(k => k !== 'seed');
80
- if (savedKeys.length !== keysCount) {
81
- return false;
82
- }
83
- for (const key of savedKeys) {
84
- if (!keysSet.has(key)) {
85
- return false;
86
- }
87
- }
88
- return true;
89
- }
90
- /** For static templates, verify arg value exists in template values */
91
- function validateStaticArgsValues(savedArgs, templates, keys, keysCount, equals) {
92
- for (let i = 0; i < keysCount; i++) {
93
- const template = templates[i];
94
- if (typeof template !== 'function') {
95
- const value = savedArgs[keys[i]];
96
- if (findLastIndex(template, value, equals) < 0) {
97
- return false;
98
- }
99
- }
100
- }
101
- return true;
102
- }
103
- /** Check if current position >= pending args position; returns false if current < pending or all args skipped */
104
- function isPositionReached(state, pendingArgs, keys, keysCount, equals) {
105
- let anyCompared = false;
106
- for (let i = 0; i < keysCount; i++) {
107
- const currentValueIndex = state.indexes[i];
108
- const pendingValue = pendingArgs[keys[i]];
109
- const pendingValueIndex = findLastIndex(state.variants[i], pendingValue, equals);
110
- // Dynamic template value not found - skip this arg from comparison
111
- if (pendingValueIndex < 0) {
112
- continue;
113
- }
114
- anyCompared = true;
115
- if (currentValueIndex < pendingValueIndex) {
116
- return false;
117
- }
118
- if (currentValueIndex > pendingValueIndex) {
119
- return true;
120
- }
121
- }
122
- // All compared args are equal - position reached; or all args skipped - keep pending
123
- return anyCompared;
124
- }
125
- /** Update per-arg limits from args values */
126
- function updateArgLimits(state, limitArgs, templates, keys, keysCount, equals, limitArgOnError) {
127
- if (!limitArgOnError) {
128
- return;
129
- }
130
- for (let i = 0; i < keysCount; i++) {
131
- const key = keys[i];
132
- const value = limitArgs[key];
133
- const values = state.variants[i].length > 0
134
- ? state.variants[i]
135
- : calcTemplateValues(templates, state.args, i);
136
- const valueIndex = findLastIndex(values, value, equals);
137
- // Skip if value not found or already at index 0
138
- if (valueIndex <= 0) {
139
- continue;
140
- }
141
- // Check callback if provided
142
- if (typeof limitArgOnError === 'function') {
143
- const shouldLimit = limitArgOnError({
144
- name: key,
145
- valueIndex,
146
- values,
147
- maxValueIndex: state.argLimits[i],
148
- });
149
- if (!shouldLimit) {
150
- continue;
151
- }
152
- }
153
- // Update limit: argLimit = min(current argLimit, valueIndex)
154
- const currentLimit = state.argLimits[i];
155
- if (currentLimit == null || valueIndex < currentLimit) {
156
- state.argLimits[i] = valueIndex;
157
- }
158
- }
159
- }
160
- /** Process pending limits; returns true if any limit was applied */
161
- function processPendingLimits(state, templates, keys, keysCount, equals, limitArgOnError) {
162
- let applied = false;
163
- for (let i = state.pendingLimits.length - 1; i >= 0; i--) {
164
- const pending = state.pendingLimits[i];
165
- if (isPositionReached(state, pending.args, keys, keysCount, equals)) {
166
- // Current position >= pending position: apply limit
167
- if (state.count == null || state.index < state.count) {
168
- state.count = state.index;
169
- state.limit = typeof pending.error !== 'undefined'
170
- ? { args: pending.args, error: pending.error }
171
- : { args: pending.args };
172
- updateArgLimits(state, pending.args, templates, keys, keysCount, equals, limitArgOnError);
173
- applied = true;
174
- }
175
- // Remove from pending
176
- state.pendingLimits.splice(i, 1);
177
- }
178
- }
179
- return applied;
180
- }
181
- /** Creates test variants iterator with limiting capabilities */
182
- function testVariantsIterator(options) {
183
- const { argsTemplates, getSeed, repeatsPerVariant: _repeatsPerVariant, equals, limitArgOnError } = options;
184
- const repeatsPerVariant = _repeatsPerVariant !== null && _repeatsPerVariant !== void 0 ? _repeatsPerVariant : 1;
185
- const keys = Object.keys(argsTemplates);
186
- const templates = Object.values(argsTemplates);
187
- const keysCount = keys.length;
188
- const keysSet = new Set(keys);
189
- // Initialize state
190
- const indexes = [];
191
- const variants = [];
192
- const argLimits = [];
193
- for (let i = 0; i < keysCount; i++) {
194
- indexes[i] = -1;
195
- variants[i] = [];
196
- argLimits[i] = null;
197
- }
198
- const state = {
199
- args: {},
200
- indexes,
201
- variants,
202
- argLimits,
203
- index: -1,
204
- cycleIndex: -1,
205
- repeatIndex: 0,
206
- count: null,
207
- limit: null,
208
- started: false,
209
- currentArgs: null,
210
- pendingLimits: [],
211
- };
212
- const iterator = {
213
- get index() {
214
- return state.index;
215
- },
216
- get cycleIndex() {
217
- return state.cycleIndex;
218
- },
219
- get count() {
220
- return state.count;
221
- },
222
- get limit() {
223
- return state.limit;
224
- },
225
- addLimit(_options) {
226
- const hasArgs = typeof (_options === null || _options === void 0 ? void 0 : _options.args) !== 'undefined' && _options.args !== null;
227
- const hasIndex = (_options === null || _options === void 0 ? void 0 : _options.index) != null;
228
- // addLimit() or addLimit({error}) - uses current args and index
229
- if (!hasArgs && !hasIndex) {
230
- if (state.index < 0) {
231
- throw new Error('[testVariantsIterator] addLimit() requires at least one next() call');
232
- }
233
- if (state.count == null || state.index < state.count) {
234
- state.count = state.index;
235
- state.limit = typeof (_options === null || _options === void 0 ? void 0 : _options.error) !== 'undefined'
236
- ? { args: state.currentArgs, error: _options.error }
237
- : { args: state.currentArgs };
238
- updateArgLimits(state, state.args, templates, keys, keysCount, equals, limitArgOnError);
239
- }
240
- return;
241
- }
242
- // addLimit({index}) - only index limiting, no args
243
- if (hasIndex && !hasArgs) {
244
- if (state.count == null || _options.index < state.count) {
245
- state.count = _options.index;
246
- }
247
- return;
248
- }
249
- // addLimit({args}) or addLimit({args, error}) - pending limit + immediate per-arg limits
250
- if (hasArgs && !hasIndex) {
251
- // Validate args keys match iterator's arg names
252
- if (!validateArgsKeys(_options.args, keysSet, keysCount)) {
253
- return; // Discard - unreproducible (templates changed)
254
- }
255
- // For static templates, verify arg value exists
256
- if (!validateStaticArgsValues(_options.args, templates, keys, keysCount, equals)) {
257
- return; // Discard - unreproducible (value not in template)
258
- }
259
- // Apply per-arg limits immediately for static templates
260
- updateArgLimits(state, _options.args, templates, keys, keysCount, equals, limitArgOnError);
261
- // Store as pending limit for count/position-based limiting
262
- const pending = typeof _options.error !== 'undefined'
263
- ? { args: _options.args, error: _options.error }
264
- : { args: _options.args };
265
- state.pendingLimits.push(pending);
266
- return;
267
- }
268
- // addLimit({args, index}) or addLimit({args, index, error}) - immediate index + pending args
269
- if (hasArgs && hasIndex) {
270
- // Check if this is earliest (before potentially updating count)
271
- const isEarliest = state.count == null || _options.index < state.count;
272
- // Always apply index limit
273
- if (isEarliest) {
274
- state.count = _options.index;
275
- }
276
- // Validate args for limit property update
277
- if (!validateArgsKeys(_options.args, keysSet, keysCount)) {
278
- return; // Skip per-arg limits and limit property update
279
- }
280
- if (!validateStaticArgsValues(_options.args, templates, keys, keysCount, equals)) {
281
- return; // Skip per-arg limits and limit property update
282
- }
283
- // Update limit if this is earliest
284
- if (isEarliest) {
285
- state.limit = typeof _options.error !== 'undefined'
286
- ? { args: _options.args, error: _options.error }
287
- : { args: _options.args };
288
- updateArgLimits(state, _options.args, templates, keys, keysCount, equals, limitArgOnError);
289
- }
290
- }
291
- },
292
- start() {
293
- state.cycleIndex++;
294
- resetIteratorState(state, templates, keysCount);
295
- state.started = true;
296
- },
297
- next() {
298
- if (!state.started) {
299
- throw new Error('[testVariantsIterator] start() must be called before next()');
300
- }
301
- // Try next repeat for current variant
302
- if (state.index >= 0 && state.repeatIndex + 1 < repeatsPerVariant) {
303
- // Check if current variant is still within limit
304
- if (state.count == null || state.index < state.count) {
305
- state.repeatIndex++;
306
- if (getSeed) {
307
- const seed = getSeed({
308
- variantIndex: state.index,
309
- cycleIndex: state.cycleIndex,
310
- repeatIndex: state.repeatIndex,
311
- });
312
- state.currentArgs = Object.assign(Object.assign({}, state.args), { seed });
313
- }
314
- else {
315
- state.currentArgs = Object.assign({}, state.args);
316
- }
317
- return state.currentArgs;
318
- }
319
- }
320
- // Move to next variant
321
- state.repeatIndex = 0;
322
- if (!advanceVariant(state, templates, keys, keysCount)) {
323
- // First complete cycle sets count to total variant count
324
- if (state.count == null) {
325
- state.count = state.index + 1;
326
- }
327
- return null;
328
- }
329
- state.index++;
330
- // Process pending limits at new position
331
- if (state.pendingLimits.length > 0) {
332
- processPendingLimits(state, templates, keys, keysCount, equals, limitArgOnError);
333
- }
334
- // Check count limit (may have been updated by pending limit)
335
- if (state.count != null && state.index >= state.count) {
336
- return null;
337
- }
338
- if (getSeed) {
339
- const seed = getSeed({
340
- variantIndex: state.index,
341
- cycleIndex: state.cycleIndex,
342
- repeatIndex: state.repeatIndex,
343
- });
344
- state.currentArgs = Object.assign(Object.assign({}, state.args), { seed });
345
- }
346
- else {
347
- state.currentArgs = Object.assign({}, state.args);
348
- }
349
- return state.currentArgs;
350
- },
351
- };
352
- return iterator;
353
- }
354
-
355
- export { testVariantsIterator };
@@ -1,289 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var tslib = require('tslib');
6
- var abortControllerFast = require('@flemist/abort-controller-fast');
7
- var asyncUtils = require('@flemist/async-utils');
8
- var timeLimits = require('@flemist/time-limits');
9
- var garbageCollect_garbageCollect = require('../garbage-collect/garbageCollect.cjs');
10
- var testVariants_saveErrorVariants = require('./saveErrorVariants.cjs');
11
- var path = require('path');
12
- require('fs');
13
-
14
- function _interopNamespace(e) {
15
- if (e && e.__esModule) return e;
16
- var n = Object.create(null);
17
- if (e) {
18
- Object.keys(e).forEach(function (k) {
19
- if (k !== 'default') {
20
- var d = Object.getOwnPropertyDescriptor(e, k);
21
- Object.defineProperty(n, k, d.get ? d : {
22
- enumerable: true,
23
- get: function () { return e[k]; }
24
- });
25
- }
26
- });
27
- }
28
- n["default"] = e;
29
- return Object.freeze(n);
30
- }
31
-
32
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
33
-
34
- function formatDuration(ms) {
35
- const seconds = ms / 1000;
36
- if (seconds < 60) {
37
- return `${seconds.toFixed(1)}s`;
38
- }
39
- const minutes = seconds / 60;
40
- if (minutes < 60) {
41
- return `${minutes.toFixed(1)}m`;
42
- }
43
- const hours = minutes / 60;
44
- return `${hours.toFixed(1)}h`;
45
- }
46
- function testVariantsRun(testRun, variants, options = {}) {
47
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
48
- return tslib.__awaiter(this, void 0, void 0, function* () {
49
- const saveErrorVariants = options.saveErrorVariants;
50
- const retriesPerVariant = (_a = saveErrorVariants === null || saveErrorVariants === void 0 ? void 0 : saveErrorVariants.retriesPerVariant) !== null && _a !== void 0 ? _a : 1;
51
- const useToFindBestError = saveErrorVariants === null || saveErrorVariants === void 0 ? void 0 : saveErrorVariants.useToFindBestError;
52
- const sessionDate = new Date();
53
- const errorVariantFilePath = saveErrorVariants
54
- ? path__namespace.resolve(saveErrorVariants.dir, (_c = (_b = saveErrorVariants.getFilePath) === null || _b === void 0 ? void 0 : _b.call(saveErrorVariants, { sessionDate })) !== null && _c !== void 0 ? _c : testVariants_saveErrorVariants.generateErrorVariantFilePath({ sessionDate }))
55
- : null;
56
- const GC_Iterations = (_d = options.GC_Iterations) !== null && _d !== void 0 ? _d : 1000000;
57
- const GC_IterationsAsync = (_e = options.GC_IterationsAsync) !== null && _e !== void 0 ? _e : 10000;
58
- const GC_Interval = (_f = options.GC_Interval) !== null && _f !== void 0 ? _f : 1000;
59
- const logInterval = (_g = options.logInterval) !== null && _g !== void 0 ? _g : 5000;
60
- const logCompleted = (_h = options.logCompleted) !== null && _h !== void 0 ? _h : true;
61
- const abortSignalExternal = options.abortSignal;
62
- const findBestError = options.findBestError;
63
- const cycles = (_j = findBestError === null || findBestError === void 0 ? void 0 : findBestError.cycles) !== null && _j !== void 0 ? _j : 1;
64
- const dontThrowIfError = findBestError === null || findBestError === void 0 ? void 0 : findBestError.dontThrowIfError;
65
- const limitTime = options.limitTime;
66
- const parallel = options.parallel === true
67
- ? Math.pow(2, 31)
68
- : !options.parallel || options.parallel <= 0
69
- ? 1
70
- : options.parallel;
71
- // Apply initial limits
72
- if (options.limitVariantsCount != null) {
73
- variants.addLimit({ index: options.limitVariantsCount });
74
- }
75
- // Replay phase: run previously saved error variants before normal iteration
76
- if (saveErrorVariants) {
77
- const files = yield testVariants_saveErrorVariants.readErrorVariantFiles(saveErrorVariants.dir);
78
- for (const filePath of files) {
79
- const args = yield testVariants_saveErrorVariants.parseErrorVariantFile(filePath, saveErrorVariants.jsonToArgs);
80
- for (let retry = 0; retry < retriesPerVariant; retry++) {
81
- try {
82
- const promiseOrResult = testRun(args, -1, null);
83
- if (asyncUtils.isPromiseLike(promiseOrResult)) {
84
- yield promiseOrResult;
85
- }
86
- }
87
- catch (error) {
88
- if (useToFindBestError && findBestError) {
89
- // Store as pending limit for findBestError cycle
90
- variants.addLimit({ args, error });
91
- break; // Exit retry loop, continue to next file
92
- }
93
- else {
94
- throw error;
95
- }
96
- }
97
- }
98
- // If no error occurred during replays, the saved variant is no longer reproducible
99
- // (templates may have changed) - silently skip
100
- }
101
- }
102
- let prevCycleVariantsCount = null;
103
- let prevCycleDuration = null;
104
- const startTime = Date.now();
105
- let cycleStartTime = startTime;
106
- const abortControllerParallel = new abortControllerFast.AbortControllerFast();
107
- const abortSignalParallel = asyncUtils.combineAbortSignals(abortSignalExternal, abortControllerParallel.signal);
108
- const abortSignalAll = abortSignalParallel;
109
- let debug = false;
110
- let iterations = 0;
111
- let iterationsAsync = 0;
112
- let prevLogTime = Date.now();
113
- let prevGC_Time = prevLogTime;
114
- let prevGC_Iterations = iterations;
115
- let prevGC_IterationsAsync = iterationsAsync;
116
- const pool = parallel <= 1
117
- ? null
118
- : new timeLimits.Pool(parallel);
119
- function onCompleted() {
120
- if (logCompleted) {
121
- console.log(`[test-variants] variants: ${variants.index}, iterations: ${iterations}, async: ${iterationsAsync}`);
122
- }
123
- }
124
- // Main iteration using iterator
125
- let timeLimitExceeded = false;
126
- variants.start();
127
- while (variants.cycleIndex < cycles && !timeLimitExceeded) {
128
- let args;
129
- while (!(abortSignalExternal === null || abortSignalExternal === void 0 ? void 0 : abortSignalExternal.aborted) && (debug || (args = variants.next()) != null)) {
130
- const _index = variants.index;
131
- const _args = args;
132
- const now = (logInterval || GC_Interval || limitTime) && Date.now();
133
- if (limitTime && now - startTime >= limitTime) {
134
- timeLimitExceeded = true;
135
- break;
136
- }
137
- if (logInterval && now - prevLogTime >= logInterval) {
138
- // the log is required to prevent the karma browserNoActivityTimeout
139
- let log = '';
140
- const cycleElapsed = now - cycleStartTime;
141
- const totalElapsed = now - startTime;
142
- if (findBestError) {
143
- log += `cycle: ${variants.cycleIndex}, variant: ${variants.index}`;
144
- let max = variants.count;
145
- if (max != null) {
146
- if (prevCycleVariantsCount != null && prevCycleVariantsCount < max) {
147
- max = prevCycleVariantsCount;
148
- }
149
- }
150
- if (max != null && variants.index > 0) {
151
- let estimatedCycleTime;
152
- if (prevCycleDuration != null && prevCycleVariantsCount != null
153
- && variants.index < prevCycleVariantsCount && cycleElapsed < prevCycleDuration) {
154
- const adjustedDuration = prevCycleDuration - cycleElapsed;
155
- const adjustedCount = prevCycleVariantsCount - variants.index;
156
- const speedForRemaining = adjustedDuration / adjustedCount;
157
- const remainingTime = (max - variants.index) * speedForRemaining;
158
- estimatedCycleTime = cycleElapsed + remainingTime;
159
- }
160
- else {
161
- estimatedCycleTime = cycleElapsed * max / variants.index;
162
- }
163
- log += `/${max} (${formatDuration(cycleElapsed)}/${formatDuration(estimatedCycleTime)})`;
164
- }
165
- else {
166
- log += ` (${formatDuration(cycleElapsed)})`;
167
- }
168
- }
169
- else {
170
- log += `variant: ${variants.index} (${formatDuration(cycleElapsed)})`;
171
- }
172
- log += `, total: ${iterations} (${formatDuration(totalElapsed)})`;
173
- console.log(log);
174
- prevLogTime = now;
175
- }
176
- if (GC_Iterations && iterations - prevGC_Iterations >= GC_Iterations
177
- || GC_IterationsAsync && iterationsAsync - prevGC_IterationsAsync >= GC_IterationsAsync
178
- || GC_Interval && now - prevGC_Time >= GC_Interval) {
179
- prevGC_Iterations = iterations;
180
- prevGC_IterationsAsync = iterationsAsync;
181
- prevGC_Time = now;
182
- yield garbageCollect_garbageCollect.garbageCollect(1);
183
- }
184
- if (abortSignalExternal === null || abortSignalExternal === void 0 ? void 0 : abortSignalExternal.aborted) {
185
- continue;
186
- }
187
- if (!pool || abortSignalParallel.aborted) {
188
- try {
189
- let promiseOrIterations = testRun(_args, _index, abortSignalParallel);
190
- if (asyncUtils.isPromiseLike(promiseOrIterations)) {
191
- promiseOrIterations = yield promiseOrIterations;
192
- }
193
- if (!promiseOrIterations) {
194
- debug = true;
195
- abortControllerParallel.abort();
196
- continue;
197
- }
198
- const { iterationsAsync: _iterationsAsync, iterationsSync: _iterationsSync } = promiseOrIterations;
199
- iterationsAsync += _iterationsAsync;
200
- iterations += _iterationsSync + _iterationsAsync;
201
- }
202
- catch (err) {
203
- if (errorVariantFilePath) {
204
- yield testVariants_saveErrorVariants.saveErrorVariantFile(_args, errorVariantFilePath, saveErrorVariants.argsToJson);
205
- }
206
- if (findBestError) {
207
- variants.addLimit({ error: err });
208
- debug = false;
209
- }
210
- else {
211
- throw err;
212
- }
213
- }
214
- }
215
- else {
216
- if (!pool.hold(1)) {
217
- yield pool.holdWait(1);
218
- }
219
- // eslint-disable-next-line @typescript-eslint/no-loop-func
220
- void (() => tslib.__awaiter(this, void 0, void 0, function* () {
221
- try {
222
- if (abortSignalParallel === null || abortSignalParallel === void 0 ? void 0 : abortSignalParallel.aborted) {
223
- return;
224
- }
225
- let promiseOrIterations = testRun(_args, _index, abortSignalParallel);
226
- if (asyncUtils.isPromiseLike(promiseOrIterations)) {
227
- promiseOrIterations = yield promiseOrIterations;
228
- }
229
- if (!promiseOrIterations) {
230
- debug = true;
231
- abortControllerParallel.abort();
232
- return;
233
- }
234
- const { iterationsAsync: _iterationsAsync, iterationsSync: _iterationsSync } = promiseOrIterations;
235
- iterationsAsync += _iterationsAsync;
236
- iterations += _iterationsSync + _iterationsAsync;
237
- }
238
- catch (err) {
239
- if (errorVariantFilePath) {
240
- yield testVariants_saveErrorVariants.saveErrorVariantFile(_args, errorVariantFilePath, saveErrorVariants.argsToJson);
241
- }
242
- if (findBestError) {
243
- variants.addLimit({ error: err });
244
- debug = false;
245
- }
246
- else {
247
- throw err;
248
- }
249
- }
250
- finally {
251
- void pool.release(1);
252
- }
253
- }))();
254
- }
255
- }
256
- // Track cycle metrics for logging
257
- prevCycleVariantsCount = variants.count;
258
- prevCycleDuration = Date.now() - cycleStartTime;
259
- cycleStartTime = Date.now();
260
- variants.start();
261
- }
262
- if (pool) {
263
- yield pool.holdWait(parallel);
264
- void pool.release(parallel);
265
- }
266
- if (abortSignalAll === null || abortSignalAll === void 0 ? void 0 : abortSignalAll.aborted) {
267
- throw abortSignalAll.reason;
268
- }
269
- onCompleted();
270
- yield garbageCollect_garbageCollect.garbageCollect(1);
271
- // Construct bestError from iterator state
272
- const bestError = variants.limit
273
- ? {
274
- error: variants.limit.error,
275
- args: variants.limit.args,
276
- index: variants.count,
277
- }
278
- : null;
279
- if (bestError && !dontThrowIfError) {
280
- throw bestError.error;
281
- }
282
- return {
283
- iterations,
284
- bestError,
285
- };
286
- });
287
- }
288
-
289
- exports.testVariantsRun = testVariantsRun;