mirror of
https://github.com/denoland/deno.git
synced 2024-12-21 23:04:45 -05:00
Adds js/unit_tests.ts (#448)
This commit is contained in:
parent
413bcf2042
commit
9d90c4ae95
5 changed files with 247 additions and 52 deletions
96
js/testing/testing.ts
Normal file
96
js/testing/testing.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*!
|
||||
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export { assert, assertEqual, equal } from "./util.ts";
|
||||
|
||||
export type TestFunction = () => void | Promise<void>;
|
||||
|
||||
export interface TestDefinition {
|
||||
fn: TestFunction;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const exitOnFail = true;
|
||||
|
||||
/* A subset of the tests can be ran by providing a filter expression.
|
||||
* In Node.js the filter is specified on the command line:
|
||||
*
|
||||
* ts-node test_node log # all tests with 'log' in the name
|
||||
* ts-node test_node ^util # tests starting with 'util'
|
||||
*
|
||||
* In the browser, the filter is specified as part of the url:
|
||||
*
|
||||
* http://localhost:9876/test.html#script=some/script.js&filter=log
|
||||
* http://localhost:9876/test.html#script=some/script.js&filter=^util
|
||||
*/
|
||||
let filterExpr: string = null;
|
||||
|
||||
const filterRegExp = filterExpr ? new RegExp(filterExpr, "i") : null;
|
||||
const tests: TestDefinition[] = [];
|
||||
|
||||
export function test(t: TestDefinition | TestFunction): void {
|
||||
const fn: TestFunction = typeof t === "function" ? t : t.fn;
|
||||
const name: string = t.name;
|
||||
|
||||
if (!name) {
|
||||
throw new Error("Test function may not be anonymous");
|
||||
}
|
||||
if (filter(name)) {
|
||||
tests.push({ fn, name });
|
||||
}
|
||||
}
|
||||
|
||||
function filter(name: string): boolean {
|
||||
if (filterRegExp) {
|
||||
return filterRegExp.test(name);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const { fn, name } = tests[i];
|
||||
console.log(`${i + 1}/${tests.length} +${passed} -${failed}: ${name}`);
|
||||
try {
|
||||
await fn();
|
||||
passed++;
|
||||
} catch (e) {
|
||||
console.error("\nTest FAIL", name);
|
||||
console.error((e && e.stack) || e);
|
||||
failed++;
|
||||
if (exitOnFail) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nDONE. Test passed: ${passed}, failed: ${failed}`);
|
||||
|
||||
if (failed === 0) {
|
||||
// All good.
|
||||
} else {
|
||||
// Use setTimeout to avoid the error being ignored due to unhandled
|
||||
// promise rejections being swallowed.
|
||||
setTimeout(() => {
|
||||
throw new Error(`There were ${failed} test failures.`);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(runTests, 0);
|
64
js/testing/util.ts
Normal file
64
js/testing/util.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*!
|
||||
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO(ry) Use unknown here for parameters types.
|
||||
// tslint:disable-next-line:no-any
|
||||
export function assertEqual(actual: any, expected: any, msg?: string) {
|
||||
if (!msg) {
|
||||
msg = `actual: ${actual} expected: ${expected}`;
|
||||
}
|
||||
if (!equal(actual, expected)) {
|
||||
console.error(
|
||||
"assertEqual failed. actual = ",
|
||||
actual,
|
||||
"expected =",
|
||||
expected
|
||||
);
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export function assert(expr: boolean, msg = "") {
|
||||
if (!expr) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ry) Use unknown here for parameters types.
|
||||
// tslint:disable-next-line:no-any
|
||||
export function equal(c: any, d: any): boolean {
|
||||
const seen = new Map();
|
||||
return (function compare(a, b) {
|
||||
if (Object.is(a, b)) {
|
||||
return true;
|
||||
}
|
||||
if (a && typeof a === "object" && b && typeof b === "object") {
|
||||
if (seen.get(a) === b) {
|
||||
return true;
|
||||
}
|
||||
if (Object.keys(a).length !== Object.keys(b).length) {
|
||||
return false;
|
||||
}
|
||||
for (const key in { ...a, ...b }) {
|
||||
if (!compare(a[key], b[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
seen.set(a, b);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})(c, d);
|
||||
}
|
40
js/testing/util_test.ts
Normal file
40
js/testing/util_test.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*!
|
||||
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { test } from "./testing.ts";
|
||||
import { assert } from "./util.ts";
|
||||
import * as util from "./util.ts";
|
||||
|
||||
test(async function util_equal() {
|
||||
assert(util.equal("world", "world"));
|
||||
assert(!util.equal("hello", "world"));
|
||||
assert(util.equal(5, 5));
|
||||
assert(!util.equal(5, 6));
|
||||
assert(util.equal(NaN, NaN));
|
||||
assert(util.equal({ hello: "world" }, { hello: "world" }));
|
||||
assert(!util.equal({ world: "hello" }, { hello: "world" }));
|
||||
assert(
|
||||
util.equal(
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
{ hello: "world", hi: { there: "everyone" } }
|
||||
)
|
||||
);
|
||||
assert(
|
||||
!util.equal(
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
{ hello: "world", hi: { there: "everyone else" } }
|
||||
)
|
||||
);
|
||||
});
|
|
@ -2,59 +2,14 @@
|
|||
// This test is executed as part of integration_test.go
|
||||
// But it can also be run manually:
|
||||
// ./deno tests.ts
|
||||
// There must also be a static file http server running on localhost:4545
|
||||
// serving the deno project directory. Try this:
|
||||
// http-server -p 4545 --cors .
|
||||
|
||||
import { test, assert, assertEqual } from "./testing/testing.ts";
|
||||
import { readFileSync, writeFileSync } from "deno";
|
||||
// import { readFileSync, writeFileSync } from "deno";
|
||||
|
||||
test(async function tests_test() {
|
||||
assert(true);
|
||||
});
|
||||
|
||||
test(async function tests_fetch() {
|
||||
const response = await fetch("http://localhost:4545/package.json");
|
||||
const json = await response.json();
|
||||
assertEqual(json.name, "deno");
|
||||
});
|
||||
|
||||
test(function tests_console_assert() {
|
||||
console.assert(true);
|
||||
|
||||
let hasThrown = false;
|
||||
try {
|
||||
console.assert(false);
|
||||
} catch {
|
||||
hasThrown = true;
|
||||
}
|
||||
assertEqual(hasThrown, true);
|
||||
});
|
||||
|
||||
test(async function tests_readFileSync() {
|
||||
const data = readFileSync("package.json");
|
||||
if (!data.byteLength) {
|
||||
throw Error(
|
||||
`Expected positive value for data.byteLength ${data.byteLength}`
|
||||
);
|
||||
}
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
const json = decoder.decode(data);
|
||||
const pkg = JSON.parse(json);
|
||||
assertEqual(pkg.name, "deno");
|
||||
});
|
||||
|
||||
test(async function tests_writeFileSync() {
|
||||
const enc = new TextEncoder();
|
||||
const data = enc.encode("Hello");
|
||||
// TODO need ability to get tmp dir.
|
||||
// const fn = "/tmp/test.txt";
|
||||
writeFileSync("/tmp/test.txt", data, 0o666);
|
||||
const dataRead = readFileSync("/tmp/test.txt");
|
||||
const dec = new TextDecoder("utf-8");
|
||||
const actual = dec.decode(dataRead);
|
||||
assertEqual("Hello", actual);
|
||||
});
|
||||
|
||||
test(function tests_console_assert() {
|
||||
console.assert(true);
|
||||
|
||||
|
@ -123,3 +78,37 @@ test(function tests_console_stringify_circular() {
|
|||
throw new Error("Expected no crash on circular object");
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
test(async function tests_fetch() {
|
||||
const response = await fetch("http://localhost:4545/package.json");
|
||||
const json = await response.json();
|
||||
assertEqual(json.name, "deno");
|
||||
});
|
||||
|
||||
test(async function tests_readFileSync() {
|
||||
const data = readFileSync("package.json");
|
||||
if (!data.byteLength) {
|
||||
throw Error(
|
||||
`Expected positive value for data.byteLength ${data.byteLength}`
|
||||
);
|
||||
}
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
const json = decoder.decode(data);
|
||||
const pkg = JSON.parse(json);
|
||||
assertEqual(pkg.name, "deno");
|
||||
});
|
||||
|
||||
test(async function tests_writeFileSync() {
|
||||
const enc = new TextEncoder();
|
||||
const data = enc.encode("Hello");
|
||||
// TODO need ability to get tmp dir.
|
||||
const fn = "/tmp/test.txt";
|
||||
writeFileSync("/tmp/test.txt", data, 0o666);
|
||||
const dataRead = readFileSync("/tmp/test.txt");
|
||||
const dec = new TextDecoder("utf-8");
|
||||
const actual = dec.decode(dataRead);
|
||||
assertEqual("Hello", actual);
|
||||
});
|
||||
|
||||
*/
|
|
@ -4,21 +4,24 @@
|
|||
import os
|
||||
import sys
|
||||
from check_output_test import check_output_test
|
||||
from util import executable_suffix, run
|
||||
from util import executable_suffix, run, build_path
|
||||
|
||||
|
||||
def check_exists(filename):
|
||||
if not os.path.exists(filename):
|
||||
print "Required target doesn't exist:", filename
|
||||
print "Build target :all"
|
||||
print "Run ./tools/build.py"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) != 2:
|
||||
print "Usage: tools/test.py [build dir]"
|
||||
if len(argv) == 2:
|
||||
build_dir = sys.argv[1]
|
||||
elif len(argv) == 1:
|
||||
build_dir = build_path()
|
||||
else:
|
||||
print "Usage: tools/test.py [build_dir]"
|
||||
sys.exit(1)
|
||||
build_dir = argv[1]
|
||||
|
||||
test_cc = os.path.join(build_dir, "test_cc" + executable_suffix)
|
||||
check_exists(test_cc)
|
||||
|
@ -29,6 +32,9 @@ def main(argv):
|
|||
run([test_rs])
|
||||
|
||||
deno_exe = os.path.join(build_dir, "deno" + executable_suffix)
|
||||
check_exists(deno_exe)
|
||||
run([deno_exe, "js/unit_tests.ts"])
|
||||
|
||||
check_exists(deno_exe)
|
||||
check_output_test(deno_exe)
|
||||
|
||||
|
|
Loading…
Reference in a new issue