Skip to content

Commit 441b9c4

Browse files
committed
wip
1 parent 4eeb963 commit 441b9c4

File tree

5 files changed

+61
-199
lines changed

5 files changed

+61
-199
lines changed

assembly/assertCollector.ts

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,3 @@
1-
import { toJson } from "./formatPrint";
2-
3-
class AssertResultCollector {
4-
total: u32 = 0;
5-
fail: u32 = 0;
6-
failed_info: Map<string, string[][]> = new Map();
7-
currentTestDescriptions: string[] = [];
8-
9-
addDescription(description: string): void {
10-
this.currentTestDescriptions.push(description);
11-
}
12-
removeDescription(): void {
13-
this.currentTestDescriptions.pop();
14-
}
15-
collectCheckResult(
16-
result: bool,
17-
codeInfoIndex: u32,
18-
actualValue: string,
19-
expectValue: string,
20-
): void {
21-
this.total++;
22-
if (!result) {
23-
this.fail++;
24-
const testCaseFullName = this.currentTestDescriptions.join(" - ");
25-
const assertMessage = [
26-
codeInfoIndex.toString(),
27-
actualValue,
28-
expectValue,
29-
];
30-
if (this.failed_info.has(testCaseFullName)) {
31-
this.failed_info.get(testCaseFullName).push(assertMessage);
32-
} else {
33-
this.failed_info.set(testCaseFullName, [assertMessage]);
34-
}
35-
}
36-
}
37-
38-
clear(): void {
39-
this.failed_info = new Map();
40-
this.currentTestDescriptions = [];
41-
__collect();
42-
}
43-
44-
totalString(): string {
45-
return `"total":` + this.total.toString();
46-
}
47-
failString(): string {
48-
return `"fail":` + this.fail.toString();
49-
}
50-
failInfoString(): string {
51-
return `"failed_info":` + toJson(this.failed_info);
52-
}
1+
export namespace assertResult {
2+
export declare function collectCheckResult();
533
}
54-
55-
export const assertResult = new AssertResultCollector();

assembly/output.ts

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,5 @@
1-
import { assertResult } from "./assertCollector";
21
import { outputTrace } from "./covInstrument";
32

4-
import {
5-
args_sizes_get,
6-
args_get,
7-
errno,
8-
errnoToString,
9-
fd,
10-
path_open,
11-
lookupflags,
12-
rights,
13-
oflags,
14-
fdflags,
15-
iovec,
16-
fd_write,
17-
fd_close,
18-
} from "@assemblyscript/wasi-shim/assembly/bindings/wasi_snapshot_preview1";
19-
203
export function output(): void {
21-
const kvPair: string[] = [];
22-
kvPair.push(assertResult.totalString());
23-
kvPair.push(assertResult.failString());
24-
kvPair.push(assertResult.failInfoString());
25-
assertResult.clear();
26-
274
outputTrace();
28-
29-
const outputString = "{" + kvPair.join(",") + "}";
30-
31-
const outputFileName = getArgs()[1].slice(0, -5) + ".assert.log";
32-
writeFile(outputFileName, outputString);
33-
}
34-
35-
let ret: errno;
36-
37-
function perror(msg: string): void {
38-
if (ret == errno.SUCCESS) {
39-
return;
40-
}
41-
assert(false, errnoToString(ret) + " " + msg);
42-
}
43-
44-
function checkMemory(offset: usize): void {
45-
assert(offset < usize(i32.MAX_VALUE), "OOM");
46-
}
47-
48-
function fromCString(cstring: usize): string {
49-
let size = 0;
50-
while (load<u8>(cstring + size) !== 0) {
51-
size++;
52-
}
53-
return String.UTF8.decodeUnsafe(cstring, size);
54-
}
55-
56-
function getArgs(): string[] {
57-
const args: string[] = [];
58-
59-
const count_and_size = memory.data(sizeof<usize>() * 2);
60-
checkMemory(count_and_size + sizeof<usize>() * 2);
61-
ret = args_sizes_get(count_and_size, count_and_size + 4);
62-
perror("args_sizes_get");
63-
const argc = load<usize>(count_and_size, 0);
64-
const argv_total_size = load<usize>(count_and_size, sizeof<usize>());
65-
66-
const argv_ptr_array = new ArrayBuffer(i32((argc + 1) * sizeof<usize>()));
67-
const argv_total_string = new ArrayBuffer(i32(argv_total_size));
68-
checkMemory(changetype<usize>(argv_ptr_array) + (argc + 1) * sizeof<usize>());
69-
checkMemory(changetype<usize>(argv_total_string) + argv_total_size);
70-
ret = args_get(
71-
changetype<usize>(argv_ptr_array),
72-
changetype<usize>(argv_total_string),
73-
);
74-
perror("args_get");
75-
for (let i: usize = 0; i < argc; i++) {
76-
const argv_ptr = load<usize>(
77-
changetype<usize>(argv_ptr_array) + i * sizeof<usize>(),
78-
);
79-
const arg = fromCString(argv_ptr);
80-
args.push(arg);
81-
}
82-
83-
return args;
84-
}
85-
86-
function writeFile(path: string, data: string): void {
87-
if (data.length == 0) return;
88-
// open
89-
const utf8path = String.UTF8.encode(path);
90-
const fdptr = memory.data(sizeof<fd>());
91-
checkMemory(changetype<usize>(utf8path) + utf8path.byteLength);
92-
ret = path_open(
93-
3,
94-
lookupflags.SYMLINK_FOLLOW,
95-
changetype<usize>(utf8path),
96-
utf8path.byteLength,
97-
oflags.CREAT | oflags.TRUNC,
98-
rights.FD_WRITE |
99-
rights.FD_SEEK |
100-
rights.FD_TELL |
101-
rights.FD_FILESTAT_GET |
102-
rights.PATH_CREATE_FILE,
103-
rights.FD_WRITE |
104-
rights.FD_SEEK |
105-
rights.FD_TELL |
106-
rights.FD_FILESTAT_GET |
107-
rights.PATH_CREATE_FILE,
108-
fdflags.SYNC,
109-
fdptr,
110-
);
111-
perror("path_open");
112-
const fileDescriptor: fd = load<fd>(fdptr);
113-
114-
// write
115-
const buf = String.UTF8.encode(data);
116-
const iov = changetype<iovec>(memory.data(sizeof<iovec>()));
117-
iov.buf = changetype<usize>(buf);
118-
iov.buf_len = buf.byteLength;
119-
const written_ptr = memory.data(sizeof<usize>());
120-
checkMemory(changetype<usize>(buf) + buf.byteLength);
121-
do {
122-
ret = fd_write(fileDescriptor, changetype<usize>(iov), 1, written_ptr);
123-
perror("fd_write");
124-
iov.buf_len -= load<usize>(written_ptr);
125-
iov.buf += load<usize>(written_ptr);
126-
} while (iov.buf_len > 0);
127-
fd_close(fileDescriptor);
1285
}

src/assertResult.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { promises } from "node:fs";
22
import { json2map } from "./utils/index.js";
3-
import { AssertErrorMessages, AssertMessages, ErrorMessages, ExpectInfo, IAssertResult } from "./interface.js";
3+
import { AssertErrorMessages, AssertMessage, ErrorMessages, ExpectInfo, IAssertResult } from "./interface.js";
44

55
const readFile = promises.readFile;
66

@@ -17,7 +17,7 @@ export class AssertResult {
1717
try {
1818
const expectContent = await readFile(expectInfoFilePath, { encoding: "utf8" });
1919
expectInfo = json2map(JSON.parse(expectContent) as ExpectInfo);
20-
for (const [key, value] of json2map<AssertMessages>(result.failed_info)) {
20+
for (const [key, value] of json2map<AssertMessage[]>(result.failed_info)) {
2121
const errorMsgs: ErrorMessages = [];
2222
for (const msg of value) {
2323
const [index, actualValue, expectValue] = msg;

src/core/execute.ts

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,63 @@
11
import { WASI } from "node:wasi";
22
import { promises } from "node:fs";
33
import { ensureDirSync } from "fs-extra";
4-
import { basename, join } from "node:path";
4+
import { basename } from "node:path";
55
import { instantiate, Imports as ASImports } from "@assemblyscript/loader";
66
import { AssertResult } from "../assertResult.js";
77
import { Imports, ImportsArgument } from "../index.js";
8-
import { IAssertResult, InstrumentResult } from "../interface.js";
8+
import { AssertFailMessage, AssertMessage, IAssertResult, InstrumentResult } from "../interface.js";
99
import { mockInstruFunc, covInstruFunc } from "../utils/import.js";
1010
import { supplyDefaultFunction } from "../utils/index.js";
1111
import { parseImportFunctionInfo } from "../utils/wasmparser.js";
1212
const readFile = promises.readFile;
1313

14-
async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
14+
class ExecutionRecorder implements IAssertResult {
15+
total: number = 0;
16+
fail: number = 0;
17+
failed_info: AssertFailMessage = {};
18+
currentTestDescriptions: string[] = [];
19+
20+
addDescription(description: string): void {
21+
this.currentTestDescriptions.push(description);
22+
}
23+
removeDescription(): void {
24+
this.currentTestDescriptions.pop();
25+
}
26+
collectCheckResult(result: boolean, codeInfoIndex: number, actualValue: string, expectValue: string): void {
27+
this.total++;
28+
if (!result) {
29+
this.fail++;
30+
const testCaseFullName = this.currentTestDescriptions.join(" - ");
31+
const assertMessage: AssertMessage = [codeInfoIndex.toString(), actualValue, expectValue];
32+
this.failed_info[testCaseFullName] = this.failed_info[testCaseFullName] || [];
33+
this.failed_info[testCaseFullName].push(assertMessage);
34+
}
35+
}
36+
37+
getCollectionFuncSet(arg: ImportsArgument): Record<string, Record<string, unknown>> {
38+
const exports = arg.exports!;
39+
return {
40+
__unittest_framework_env: {
41+
addDescription: (description: number): void => {
42+
this.addDescription(exports.__getString(description));
43+
},
44+
removeDescription: (): void => {
45+
this.removeDescription();
46+
},
47+
collectCheckResult: (result: number, codeInfoIndex: number, actualValue: number, expectValue: number): void => {
48+
this.collectCheckResult(
49+
result != 0,
50+
codeInfoIndex,
51+
exports.__getString(actualValue),
52+
exports.__getString(expectValue)
53+
);
54+
},
55+
},
56+
};
57+
}
58+
}
59+
60+
async function nodeExecutor(wasm: string, outFolder: string, imports: Imports): Promise<ExecutionRecorder> {
1561
const wasi = new WASI({
1662
args: ["node", basename(wasm)],
1763
env: process.env,
@@ -21,10 +67,13 @@ async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
2167
version: "preview1",
2268
});
2369

70+
const recorder = new ExecutionRecorder();
71+
2472
const importsArg = new ImportsArgument();
2573
const userDefinedImportsObject = imports === null ? {} : imports(importsArg);
2674
const importObject: ASImports = {
2775
wasi_snapshot_preview1: wasi.wasiImport,
76+
...recorder.getCollectionFuncSet(importsArg),
2877
mockInstrument: mockInstruFunc,
2978
...covInstruFunc(wasm),
3079
...userDefinedImportsObject,
@@ -45,6 +94,7 @@ async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
4594
}
4695
throw new Error("node executor abort.");
4796
}
97+
return recorder;
4898
}
4999

50100
export async function execWasmBinarys(
@@ -56,22 +106,9 @@ export async function execWasmBinarys(
56106
ensureDirSync(outFolder);
57107
await Promise.all<void>(
58108
instrumentResult.map(async (res): Promise<void> => {
59-
await nodeExecutor(res.instrumentedWasm, outFolder, imports);
60109
const { instrumentedWasm, expectInfo } = res;
61-
const assertLogFilePath = join(outFolder, basename(instrumentedWasm).slice(0, -4).concat("assert.log"));
62-
63-
let content;
64-
try {
65-
content = await readFile(assertLogFilePath, { encoding: "utf8" });
66-
} catch (error) {
67-
if (error instanceof Error) {
68-
console.error(error.stack);
69-
}
70-
throw new Error(`maybe forget call "endTest()" at the end of "*.test.ts" or Job abort before output`);
71-
}
72-
const assertResult = JSON.parse(content) as IAssertResult;
73-
74-
await assertRes.merge(assertResult, expectInfo);
110+
const recorder: ExecutionRecorder = await nodeExecutor(instrumentedWasm, outFolder, imports);
111+
await assertRes.merge(recorder, expectInfo);
75112
})
76113
);
77114
return assertRes;

src/interface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ export type TestCaseName = string;
5151
export type ExpectInfoIndex = string;
5252
export type AssertExpectValue = string;
5353
export type AssertActualValue = string;
54-
export type AssertMessages = [ExpectInfoIndex, AssertActualValue, AssertExpectValue][];
55-
export type AssertFailMessage = Record<TestCaseName, AssertMessages>;
54+
export type AssertMessage = [ExpectInfoIndex, AssertActualValue, AssertExpectValue];
55+
export type AssertFailMessage = Record<TestCaseName, AssertMessage[]>;
5656

5757
export type ErrorMessages = string[];
5858
export type AssertErrorMessages = Map<TestCaseName, ErrorMessages>;

0 commit comments

Comments
 (0)