deno/js/console_test.ts
Kitson Kelly a21a5ad2fa Add Deno global namespace (#1748)
Resolves #1705

This PR adds the Deno APIs as a global namespace named `Deno`. For backwards
compatibility, the ability to `import * from "deno"` is preserved. I have tried
to convert every test and internal code the references the module to use the
namespace instead, but because I didn't break compatibility I am not sure.

On the REPL, `deno` no longer exists, replaced only with `Deno` to align with
the regular runtime.

The runtime type library includes both the namespace and module. This means it
duplicates the whole type information. When we remove the functionality from the
runtime, it will be a one line change to the library generator to remove the
module definition from the type library.

I marked a `TODO` in a couple places where to remove the `"deno"` module, but
there are additional places I know I didn't mark.
2019-02-12 10:08:56 -05:00

310 lines
10 KiB
TypeScript

// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { test, assertEqual, assert } from "./test_util.ts";
const { Console, libdeno, stringifyArgs, inspect, write, stdout } = Deno;
const console = new Console(libdeno.print);
// tslint:disable-next-line:no-any
function stringify(...args: any[]): string {
return stringifyArgs(args);
}
test(function consoleTestAssertShouldNotThrowError() {
console.assert(true);
let hasThrown = undefined;
try {
console.assert(false);
hasThrown = false;
} catch {
hasThrown = true;
}
assertEqual(hasThrown, false);
});
test(function consoleTestStringifyComplexObjects() {
assertEqual(stringify("foo"), "foo");
assertEqual(stringify(["foo", "bar"]), `[ "foo", "bar" ]`);
assertEqual(stringify({ foo: "bar" }), `{ foo: "bar" }`);
});
test(function consoleTestStringifyCircular() {
class Base {
a = 1;
m1() {}
}
class Extended extends Base {
b = 2;
m2() {}
}
// tslint:disable-next-line:no-any
const nestedObj: any = {
num: 1,
bool: true,
str: "a",
method() {},
async asyncMethod() {},
*generatorMethod() {},
un: undefined,
nu: null,
arrowFunc: () => {},
extendedClass: new Extended(),
nFunc: new Function(),
extendedCstr: Extended
};
const circularObj = {
num: 2,
bool: false,
str: "b",
method() {},
un: undefined,
nu: null,
nested: nestedObj,
emptyObj: {},
arr: [1, "s", false, null, nestedObj],
baseClass: new Base()
};
nestedObj.o = circularObj;
// tslint:disable-next-line:max-line-length
const nestedObjExpected = `{ num: 1, bool: true, str: "a", method: [Function: method], asyncMethod: [AsyncFunction: asyncMethod], generatorMethod: [GeneratorFunction: generatorMethod], un: undefined, nu: null, arrowFunc: [Function: arrowFunc], extendedClass: Extended { a: 1, b: 2 }, nFunc: [Function], extendedCstr: [Function: Extended], o: { num: 2, bool: false, str: "b", method: [Function: method], un: undefined, nu: null, nested: [Circular], emptyObj: {}, arr: [ 1, "s", false, null, [Circular] ], baseClass: Base { a: 1 } } }`;
assertEqual(stringify(1), "1");
assertEqual(stringify(1n), "1n");
assertEqual(stringify("s"), "s");
assertEqual(stringify(false), "false");
// tslint:disable-next-line:no-construct
assertEqual(stringify(new Number(1)), "[Number: 1]");
// tslint:disable-next-line:no-construct
assertEqual(stringify(new Boolean(true)), "[Boolean: true]");
// tslint:disable-next-line:no-construct
assertEqual(stringify(new String("deno")), `[String: "deno"]`);
assertEqual(stringify(/[0-9]*/), "/[0-9]*/");
assertEqual(
stringify(new Date("2018-12-10T02:26:59.002Z")),
"2018-12-10T02:26:59.002Z"
);
assertEqual(stringify(new Set([1, 2, 3])), "Set { 1, 2, 3 }");
assertEqual(
stringify(new Map([[1, "one"], [2, "two"]])),
`Map { 1 => "one", 2 => "two" }`
);
assertEqual(stringify(new WeakSet()), "WeakSet { [items unknown] }");
assertEqual(stringify(new WeakMap()), "WeakMap { [items unknown] }");
assertEqual(stringify(Symbol(1)), "Symbol(1)");
assertEqual(stringify(null), "null");
assertEqual(stringify(undefined), "undefined");
assertEqual(stringify(new Extended()), "Extended { a: 1, b: 2 }");
assertEqual(stringify(function f() {}), "[Function: f]");
assertEqual(stringify(async function af() {}), "[AsyncFunction: af]");
assertEqual(stringify(function* gf() {}), "[GeneratorFunction: gf]");
assertEqual(
stringify(async function* agf() {}),
"[AsyncGeneratorFunction: agf]"
);
assertEqual(stringify(new Uint8Array([1, 2, 3])), "Uint8Array [ 1, 2, 3 ]");
assertEqual(stringify(Uint8Array.prototype), "TypedArray []");
assertEqual(
stringify({ a: { b: { c: { d: new Set([1]) } } } }),
"{ a: { b: { c: { d: [Set] } } } }"
);
assertEqual(stringify(nestedObj), nestedObjExpected);
assertEqual(stringify(JSON), "{}");
assertEqual(
stringify(console),
// tslint:disable-next-line:max-line-length
"Console { printFunc: [Function], log: [Function], debug: [Function], info: [Function], dir: [Function], warn: [Function], error: [Function], assert: [Function], count: [Function], countReset: [Function], table: [Function], time: [Function], timeLog: [Function], timeEnd: [Function], group: [Function], groupCollapsed: [Function], groupEnd: [Function], clear: [Function], indentLevel: 0, collapsedAt: null }"
);
// test inspect is working the same
assertEqual(inspect(nestedObj), nestedObjExpected);
});
test(function consoleTestStringifyWithDepth() {
// tslint:disable-next-line:no-any
const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };
assertEqual(
stringifyArgs([nestedObj], { depth: 3 }),
"{ a: { b: { c: [Object] } } }"
);
assertEqual(
stringifyArgs([nestedObj], { depth: 4 }),
"{ a: { b: { c: { d: [Object] } } } }"
);
assertEqual(stringifyArgs([nestedObj], { depth: 0 }), "[Object]");
assertEqual(
stringifyArgs([nestedObj], { depth: null }),
"{ a: { b: { c: { d: [Object] } } } }"
);
// test inspect is working the same way
assertEqual(
inspect(nestedObj, { depth: 4 }),
"{ a: { b: { c: { d: [Object] } } } }"
);
});
test(function consoleTestWithIntegerFormatSpecifier() {
assertEqual(stringify("%i"), "%i");
assertEqual(stringify("%i", 42.0), "42");
assertEqual(stringify("%i", 42), "42");
assertEqual(stringify("%i", "42"), "42");
assertEqual(stringify("%i", "42.0"), "42");
assertEqual(stringify("%i", 1.5), "1");
assertEqual(stringify("%i", -0.5), "0");
assertEqual(stringify("%i", ""), "NaN");
assertEqual(stringify("%i", Symbol()), "NaN");
assertEqual(stringify("%i %d", 42, 43), "42 43");
assertEqual(stringify("%d %i", 42), "42 %i");
assertEqual(stringify("%d", 12345678901234567890123), "1");
assertEqual(
stringify("%i", 12345678901234567890123n),
"12345678901234567890123n"
);
});
test(function consoleTestWithFloatFormatSpecifier() {
assertEqual(stringify("%f"), "%f");
assertEqual(stringify("%f", 42.0), "42");
assertEqual(stringify("%f", 42), "42");
assertEqual(stringify("%f", "42"), "42");
assertEqual(stringify("%f", "42.0"), "42");
assertEqual(stringify("%f", 1.5), "1.5");
assertEqual(stringify("%f", -0.5), "-0.5");
assertEqual(stringify("%f", Math.PI), "3.141592653589793");
assertEqual(stringify("%f", ""), "NaN");
assertEqual(stringify("%f", Symbol("foo")), "NaN");
assertEqual(stringify("%f", 5n), "5");
assertEqual(stringify("%f %f", 42, 43), "42 43");
assertEqual(stringify("%f %f", 42), "42 %f");
});
test(function consoleTestWithStringFormatSpecifier() {
assertEqual(stringify("%s"), "%s");
assertEqual(stringify("%s", undefined), "undefined");
assertEqual(stringify("%s", "foo"), "foo");
assertEqual(stringify("%s", 42), "42");
assertEqual(stringify("%s", "42"), "42");
assertEqual(stringify("%s %s", 42, 43), "42 43");
assertEqual(stringify("%s %s", 42), "42 %s");
assertEqual(stringify("%s", Symbol("foo")), "Symbol(foo)");
});
test(function consoleTestWithObjectFormatSpecifier() {
assertEqual(stringify("%o"), "%o");
assertEqual(stringify("%o", 42), "42");
assertEqual(stringify("%o", "foo"), "foo");
assertEqual(stringify("o: %o, a: %O", {}, []), "o: {}, a: []");
assertEqual(stringify("%o", { a: 42 }), "{ a: 42 }");
assertEqual(
stringify("%o", { a: { b: { c: { d: new Set([1]) } } } }),
"{ a: { b: { c: { d: [Set] } } } }"
);
});
test(function consoleTestWithVariousOrInvalidFormatSpecifier() {
assertEqual(stringify("%s:%s"), "%s:%s");
assertEqual(stringify("%i:%i"), "%i:%i");
assertEqual(stringify("%d:%d"), "%d:%d");
assertEqual(stringify("%%s%s", "foo"), "%sfoo");
assertEqual(stringify("%s:%s", undefined), "undefined:%s");
assertEqual(stringify("%s:%s", "foo", "bar"), "foo:bar");
assertEqual(stringify("%s:%s", "foo", "bar", "baz"), "foo:bar baz");
assertEqual(stringify("%%%s%%", "hi"), "%hi%");
assertEqual(stringify("%d:%d", 12), "12:%d");
assertEqual(stringify("%i:%i", 12), "12:%i");
assertEqual(stringify("%f:%f", 12), "12:%f");
assertEqual(stringify("o: %o, a: %o", {}), "o: {}, a: %o");
assertEqual(stringify("abc%", 1), "abc% 1");
});
test(function consoleTestCallToStringOnLabel() {
const methods = ["count", "countReset", "time", "timeLog", "timeEnd"];
for (const method of methods) {
let hasCalled = false;
console[method]({
toString() {
hasCalled = true;
}
});
assertEqual(hasCalled, true);
}
});
test(function consoleTestError() {
class MyError extends Error {
constructor(errStr: string) {
super(errStr);
this.name = "MyError";
}
}
try {
throw new MyError("This is an error");
} catch (e) {
assert(
stringify(e)
.split("\n")[3]
.includes("MyError: This is an error")
);
}
});
test(function consoleTestClear() {
const stdoutWrite = stdout.write;
const uint8 = new TextEncoder().encode("\x1b[1;1H" + "\x1b[0J");
let buffer = new Uint8Array(0);
stdout.write = async u8 => {
const tmp = new Uint8Array(buffer.length + u8.length);
tmp.set(buffer, 0);
tmp.set(u8, buffer.length);
buffer = tmp;
return await write(stdout.rid, u8);
};
console.clear();
stdout.write = stdoutWrite;
assertEqual(buffer, uint8);
});
// Test bound this issue
test(function consoleDetachedLog() {
const log = console.log;
const dir = console.dir;
const debug = console.debug;
const info = console.info;
const warn = console.warn;
const error = console.error;
const consoleAssert = console.assert;
const consoleCount = console.count;
const consoleCountReset = console.countReset;
const consoleTable = console.table;
const consoleTime = console.time;
const consoleTimeLog = console.timeLog;
const consoleTimeEnd = console.timeEnd;
const consoleGroup = console.group;
const consoleGroupEnd = console.groupEnd;
const consoleClear = console.clear;
log("Hello world");
dir("Hello world");
debug("Hello world");
info("Hello world");
warn("Hello world");
error("Hello world");
consoleAssert(true);
consoleCount("Hello world");
consoleCountReset("Hello world");
consoleTable({ test: "Hello world" });
consoleTime("Hello world");
consoleTimeLog("Hello world");
consoleTimeEnd("Hello world");
consoleGroup("Hello world");
consoleGroupEnd();
consoleClear();
});