as-test 1.1.7 → 1.1.9
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2026-05-19 - v1.1.9
|
|
4
|
+
|
|
5
|
+
- fix: spec files that share a basename across subdirectories (e.g. `sqli/flags.spec.ts` and `sqli_v2/flags.spec.ts`) now build to their disambiguated artifact names across `ast test`, `ast run`, and `ast fuzz` — even when only one of them is being built. Previously the single-file build paths, the selector-filtered top-level build, the per-mode test/run dispatch, the plan listing, and the fuzz runner all computed duplicates from a local (and often single-element) file list, never matched anything, and clobbered each other into a single `flags.spec.wasm` / `parser.fuzz.wasm`; the runner then reported `bindings artifact not found`. Every call site now computes the duplicate set against the full configured input glob (`config.input` for tests/runs, `config.fuzz.input` when `overrides.kind === "fuzz"`), matching the runner's lookup behavior.
|
|
6
|
+
- chore: as-test's own suite now includes nested fixtures (`assembly/__tests__/nested/array.spec.ts`, `assembly/__fuzz__/nested/array.fuzz.ts`) that share basenames with siblings at the top level, exercising the disambiguation path end-to-end against the real build/run pipeline. The repo `as-test.config.json` inputs were widened to `**/*.spec.ts` / `**/*.fuzz.ts` to pick them up.
|
|
7
|
+
- chore: `npm test` now runs both the AssemblyScript spec suite (`npm run test:as`) and the Node integration suite (`npm run test:integration`) in one command. `release:check` and `prepublishOnly` no longer need to invoke `test:integration` separately.
|
|
8
|
+
- chore: GitHub workflows (`as-test.yml`, `release.yml`) now run `test:integration` after `test:ci`, so the Node integration suite gates PRs and releases (previously CI only ran the AS spec suite).
|
|
9
|
+
|
|
10
|
+
## 2026-05-18 - v1.1.8
|
|
11
|
+
|
|
12
|
+
- chore: `ast init` now writes `json-as` (`^1.3.5`) into the consumer's `devDependencies` so a fresh project installs everything it needs in one step.
|
|
13
|
+
- fix: align the `covered, missing` column in coverage file breakdowns so long file paths no longer push the counts out of column.
|
|
14
|
+
- feat: `--show-coverage` (and `--show-coverage=all`) now auto-enable coverage when coverage hasn't been explicitly toggled, removing the "coverage is disabled" warning when only the show flag is passed.
|
|
15
|
+
|
|
3
16
|
## 2026-05-18 - v1.1.7
|
|
4
17
|
|
|
5
18
|
### Modes & CLI
|
|
@@ -10,7 +23,7 @@
|
|
|
10
23
|
### Runtime
|
|
11
24
|
|
|
12
25
|
- chore: replace the homegrown JSON serialization helpers (`quote`, `rawOrNull`, `stringifyValue`, `escape`, `unicodeEscape`, `stringifyArray`) with `json-as` across the AssemblyScript runtime and transform, and delete `assembly/util/json.ts`. The `LogTransform` now injects `import { JSON } from "json-as/assembly"` per instrumented source and inlines `JSON.stringify<T>()` into the log helper.
|
|
13
|
-
- chore: promote `json-as` to a required peer dependency (`>=1.
|
|
26
|
+
- chore: promote `json-as` to a required peer dependency (`>=1.3.5`, the first version compatible with the AS NodeKind tuple changes used here). npm 7+ installs it automatically; pnpm and yarn users must add `json-as` to their own `devDependencies` alongside `as-test`.
|
|
14
27
|
- chore: remove the unused `__as_test_log_default` and `__as_test_json_value` exports.
|
|
15
28
|
|
|
16
29
|
## 2026-05-14 - v1.1.6
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, fuzz, FuzzSeed } from "as-test";
|
|
2
|
+
|
|
3
|
+
fuzz(
|
|
4
|
+
"nested array.fuzz: index windows stay ordered",
|
|
5
|
+
(start: i32, end: i32): bool => {
|
|
6
|
+
expect(start <= end).toBe(true);
|
|
7
|
+
return end - start <= 64;
|
|
8
|
+
},
|
|
9
|
+
).generate((seed: FuzzSeed, run: (start: i32, end: i32) => bool): void => {
|
|
10
|
+
const start = seed.i32({ min: 0, max: 64 });
|
|
11
|
+
const width = seed.i32({ min: 0, max: 64 });
|
|
12
|
+
run(start, start + width);
|
|
13
|
+
});
|
|
@@ -58,11 +58,17 @@ export async function build(
|
|
|
58
58
|
ensureDeps(config);
|
|
59
59
|
}
|
|
60
60
|
const pkgRunner = getPkgRunner();
|
|
61
|
-
const
|
|
61
|
+
const sourceInputPatterns =
|
|
62
|
+
overrides.kind === "fuzz" ? config.fuzz.input : config.input;
|
|
63
|
+
const inputPatterns = resolveInputPatterns(sourceInputPatterns, selectors);
|
|
62
64
|
const inputFiles = (await glob(inputPatterns)).sort((a, b) =>
|
|
63
65
|
a.localeCompare(b),
|
|
64
66
|
);
|
|
65
|
-
|
|
67
|
+
// Disambiguation must consider the entire configured input set, not just the
|
|
68
|
+
// selector-filtered subset, otherwise running `ast test <one-spec>` writes
|
|
69
|
+
// an artifact name the runner won't look up (it always globs full input).
|
|
70
|
+
const duplicateSpecBasenames =
|
|
71
|
+
await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
|
|
66
72
|
const coverageEnabled = resolveCoverageEnabled(
|
|
67
73
|
config.coverage,
|
|
68
74
|
featureToggles.coverage,
|
|
@@ -181,7 +187,10 @@ export async function getBuildInvocationPreview(
|
|
|
181
187
|
if (overrides.args?.length) {
|
|
182
188
|
config.buildOptions.args = [...config.buildOptions.args, ...overrides.args];
|
|
183
189
|
}
|
|
184
|
-
const
|
|
190
|
+
const sourceInputPatterns =
|
|
191
|
+
overrides.kind === "fuzz" ? config.fuzz.input : config.input;
|
|
192
|
+
const duplicateSpecBasenames =
|
|
193
|
+
await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
|
|
185
194
|
const outFile = `${config.outDir}/${resolveArtifactFileName(file, config.buildOptions.target, modeName, duplicateSpecBasenames)}`;
|
|
186
195
|
return getBuildCommand(
|
|
187
196
|
config,
|
|
@@ -218,7 +227,10 @@ export async function getBuildReuseInfo(
|
|
|
218
227
|
if (hasCustomBuildCommand(config)) {
|
|
219
228
|
return null;
|
|
220
229
|
}
|
|
221
|
-
const
|
|
230
|
+
const sourceInputPatterns =
|
|
231
|
+
overrides.kind === "fuzz" ? config.fuzz.input : config.input;
|
|
232
|
+
const duplicateSpecBasenames =
|
|
233
|
+
await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
|
|
222
234
|
const outFile = `${config.outDir}/${resolveArtifactFileName(file, config.buildOptions.target, modeName, duplicateSpecBasenames)}`;
|
|
223
235
|
const invocation = getBuildCommand(
|
|
224
236
|
config,
|
|
@@ -368,6 +380,11 @@ function resolveArtifactFileName(
|
|
|
368
380
|
const stem = ext.length ? legacy.slice(0, -ext.length) : legacy;
|
|
369
381
|
return `${stem}.${disambiguator}${ext}`;
|
|
370
382
|
}
|
|
383
|
+
async function resolveAllConfiguredDuplicateBasenames(configured) {
|
|
384
|
+
const patterns = Array.isArray(configured) ? configured : [configured];
|
|
385
|
+
const files = await glob(patterns);
|
|
386
|
+
return resolveDuplicateBasenames(files);
|
|
387
|
+
}
|
|
371
388
|
function resolveDuplicateBasenames(files) {
|
|
372
389
|
const counts = new Map();
|
|
373
390
|
for (const file of files) {
|
|
@@ -575,9 +592,8 @@ function getDefaultBuildArgs(config, featureToggles) {
|
|
|
575
592
|
const buildArgs = [];
|
|
576
593
|
const tryAsEnabled = resolveTryAsEnabled(featureToggles.tryAs);
|
|
577
594
|
buildArgs.push("--transform", "as-test/transform");
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
buildArgs.push("--transform", jsonAsTransform);
|
|
595
|
+
if (resolveProjectModule("json-as/transform")) {
|
|
596
|
+
buildArgs.push("--transform", "json-as/transform");
|
|
581
597
|
}
|
|
582
598
|
if (tryAsEnabled) {
|
|
583
599
|
buildArgs.push("--transform", "try-as/transform");
|
|
@@ -626,6 +642,7 @@ function resolveTryAsEnabled(override) {
|
|
|
626
642
|
'try-as feature was enabled, but package "try-as" is not installed',
|
|
627
643
|
);
|
|
628
644
|
}
|
|
645
|
+
if (override === true) return true;
|
|
629
646
|
return false;
|
|
630
647
|
}
|
|
631
648
|
function resolveCoverageEnabled(rawCoverage, override) {
|
|
@@ -29,7 +29,13 @@ export async function fuzz(
|
|
|
29
29
|
`No fuzz files matched: ${selectors.length ? selectors.join(", ") : "configured input patterns"}`,
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
// Disambiguation must consider the full configured fuzz input set, not the
|
|
33
|
+
// selector-filtered subset, so artifact names stay consistent across runs.
|
|
34
|
+
const fullPatterns = Array.isArray(config.input)
|
|
35
|
+
? config.input
|
|
36
|
+
: [config.input];
|
|
37
|
+
const allFuzzFiles = await glob(fullPatterns);
|
|
38
|
+
const duplicateBasenames = resolveDuplicateBasenames(allFuzzFiles);
|
|
33
39
|
const results = [];
|
|
34
40
|
for (const file of inputFiles) {
|
|
35
41
|
const buildStartedAt = Date.now();
|
|
@@ -650,6 +650,9 @@ function applyInit(root, target, example, fuzzExample, force) {
|
|
|
650
650
|
if (!devDependencies["as-test"]) {
|
|
651
651
|
devDependencies["as-test"] = "^" + getCliVersion();
|
|
652
652
|
}
|
|
653
|
+
if (!hasDependency(pkg, "json-as")) {
|
|
654
|
+
devDependencies["json-as"] = "^1.3.5";
|
|
655
|
+
}
|
|
653
656
|
if (!hasDependency(pkg, "assemblyscript")) {
|
|
654
657
|
devDependencies["assemblyscript"] = "^0.28.9";
|
|
655
658
|
}
|
package/bin/index.js
CHANGED
|
@@ -734,8 +734,24 @@ function resolveFeatureToggles(rawArgs, command) {
|
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
736
|
}
|
|
737
|
+
if (out.coverage === undefined && hasShowCoverageFlag(rawArgs, command)) {
|
|
738
|
+
out.coverage = true;
|
|
739
|
+
}
|
|
737
740
|
return out;
|
|
738
741
|
}
|
|
742
|
+
function hasShowCoverageFlag(rawArgs, command) {
|
|
743
|
+
let seenCommand = false;
|
|
744
|
+
for (const arg of rawArgs) {
|
|
745
|
+
if (!seenCommand) {
|
|
746
|
+
if (arg == command) seenCommand = true;
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (arg == "--show-coverage" || arg.startsWith("--show-coverage=")) {
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
739
755
|
function resolveFuzzOverrides(rawArgs, command) {
|
|
740
756
|
const out = {};
|
|
741
757
|
let seenCommand = false;
|
|
@@ -1350,7 +1366,8 @@ async function runTestSequential(
|
|
|
1350
1366
|
const results = [];
|
|
1351
1367
|
let failed = false;
|
|
1352
1368
|
const buildIntervals = [];
|
|
1353
|
-
const duplicateSpecBasenames =
|
|
1369
|
+
const duplicateSpecBasenames =
|
|
1370
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
1354
1371
|
for (const file of files) {
|
|
1355
1372
|
const buildStartedAt = Date.now();
|
|
1356
1373
|
let result;
|
|
@@ -1628,7 +1645,8 @@ async function runRuntimeMatrix(
|
|
|
1628
1645
|
failed: false,
|
|
1629
1646
|
passed: false,
|
|
1630
1647
|
}));
|
|
1631
|
-
const duplicateSpecBasenames =
|
|
1648
|
+
const duplicateSpecBasenames =
|
|
1649
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
1632
1650
|
const buildIntervals = [];
|
|
1633
1651
|
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
|
1634
1652
|
const file = files[fileIndex];
|
|
@@ -2088,7 +2106,8 @@ async function runTestMatrix(
|
|
|
2088
2106
|
failed: false,
|
|
2089
2107
|
passed: false,
|
|
2090
2108
|
}));
|
|
2091
|
-
const duplicateSpecBasenames =
|
|
2109
|
+
const duplicateSpecBasenames =
|
|
2110
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
2092
2111
|
const buildIntervals = [];
|
|
2093
2112
|
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
|
2094
2113
|
const file = files[fileIndex];
|
|
@@ -2394,7 +2413,8 @@ async function runRuntimeMatrixParallel(
|
|
|
2394
2413
|
const silentReporter = {};
|
|
2395
2414
|
const modeLabels = modes.map((modeName) => modeName ?? "default");
|
|
2396
2415
|
const showPerModeTimes = Boolean(runFlags.verbose);
|
|
2397
|
-
const duplicateSpecBasenames =
|
|
2416
|
+
const duplicateSpecBasenames =
|
|
2417
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
2398
2418
|
const ordered = new Array(files.length);
|
|
2399
2419
|
const useQueueDisplay = reporterSession.reporterKind == "default";
|
|
2400
2420
|
const queueDisplay = new ParallelQueueDisplay(
|
|
@@ -2543,7 +2563,8 @@ async function runTestSingleParallel(
|
|
|
2543
2563
|
snapshotEnabled,
|
|
2544
2564
|
createSnapshots: runFlags.createSnapshots,
|
|
2545
2565
|
});
|
|
2546
|
-
const duplicateSpecBasenames =
|
|
2566
|
+
const duplicateSpecBasenames =
|
|
2567
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
2547
2568
|
const results = new Array(files.length);
|
|
2548
2569
|
const useQueueDisplay = reporterSession.reporterKind == "default";
|
|
2549
2570
|
const queueDisplay = new ParallelQueueDisplay(
|
|
@@ -2713,7 +2734,8 @@ async function runTestMatrixParallel(
|
|
|
2713
2734
|
const silentReporter = {};
|
|
2714
2735
|
const modeLabels = modes.map((modeName) => modeName ?? "default");
|
|
2715
2736
|
const showPerModeTimes = Boolean(runFlags.verbose);
|
|
2716
|
-
const duplicateSpecBasenames =
|
|
2737
|
+
const duplicateSpecBasenames =
|
|
2738
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
2717
2739
|
const ordered = new Array(files.length);
|
|
2718
2740
|
const useQueueDisplay = reporterSession.reporterKind == "default";
|
|
2719
2741
|
const queueDisplay = new ParallelQueueDisplay(
|
|
@@ -3591,6 +3613,26 @@ function resolveDuplicateSpecBasenames(files) {
|
|
|
3591
3613
|
}
|
|
3592
3614
|
return duplicates;
|
|
3593
3615
|
}
|
|
3616
|
+
// Disambiguation must consider the full configured input set, not the
|
|
3617
|
+
// selector-filtered subset, otherwise running a single spec writes/looks up an
|
|
3618
|
+
// artifact name that the rest of the toolchain doesn't agree on.
|
|
3619
|
+
async function resolveAllConfiguredDuplicateSpecBasenames(configPath) {
|
|
3620
|
+
const resolvedConfigPath =
|
|
3621
|
+
configPath ?? path.join(process.cwd(), "./as-test.config.json");
|
|
3622
|
+
const config = loadConfig(resolvedConfigPath, false);
|
|
3623
|
+
return resolveDuplicateBasenamesForPatterns(config.input);
|
|
3624
|
+
}
|
|
3625
|
+
async function resolveAllConfiguredDuplicateFuzzBasenames(configPath) {
|
|
3626
|
+
const resolvedConfigPath =
|
|
3627
|
+
configPath ?? path.join(process.cwd(), "./as-test.config.json");
|
|
3628
|
+
const config = loadConfig(resolvedConfigPath, false);
|
|
3629
|
+
return resolveDuplicateBasenamesForPatterns(config.fuzz.input);
|
|
3630
|
+
}
|
|
3631
|
+
async function resolveDuplicateBasenamesForPatterns(configured) {
|
|
3632
|
+
const patterns = Array.isArray(configured) ? configured : [configured];
|
|
3633
|
+
const files = await glob(patterns);
|
|
3634
|
+
return resolveDuplicateSpecBasenames(files);
|
|
3635
|
+
}
|
|
3594
3636
|
function resolvePerFileArtifactKey(file, duplicateSpecBasenames) {
|
|
3595
3637
|
const base = path.basename(file);
|
|
3596
3638
|
let raw = base;
|
|
@@ -4159,8 +4201,10 @@ async function listExecutionPlan(
|
|
|
4159
4201
|
: `No test files matched: ${scope}`,
|
|
4160
4202
|
);
|
|
4161
4203
|
}
|
|
4162
|
-
const duplicateSpecBasenames =
|
|
4163
|
-
|
|
4204
|
+
const duplicateSpecBasenames =
|
|
4205
|
+
await resolveAllConfiguredDuplicateSpecBasenames(configPath);
|
|
4206
|
+
const duplicateFuzzBasenames =
|
|
4207
|
+
await resolveAllConfiguredDuplicateFuzzBasenames(configPath);
|
|
4164
4208
|
if (specFiles.length) {
|
|
4165
4209
|
process.stdout.write(chalk.bold("Resolved files:\n"));
|
|
4166
4210
|
for (const file of specFiles) {
|
package/bin/reporters/default.js
CHANGED
|
@@ -897,7 +897,12 @@ function renderCoverageSummary(summary, showCoverage) {
|
|
|
897
897
|
return a.file.localeCompare(b.file);
|
|
898
898
|
});
|
|
899
899
|
console.log(chalk.bold(" File Breakdown"));
|
|
900
|
-
|
|
900
|
+
const displayed = ranked.slice(0, 8);
|
|
901
|
+
const fileNameWidth = displayed.reduce(
|
|
902
|
+
(max, file) => Math.max(max, toRelativeResultPath(file.file).length),
|
|
903
|
+
0,
|
|
904
|
+
);
|
|
905
|
+
for (const file of displayed) {
|
|
901
906
|
const filePct = file.total
|
|
902
907
|
? ((file.covered * 100) / file.total).toFixed(2)
|
|
903
908
|
: "100.00";
|
|
@@ -910,11 +915,11 @@ function renderCoverageSummary(summary, showCoverage) {
|
|
|
910
915
|
const suffix =
|
|
911
916
|
file.uncovered > 0 ? `${file.uncovered} missing` : "fully covered";
|
|
912
917
|
console.log(
|
|
913
|
-
`
|
|
918
|
+
` ${fileColor(filePct.padStart(6) + "%")} ${toRelativeResultPath(file.file).padEnd(fileNameWidth)} ${chalk.dim(`${file.covered}/${file.total} covered, ${suffix}`)}`,
|
|
914
919
|
);
|
|
915
920
|
}
|
|
916
921
|
if (ranked.length > 8) {
|
|
917
|
-
console.log(chalk.dim(`
|
|
922
|
+
console.log(chalk.dim(` ... ${ranked.length - 8} more files`));
|
|
918
923
|
}
|
|
919
924
|
}
|
|
920
925
|
function renderCoveragePoints(files, expandNested) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "as-test",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"author": "Jairus Tanaka",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"wipc-js": "^0.1.1"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"json-as": ">=1.
|
|
16
|
+
"json-as": ">=1.3.5"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@assemblyscript/wasi-shim": "^0.1.0",
|
|
@@ -75,7 +75,8 @@
|
|
|
75
75
|
"access": "public"
|
|
76
76
|
},
|
|
77
77
|
"scripts": {
|
|
78
|
-
"test": "
|
|
78
|
+
"test": "npm run test:as && npm run test:integration",
|
|
79
|
+
"test:as": "node ./bin/index.js test --parallel",
|
|
79
80
|
"test:integration": "npm run build:cli && npm run build:lib && node --test tests/*.test.mjs",
|
|
80
81
|
"test:ci": "node ./bin/index.js test --parallel --tap --config ./as-test.ci.config.json",
|
|
81
82
|
"fuzz": "node ./bin/index.js fuzz",
|
|
@@ -96,8 +97,8 @@
|
|
|
96
97
|
"docs:build": "vitepress build docs",
|
|
97
98
|
"docs:preview": "vitepress preview docs",
|
|
98
99
|
"format": "prettier -w .",
|
|
99
|
-
"release:check": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run test:
|
|
100
|
-
"prepublishOnly": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run
|
|
100
|
+
"release:check": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run test:examples && npm pack --dry-run --cache /tmp/as-test-npm-cache",
|
|
101
|
+
"prepublishOnly": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run format"
|
|
101
102
|
},
|
|
102
103
|
"type": "module"
|
|
103
104
|
}
|