Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions assembly/assertCollector.ts

This file was deleted.

18 changes: 18 additions & 0 deletions assembly/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export namespace assertResult {

@external("__unittest_framework_env","addDescription")
export declare function addDescription(description: string): void;


@external("__unittest_framework_env","removeDescription")
export declare function removeDescription(): void;


@external("__unittest_framework_env","collectCheckResult")
export declare function collectCheckResult(
result: bool,
codeInfoIndex: number,
actualValue: string,
expectValue: string,
): void;
}
2 changes: 1 addition & 1 deletion assembly/expect.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { equal, isNull } from "./comparison";
import { assertResult } from "./assertCollector";
import { assertResult } from "./env";
import { toJson } from "./formatPrint";


Expand Down
2 changes: 1 addition & 1 deletion assembly/implement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assertResult } from "./assertCollector";
import { assertResult } from "./env";
import { MockFn, mockFunctionStatus } from "./mockInstrument";

export function describeImpl(
Expand Down
123 changes: 0 additions & 123 deletions assembly/output.ts
Original file line number Diff line number Diff line change
@@ -1,128 +1,5 @@
import { assertResult } from "./assertCollector";
import { outputTrace } from "./covInstrument";

import {
args_sizes_get,
args_get,
errno,
errnoToString,
fd,
path_open,
lookupflags,
rights,
oflags,
fdflags,
iovec,
fd_write,
fd_close,
} from "@assemblyscript/wasi-shim/assembly/bindings/wasi_snapshot_preview1";

export function output(): void {
const kvPair: string[] = [];
kvPair.push(assertResult.totalString());
kvPair.push(assertResult.failString());
kvPair.push(assertResult.failInfoString());
assertResult.clear();

outputTrace();

const outputString = "{" + kvPair.join(",") + "}";

const outputFileName = getArgs()[1].slice(0, -5) + ".assert.log";
writeFile(outputFileName, outputString);
}

let ret: errno;

function perror(msg: string): void {
if (ret == errno.SUCCESS) {
return;
}
assert(false, errnoToString(ret) + " " + msg);
}

function checkMemory(offset: usize): void {
assert(offset < usize(i32.MAX_VALUE), "OOM");
}

function fromCString(cstring: usize): string {
let size = 0;
while (load<u8>(cstring + size) !== 0) {
size++;
}
return String.UTF8.decodeUnsafe(cstring, size);
}

function getArgs(): string[] {
const args: string[] = [];

const count_and_size = memory.data(sizeof<usize>() * 2);
checkMemory(count_and_size + sizeof<usize>() * 2);
ret = args_sizes_get(count_and_size, count_and_size + 4);
perror("args_sizes_get");
const argc = load<usize>(count_and_size, 0);
const argv_total_size = load<usize>(count_and_size, sizeof<usize>());

const argv_ptr_array = new ArrayBuffer(i32((argc + 1) * sizeof<usize>()));
const argv_total_string = new ArrayBuffer(i32(argv_total_size));
checkMemory(changetype<usize>(argv_ptr_array) + (argc + 1) * sizeof<usize>());
checkMemory(changetype<usize>(argv_total_string) + argv_total_size);
ret = args_get(
changetype<usize>(argv_ptr_array),
changetype<usize>(argv_total_string),
);
perror("args_get");
for (let i: usize = 0; i < argc; i++) {
const argv_ptr = load<usize>(
changetype<usize>(argv_ptr_array) + i * sizeof<usize>(),
);
const arg = fromCString(argv_ptr);
args.push(arg);
}

return args;
}

function writeFile(path: string, data: string): void {
if (data.length == 0) return;
// open
const utf8path = String.UTF8.encode(path);
const fdptr = memory.data(sizeof<fd>());
checkMemory(changetype<usize>(utf8path) + utf8path.byteLength);
ret = path_open(
3,
lookupflags.SYMLINK_FOLLOW,
changetype<usize>(utf8path),
utf8path.byteLength,
oflags.CREAT | oflags.TRUNC,
rights.FD_WRITE |
rights.FD_SEEK |
rights.FD_TELL |
rights.FD_FILESTAT_GET |
rights.PATH_CREATE_FILE,
rights.FD_WRITE |
rights.FD_SEEK |
rights.FD_TELL |
rights.FD_FILESTAT_GET |
rights.PATH_CREATE_FILE,
fdflags.SYNC,
fdptr,
);
perror("path_open");
const fileDescriptor: fd = load<fd>(fdptr);

// write
const buf = String.UTF8.encode(data);
const iov = changetype<iovec>(memory.data(sizeof<iovec>()));
iov.buf = changetype<usize>(buf);
iov.buf_len = buf.byteLength;
const written_ptr = memory.data(sizeof<usize>());
checkMemory(changetype<usize>(buf) + buf.byteLength);
do {
ret = fd_write(fileDescriptor, changetype<usize>(iov), 1, written_ptr);
perror("fd_write");
iov.buf_len -= load<usize>(written_ptr);
iov.buf += load<usize>(written_ptr);
} while (iov.buf_len > 0);
fd_close(fileDescriptor);
}
4 changes: 2 additions & 2 deletions src/assertResult.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { promises } from "node:fs";
import { json2map } from "./utils/index.js";
import { AssertErrorMessages, AssertMessages, ErrorMessages, ExpectInfo, IAssertResult } from "./interface.js";
import { AssertErrorMessages, AssertMessage, ErrorMessages, ExpectInfo, IAssertResult } from "./interface.js";

const readFile = promises.readFile;

Expand All @@ -17,7 +17,7 @@ export class AssertResult {
try {
const expectContent = await readFile(expectInfoFilePath, { encoding: "utf8" });
expectInfo = json2map(JSON.parse(expectContent) as ExpectInfo);
for (const [key, value] of json2map<AssertMessages>(result.failed_info)) {
for (const [key, value] of json2map<AssertMessage[]>(result.failed_info)) {
const errorMsgs: ErrorMessages = [];
for (const msg of value) {
const [index, actualValue, expectValue] = msg;
Expand Down
29 changes: 11 additions & 18 deletions src/core/execute.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { WASI } from "node:wasi";
import { promises } from "node:fs";
import { ensureDirSync } from "fs-extra";
import { basename, join } from "node:path";
import { basename } from "node:path";
import { instantiate, Imports as ASImports } from "@assemblyscript/loader";
import { AssertResult } from "../assertResult.js";
import { Imports, ImportsArgument } from "../index.js";
import { IAssertResult, InstrumentResult } from "../interface.js";
import { InstrumentResult } from "../interface.js";
import { mockInstruFunc, covInstruFunc } from "../utils/import.js";
import { supplyDefaultFunction } from "../utils/index.js";
import { parseImportFunctionInfo } from "../utils/wasmparser.js";
import { ExecutionRecorder } from "./executionRecorder.js";

const readFile = promises.readFile;

async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
async function nodeExecutor(wasm: string, outFolder: string, imports: Imports): Promise<ExecutionRecorder> {
const wasi = new WASI({
args: ["node", basename(wasm)],
env: process.env,
Expand All @@ -21,10 +23,13 @@ async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
version: "preview1",
});

const recorder = new ExecutionRecorder();

const importsArg = new ImportsArgument();
const userDefinedImportsObject = imports === null ? {} : imports(importsArg);
const importObject: ASImports = {
wasi_snapshot_preview1: wasi.wasiImport,
...recorder.getCollectionFuncSet(importsArg),
mockInstrument: mockInstruFunc,
...covInstruFunc(wasm),
...userDefinedImportsObject,
Expand All @@ -45,6 +50,7 @@ async function nodeExecutor(wasm: string, outFolder: string, imports: Imports) {
}
throw new Error("node executor abort.");
}
return recorder;
}

export async function execWasmBinarys(
Expand All @@ -56,22 +62,9 @@ export async function execWasmBinarys(
ensureDirSync(outFolder);
await Promise.all<void>(
instrumentResult.map(async (res): Promise<void> => {
await nodeExecutor(res.instrumentedWasm, outFolder, imports);
const { instrumentedWasm, expectInfo } = res;
const assertLogFilePath = join(outFolder, basename(instrumentedWasm).slice(0, -4).concat("assert.log"));

let content;
try {
content = await readFile(assertLogFilePath, { encoding: "utf8" });
} catch (error) {
if (error instanceof Error) {
console.error(error.stack);
}
throw new Error(`maybe forget call "endTest()" at the end of "*.test.ts" or Job abort before output`);
}
const assertResult = JSON.parse(content) as IAssertResult;

await assertRes.merge(assertResult, expectInfo);
const recorder: ExecutionRecorder = await nodeExecutor(instrumentedWasm, outFolder, imports);
await assertRes.merge(recorder, expectInfo);
})
);
return assertRes;
Expand Down
47 changes: 47 additions & 0 deletions src/core/executionRecorder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ImportsArgument } from "../index.js";
import { AssertFailMessage, AssertMessage, IAssertResult } from "../interface.js";

export class ExecutionRecorder implements IAssertResult {
total: number = 0;
fail: number = 0;
failed_info: AssertFailMessage = {};
_currentTestDescriptions: string[] = [];

_addDescription(description: string): void {
this._currentTestDescriptions.push(description);
}
_removeDescription(): void {
this._currentTestDescriptions.pop();
}
collectCheckResult(result: boolean, codeInfoIndex: number, actualValue: string, expectValue: string): void {
this.total++;
if (!result) {
this.fail++;
const testCaseFullName = this._currentTestDescriptions.join(" - ");
const assertMessage: AssertMessage = [codeInfoIndex.toString(), actualValue, expectValue];
this.failed_info[testCaseFullName] = this.failed_info[testCaseFullName] || [];
this.failed_info[testCaseFullName].push(assertMessage);
}
}

getCollectionFuncSet(arg: ImportsArgument): Record<string, Record<string, unknown>> {
return {
__unittest_framework_env: {
addDescription: (description: number): void => {
this._addDescription(arg.exports!.__getString(description));
},
removeDescription: (): void => {
this._removeDescription();
},
collectCheckResult: (result: number, codeInfoIndex: number, actualValue: number, expectValue: number): void => {
this.collectCheckResult(
result !== 0,
codeInfoIndex,
arg.exports!.__getString(actualValue),
arg.exports!.__getString(expectValue)
);
},
},
};
}
}
4 changes: 2 additions & 2 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ export type TestCaseName = string;
export type ExpectInfoIndex = string;
export type AssertExpectValue = string;
export type AssertActualValue = string;
export type AssertMessages = [ExpectInfoIndex, AssertActualValue, AssertExpectValue][];
export type AssertFailMessage = Record<TestCaseName, AssertMessages>;
export type AssertMessage = [ExpectInfoIndex, AssertActualValue, AssertExpectValue];
export type AssertFailMessage = Record<TestCaseName, AssertMessage[]>;

export type ErrorMessages = string[];
export type AssertErrorMessages = Map<TestCaseName, ErrorMessages>;
Expand Down
Loading