mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
4983f763d4
This commit fixes the error format when the cause is assigned separately, ensuring that the cause is only printed once instead of twice. The fix addresses issue [#21651](https://github.com/denoland/deno/issues/21651).
2471 lines
63 KiB
TypeScript
2471 lines
63 KiB
TypeScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
// TODO(ry) The unit test functions in this module are too coarse. They should
|
|
// be broken up into smaller bits.
|
|
|
|
// TODO(ry) These tests currently strip all the ANSI colors out. We don't have a
|
|
// good way to control whether we produce color output or not since
|
|
// std/fmt/colors auto determines whether to put colors in or not. We need
|
|
// better infrastructure here so we can properly test the colors.
|
|
|
|
// deno-lint-ignore-file no-console
|
|
|
|
import {
|
|
assert,
|
|
assertEquals,
|
|
assertStringIncludes,
|
|
assertThrows,
|
|
} from "./test_util.ts";
|
|
import { stripAnsiCode } from "@std/fmt/colors";
|
|
|
|
const customInspect = Symbol.for("Deno.customInspect");
|
|
const {
|
|
Console,
|
|
cssToAnsi: cssToAnsi_,
|
|
inspectArgs,
|
|
parseCss: parseCss_,
|
|
parseCssColor: parseCssColor_,
|
|
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
|
|
} = Deno[Deno.internal];
|
|
|
|
function stringify(...args: unknown[]): string {
|
|
return stripAnsiCode(inspectArgs(args).replace(/\n$/, ""));
|
|
}
|
|
|
|
interface Css {
|
|
backgroundColor: [number, number, number] | string | null;
|
|
color: [number, number, number] | string | null;
|
|
fontWeight: string | null;
|
|
fontStyle: string | null;
|
|
textDecorationColor: [number, number, number] | null;
|
|
textDecorationLine: string[];
|
|
}
|
|
|
|
const DEFAULT_CSS: Css = {
|
|
backgroundColor: null,
|
|
color: null,
|
|
fontWeight: null,
|
|
fontStyle: null,
|
|
textDecorationColor: null,
|
|
textDecorationLine: [],
|
|
};
|
|
|
|
function parseCss(cssString: string): Css {
|
|
return parseCss_(cssString);
|
|
}
|
|
|
|
function parseCssColor(colorString: string): [number, number, number] | null {
|
|
return parseCssColor_(colorString);
|
|
}
|
|
|
|
/** ANSI-fy the CSS, replace "\x1b" with "_". */
|
|
function cssToAnsiEsc(css: Css, prevCss: Css | null = null): string {
|
|
return cssToAnsi_(css, prevCss).replaceAll("\x1b", "_");
|
|
}
|
|
|
|
// test cases from web-platform-tests
|
|
// via https://github.com/web-platform-tests/wpt/blob/master/console/console-is-a-namespace.any.js
|
|
Deno.test(function consoleShouldBeANamespace() {
|
|
const prototype1 = Object.getPrototypeOf(console);
|
|
const prototype2 = Object.getPrototypeOf(prototype1);
|
|
|
|
assertEquals(Object.getOwnPropertyNames(prototype1).length, 0);
|
|
assertEquals(prototype2, Object.prototype);
|
|
});
|
|
|
|
Deno.test(function consoleHasRightInstance() {
|
|
assert(console instanceof Console);
|
|
assertEquals({} instanceof Console, false);
|
|
});
|
|
|
|
Deno.test(function consoleTestAssertShouldNotThrowError() {
|
|
mockConsole((console) => {
|
|
console.assert(true);
|
|
let hasThrown = undefined;
|
|
try {
|
|
console.assert(false);
|
|
hasThrown = false;
|
|
} catch {
|
|
hasThrown = true;
|
|
}
|
|
assertEquals(hasThrown, false);
|
|
});
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyComplexObjects() {
|
|
assertEquals(stringify("foo"), "foo");
|
|
assertEquals(stringify(["foo", "bar"]), `[ "foo", "bar" ]`);
|
|
assertEquals(stringify({ foo: "bar" }), `{ foo: "bar" }`);
|
|
});
|
|
|
|
Deno.test(
|
|
function consoleTestStringifyComplexObjectsWithEscapedSequences() {
|
|
assertEquals(
|
|
stringify(
|
|
["foo\b", "foo\f", "foo\n", "foo\r", "foo\t", "foo\v", "foo\0"],
|
|
),
|
|
`[
|
|
"foo\\b", "foo\\f",
|
|
"foo\\n", "foo\\r",
|
|
"foo\\t", "foo\\v",
|
|
"foo\\x00"
|
|
]`,
|
|
);
|
|
assertEquals(
|
|
stringify(
|
|
[
|
|
Symbol(),
|
|
Symbol(""),
|
|
Symbol("foo\b"),
|
|
Symbol("foo\f"),
|
|
Symbol("foo\n"),
|
|
Symbol("foo\r"),
|
|
Symbol("foo\t"),
|
|
Symbol("foo\v"),
|
|
Symbol("foo\0"),
|
|
],
|
|
),
|
|
`[
|
|
Symbol(),
|
|
Symbol(""),
|
|
Symbol("foo\\b"),
|
|
Symbol("foo\\f"),
|
|
Symbol("foo\\n"),
|
|
Symbol("foo\\r"),
|
|
Symbol("foo\\t"),
|
|
Symbol("foo\\v"),
|
|
Symbol("foo\\x00")
|
|
]`,
|
|
);
|
|
assertEquals(
|
|
stringify(
|
|
{ "foo\b": "bar\n", "bar\r": "baz\t", "qux\0": "qux\0" },
|
|
),
|
|
`{ "foo\\b": "bar\\n", "bar\\r": "baz\\t", "qux\\x00": "qux\\x00" }`,
|
|
);
|
|
assertEquals(
|
|
stringify(
|
|
{
|
|
[Symbol("foo\b")]: `Symbol("foo\n")`,
|
|
[Symbol("bar\n")]: `Symbol("bar\n")`,
|
|
[Symbol("bar\r")]: `Symbol("bar\r")`,
|
|
[Symbol("baz\t")]: `Symbol("baz\t")`,
|
|
[Symbol("qux\0")]: `Symbol("qux\0")`,
|
|
},
|
|
),
|
|
`{
|
|
[Symbol("foo\\b")]: 'Symbol("foo\\n")',
|
|
[Symbol("bar\\n")]: 'Symbol("bar\\n")',
|
|
[Symbol("bar\\r")]: 'Symbol("bar\\r")',
|
|
[Symbol("baz\\t")]: 'Symbol("baz\\t")',
|
|
[Symbol("qux\\x00")]: 'Symbol("qux\\x00")'
|
|
}`,
|
|
);
|
|
assertEquals(
|
|
stringify(new Set(["foo\n", "foo\r", "foo\0"])),
|
|
`Set(3) { "foo\\n", "foo\\r", "foo\\x00" }`,
|
|
);
|
|
},
|
|
);
|
|
|
|
Deno.test(function consoleTestStringifyQuotes() {
|
|
assertEquals(stringify(["\\"]), `[ "\\\\" ]`);
|
|
assertEquals(stringify(['\\,"']), `[ '\\\\,"' ]`);
|
|
assertEquals(stringify([`\\,",'`]), `[ \`\\\\,",'\` ]`);
|
|
assertEquals(stringify(["\\,\",',`"]), `[ "\\\\,\\",',\`" ]`);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyLongStrings() {
|
|
const veryLongString = "a".repeat(10_100);
|
|
// If we stringify an object containing the long string, it gets abbreviated.
|
|
let actual = stringify({ veryLongString });
|
|
assert(actual.includes("..."));
|
|
assert(actual.length < 10_100);
|
|
// However if we stringify the string itself, we get it exactly.
|
|
actual = stringify(veryLongString);
|
|
assertEquals(actual, veryLongString);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyCircular() {
|
|
class Base {
|
|
a = 1;
|
|
m1() {}
|
|
}
|
|
|
|
class Extended extends Base {
|
|
b = 2;
|
|
m2() {}
|
|
}
|
|
|
|
// deno-lint-ignore no-explicit-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;
|
|
const nestedObjExpected = `<ref *1> {
|
|
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: anonymous],
|
|
extendedCstr: [class Extended extends Base],
|
|
o: {
|
|
num: 2,
|
|
bool: false,
|
|
str: "b",
|
|
method: [Function: method],
|
|
un: undefined,
|
|
nu: null,
|
|
nested: [Circular *1],
|
|
emptyObj: {},
|
|
arr: [ 1, "s", false, null, [Circular *1] ],
|
|
baseClass: Base { a: 1 }
|
|
}
|
|
}`;
|
|
|
|
assertEquals(stringify(1), "1");
|
|
assertEquals(stringify(-0), "-0");
|
|
assertEquals(stringify(1n), "1n");
|
|
assertEquals(stringify("s"), "s");
|
|
assertEquals(stringify(false), "false");
|
|
assertEquals(stringify(new Number(1)), "[Number: 1]");
|
|
assertEquals(stringify(new Number(-0)), "[Number: -0]");
|
|
assertEquals(stringify(Object(1n)), "[BigInt: 1n]");
|
|
assertEquals(stringify(new Boolean(true)), "[Boolean: true]");
|
|
assertEquals(stringify(new String("deno")), `[String: "deno"]`);
|
|
assertEquals(stringify(/[0-9]*/), "/[0-9]*/");
|
|
assertEquals(
|
|
stringify(new Date("2018-12-10T02:26:59.002Z")),
|
|
"2018-12-10T02:26:59.002Z",
|
|
);
|
|
assertEquals(stringify(new Set([1, 2, 3])), "Set(3) { 1, 2, 3 }");
|
|
assertEquals(
|
|
stringify(new Set([1, 2, 3]).values()),
|
|
"[Set Iterator] { 1, 2, 3 }",
|
|
);
|
|
assertEquals(
|
|
stringify(new Set([1, 2, 3]).entries()),
|
|
"[Set Entries] { [ 1, 1 ], [ 2, 2 ], [ 3, 3 ] }",
|
|
);
|
|
assertEquals(
|
|
stringify(
|
|
new Map([
|
|
[1, "one"],
|
|
[2, "two"],
|
|
]),
|
|
),
|
|
`Map(2) { 1 => "one", 2 => "two" }`,
|
|
);
|
|
assertEquals(
|
|
stringify(new Map([[1, "one"], [2, "two"]]).values()),
|
|
`[Map Iterator] { "one", "two" }`,
|
|
);
|
|
assertEquals(
|
|
stringify(new Map([[1, "one"], [2, "two"]]).entries()),
|
|
`[Map Entries] { [ 1, "one" ], [ 2, "two" ] }`,
|
|
);
|
|
assertEquals(stringify(new WeakSet()), "WeakSet { <items unknown> }");
|
|
assertEquals(stringify(new WeakMap()), "WeakMap { <items unknown> }");
|
|
assertEquals(stringify(Symbol(1)), `Symbol("1")`);
|
|
assertEquals(stringify(Object(Symbol(1))), `[Symbol: Symbol("1")]`);
|
|
assertEquals(stringify(null), "null");
|
|
assertEquals(stringify(undefined), "undefined");
|
|
assertEquals(stringify(new Extended()), "Extended { a: 1, b: 2 }");
|
|
assertEquals(
|
|
stringify(function f() {}),
|
|
"[Function: f]",
|
|
);
|
|
assertEquals(
|
|
stringify(async function af() {}),
|
|
"[AsyncFunction: af]",
|
|
);
|
|
assertEquals(
|
|
stringify(function* gf() {}),
|
|
"[GeneratorFunction: gf]",
|
|
);
|
|
assertEquals(
|
|
stringify(async function* agf() {}),
|
|
"[AsyncGeneratorFunction: agf]",
|
|
);
|
|
assertEquals(
|
|
stringify(new Uint8Array([1, 2, 3])),
|
|
"Uint8Array(3) [ 1, 2, 3 ]",
|
|
);
|
|
assertEquals(stringify(Uint8Array.prototype), "TypedArray {}");
|
|
assertEquals(
|
|
stringify({ a: { b: { c: { d: new Set([1]) } } } }),
|
|
`{
|
|
a: {
|
|
b: { c: { d: Set(1) { 1 } } }
|
|
}
|
|
}`,
|
|
);
|
|
assertEquals(stringify(nestedObj), nestedObjExpected);
|
|
assertEquals(
|
|
stringify(JSON),
|
|
"Object [JSON] {}",
|
|
);
|
|
assertEquals(
|
|
stringify(new Console(() => {})),
|
|
`Object [console] {
|
|
log: [Function: log],
|
|
debug: [Function: debug],
|
|
info: [Function: info],
|
|
dir: [Function: dir],
|
|
dirxml: [Function: dir],
|
|
warn: [Function: warn],
|
|
error: [Function: error],
|
|
assert: [Function: assert],
|
|
count: [Function: count],
|
|
countReset: [Function: countReset],
|
|
table: [Function: table],
|
|
time: [Function: time],
|
|
timeLog: [Function: timeLog],
|
|
timeEnd: [Function: timeEnd],
|
|
group: [Function: group],
|
|
groupCollapsed: [Function: group],
|
|
groupEnd: [Function: groupEnd],
|
|
clear: [Function: clear],
|
|
trace: [Function: trace],
|
|
profile: [Function: profile],
|
|
profileEnd: [Function: profileEnd],
|
|
timeStamp: [Function: timeStamp],
|
|
indentLevel: 0,
|
|
[Symbol(isConsoleInstance)]: true
|
|
}`,
|
|
);
|
|
assertEquals(
|
|
stringify({ str: 1, [Symbol.for("sym")]: 2, [Symbol.toStringTag]: "TAG" }),
|
|
`Object [TAG] {
|
|
str: 1,
|
|
[Symbol(sym)]: 2,
|
|
[Symbol(Symbol.toStringTag)]: "TAG"
|
|
}`,
|
|
);
|
|
// test inspect is working the same
|
|
assertEquals(stripAnsiCode(Deno.inspect(nestedObj)), nestedObjExpected);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyMultipleCircular() {
|
|
const y = { a: { b: {} }, foo: { bar: {} } };
|
|
y.a.b = y.a;
|
|
y.foo.bar = y.foo;
|
|
assertEquals(
|
|
stringify(y),
|
|
"{\n" +
|
|
" a: <ref *1> { b: [Circular *1] },\n" +
|
|
" foo: <ref *2> { bar: [Circular *2] }\n" +
|
|
"}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyFunctionWithPrototypeRemoved() {
|
|
const f = function f() {};
|
|
Reflect.setPrototypeOf(f, null);
|
|
assertEquals(stringify(f), "[Function (null prototype): f]");
|
|
const af = async function af() {};
|
|
Reflect.setPrototypeOf(af, null);
|
|
assertEquals(stringify(af), "[AsyncFunction (null prototype): af]");
|
|
const gf = function* gf() {};
|
|
Reflect.setPrototypeOf(gf, null);
|
|
assertEquals(stringify(gf), "[GeneratorFunction (null prototype): gf]");
|
|
const agf = async function* agf() {};
|
|
Reflect.setPrototypeOf(agf, null);
|
|
assertEquals(
|
|
stringify(agf),
|
|
"[AsyncGeneratorFunction (null prototype): agf]",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyFunctionWithProperties() {
|
|
const f = () => "test";
|
|
f.x = () => "foo";
|
|
f.y = 3;
|
|
f.z = () => "baz";
|
|
f.b = function bar() {};
|
|
f.a = new Map();
|
|
assertEquals(
|
|
stringify({ f }),
|
|
`{
|
|
f: [Function: f] {
|
|
x: [Function (anonymous)],
|
|
y: 3,
|
|
z: [Function (anonymous)],
|
|
b: [Function: bar],
|
|
a: Map(0) {}
|
|
}
|
|
}`,
|
|
);
|
|
|
|
const t = () => {};
|
|
t.x = f;
|
|
f.s = f;
|
|
f.t = t;
|
|
assertEquals(
|
|
stringify({ f }),
|
|
`{
|
|
f: <ref *1> [Function: f] {
|
|
x: [Function (anonymous)],
|
|
y: 3,
|
|
z: [Function (anonymous)],
|
|
b: [Function: bar],
|
|
a: Map(0) {},
|
|
s: [Circular *1],
|
|
t: [Function: t] { x: [Circular *1] }
|
|
}
|
|
}`,
|
|
);
|
|
|
|
assertEquals(
|
|
stringify(Array),
|
|
`[Function: Array]`,
|
|
);
|
|
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(Array, { showHidden: true })),
|
|
`<ref *1> [Function: Array] {
|
|
[length]: 1,
|
|
[name]: "Array",
|
|
[prototype]: Object(0) [
|
|
[length]: 0,
|
|
[constructor]: [Circular *1],
|
|
[at]: [Function: at] { [length]: 1, [name]: "at" },
|
|
[concat]: [Function: concat] { [length]: 1, [name]: "concat" },
|
|
[copyWithin]: [Function: copyWithin] { [length]: 2, [name]: "copyWithin" },
|
|
[fill]: [Function: fill] { [length]: 1, [name]: "fill" },
|
|
[find]: [Function: find] { [length]: 1, [name]: "find" },
|
|
[findIndex]: [Function: findIndex] { [length]: 1, [name]: "findIndex" },
|
|
[findLast]: [Function: findLast] { [length]: 1, [name]: "findLast" },
|
|
[findLastIndex]: [Function: findLastIndex] { [length]: 1, [name]: "findLastIndex" },
|
|
[lastIndexOf]: [Function: lastIndexOf] { [length]: 1, [name]: "lastIndexOf" },
|
|
[pop]: [Function: pop] { [length]: 0, [name]: "pop" },
|
|
[push]: [Function: push] { [length]: 1, [name]: "push" },
|
|
[reverse]: [Function: reverse] { [length]: 0, [name]: "reverse" },
|
|
[shift]: [Function: shift] { [length]: 0, [name]: "shift" },
|
|
[unshift]: [Function: unshift] { [length]: 1, [name]: "unshift" },
|
|
[slice]: [Function: slice] { [length]: 2, [name]: "slice" },
|
|
[sort]: [Function: sort] { [length]: 1, [name]: "sort" },
|
|
[splice]: [Function: splice] { [length]: 2, [name]: "splice" },
|
|
[includes]: [Function: includes] { [length]: 1, [name]: "includes" },
|
|
[indexOf]: [Function: indexOf] { [length]: 1, [name]: "indexOf" },
|
|
[join]: [Function: join] { [length]: 1, [name]: "join" },
|
|
[keys]: [Function: keys] { [length]: 0, [name]: "keys" },
|
|
[entries]: [Function: entries] { [length]: 0, [name]: "entries" },
|
|
[values]: [Function: values] { [length]: 0, [name]: "values" },
|
|
[forEach]: [Function: forEach] { [length]: 1, [name]: "forEach" },
|
|
[filter]: [Function: filter] { [length]: 1, [name]: "filter" },
|
|
[flat]: [Function: flat] { [length]: 0, [name]: "flat" },
|
|
[flatMap]: [Function: flatMap] { [length]: 1, [name]: "flatMap" },
|
|
[map]: [Function: map] { [length]: 1, [name]: "map" },
|
|
[every]: [Function: every] { [length]: 1, [name]: "every" },
|
|
[some]: [Function: some] { [length]: 1, [name]: "some" },
|
|
[reduce]: [Function: reduce] { [length]: 1, [name]: "reduce" },
|
|
[reduceRight]: [Function: reduceRight] { [length]: 1, [name]: "reduceRight" },
|
|
[toReversed]: [Function: toReversed] { [length]: 0, [name]: "toReversed" },
|
|
[toSorted]: [Function: toSorted] { [length]: 1, [name]: "toSorted" },
|
|
[toSpliced]: [Function: toSpliced] { [length]: 2, [name]: "toSpliced" },
|
|
[with]: [Function: with] { [length]: 2, [name]: "with" },
|
|
[toLocaleString]: [Function: toLocaleString] { [length]: 0, [name]: "toLocaleString" },
|
|
[toString]: [Function: toString] { [length]: 0, [name]: "toString" },
|
|
[Symbol(Symbol.iterator)]: [Function: values] { [length]: 0, [name]: "values" },
|
|
[Symbol(Symbol.unscopables)]: [Object: null prototype] {
|
|
at: true,
|
|
copyWithin: true,
|
|
entries: true,
|
|
fill: true,
|
|
find: true,
|
|
findIndex: true,
|
|
findLast: true,
|
|
findLastIndex: true,
|
|
flat: true,
|
|
flatMap: true,
|
|
includes: true,
|
|
keys: true,
|
|
toReversed: true,
|
|
toSorted: true,
|
|
toSpliced: true,
|
|
values: true
|
|
}
|
|
],
|
|
[isArray]: [Function: isArray] { [length]: 1, [name]: "isArray" },
|
|
[from]: [Function: from] { [length]: 1, [name]: "from" },
|
|
[fromAsync]: [Function: fromAsync] { [length]: 1, [name]: "fromAsync" },
|
|
[of]: [Function: of] { [length]: 0, [name]: "of" },
|
|
[Symbol(Symbol.species)]: [Getter]
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyWithDepth() {
|
|
// deno-lint-ignore no-explicit-any
|
|
const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };
|
|
assertEquals(
|
|
stripAnsiCode(inspectArgs([nestedObj], { depth: 3 })),
|
|
"{\n a: { b: { c: { d: [Object] } } }\n}",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(inspectArgs([nestedObj], { depth: 4 })),
|
|
"{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(inspectArgs([nestedObj], { depth: 0 })),
|
|
"{ a: [Object] }",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(inspectArgs([nestedObj])),
|
|
"{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
|
|
);
|
|
// test inspect is working the same way
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(nestedObj, { depth: 4 })),
|
|
"{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyLargeObject() {
|
|
const obj = {
|
|
a: 2,
|
|
o: {
|
|
a: "1",
|
|
b: "2",
|
|
c: "3",
|
|
d: "4",
|
|
e: "5",
|
|
f: "6",
|
|
g: 10,
|
|
asd: 2,
|
|
asda: 3,
|
|
x: { a: "asd", x: 3 },
|
|
},
|
|
};
|
|
assertEquals(
|
|
stringify(obj),
|
|
`{
|
|
a: 2,
|
|
o: {
|
|
a: "1",
|
|
b: "2",
|
|
c: "3",
|
|
d: "4",
|
|
e: "5",
|
|
f: "6",
|
|
g: 10,
|
|
asd: 2,
|
|
asda: 3,
|
|
x: { a: "asd", x: 3 }
|
|
}
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyIterable() {
|
|
const shortArray = [1, 2, 3, 4, 5];
|
|
assertEquals(stringify(shortArray), "[ 1, 2, 3, 4, 5 ]");
|
|
|
|
const longArray = new Array(200).fill(0);
|
|
assertEquals(
|
|
stringify(longArray),
|
|
`[
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
... 100 more items
|
|
]`,
|
|
);
|
|
|
|
const obj = { a: "a", longArray };
|
|
assertEquals(
|
|
stringify(obj),
|
|
`{
|
|
a: "a",
|
|
longArray: [
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
... 100 more items
|
|
]
|
|
}`,
|
|
);
|
|
|
|
const shortMap = new Map([
|
|
["a", 0],
|
|
["b", 1],
|
|
]);
|
|
assertEquals(stringify(shortMap), `Map(2) { "a" => 0, "b" => 1 }`);
|
|
|
|
const longMap = new Map();
|
|
for (const key of Array(200).keys()) {
|
|
longMap.set(`${key}`, key);
|
|
}
|
|
assertEquals(
|
|
stringify(longMap),
|
|
`Map(200) {
|
|
"0" => 0,
|
|
"1" => 1,
|
|
"2" => 2,
|
|
"3" => 3,
|
|
"4" => 4,
|
|
"5" => 5,
|
|
"6" => 6,
|
|
"7" => 7,
|
|
"8" => 8,
|
|
"9" => 9,
|
|
"10" => 10,
|
|
"11" => 11,
|
|
"12" => 12,
|
|
"13" => 13,
|
|
"14" => 14,
|
|
"15" => 15,
|
|
"16" => 16,
|
|
"17" => 17,
|
|
"18" => 18,
|
|
"19" => 19,
|
|
"20" => 20,
|
|
"21" => 21,
|
|
"22" => 22,
|
|
"23" => 23,
|
|
"24" => 24,
|
|
"25" => 25,
|
|
"26" => 26,
|
|
"27" => 27,
|
|
"28" => 28,
|
|
"29" => 29,
|
|
"30" => 30,
|
|
"31" => 31,
|
|
"32" => 32,
|
|
"33" => 33,
|
|
"34" => 34,
|
|
"35" => 35,
|
|
"36" => 36,
|
|
"37" => 37,
|
|
"38" => 38,
|
|
"39" => 39,
|
|
"40" => 40,
|
|
"41" => 41,
|
|
"42" => 42,
|
|
"43" => 43,
|
|
"44" => 44,
|
|
"45" => 45,
|
|
"46" => 46,
|
|
"47" => 47,
|
|
"48" => 48,
|
|
"49" => 49,
|
|
"50" => 50,
|
|
"51" => 51,
|
|
"52" => 52,
|
|
"53" => 53,
|
|
"54" => 54,
|
|
"55" => 55,
|
|
"56" => 56,
|
|
"57" => 57,
|
|
"58" => 58,
|
|
"59" => 59,
|
|
"60" => 60,
|
|
"61" => 61,
|
|
"62" => 62,
|
|
"63" => 63,
|
|
"64" => 64,
|
|
"65" => 65,
|
|
"66" => 66,
|
|
"67" => 67,
|
|
"68" => 68,
|
|
"69" => 69,
|
|
"70" => 70,
|
|
"71" => 71,
|
|
"72" => 72,
|
|
"73" => 73,
|
|
"74" => 74,
|
|
"75" => 75,
|
|
"76" => 76,
|
|
"77" => 77,
|
|
"78" => 78,
|
|
"79" => 79,
|
|
"80" => 80,
|
|
"81" => 81,
|
|
"82" => 82,
|
|
"83" => 83,
|
|
"84" => 84,
|
|
"85" => 85,
|
|
"86" => 86,
|
|
"87" => 87,
|
|
"88" => 88,
|
|
"89" => 89,
|
|
"90" => 90,
|
|
"91" => 91,
|
|
"92" => 92,
|
|
"93" => 93,
|
|
"94" => 94,
|
|
"95" => 95,
|
|
"96" => 96,
|
|
"97" => 97,
|
|
"98" => 98,
|
|
"99" => 99,
|
|
... 100 more items
|
|
}`,
|
|
);
|
|
|
|
const shortSet = new Set([1, 2, 3]);
|
|
assertEquals(stringify(shortSet), `Set(3) { 1, 2, 3 }`);
|
|
const longSet = new Set();
|
|
for (const key of Array(200).keys()) {
|
|
longSet.add(key);
|
|
}
|
|
assertEquals(
|
|
stringify(longSet),
|
|
`Set(200) {
|
|
0,
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
12,
|
|
13,
|
|
14,
|
|
15,
|
|
16,
|
|
17,
|
|
18,
|
|
19,
|
|
20,
|
|
21,
|
|
22,
|
|
23,
|
|
24,
|
|
25,
|
|
26,
|
|
27,
|
|
28,
|
|
29,
|
|
30,
|
|
31,
|
|
32,
|
|
33,
|
|
34,
|
|
35,
|
|
36,
|
|
37,
|
|
38,
|
|
39,
|
|
40,
|
|
41,
|
|
42,
|
|
43,
|
|
44,
|
|
45,
|
|
46,
|
|
47,
|
|
48,
|
|
49,
|
|
50,
|
|
51,
|
|
52,
|
|
53,
|
|
54,
|
|
55,
|
|
56,
|
|
57,
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
62,
|
|
63,
|
|
64,
|
|
65,
|
|
66,
|
|
67,
|
|
68,
|
|
69,
|
|
70,
|
|
71,
|
|
72,
|
|
73,
|
|
74,
|
|
75,
|
|
76,
|
|
77,
|
|
78,
|
|
79,
|
|
80,
|
|
81,
|
|
82,
|
|
83,
|
|
84,
|
|
85,
|
|
86,
|
|
87,
|
|
88,
|
|
89,
|
|
90,
|
|
91,
|
|
92,
|
|
93,
|
|
94,
|
|
95,
|
|
96,
|
|
97,
|
|
98,
|
|
99,
|
|
... 100 more items
|
|
}`,
|
|
);
|
|
|
|
const withEmptyEl = Array(10);
|
|
withEmptyEl.fill(0, 4, 6);
|
|
assertEquals(
|
|
stringify(withEmptyEl),
|
|
`[ <4 empty items>, 0, 0, <4 empty items> ]`,
|
|
);
|
|
|
|
const emptyArray = Array(5000);
|
|
assertEquals(
|
|
stringify(emptyArray),
|
|
`[ <5000 empty items> ]`,
|
|
);
|
|
|
|
assertEquals(
|
|
stringify(Array(1)),
|
|
`[ <1 empty item> ]`,
|
|
);
|
|
|
|
assertEquals(
|
|
stringify([, , 1]),
|
|
`[ <2 empty items>, 1 ]`,
|
|
);
|
|
|
|
assertEquals(
|
|
stringify([1, , , 1]),
|
|
`[ 1, <2 empty items>, 1 ]`,
|
|
);
|
|
|
|
const withEmptyElAndMoreItems = Array(500);
|
|
withEmptyElAndMoreItems.fill(0, 50, 80);
|
|
withEmptyElAndMoreItems.fill(2, 100, 120);
|
|
withEmptyElAndMoreItems.fill(3, 140, 160);
|
|
withEmptyElAndMoreItems.fill(4, 180);
|
|
assertEquals(
|
|
stringify(withEmptyElAndMoreItems),
|
|
`[
|
|
<50 empty items>, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, <20 empty items>,
|
|
2, 2, 2, 2,
|
|
2, 2, 2, 2,
|
|
2, 2, 2, 2,
|
|
2, 2, 2, 2,
|
|
2, 2, 2, 2,
|
|
<20 empty items>, 3, 3, 3,
|
|
3, 3, 3, 3,
|
|
3, 3, 3, 3,
|
|
3, 3, 3, 3,
|
|
3, 3, 3, 3,
|
|
3, <20 empty items>, 4, 4,
|
|
4, 4, 4, 4,
|
|
4, 4, 4, 4,
|
|
4, 4, 4, 4,
|
|
4, 4, 4, 4,
|
|
4, 4, 4, 4,
|
|
4, 4, 4, 4,
|
|
... 294 more items
|
|
]`,
|
|
);
|
|
|
|
const lWithEmptyEl = Array(200);
|
|
lWithEmptyEl.fill(0, 50, 80);
|
|
assertEquals(
|
|
stringify(lWithEmptyEl),
|
|
`[
|
|
<50 empty items>, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, <120 empty items>
|
|
]`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyIterableWhenGrouped() {
|
|
const withOddNumberOfEls = new Float64Array(
|
|
[
|
|
2.1,
|
|
2.01,
|
|
2.001,
|
|
2.0001,
|
|
2.00001,
|
|
2.000001,
|
|
2.0000001,
|
|
2.00000001,
|
|
2.000000001,
|
|
2.0000000001,
|
|
2,
|
|
],
|
|
);
|
|
assertEquals(
|
|
stringify(withOddNumberOfEls),
|
|
`Float64Array(11) [
|
|
2.1, 2.01,
|
|
2.001, 2.0001,
|
|
2.00001, 2.000001,
|
|
2.0000001, 2.00000001,
|
|
2.000000001, 2.0000000001,
|
|
2
|
|
]`,
|
|
);
|
|
const withEvenNumberOfEls = new Float64Array(
|
|
[
|
|
2.1,
|
|
2.01,
|
|
2.001,
|
|
2.0001,
|
|
2.00001,
|
|
2.000001,
|
|
2.0000001,
|
|
2.00000001,
|
|
2.000000001,
|
|
2.0000000001,
|
|
2,
|
|
2,
|
|
],
|
|
);
|
|
assertEquals(
|
|
stringify(withEvenNumberOfEls),
|
|
`Float64Array(12) [
|
|
2.1, 2.01,
|
|
2.001, 2.0001,
|
|
2.00001, 2.000001,
|
|
2.0000001, 2.00000001,
|
|
2.000000001, 2.0000000001,
|
|
2, 2
|
|
]`,
|
|
);
|
|
const withThreeColumns = [
|
|
2,
|
|
2.1,
|
|
2.11,
|
|
2,
|
|
2.111,
|
|
2.1111,
|
|
2,
|
|
2.1,
|
|
2.11,
|
|
2,
|
|
2.1,
|
|
];
|
|
assertEquals(
|
|
stringify(withThreeColumns),
|
|
`[
|
|
2, 2.1, 2.11,
|
|
2, 2.111, 2.1111,
|
|
2, 2.1, 2.11,
|
|
2, 2.1
|
|
]`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestIteratorValueAreNotConsumed() {
|
|
const setIterator = new Set([1, 2, 3]).values();
|
|
assertEquals(
|
|
stringify(setIterator),
|
|
"[Set Iterator] { 1, 2, 3 }",
|
|
);
|
|
assertEquals([...setIterator], [1, 2, 3]);
|
|
});
|
|
|
|
Deno.test(function consoleTestWeakSetAndWeakMapWithShowHidden() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(new WeakSet([{}]), { showHidden: true })),
|
|
"WeakSet { {} }",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(
|
|
Deno.inspect(new WeakMap([[{}, "foo"]]), { showHidden: true }),
|
|
),
|
|
'WeakMap { {} => "foo" }',
|
|
);
|
|
});
|
|
|
|
Deno.test(async function consoleTestStringifyPromises() {
|
|
const pendingPromise = new Promise((_res, _rej) => {});
|
|
assertEquals(stringify(pendingPromise), "Promise { <pending> }");
|
|
|
|
const resolvedPromise = new Promise((res, _rej) => {
|
|
res("Resolved!");
|
|
});
|
|
assertEquals(stringify(resolvedPromise), `Promise { "Resolved!" }`);
|
|
|
|
let rejectedPromise;
|
|
try {
|
|
rejectedPromise = new Promise((_, rej) => {
|
|
rej(Error("Whoops"));
|
|
});
|
|
await rejectedPromise;
|
|
} catch (_err) {
|
|
// pass
|
|
}
|
|
const strLines = stringify(rejectedPromise).split("\n");
|
|
assertEquals(strLines[0], "Promise {");
|
|
assertEquals(strLines[1], " <rejected> Error: Whoops");
|
|
});
|
|
|
|
Deno.test(function consoleTestStringifyIntlLocale() {
|
|
assertEquals(
|
|
stringify(new Intl.Locale("zh-Hant-TW", { hourCycle: "h12" })),
|
|
`Locale [Intl.Locale] {
|
|
baseName: "zh-Hant-TW",
|
|
calendar: undefined,
|
|
caseFirst: undefined,
|
|
collation: undefined,
|
|
hourCycle: "h12",
|
|
language: "zh",
|
|
numberingSystem: undefined,
|
|
numeric: false,
|
|
region: "TW",
|
|
script: "Hant"
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestWithCustomInspector() {
|
|
class A {
|
|
[customInspect](
|
|
inspect: unknown,
|
|
options: Deno.InspectOptions,
|
|
): string {
|
|
assertEquals(typeof inspect, "function");
|
|
assertEquals(typeof options, "object");
|
|
return "b";
|
|
}
|
|
}
|
|
|
|
assertEquals(stringify(new A()), "b");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithCustomInspectorUsingInspectFunc() {
|
|
class A {
|
|
[customInspect](
|
|
inspect: (v: unknown, opts?: Deno.InspectOptions) => string,
|
|
): string {
|
|
return "b " + inspect({ c: 1 });
|
|
}
|
|
}
|
|
|
|
assertEquals(stringify(new A()), "b { c: 1 }");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithConstructorError() {
|
|
const obj = new Proxy({}, {
|
|
getOwnPropertyDescriptor(_target, name) {
|
|
if (name == "constructor") {
|
|
throw "yikes";
|
|
}
|
|
return undefined;
|
|
},
|
|
});
|
|
assertEquals(Deno.inspect(obj), "{}");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithCustomInspectorError() {
|
|
class A {
|
|
[customInspect](): never {
|
|
throw new Error("BOOM");
|
|
}
|
|
}
|
|
|
|
const a = new A();
|
|
assertThrows(
|
|
() => stringify(a),
|
|
Error,
|
|
"BOOM",
|
|
"Custom inspect won't attempt to parse if user defined function throws",
|
|
);
|
|
assertThrows(
|
|
() => stringify(a),
|
|
Error,
|
|
"BOOM",
|
|
"Inspect should fail and maintain a clear CTX_STACK",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestWithCustomInspectFunction() {
|
|
function a() {}
|
|
Object.assign(a, {
|
|
[customInspect]() {
|
|
return "b";
|
|
},
|
|
});
|
|
|
|
assertEquals(stringify(a), "b");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithIntegerFormatSpecifier() {
|
|
assertEquals(stringify("%i"), "%i");
|
|
assertEquals(stringify("%i", 42.0), "42");
|
|
assertEquals(stringify("%i", 42), "42");
|
|
assertEquals(stringify("%i", "42"), "NaN");
|
|
assertEquals(stringify("%i", 1.5), "1");
|
|
assertEquals(stringify("%i", -0.5), "0");
|
|
assertEquals(stringify("%i", ""), "NaN");
|
|
assertEquals(stringify("%i", Symbol()), "NaN");
|
|
assertEquals(stringify("%i %d", 42, 43), "42 43");
|
|
assertEquals(stringify("%d %i", 42), "42 %i");
|
|
assertEquals(stringify("%d", 12345678901234567890123), "1");
|
|
assertEquals(
|
|
stringify("%i", 12345678901234567890123n),
|
|
"12345678901234567890123n",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestWithFloatFormatSpecifier() {
|
|
assertEquals(stringify("%f"), "%f");
|
|
assertEquals(stringify("%f", 42.0), "42");
|
|
assertEquals(stringify("%f", 42), "42");
|
|
assertEquals(stringify("%f", "42"), "NaN");
|
|
assertEquals(stringify("%f", 1.5), "1.5");
|
|
assertEquals(stringify("%f", -0.5), "-0.5");
|
|
assertEquals(stringify("%f", Math.PI), "3.141592653589793");
|
|
assertEquals(stringify("%f", ""), "NaN");
|
|
assertEquals(stringify("%f", Symbol("foo")), "NaN");
|
|
assertEquals(stringify("%f", 5n), "NaN");
|
|
assertEquals(stringify("%f %f", 42, 43), "42 43");
|
|
assertEquals(stringify("%f %f", 42), "42 %f");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithStringFormatSpecifier() {
|
|
assertEquals(stringify("%s"), "%s");
|
|
assertEquals(stringify("%s", undefined), "undefined");
|
|
assertEquals(stringify("%s", "foo"), "foo");
|
|
assertEquals(stringify("%s", 42), "42");
|
|
assertEquals(stringify("%s", "42"), "42");
|
|
assertEquals(stringify("%s %s", 42, 43), "42 43");
|
|
assertEquals(stringify("%s %s", 42), "42 %s");
|
|
assertEquals(stringify("%s", Symbol("foo")), "Symbol(foo)");
|
|
});
|
|
|
|
Deno.test(function consoleTestWithObjectFormatSpecifier() {
|
|
assertEquals(stringify("%o"), "%o");
|
|
assertEquals(stringify("%o", 42), "42");
|
|
assertEquals(stringify("%o", "foo"), `"foo"`);
|
|
assertEquals(stringify("o: %o, a: %O", {}, []), "o: {}, a: []");
|
|
assertEquals(stringify("%o", { a: 42 }), "{ a: 42 }");
|
|
assertEquals(
|
|
stringify("%o", { a: { b: { c: { d: new Set([1]) } } } }),
|
|
"{\n a: {\n b: { c: { d: Set(1) { 1 } } }\n }\n}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestWithStyleSpecifier() {
|
|
assertEquals(stringify("%cfoo%cbar"), "%cfoo%cbar");
|
|
assertEquals(stringify("%cfoo%cbar", ""), "foo%cbar");
|
|
assertEquals(
|
|
stripAnsiCode(stringify("%cfoo%cbar", "", "color: red")),
|
|
"foobar",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleParseCssColor() {
|
|
assertEquals(parseCssColor("inherit"), null);
|
|
assertEquals(parseCssColor("black"), [0, 0, 0]);
|
|
assertEquals(parseCssColor("darkmagenta"), [139, 0, 139]);
|
|
assertEquals(parseCssColor("slateblue"), [106, 90, 205]);
|
|
assertEquals(parseCssColor("#ffaa00"), [255, 170, 0]);
|
|
assertEquals(parseCssColor("#ffAA00"), [255, 170, 0]);
|
|
assertEquals(parseCssColor("#fa0"), [255, 170, 0]);
|
|
assertEquals(parseCssColor("#FA0"), [255, 170, 0]);
|
|
assertEquals(parseCssColor("#18d"), [17, 136, 221]);
|
|
assertEquals(parseCssColor("#18D"), [17, 136, 221]);
|
|
assertEquals(parseCssColor("#1188DD"), [17, 136, 221]);
|
|
assertEquals(parseCssColor("rgb(100, 200, 50)"), [100, 200, 50]);
|
|
assertEquals(parseCssColor("rgb(+100.3, -200, .5)"), [100, 0, 1]);
|
|
assertEquals(parseCssColor("hsl(75, 60%, 40%)"), [133, 163, 41]);
|
|
|
|
assertEquals(parseCssColor("rgb(100,200,50)"), [100, 200, 50]);
|
|
assertEquals(
|
|
parseCssColor("rgb( \t\n100 \t\n, \t\n200 \t\n, \t\n50 \t\n)"),
|
|
[100, 200, 50],
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleParseCss() {
|
|
assertEquals(
|
|
parseCss("background-color: inherit"),
|
|
{ ...DEFAULT_CSS, backgroundColor: "inherit" },
|
|
);
|
|
assertEquals(
|
|
parseCss("color: inherit"),
|
|
{ ...DEFAULT_CSS, color: "inherit" },
|
|
);
|
|
assertEquals(
|
|
parseCss("background-color: red"),
|
|
{ ...DEFAULT_CSS, backgroundColor: "red" },
|
|
);
|
|
assertEquals(parseCss("color: blue"), { ...DEFAULT_CSS, color: "blue" });
|
|
assertEquals(
|
|
parseCss("font-weight: bold"),
|
|
{ ...DEFAULT_CSS, fontWeight: "bold" },
|
|
);
|
|
assertEquals(
|
|
parseCss("font-style: italic"),
|
|
{ ...DEFAULT_CSS, fontStyle: "italic" },
|
|
);
|
|
assertEquals(
|
|
parseCss("font-style: oblique"),
|
|
{ ...DEFAULT_CSS, fontStyle: "italic" },
|
|
);
|
|
assertEquals(
|
|
parseCss("text-decoration-color: green"),
|
|
{ ...DEFAULT_CSS, textDecorationColor: [0, 128, 0] },
|
|
);
|
|
assertEquals(
|
|
parseCss("text-decoration-line: underline overline line-through"),
|
|
{
|
|
...DEFAULT_CSS,
|
|
textDecorationLine: ["underline", "overline", "line-through"],
|
|
},
|
|
);
|
|
assertEquals(
|
|
parseCss("text-decoration: yellow underline"),
|
|
{
|
|
...DEFAULT_CSS,
|
|
textDecorationColor: [255, 255, 0],
|
|
textDecorationLine: ["underline"],
|
|
},
|
|
);
|
|
|
|
assertEquals(
|
|
parseCss("color:red;font-weight:bold;"),
|
|
{ ...DEFAULT_CSS, color: "red", fontWeight: "bold" },
|
|
);
|
|
assertEquals(
|
|
parseCss(
|
|
" \t\ncolor \t\n: \t\nred \t\n; \t\nfont-weight \t\n: \t\nbold \t\n; \t\n",
|
|
),
|
|
{ ...DEFAULT_CSS, color: "red", fontWeight: "bold" },
|
|
);
|
|
assertEquals(
|
|
parseCss("color: red; font-weight: bold, font-style: italic"),
|
|
{ ...DEFAULT_CSS, color: "red" },
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleCssToAnsi() {
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "inherit" }),
|
|
"_[49m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "foo" }),
|
|
"_[49m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "black" }),
|
|
"_[40m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, color: "inherit" }),
|
|
"_[39m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, color: "blue" }),
|
|
"_[34m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: [200, 201, 202] }),
|
|
"_[48;2;200;201;202m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, color: [203, 204, 205] }),
|
|
"_[38;2;203;204;205m",
|
|
);
|
|
assertEquals(cssToAnsiEsc({ ...DEFAULT_CSS, fontWeight: "bold" }), "_[1m");
|
|
assertEquals(cssToAnsiEsc({ ...DEFAULT_CSS, fontStyle: "italic" }), "_[3m");
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, textDecorationColor: [206, 207, 208] }),
|
|
"_[58;2;206;207;208m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc({ ...DEFAULT_CSS, textDecorationLine: ["underline"] }),
|
|
"_[4m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc(
|
|
{ ...DEFAULT_CSS, textDecorationLine: ["overline", "line-through"] },
|
|
),
|
|
"_[9m_[53m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc(
|
|
{ ...DEFAULT_CSS, color: [203, 204, 205], fontWeight: "bold" },
|
|
),
|
|
"_[38;2;203;204;205m_[1m",
|
|
);
|
|
assertEquals(
|
|
cssToAnsiEsc(
|
|
{ ...DEFAULT_CSS, color: [0, 0, 0], fontWeight: "bold" },
|
|
{ ...DEFAULT_CSS, color: [203, 204, 205], fontStyle: "italic" },
|
|
),
|
|
"_[38;2;0;0;0m_[1m_[23m",
|
|
);
|
|
});
|
|
|
|
Deno.test(function consoleTestWithVariousOrInvalidFormatSpecifier() {
|
|
assertEquals(stringify("%s:%s"), "%s:%s");
|
|
assertEquals(stringify("%i:%i"), "%i:%i");
|
|
assertEquals(stringify("%d:%d"), "%d:%d");
|
|
assertEquals(stringify("%%s%s", "foo"), "%sfoo");
|
|
assertEquals(stringify("%s:%s", undefined), "undefined:%s");
|
|
assertEquals(stringify("%s:%s", "foo", "bar"), "foo:bar");
|
|
assertEquals(stringify("%s:%s", "foo", "bar", "baz"), "foo:bar baz");
|
|
assertEquals(stringify("%%%s%%", "hi"), "%hi%");
|
|
assertEquals(stringify("%d:%d", 12), "12:%d");
|
|
assertEquals(stringify("%i:%i", 12), "12:%i");
|
|
assertEquals(stringify("%f:%f", 12), "12:%f");
|
|
assertEquals(stringify("o: %o, a: %o", {}), "o: {}, a: %o");
|
|
assertEquals(stringify("abc%", 1), "abc% 1");
|
|
});
|
|
|
|
Deno.test(function consoleTestCallToStringOnLabel() {
|
|
const methods = ["count", "countReset", "time", "timeLog", "timeEnd"];
|
|
mockConsole((console) => {
|
|
for (const method of methods) {
|
|
let hasCalled = false;
|
|
console[method]({
|
|
toString() {
|
|
hasCalled = true;
|
|
},
|
|
});
|
|
assertEquals(hasCalled, true);
|
|
}
|
|
});
|
|
});
|
|
|
|
Deno.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")[0] // error has been caught
|
|
.includes("MyError: This is an error"),
|
|
);
|
|
}
|
|
});
|
|
|
|
Deno.test(function consoleTestClear() {
|
|
mockConsole((console, out) => {
|
|
console.clear();
|
|
assertEquals(out.toString(), "\x1b[1;1H" + "\x1b[0J");
|
|
});
|
|
});
|
|
|
|
// Test bound this issue
|
|
Deno.test(function consoleDetachedLog() {
|
|
mockConsole((console) => {
|
|
const log = console.log;
|
|
const dir = console.dir;
|
|
const dirxml = console.dirxml;
|
|
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");
|
|
dirxml("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();
|
|
});
|
|
});
|
|
|
|
class StringBuffer {
|
|
chunks: string[] = [];
|
|
add(x: string) {
|
|
this.chunks.push(x);
|
|
}
|
|
toString(): string {
|
|
return this.chunks.join("");
|
|
}
|
|
}
|
|
|
|
type ConsoleExamineFunc = (
|
|
// deno-lint-ignore no-explicit-any
|
|
csl: any,
|
|
out: StringBuffer,
|
|
err?: StringBuffer,
|
|
both?: StringBuffer,
|
|
) => void;
|
|
|
|
function mockConsole(f: ConsoleExamineFunc) {
|
|
const out = new StringBuffer();
|
|
const err = new StringBuffer();
|
|
const both = new StringBuffer();
|
|
const csl = new Console(
|
|
(x: string, level: number, printsNewLine: boolean) => {
|
|
const content = x + (printsNewLine ? "\n" : "");
|
|
const buf = level > 1 ? err : out;
|
|
buf.add(content);
|
|
both.add(content);
|
|
},
|
|
);
|
|
f(csl, out, err, both);
|
|
}
|
|
|
|
// console.group test
|
|
Deno.test(function consoleGroup() {
|
|
mockConsole((console, out) => {
|
|
console.group("1");
|
|
console.log("2");
|
|
console.group("3");
|
|
console.log("4");
|
|
console.groupEnd();
|
|
console.groupEnd();
|
|
console.log("5");
|
|
console.log("6");
|
|
|
|
assertEquals(
|
|
out.toString(),
|
|
`1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
`,
|
|
);
|
|
});
|
|
});
|
|
|
|
// console.group with console.warn test
|
|
Deno.test(function consoleGroupWarn() {
|
|
mockConsole((console, _out, _err, both) => {
|
|
assert(both);
|
|
console.warn("1");
|
|
console.group();
|
|
console.warn("2");
|
|
console.group();
|
|
console.warn("3");
|
|
console.groupEnd();
|
|
console.warn("4");
|
|
console.groupEnd();
|
|
console.warn("5");
|
|
|
|
console.warn("6");
|
|
console.warn("7");
|
|
assertEquals(
|
|
both.toString(),
|
|
`1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
`,
|
|
);
|
|
});
|
|
});
|
|
|
|
// console.table test
|
|
Deno.test(function consoleTable() {
|
|
mockConsole((console, out) => {
|
|
console.table({ a: "test", b: 1 });
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬────────┐
|
|
│ (idx) │ Values │
|
|
├───────┼────────┤
|
|
│ a │ "test" │
|
|
│ b │ 1 │
|
|
└───────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table({ a: { b: 10 }, b: { b: 20, c: 30 } }, ["c"]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬────┐
|
|
│ (idx) │ c │
|
|
├───────┼────┤
|
|
│ a │ │
|
|
│ b │ 30 │
|
|
└───────┴────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([[1, 1], [234, 2.34], [56789, 56.789]]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───────┬────────┐
|
|
│ (idx) │ 0 │ 1 │
|
|
├───────┼───────┼────────┤
|
|
│ 0 │ 1 │ 1 │
|
|
│ 1 │ 234 │ 2.34 │
|
|
│ 2 │ 56789 │ 56.789 │
|
|
└───────┴───────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([1, 2, [3, [4]], [5, 6], [[7], [8]]]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───────┬───────┬────────┐
|
|
│ (idx) │ 0 │ 1 │ Values │
|
|
├───────┼───────┼───────┼────────┤
|
|
│ 0 │ │ │ 1 │
|
|
│ 1 │ │ │ 2 │
|
|
│ 2 │ 3 │ [ 4 ] │ │
|
|
│ 3 │ 5 │ 6 │ │
|
|
│ 4 │ [ 7 ] │ [ 8 ] │ │
|
|
└───────┴───────┴───────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(new Set([1, 2, 3, "test"]));
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌────────────┬────────┐
|
|
│ (iter idx) │ Values │
|
|
├────────────┼────────┤
|
|
│ 0 │ 1 │
|
|
│ 1 │ 2 │
|
|
│ 2 │ 3 │
|
|
│ 3 │ "test" │
|
|
└────────────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(
|
|
new Map([
|
|
[1, "one"],
|
|
[2, "two"],
|
|
]),
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌────────────┬─────┬────────┐
|
|
│ (iter idx) │ Key │ Values │
|
|
├────────────┼─────┼────────┤
|
|
│ 0 │ 1 │ "one" │
|
|
│ 1 │ 2 │ "two" │
|
|
└────────────┴─────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table({
|
|
a: true,
|
|
b: { c: { d: 10 }, e: [1, 2, [5, 6]] },
|
|
f: "test",
|
|
g: new Set([1, 2, 3, "test"]),
|
|
h: new Map([[1, "one"]]),
|
|
});
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───────────┬────────────────────┬────────┐
|
|
│ (idx) │ c │ e │ Values │
|
|
├───────┼───────────┼────────────────────┼────────┤
|
|
│ a │ │ │ true │
|
|
│ b │ { d: 10 } │ [ 1, 2, [ 5, 6 ] ] │ │
|
|
│ f │ │ │ "test" │
|
|
│ g │ │ │ │
|
|
│ h │ │ │ │
|
|
└───────┴───────────┴────────────────────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([
|
|
1,
|
|
"test",
|
|
false,
|
|
{ a: 10 },
|
|
["test", { b: 20, c: "test" }],
|
|
]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬────────┬──────────────────────┬────┬────────┐
|
|
│ (idx) │ 0 │ 1 │ a │ Values │
|
|
├───────┼────────┼──────────────────────┼────┼────────┤
|
|
│ 0 │ │ │ │ 1 │
|
|
│ 1 │ │ │ │ "test" │
|
|
│ 2 │ │ │ │ false │
|
|
│ 3 │ │ │ 10 │ │
|
|
│ 4 │ "test" │ { b: 20, c: "test" } │ │ │
|
|
└───────┴────────┴──────────────────────┴────┴────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┐
|
|
│ (idx) │
|
|
├───────┤
|
|
└───────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table({});
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┐
|
|
│ (idx) │
|
|
├───────┤
|
|
└───────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(new Set());
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌────────────┐
|
|
│ (iter idx) │
|
|
├────────────┤
|
|
└────────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(new Map());
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌────────────┐
|
|
│ (iter idx) │
|
|
├────────────┤
|
|
└────────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table("test");
|
|
assertEquals(out.toString(), "test\n");
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(["Hello", "你好", "Amapá"]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬─────────┐
|
|
│ (idx) │ Values │
|
|
├───────┼─────────┤
|
|
│ 0 │ "Hello" │
|
|
│ 1 │ "你好" │
|
|
│ 2 │ "Amapá" │
|
|
└───────┴─────────┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([
|
|
[1, 2],
|
|
[3, 4],
|
|
]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───┬───┐
|
|
│ (idx) │ 0 │ 1 │
|
|
├───────┼───┼───┤
|
|
│ 0 │ 1 │ 2 │
|
|
│ 1 │ 3 │ 4 │
|
|
└───────┴───┴───┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table({ 1: { a: 4, b: 5 }, 2: null, 3: { b: 6, c: 7 } }, ["b"]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───┐
|
|
│ (idx) │ b │
|
|
├───────┼───┤
|
|
│ 1 │ 5 │
|
|
│ 2 │ │
|
|
│ 3 │ 6 │
|
|
└───────┴───┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table([{ a: 0 }, { a: 1, b: 1 }, { a: 2 }, { a: 3, b: 3 }]);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───┬───┐
|
|
│ (idx) │ a │ b │
|
|
├───────┼───┼───┤
|
|
│ 0 │ 0 │ │
|
|
│ 1 │ 1 │ 1 │
|
|
│ 2 │ 2 │ │
|
|
│ 3 │ 3 │ 3 │
|
|
└───────┴───┴───┘
|
|
`,
|
|
);
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.table(
|
|
[{ a: 0 }, { a: 1, c: 1 }, { a: 2 }, { a: 3, c: 3 }],
|
|
["a", "b", "c"],
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(out.toString()),
|
|
`\
|
|
┌───────┬───┬───┬───┐
|
|
│ (idx) │ a │ b │ c │
|
|
├───────┼───┼───┼───┤
|
|
│ 0 │ 0 │ │ │
|
|
│ 1 │ 1 │ │ 1 │
|
|
│ 2 │ 2 │ │ │
|
|
│ 3 │ 3 │ │ 3 │
|
|
└───────┴───┴───┴───┘
|
|
`,
|
|
);
|
|
});
|
|
});
|
|
|
|
// console.log(Error) test
|
|
Deno.test(function consoleLogShouldNotThrowError() {
|
|
mockConsole((console) => {
|
|
let result = 0;
|
|
try {
|
|
console.log(new Error("foo"));
|
|
result = 1;
|
|
} catch (_e) {
|
|
result = 2;
|
|
}
|
|
assertEquals(result, 1);
|
|
});
|
|
|
|
// output errors to the console should not include "Uncaught"
|
|
mockConsole((console, out) => {
|
|
console.log(new Error("foo"));
|
|
assertEquals(out.toString().includes("Uncaught"), false);
|
|
});
|
|
});
|
|
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInvalidCssColorsAreGiven() {
|
|
mockConsole((console, out) => {
|
|
console.log("%cfoo", "color: foo; background-color: bar;");
|
|
assertEquals(stripAnsiCode(out.toString()), "foo\n");
|
|
});
|
|
});
|
|
|
|
// console.log(Invalid Date) test
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInvalidDateIsPassed() {
|
|
mockConsole((console, out) => {
|
|
const invalidDate = new Date("test");
|
|
console.log(invalidDate);
|
|
assertEquals(stripAnsiCode(out.toString()), "Invalid Date\n");
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new Set(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedSet() {
|
|
mockConsole((console, out) => {
|
|
const proxiedSet = new Proxy(new Set([1, 2]), {});
|
|
console.log(proxiedSet);
|
|
assertEquals(stripAnsiCode(out.toString()), "Set(2) { 1, 2 }\n");
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new Map(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedMap() {
|
|
mockConsole((console, out) => {
|
|
const proxiedMap = new Proxy(new Map([[1, 1], [2, 2]]), {});
|
|
console.log(proxiedMap);
|
|
assertEquals(stripAnsiCode(out.toString()), "Map(2) { 1 => 1, 2 => 2 }\n");
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new Uint8Array(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedTypedArray() {
|
|
mockConsole((console, out) => {
|
|
const proxiedUint8Array = new Proxy(new Uint8Array([1, 2]), {});
|
|
console.log(proxiedUint8Array);
|
|
assertEquals(stripAnsiCode(out.toString()), "Uint8Array(2) [ 1, 2 ]\n");
|
|
});
|
|
});
|
|
|
|
Deno.test(function consoleLogWhenCauseIsAssignedShouldNotPrintCauseTwice() {
|
|
mockConsole((console, out) => {
|
|
const typeError = new TypeError("Type incorrect");
|
|
const syntaxError = new SyntaxError("Improper syntax");
|
|
typeError.cause = syntaxError;
|
|
console.log(typeError);
|
|
const result = stripAnsiCode(out.toString());
|
|
// Filter out stack trace lines, keeping only the first line and the cause line
|
|
const filteredOutput = result
|
|
.split("\n")
|
|
.filter((line) => !line.trim().startsWith("at"))
|
|
.join("\n");
|
|
|
|
const expectedResult =
|
|
"TypeError: Type incorrect\nCaused by SyntaxError: Improper syntax\n";
|
|
assertEquals(filteredOutput.trim(), expectedResult.trim());
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new RegExp(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedRegExp() {
|
|
mockConsole((console, out) => {
|
|
const proxiedRegExp = new Proxy(/aaaa/, {});
|
|
console.log(proxiedRegExp);
|
|
assertEquals(stripAnsiCode(out.toString()), "/aaaa/\n");
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new Date(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedDate() {
|
|
mockConsole((console, out) => {
|
|
const proxiedDate = new Proxy(new Date("2022-09-24T15:59:39.529Z"), {});
|
|
console.log(proxiedDate);
|
|
assertEquals(stripAnsiCode(out.toString()), "2022-09-24T15:59:39.529Z\n");
|
|
});
|
|
});
|
|
|
|
// console.log(new Proxy(new Error(), {}))
|
|
Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedError() {
|
|
mockConsole((console, out) => {
|
|
const proxiedError = new Proxy(new Error("message"), {});
|
|
console.log(proxiedError);
|
|
assertStringIncludes(stripAnsiCode(out.toString()), "Error: message\n");
|
|
});
|
|
});
|
|
|
|
// console.dir test
|
|
Deno.test(function consoleDir() {
|
|
mockConsole((console, out) => {
|
|
console.dir("DIR");
|
|
assertEquals(out.toString(), "DIR\n");
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.dir("DIR", { indentLevel: 2 });
|
|
assertEquals(out.toString(), " DIR\n");
|
|
});
|
|
});
|
|
|
|
// console.dir test
|
|
Deno.test(function consoleDirXml() {
|
|
mockConsole((console, out) => {
|
|
console.dirxml("DIRXML");
|
|
assertEquals(out.toString(), "DIRXML\n");
|
|
});
|
|
mockConsole((console, out) => {
|
|
console.dirxml("DIRXML", { indentLevel: 2 });
|
|
assertEquals(out.toString(), " DIRXML\n");
|
|
});
|
|
});
|
|
|
|
// console.trace test
|
|
Deno.test(function consoleTrace() {
|
|
mockConsole((console, _out, err) => {
|
|
console.trace("%s", "custom message");
|
|
assert(err);
|
|
assert(err.toString().includes("Trace: custom message"));
|
|
});
|
|
});
|
|
|
|
Deno.test(function inspectString() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect("\0")),
|
|
`"\\x00"`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect("\x1b[2J")),
|
|
`"\\x1b[2J"`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectGetters() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect({
|
|
get foo() {
|
|
return 0;
|
|
},
|
|
})),
|
|
"{ foo: [Getter] }",
|
|
);
|
|
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect({
|
|
get foo() {
|
|
return 0;
|
|
},
|
|
}, { getters: true })),
|
|
"{ foo: [Getter: 0] }",
|
|
);
|
|
|
|
assertEquals(
|
|
Deno.inspect({
|
|
get foo() {
|
|
throw new Error("bar");
|
|
},
|
|
}, { getters: true }),
|
|
"{ foo: [Getter: <Inspection threw (bar)>] }",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectPrototype() {
|
|
class A {}
|
|
assertEquals(Deno.inspect(A.prototype), "{}");
|
|
});
|
|
|
|
Deno.test(function inspectSorted() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect({ b: 2, a: 1 }, { sorted: true })),
|
|
"{ a: 1, b: 2 }",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(new Set(["b", "a"]), { sorted: true })),
|
|
`Set(2) { "a", "b" }`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Map([
|
|
["b", 2],
|
|
["a", 1],
|
|
]),
|
|
{ sorted: true },
|
|
)),
|
|
`Map(2) { "a" => 1, "b" => 2 }`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectTrailingComma() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
[
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
],
|
|
{ trailingComma: true },
|
|
)),
|
|
`[
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
]`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
{
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: 1,
|
|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: 2,
|
|
},
|
|
{ trailingComma: true },
|
|
)),
|
|
`{
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: 1,
|
|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: 2,
|
|
}`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Set([
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
]),
|
|
{ trailingComma: true },
|
|
)),
|
|
`Set(2) {
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
}`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Map([
|
|
["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 1],
|
|
["bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 2],
|
|
]),
|
|
{ trailingComma: true },
|
|
)),
|
|
`Map(2) {
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" => 1,
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" => 2,
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectCompact() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect({ a: 1, b: 2 }, { compact: false })),
|
|
`{
|
|
a: 1,
|
|
b: 2
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectIterableLimit() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(["a", "b", "c"], { iterableLimit: 2 })),
|
|
`[ "a", "b", ... 1 more item ]`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(new Set(["a", "b", "c"]), { iterableLimit: 2 })),
|
|
`Set(3) { "a", "b", ... 1 more item }`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Map([
|
|
["a", 1],
|
|
["b", 2],
|
|
["c", 3],
|
|
]),
|
|
{ iterableLimit: 2 },
|
|
)),
|
|
`Map(3) { "a" => 1, "b" => 2, ... 1 more item }`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectProxy() {
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy([1, 2, 3], {}),
|
|
)),
|
|
"[ 1, 2, 3 ]",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy({ key: "value" }, {}),
|
|
)),
|
|
`{ key: "value" }`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy({}, {
|
|
get(_target, key) {
|
|
if (key === Symbol.toStringTag) {
|
|
return "MyProxy";
|
|
} else {
|
|
return 5;
|
|
}
|
|
},
|
|
getOwnPropertyDescriptor() {
|
|
return {
|
|
enumerable: true,
|
|
configurable: true,
|
|
value: 5,
|
|
};
|
|
},
|
|
ownKeys() {
|
|
return ["prop1", "prop2"];
|
|
},
|
|
}),
|
|
)),
|
|
`Object [MyProxy] { prop1: 5, prop2: 5 }`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy([1, 2, 3], { get() {} }),
|
|
{ showProxy: true },
|
|
)),
|
|
"Proxy [ [ 1, 2, 3 ], { get: [Function: get] } ]",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy({ a: 1 }, {
|
|
set(): boolean {
|
|
return false;
|
|
},
|
|
}),
|
|
{ showProxy: true },
|
|
)),
|
|
"Proxy [ { a: 1 }, { set: [Function: set] } ]",
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy([1, 2, 3, 4, 5, 6, 7], { get() {} }),
|
|
{ showProxy: true },
|
|
)),
|
|
`Proxy [
|
|
[
|
|
1, 2, 3, 4,
|
|
5, 6, 7
|
|
],
|
|
{ get: [Function: get] }
|
|
]`,
|
|
);
|
|
assertEquals(
|
|
stripAnsiCode(Deno.inspect(
|
|
new Proxy(function fn() {}, { get() {} }),
|
|
{ showProxy: true },
|
|
)),
|
|
"Proxy [ [Function: fn], { get: [Function: get] } ]",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectError() {
|
|
const error1 = new Error("This is an error");
|
|
const error2 = new Error("This is an error", {
|
|
cause: new Error("This is a cause error"),
|
|
});
|
|
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error1)),
|
|
"Error: This is an error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error2)),
|
|
"Error: This is an error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error2)),
|
|
"Caused by Error: This is a cause error",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectErrorCircular() {
|
|
const error1 = new Error("This is an error");
|
|
const error2 = new Error("This is an error", {
|
|
cause: new Error("This is a cause error"),
|
|
});
|
|
error1.cause = error1;
|
|
assert(error2.cause instanceof Error);
|
|
error2.cause.cause = error2;
|
|
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error1)),
|
|
"Error: This is an error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error2)),
|
|
"<ref *1> Error: This is an error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error2)),
|
|
"Caused by Error: This is a cause error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error2)),
|
|
"Caused by [Circular *1]",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectErrorWithCauseFormat() {
|
|
const error = new Error("This is an error", {
|
|
cause: {
|
|
code: 100500,
|
|
},
|
|
});
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error)),
|
|
"Error: This is an error",
|
|
);
|
|
assertStringIncludes(
|
|
stripAnsiCode(Deno.inspect(error)),
|
|
"Caused by { code: 100500 }",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectColors() {
|
|
assertEquals(Deno.inspect(1), "1");
|
|
assertStringIncludes(Deno.inspect(1, { colors: true }), "\x1b[");
|
|
});
|
|
|
|
Deno.test(function inspectEmptyArray() {
|
|
const arr: string[] = [];
|
|
|
|
assertEquals(
|
|
Deno.inspect(arr, {
|
|
compact: false,
|
|
trailingComma: true,
|
|
}),
|
|
"[]",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectDeepEmptyArray() {
|
|
const obj = {
|
|
arr: [],
|
|
};
|
|
|
|
assertEquals(
|
|
Deno.inspect(obj, {
|
|
compact: false,
|
|
trailingComma: true,
|
|
}),
|
|
`{
|
|
arr: [],
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectEmptyMap() {
|
|
const map = new Map();
|
|
|
|
assertEquals(
|
|
Deno.inspect(map, {
|
|
compact: false,
|
|
trailingComma: true,
|
|
}),
|
|
"Map(0) {}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectEmptySet() {
|
|
const set = new Set();
|
|
|
|
assertEquals(
|
|
Deno.inspect(set, {
|
|
compact: false,
|
|
trailingComma: true,
|
|
}),
|
|
"Set(0) {}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectEmptyUint8Array() {
|
|
const typedArray = new Uint8Array(0);
|
|
|
|
assertEquals(
|
|
Deno.inspect(typedArray, {
|
|
compact: false,
|
|
trailingComma: true,
|
|
}),
|
|
"Uint8Array(0) []",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectLargeArrayBuffer() {
|
|
const arrayBuffer = new ArrayBuffer(2 ** 32 + 1);
|
|
assertEquals(
|
|
Deno.inspect(arrayBuffer),
|
|
`ArrayBuffer {
|
|
[Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 4294967197 more bytes>,
|
|
byteLength: 4294967297
|
|
}`,
|
|
);
|
|
structuredClone(arrayBuffer, { transfer: [arrayBuffer] });
|
|
assertEquals(
|
|
Deno.inspect(arrayBuffer),
|
|
"ArrayBuffer { (detached), byteLength: 0 }",
|
|
);
|
|
|
|
const sharedArrayBuffer = new SharedArrayBuffer(2 ** 32 + 1);
|
|
assertEquals(
|
|
Deno.inspect(sharedArrayBuffer),
|
|
`SharedArrayBuffer {
|
|
[Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 4294967197 more bytes>,
|
|
byteLength: 4294967297
|
|
}`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectStringAbbreviation() {
|
|
const LONG_STRING =
|
|
"This is a really long string which will be abbreviated with ellipsis.";
|
|
const obj = {
|
|
str: LONG_STRING,
|
|
};
|
|
const arr = [LONG_STRING];
|
|
|
|
assertEquals(
|
|
Deno.inspect(obj, { strAbbreviateSize: 10 }),
|
|
'{ str: "This is a "... 59 more characters }',
|
|
);
|
|
|
|
assertEquals(
|
|
Deno.inspect(arr, { strAbbreviateSize: 10 }),
|
|
'[ "This is a "... 59 more characters ]',
|
|
);
|
|
});
|
|
|
|
Deno.test(async function inspectAggregateError() {
|
|
try {
|
|
await Promise.any([]);
|
|
} catch (err) {
|
|
assertEquals(
|
|
Deno.inspect(err).trimEnd(),
|
|
"AggregateError: All promises were rejected",
|
|
);
|
|
}
|
|
});
|
|
|
|
Deno.test(function inspectWithPrototypePollution() {
|
|
const originalExec = RegExp.prototype.exec;
|
|
try {
|
|
RegExp.prototype.exec = () => {
|
|
throw Error();
|
|
};
|
|
Deno.inspect("foo");
|
|
} finally {
|
|
RegExp.prototype.exec = originalExec;
|
|
}
|
|
});
|
|
|
|
Deno.test(function inspectPromiseLike() {
|
|
assertEquals(
|
|
Deno.inspect(Object.create(Promise.prototype)),
|
|
"Promise {}",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectorMethods() {
|
|
console.timeStamp("test");
|
|
console.profile("test");
|
|
console.profileEnd("test");
|
|
});
|
|
|
|
Deno.test(function inspectQuotesOverride() {
|
|
assertEquals(
|
|
// @ts-ignore - 'quotes' is an internal option
|
|
Deno.inspect("foo", { quotes: ["'", '"', "`"] }),
|
|
"'foo'",
|
|
);
|
|
assertEquals(
|
|
// @ts-ignore - 'quotes' is an internal option
|
|
Deno.inspect("'foo'", { quotes: ["'", '"', "`"] }),
|
|
`"'foo'"`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectAnonymousFunctions() {
|
|
assertEquals(Deno.inspect(() => {}), "[Function (anonymous)]");
|
|
assertEquals(Deno.inspect(function () {}), "[Function (anonymous)]");
|
|
assertEquals(Deno.inspect(async () => {}), "[AsyncFunction (anonymous)]");
|
|
assertEquals(
|
|
Deno.inspect(async function () {}),
|
|
"[AsyncFunction (anonymous)]",
|
|
);
|
|
assertEquals(
|
|
Deno.inspect(function* () {}),
|
|
"[GeneratorFunction (anonymous)]",
|
|
);
|
|
assertEquals(
|
|
Deno.inspect(async function* () {}),
|
|
"[AsyncGeneratorFunction (anonymous)]",
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectBreakLengthOption() {
|
|
assertEquals(
|
|
Deno.inspect("123456789\n".repeat(3), { breakLength: 34 }),
|
|
`"123456789\\n123456789\\n123456789\\n"`,
|
|
);
|
|
assertEquals(
|
|
Deno.inspect("123456789\n".repeat(3), { breakLength: 33 }),
|
|
`"123456789\\n" +
|
|
"123456789\\n" +
|
|
"123456789\\n"`,
|
|
);
|
|
});
|
|
|
|
Deno.test(function inspectEscapeSequencesFalse() {
|
|
assertEquals(
|
|
Deno.inspect("foo\nbar", { escapeSequences: true }),
|
|
'"foo\\nbar"',
|
|
); // default behavior
|
|
assertEquals(
|
|
Deno.inspect("foo\nbar", { escapeSequences: false }),
|
|
'"foo\nbar"',
|
|
);
|
|
});
|