summaryrefslogtreecommitdiff
path: root/std/testing/format_test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'std/testing/format_test.ts')
-rw-r--r--std/testing/format_test.ts805
1 files changed, 805 insertions, 0 deletions
diff --git a/std/testing/format_test.ts b/std/testing/format_test.ts
new file mode 100644
index 000000000..e2bb8df23
--- /dev/null
+++ b/std/testing/format_test.ts
@@ -0,0 +1,805 @@
+// This file is ported from pretty-format@24.0.0
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ */
+import { test } from "./mod.ts";
+import { assertEquals } from "../testing/asserts.ts";
+import { format } from "./format.ts";
+
+// eslint-disable-next-line max-len
+// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any
+function returnArguments(...args: any[]): IArguments {
+ // eslint-disable-next-line prefer-rest-params
+ return arguments;
+}
+
+function MyObject(value: unknown): void {
+ // @ts-ignore
+ this.name = value;
+}
+
+class MyArray<T> extends Array<T> {}
+
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+const createVal = () => [
+ {
+ id: "8658c1d0-9eda-4a90-95e1-8001e8eb6036",
+ text: "Add alternative serialize API for pretty-format plugins",
+ type: "ADD_TODO"
+ },
+ {
+ id: "8658c1d0-9eda-4a90-95e1-8001e8eb6036",
+ type: "TOGGLE_TODO"
+ }
+];
+
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+const createExpected = () =>
+ [
+ "Array [",
+ " Object {",
+ ' "id": "8658c1d0-9eda-4a90-95e1-8001e8eb6036",',
+ ' "text": "Add alternative serialize API for pretty-format plugins",',
+ ' "type": "ADD_TODO",',
+ " },",
+ " Object {",
+ ' "id": "8658c1d0-9eda-4a90-95e1-8001e8eb6036",',
+ ' "type": "TOGGLE_TODO",',
+ " },",
+ "]"
+ ].join("\n");
+
+test({
+ name: "prints empty arguments",
+ fn(): void {
+ const val = returnArguments();
+ assertEquals(format(val), "Arguments []");
+ }
+});
+
+test({
+ name: "prints an empty array",
+ fn(): void {
+ const val: unknown[] = [];
+ assertEquals(format(val), "Array []");
+ }
+});
+
+test({
+ name: "prints an array with items",
+ fn(): void {
+ const val = [1, 2, 3];
+ assertEquals(format(val), "Array [\n 1,\n 2,\n 3,\n]");
+ }
+});
+
+test({
+ name: "prints a empty typed array",
+ fn(): void {
+ const val = new Uint32Array(0);
+ assertEquals(format(val), "Uint32Array []");
+ }
+});
+
+test({
+ name: "prints a typed array with items",
+ fn(): void {
+ const val = new Uint32Array(3);
+ assertEquals(format(val), "Uint32Array [\n 0,\n 0,\n 0,\n]");
+ }
+});
+
+test({
+ name: "prints an array buffer",
+ fn(): void {
+ const val = new ArrayBuffer(3);
+ assertEquals(format(val), "ArrayBuffer []");
+ }
+});
+
+test({
+ name: "prints a nested array",
+ fn(): void {
+ const val = [[1, 2, 3]];
+ assertEquals(
+ format(val),
+ "Array [\n Array [\n 1,\n 2,\n 3,\n ],\n]"
+ );
+ }
+});
+
+test({
+ name: "prints true",
+ fn(): void {
+ const val = true;
+ assertEquals(format(val), "true");
+ }
+});
+
+test({
+ name: "prints false",
+ fn(): void {
+ const val = false;
+ assertEquals(format(val), "false");
+ }
+});
+
+test({
+ name: "prints an error",
+ fn(): void {
+ const val = new Error();
+ assertEquals(format(val), "[Error]");
+ }
+});
+
+test({
+ name: "prints a typed error with a message",
+ fn(): void {
+ const val = new TypeError("message");
+ assertEquals(format(val), "[TypeError: message]");
+ }
+});
+
+test({
+ name: "prints a function constructor",
+ fn(): void {
+ // tslint:disable-next-line:function-constructor
+ const val = new Function();
+ assertEquals(format(val), "[Function anonymous]");
+ }
+});
+
+test({
+ name: "prints an anonymous callback function",
+ fn(): void {
+ let val;
+ function f(cb: () => void): void {
+ val = cb;
+ }
+ // tslint:disable-next-line:no-empty
+ f((): void => {});
+ assertEquals(format(val), "[Function anonymous]");
+ }
+});
+
+test({
+ name: "prints an anonymous assigned function",
+ fn(): void {
+ // tslint:disable-next-line:no-empty
+ const val = (): void => {};
+ const formatted = format(val);
+ assertEquals(
+ formatted === "[Function anonymous]" || formatted === "[Function val]",
+ true
+ );
+ }
+});
+
+test({
+ name: "prints a named function",
+ fn(): void {
+ // tslint:disable-next-line:no-empty
+ const val = function named(): void {};
+ assertEquals(format(val), "[Function named]");
+ }
+});
+
+test({
+ name: "prints a named generator function",
+ fn(): void {
+ const val = function* generate(): IterableIterator<number> {
+ yield 1;
+ yield 2;
+ yield 3;
+ };
+ assertEquals(format(val), "[Function generate]");
+ }
+});
+
+test({
+ name: "can customize function names",
+ fn(): void {
+ // tslint:disable-next-line:no-empty
+ const val = function named(): void {};
+ assertEquals(
+ format(val, {
+ printFunctionName: false
+ }),
+ "[Function]"
+ );
+ }
+});
+
+test({
+ name: "prints Infinity",
+ fn(): void {
+ const val = Infinity;
+ assertEquals(format(val), "Infinity");
+ }
+});
+
+test({
+ name: "prints -Infinity",
+ fn(): void {
+ const val = -Infinity;
+ assertEquals(format(val), "-Infinity");
+ }
+});
+
+test({
+ name: "prints an empty map",
+ fn(): void {
+ const val = new Map();
+ assertEquals(format(val), "Map {}");
+ }
+});
+
+test({
+ name: "prints a map with values",
+ fn(): void {
+ const val = new Map();
+ val.set("prop1", "value1");
+ val.set("prop2", "value2");
+ assertEquals(
+ format(val),
+ 'Map {\n "prop1" => "value1",\n "prop2" => "value2",\n}'
+ );
+ }
+});
+
+test({
+ name: "prints a map with non-string keys",
+ fn(): void {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const val = new Map<any, any>([
+ [false, "boolean"],
+ ["false", "string"],
+ [0, "number"],
+ ["0", "string"],
+ [null, "null"],
+ ["null", "string"],
+ [undefined, "undefined"],
+ ["undefined", "string"],
+ [Symbol("description"), "symbol"],
+ ["Symbol(description)", "string"],
+ [["array", "key"], "array"],
+ [{ key: "value" }, "object"]
+ ]);
+ const expected = [
+ "Map {",
+ ' false => "boolean",',
+ ' "false" => "string",',
+ ' 0 => "number",',
+ ' "0" => "string",',
+ ' null => "null",',
+ ' "null" => "string",',
+ ' undefined => "undefined",',
+ ' "undefined" => "string",',
+ ' Symbol(description) => "symbol",',
+ ' "Symbol(description)" => "string",',
+ " Array [",
+ ' "array",',
+ ' "key",',
+ ' ] => "array",',
+ " Object {",
+ ' "key": "value",',
+ ' } => "object",',
+ "}"
+ ].join("\n");
+ assertEquals(format(val), expected);
+ }
+});
+
+test({
+ name: "prints NaN",
+ fn(): void {
+ const val = NaN;
+ assertEquals(format(val), "NaN");
+ }
+});
+
+test({
+ name: "prints null",
+ fn(): void {
+ const val = null;
+ assertEquals(format(val), "null");
+ }
+});
+
+test({
+ name: "prints a positive number",
+ fn(): void {
+ const val = 123;
+ assertEquals(format(val), "123");
+ }
+});
+
+test({
+ name: "prints a negative number",
+ fn(): void {
+ const val = -123;
+ assertEquals(format(val), "-123");
+ }
+});
+
+test({
+ name: "prints zero",
+ fn(): void {
+ const val = 0;
+ assertEquals(format(val), "0");
+ }
+});
+
+test({
+ name: "prints negative zero",
+ fn(): void {
+ const val = -0;
+ assertEquals(format(val), "-0");
+ }
+});
+
+test({
+ name: "prints a date",
+ fn(): void {
+ const val = new Date(10e11);
+ assertEquals(format(val), "2001-09-09T01:46:40.000Z");
+ }
+});
+
+test({
+ name: "prints an invalid date",
+ fn(): void {
+ const val = new Date(Infinity);
+ assertEquals(format(val), "Date { NaN }");
+ }
+});
+
+test({
+ name: "prints an empty object",
+ fn(): void {
+ const val = {};
+ assertEquals(format(val), "Object {}");
+ }
+});
+
+test({
+ name: "prints an object with properties",
+ fn(): void {
+ const val = { prop1: "value1", prop2: "value2" };
+ assertEquals(
+ format(val),
+ 'Object {\n "prop1": "value1",\n "prop2": "value2",\n}'
+ );
+ }
+});
+
+test({
+ name: "prints an object with properties and symbols",
+ fn(): void {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const val: any = {};
+ val[Symbol("symbol1")] = "value2";
+ val[Symbol("symbol2")] = "value3";
+ val.prop = "value1";
+ assertEquals(
+ format(val),
+ 'Object {\n "prop": "value1",\n Symbol(symbol1): "value2",\n ' +
+ 'Symbol(symbol2): "value3",\n}'
+ );
+ }
+});
+
+test({
+ name:
+ "prints an object without non-enumerable properties which have string key",
+ fn(): void {
+ const val = {
+ enumerable: true
+ };
+ const key = "non-enumerable";
+ Object.defineProperty(val, key, {
+ enumerable: false,
+ value: false
+ });
+ assertEquals(format(val), 'Object {\n "enumerable": true,\n}');
+ }
+});
+
+test({
+ name:
+ "prints an object without non-enumerable properties which have symbol key",
+ fn(): void {
+ const val = {
+ enumerable: true
+ };
+ const key = Symbol("non-enumerable");
+ Object.defineProperty(val, key, {
+ enumerable: false,
+ value: false
+ });
+ assertEquals(format(val), 'Object {\n "enumerable": true,\n}');
+ }
+});
+
+test({
+ name: "prints an object with sorted properties",
+ fn(): void {
+ const val = { b: 1, a: 2 };
+ assertEquals(format(val), 'Object {\n "a": 2,\n "b": 1,\n}');
+ }
+});
+
+test({
+ name: "prints regular expressions from constructors",
+ fn(): void {
+ const val = new RegExp("regexp");
+ assertEquals(format(val), "/regexp/");
+ }
+});
+
+test({
+ name: "prints regular expressions from literals",
+ fn(): void {
+ const val = /regexp/gi;
+ assertEquals(format(val), "/regexp/gi");
+ }
+});
+
+test({
+ name: "prints regular expressions {escapeRegex: false}",
+ fn(): void {
+ const val = /regexp\d/gi;
+ assertEquals(format(val), "/regexp\\d/gi");
+ }
+});
+
+test({
+ name: "prints regular expressions {escapeRegex: true}",
+ fn(): void {
+ const val = /regexp\d/gi;
+ assertEquals(format(val, { escapeRegex: true }), "/regexp\\\\d/gi");
+ }
+});
+
+test({
+ name: "escapes regular expressions nested inside object",
+ fn(): void {
+ const obj = { test: /regexp\d/gi };
+ assertEquals(
+ format(obj, { escapeRegex: true }),
+ 'Object {\n "test": /regexp\\\\d/gi,\n}'
+ );
+ }
+});
+
+test({
+ name: "prints an empty set",
+ fn(): void {
+ const val = new Set();
+ assertEquals(format(val), "Set {}");
+ }
+});
+
+test({
+ name: "prints a set with values",
+ fn(): void {
+ const val = new Set();
+ val.add("value1");
+ val.add("value2");
+ assertEquals(format(val), 'Set {\n "value1",\n "value2",\n}');
+ }
+});
+
+test({
+ name: "prints a string",
+ fn(): void {
+ const val = "string";
+ assertEquals(format(val), '"string"');
+ }
+});
+
+test({
+ name: "prints and escape a string",
+ fn(): void {
+ const val = "\"'\\";
+ assertEquals(format(val), '"\\"\'\\\\"');
+ }
+});
+
+test({
+ name: "doesn't escape string with {excapeString: false}",
+ fn(): void {
+ const val = "\"'\\n";
+ assertEquals(format(val, { escapeString: false }), '""\'\\n"');
+ }
+});
+
+test({
+ name: "prints a string with escapes",
+ fn(): void {
+ assertEquals(format('"-"'), '"\\"-\\""');
+ assertEquals(format("\\ \\\\"), '"\\\\ \\\\\\\\"');
+ }
+});
+
+test({
+ name: "prints a multiline string",
+ fn(): void {
+ const val = ["line 1", "line 2", "line 3"].join("\n");
+ assertEquals(format(val), '"' + val + '"');
+ }
+});
+
+test({
+ name: "prints a multiline string as value of object property",
+ fn(): void {
+ const polyline = {
+ props: {
+ id: "J",
+ points: ["0.5,0.460", "0.5,0.875", "0.25,0.875"].join("\n")
+ },
+ type: "polyline"
+ };
+ const val = {
+ props: {
+ children: polyline
+ },
+ type: "svg"
+ };
+ assertEquals(
+ format(val),
+ [
+ "Object {",
+ ' "props": Object {',
+ ' "children": Object {',
+ ' "props": Object {',
+ ' "id": "J",',
+ ' "points": "0.5,0.460',
+ "0.5,0.875",
+ '0.25,0.875",',
+ " },",
+ ' "type": "polyline",',
+ " },",
+ " },",
+ ' "type": "svg",',
+ "}"
+ ].join("\n")
+ );
+ }
+});
+
+test({
+ name: "prints a symbol",
+ fn(): void {
+ const val = Symbol("symbol");
+ assertEquals(format(val), "Symbol(symbol)");
+ }
+});
+
+test({
+ name: "prints undefined",
+ fn(): void {
+ const val = undefined;
+ assertEquals(format(val), "undefined");
+ }
+});
+
+test({
+ name: "prints a WeakMap",
+ fn(): void {
+ const val = new WeakMap();
+ assertEquals(format(val), "WeakMap {}");
+ }
+});
+
+test({
+ name: "prints a WeakSet",
+ fn(): void {
+ const val = new WeakSet();
+ assertEquals(format(val), "WeakSet {}");
+ }
+});
+
+test({
+ name: "prints deeply nested objects",
+ fn(): void {
+ const val = { prop: { prop: { prop: "value" } } };
+ assertEquals(
+ format(val),
+ 'Object {\n "prop": Object {\n "prop": Object {\n "prop": ' +
+ '"value",\n },\n },\n}'
+ );
+ }
+});
+
+test({
+ name: "prints circular references",
+ fn(): void {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const val: any = {};
+ val.prop = val;
+ assertEquals(format(val), 'Object {\n "prop": [Circular],\n}');
+ }
+});
+
+test({
+ name: "prints parallel references",
+ fn(): void {
+ const inner = {};
+ const val = { prop1: inner, prop2: inner };
+ assertEquals(
+ format(val),
+ 'Object {\n "prop1": Object {},\n "prop2": Object {},\n}'
+ );
+ }
+});
+
+test({
+ name: "default implicit: 2 spaces",
+ fn(): void {
+ assertEquals(format(createVal()), createExpected());
+ }
+});
+
+test({
+ name: "default explicit: 2 spaces",
+ fn(): void {
+ assertEquals(format(createVal(), { indent: 2 }), createExpected());
+ }
+});
+
+// Tests assume that no strings in val contain multiple adjacent spaces!
+test({
+ name: "non-default: 0 spaces",
+ fn(): void {
+ const indent = 0;
+ assertEquals(
+ format(createVal(), { indent }),
+ createExpected().replace(/ {2}/g, " ".repeat(indent))
+ );
+ }
+});
+
+test({
+ name: "non-default: 4 spaces",
+ fn(): void {
+ const indent = 4;
+ assertEquals(
+ format(createVal(), { indent }),
+ createExpected().replace(/ {2}/g, " ".repeat(indent))
+ );
+ }
+});
+
+test({
+ name: "can customize the max depth",
+ fn(): void {
+ const v = [
+ {
+ "arguments empty": returnArguments(),
+ "arguments non-empty": returnArguments("arg"),
+ "array literal empty": [],
+ "array literal non-empty": ["item"],
+ "extended array empty": new MyArray(),
+ "map empty": new Map(),
+ "map non-empty": new Map([["name", "value"]]),
+ "object literal empty": {},
+ "object literal non-empty": { name: "value" },
+ // @ts-ignore
+ "object with constructor": new MyObject("value"),
+ "object without constructor": Object.create(null),
+ "set empty": new Set(),
+ "set non-empty": new Set(["value"])
+ }
+ ];
+ assertEquals(
+ format(v, { maxDepth: 2 }),
+ [
+ "Array [",
+ " Object {",
+ ' "arguments empty": [Arguments],',
+ ' "arguments non-empty": [Arguments],',
+ ' "array literal empty": [Array],',
+ ' "array literal non-empty": [Array],',
+ ' "extended array empty": [MyArray],',
+ ' "map empty": [Map],',
+ ' "map non-empty": [Map],',
+ ' "object literal empty": [Object],',
+ ' "object literal non-empty": [Object],',
+ ' "object with constructor": [MyObject],',
+ ' "object without constructor": [Object],',
+ ' "set empty": [Set],',
+ ' "set non-empty": [Set],',
+ " },",
+ "]"
+ ].join("\n")
+ );
+ }
+});
+
+test({
+ name: "prints objects with no constructor",
+ fn(): void {
+ assertEquals(format(Object.create(null)), "Object {}");
+ }
+});
+
+test({
+ name: "prints identity-obj-proxy with string constructor",
+ fn(): void {
+ const obj = Object.create(null);
+ obj.constructor = "constructor";
+ const expected = [
+ "Object {", // Object instead of undefined
+ ' "constructor": "constructor",',
+ "}"
+ ].join("\n");
+ assertEquals(format(obj), expected);
+ }
+});
+
+test({
+ name: "calls toJSON and prints its return value",
+ fn(): void {
+ assertEquals(
+ format({
+ toJSON: (): unknown => ({ value: false }),
+ value: true
+ }),
+ 'Object {\n "value": false,\n}'
+ );
+ }
+});
+
+test({
+ name: "calls toJSON and prints an internal representation.",
+ fn(): void {
+ assertEquals(
+ format({
+ toJSON: (): string => "[Internal Object]",
+ value: true
+ }),
+ '"[Internal Object]"'
+ );
+ }
+});
+
+test({
+ name: "calls toJSON only on functions",
+ fn(): void {
+ assertEquals(
+ format({
+ toJSON: false,
+ value: true
+ }),
+ 'Object {\n "toJSON": false,\n "value": true,\n}'
+ );
+ }
+});
+
+test({
+ name: "does not call toJSON recursively",
+ fn(): void {
+ assertEquals(
+ format({
+ toJSON: (): unknown => ({ toJSON: (): unknown => ({ value: true }) }),
+ value: false
+ }),
+ 'Object {\n "toJSON": [Function toJSON],\n}'
+ );
+ }
+});
+
+test({
+ name: "calls toJSON on Sets",
+ fn(): void {
+ const set = new Set([1]);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (set as any).toJSON = (): string => "map";
+ assertEquals(format(set), '"map"');
+ }
+});