Skip to content

Commit

Permalink
Adds js/unit_tests.ts (denoland#448)
Browse files Browse the repository at this point in the history
  • Loading branch information
ry authored Aug 9, 2018
1 parent 413bcf2 commit 9d90c4a
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 52 deletions.
96 changes: 96 additions & 0 deletions js/testing/testing.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 64 additions & 0 deletions js/testing/util.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 40 additions & 0 deletions js/testing/util_test.ts
Original file line number Diff line number Diff line change
@@ -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" } }
)
);
});
83 changes: 36 additions & 47 deletions js/tests.ts → js/unit_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
});
*/
16 changes: 11 additions & 5 deletions tools/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

Expand Down

0 comments on commit 9d90c4a

Please sign in to comment.