Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/tools/test.ts
1396 views
1
/*
2
* Copyright (C) 2021 William Stein <[email protected]>
3
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
*
5
* Distributed under terms of the BSD license
6
*/
7
8
import { basename, join } from "path";
9
import { readFileSync, readdirSync, writeFileSync } from "fs";
10
import createCompiler from "./compiler";
11
import { colored } from "./utils";
12
import { deepEqual as origDeepEqual, AssertionError } from "assert";
13
import { tmpdir } from "os";
14
import { runInNewContext } from "vm";
15
16
const PyLang = createCompiler();
17
18
export default function (
19
argv: { files: string[] },
20
basePath,
21
srcPath,
22
libPath
23
) {
24
// run all tests and exit
25
const failures: string[] = [];
26
let compilerDir = libPath;
27
const testPath = join(basePath, "test");
28
const baselib = readFileSync(
29
join(libPath, "baselib-plain-pretty.js"),
30
"utf-8"
31
);
32
33
const files =
34
argv.files.length > 0
35
? argv.files.map((fname: string) =>
36
fname.endsWith(".py") ? fname : fname + ".py"
37
)
38
: readdirSync(testPath)
39
.filter((name) => /^[^_].*\.py$/.test(name))
40
.map((name) => join(testPath, name));
41
42
const t_start = new Date().valueOf();
43
44
for (const filename of files) {
45
const t0 = new Date().valueOf();
46
let failed = false;
47
let toplevel: any = undefined;
48
try {
49
const file = readFileSync(filename, "utf-8");
50
if (file.toString().includes("# DISABLED")) {
51
console.log(`Skipping ${filename}`);
52
continue;
53
}
54
toplevel = PyLang.parse(file, {
55
filename,
56
toplevel: toplevel,
57
basedir: testPath,
58
libdir: join(srcPath, "lib"),
59
});
60
} catch (err) {
61
failures.push(filename);
62
failed = true;
63
console.log(colored(filename, "red") + ": " + err + "\n\n");
64
break;
65
}
66
67
// generate output
68
const output = new PyLang.OutputStream({
69
baselib_plain: baselib,
70
beautify: true,
71
keep_docstrings: true,
72
});
73
toplevel.print(output);
74
75
// test that output performs correct JS operations
76
const jsfile = join(tmpdir(), basename(filename) + ".js");
77
const code = output.toString();
78
const assrt = { ...require("assert"), deepEqual };
79
80
// We save and restore the console attributes since some tests,
81
// e.g., repl, have a side effect of stealing them, which means
82
// we suddenly can't report results.
83
const saveConsole = { ...console };
84
const restoreConsole = () => {
85
for (let name in saveConsole) {
86
console[name] = saveConsole[name];
87
}
88
};
89
try {
90
runInNewContext(
91
code,
92
{
93
assrt, // patched version
94
__name__: jsfile,
95
require: require,
96
fs: require("fs"),
97
PyLang,
98
console,
99
compiler_dir: compilerDir,
100
test_path: testPath,
101
Buffer,
102
},
103
{ filename: jsfile }
104
);
105
restoreConsole();
106
} catch (err) {
107
restoreConsole();
108
failures.push(filename);
109
failed = true;
110
writeFileSync(jsfile, code);
111
console.error("Failed running: " + colored(jsfile, "red"));
112
if (err.stack) {
113
console.error(colored(filename, "red") + ":\n" + err.stack + "\n\n");
114
} else {
115
console.error(colored(filename, "red") + ": " + err + "\n\n");
116
}
117
}
118
console.log(
119
`${colored(filename, "green")}: test ${
120
failed ? "FAILED" : "completed successfully"
121
} (${new Date().valueOf() - t0}ms)`
122
);
123
}
124
125
if (failures.length > 0) {
126
console.log(
127
colored("There were " + failures.length + " test failure(s):", "red")
128
);
129
console.log.apply(console, failures);
130
} else {
131
console.log(
132
colored(
133
`All tests passed! (${new Date().valueOf() - t_start}ms)`,
134
"green"
135
)
136
);
137
}
138
process.exit(failures.length ? 1 : 0);
139
}
140
141
// Modified version of deepEqual test assertion that is more suitable
142
// for testing python code.
143
function deepEqual(a: any, b: any, message: any): void {
144
if (Array.isArray(a) && Array.isArray(b)) {
145
// Compare array objects that have extra properties as simple arrays
146
if (a === b) return;
147
if (a.length !== b.length)
148
throw new AssertionError({
149
actual: a,
150
expected: b,
151
operator: "deepEqual",
152
stackStartFn: deepEqual,
153
});
154
for (let i = 0; i < a.length; i++) {
155
deepEqual(a[i], b[i], message);
156
}
157
} else if (typeof a?.__eq__ === "function") {
158
// Python operator overloading
159
if (!a.__eq__(b))
160
throw new AssertionError({
161
actual: a,
162
expected: b,
163
operator: "deepEqual",
164
stackStartFn: deepEqual,
165
});
166
} else {
167
// Fallback to standard version in nodejs library.
168
return origDeepEqual(a, b, message);
169
}
170
}
171
172