Skip to content

Commit

Permalink
Add unit_tests.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed Aug 9, 2018
1 parent fb87cb3 commit dd3ffd1
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 49 deletions.
96 changes: 96 additions & 0 deletions js/testing/testing.ts
@@ -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);
70 changes: 70 additions & 0 deletions js/testing/util.ts
@@ -0,0 +1,70 @@
/*!
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.
*/

// 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);
}
}

// tslint:disable-next-line:no-any
export function equal(c: any, d: any): boolean {
const seen = new Map();
return (function compare(a, b) {
if (a === b) {
return true;
}
if (
typeof a === "number" &&
typeof b === "number" &&
isNaN(a) &&
isNaN(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
@@ -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" } }
)
);
});
79 changes: 35 additions & 44 deletions js/tests.ts → js/unit_tests.ts
Expand Up @@ -6,55 +6,12 @@
// 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 +80,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);
});
*/
15 changes: 10 additions & 5 deletions tools/test.py
Expand Up @@ -4,21 +4,23 @@
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]"
build_dir = build_path()
if len(argv) == 2:
build_dir = sys.argv[1]
elif len(argv) != 1:
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 +31,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 dd3ffd1

Please sign in to comment.