diff --git a/Jakefile.js b/Jakefile.js index b68e869aaee..e016c1bd0bd 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -130,6 +130,7 @@ var harnessSources = harnessCoreSources.concat([ "textStorage.ts", "moduleResolution.ts", "tsconfigParsing.ts", + "asserts.ts", "builder.ts", "commandLineParsing.ts", "configurationExtension.ts", diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f4a58352b16..b38bd523fae 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -32,9 +32,30 @@ // this will work in the browser via browserify var _chai: typeof chai = require("chai"); var assert: typeof _chai.assert = _chai.assert; -// chai's builtin `assert.isFalse` is featureful but slow - we don't use those features, -// so we'll just overwrite it as an alterative to migrating a bunch of code off of chai -assert.isFalse = (expr, msg) => { if (expr as any as boolean !== false) throw new Error(msg); }; +{ + // chai's builtin `assert.isFalse` is featureful but slow - we don't use those features, + // so we'll just overwrite it as an alterative to migrating a bunch of code off of chai + assert.isFalse = (expr, msg) => { if (expr as any as boolean !== false) throw new Error(msg); }; + + const assertDeepImpl = assert.deepEqual; + assert.deepEqual = (a, b, msg) => { + if (ts.isArray(a) && ts.isArray(b)) { + assertDeepImpl(arrayExtraKeysObject(a), arrayExtraKeysObject(b), "Array extra keys differ"); + } + assertDeepImpl(a, b, msg); + + function arrayExtraKeysObject(a: ReadonlyArray<{} | null | undefined>): object { + const obj: { [key: string]: {} | null | undefined } = {}; + for (const key in a) { + if (Number.isNaN(Number(key))) { + obj[key] = a[key]; + } + } + return obj; + } + }; +} + declare var __dirname: string; // Node-specific var global: NodeJS.Global = Function("return this").call(undefined); diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index db38b95ba6a..25642ab5179 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -108,6 +108,7 @@ "./unittests/reuseProgramStructure.ts", "./unittests/moduleResolution.ts", "./unittests/tsconfigParsing.ts", + "./unittests/asserts.ts", "./unittests/builder.ts", "./unittests/commandLineParsing.ts", "./unittests/configurationExtension.ts", diff --git a/src/harness/unittests/asserts.ts b/src/harness/unittests/asserts.ts new file mode 100644 index 00000000000..ec274c44c22 --- /dev/null +++ b/src/harness/unittests/asserts.ts @@ -0,0 +1,11 @@ +/// + +namespace ts { + describe("assert", () => { + it("deepEqual", () => { + assert.throws(() => assert.deepEqual(createNodeArray([createIdentifier("A")]), createNodeArray([createIdentifier("B")]))); + assert.throws(() => assert.deepEqual(createNodeArray([], /*hasTrailingComma*/ true), createNodeArray([], /*hasTrailingComma*/ false))); + assert.deepEqual(createNodeArray([createIdentifier("A")], /*hasTrailingComma*/ true), createNodeArray([createIdentifier("A")], /*hasTrailingComma*/ true)); + }); + }); +} diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index 1c0a210f442..4a76a479b18 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -345,7 +345,7 @@ namespace ts { const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]); const program2 = updateProgram(program1, ["a.ts"], options, noop, newTexts); - assert.deepEqual(emptyArray, program2.getMissingFilePaths()); + assert.lengthOf(program2.getMissingFilePaths(), 0); assert.equal(StructureIsReused.Not, program1.structureIsReused); }); @@ -839,12 +839,12 @@ namespace ts { updateProgramText(files, root, "const x = 1;"); }); assert.equal(program1.structureIsReused, StructureIsReused.Completely); - assert.deepEqual(program2.getSemanticDiagnostics(), emptyArray); + assert.lengthOf(program2.getSemanticDiagnostics(), 0); }); it("Target changes -> redirect broken", () => { const program1 = createRedirectProgram(); - assert.deepEqual(program1.getSemanticDiagnostics(), emptyArray); + assert.lengthOf(program1.getSemanticDiagnostics(), 0); const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");