From 1758e9d268969bdda572dc85afc57db7b6874cde Mon Sep 17 00:00:00 2001 From: Julian Gruber Date: Sat, 26 Mar 2022 12:34:37 +0100 Subject: [PATCH] add message test, fix matcher implementation --- package-lock.json | 65 +--- package.json | 1 - test/message.js | 12 +- test/message/test_runner_no_refs.out | 7 + test/message/test_runner_output.js | 288 ++++++++++++++++++ test/message/test_runner_output.out | 426 +++++++++++++++++++++++++++ 6 files changed, 740 insertions(+), 59 deletions(-) create mode 100644 test/message/test_runner_output.js create mode 100644 test/message/test_runner_output.out diff --git a/package-lock.json b/package-lock.json index 75a04d9..c7d9143 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "string.prototype.replaceall": "^1.0.6" }, "devDependencies": { - "matcher": "^5.0.0", "prettier-standard": "^16.4.1", "standard": "^16.0.4" } @@ -3579,33 +3578,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/matcher": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", - "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/matcher/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mem": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", @@ -3636,13 +3608,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -9379,23 +9351,6 @@ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", "dev": true }, - "matcher": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", - "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - } - } - }, "mem": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", @@ -9420,13 +9375,13 @@ "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mimic-fn": { diff --git a/package.json b/package.json index cde1407..107d30e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "test": "prettier-standard && standard && node test/parallel/* && node test/message" }, "devDependencies": { - "matcher": "^5.0.0", "prettier-standard": "^16.4.1", "standard": "^16.0.4" }, diff --git a/test/message.js b/test/message.js index 4772210..c82812e 100644 --- a/test/message.js +++ b/test/message.js @@ -7,8 +7,6 @@ const { exec } = require('child_process') const assert = require('assert') const main = async () => { - const { isMatch } = await import('matcher') - const dir = join(__dirname, 'message') for (const fileName of await fs.readdir(dir)) { if (extname(fileName) === '.js') { @@ -17,6 +15,7 @@ const main = async () => { filePath.replace('.js', '.out'), 'utf8' ) + console.log(fileName) let actual try { const res = await promisify(exec)(`node ${filePath}`) @@ -24,13 +23,20 @@ const main = async () => { } catch (err) { actual = err.stdout.trim() } + const reg = new RegExp( + expected + .replace(/\+/g, '\\+') + .replace(/\*/g, '.*') + ) try { - assert(isMatch(actual, expected, actual)) + assert(reg.test(actual)) } catch (err) { console.error('expected:') console.error(expected) console.error('actual:') console.error(actual) + console.error('reg:') + console.error(reg) throw err } } diff --git a/test/message/test_runner_no_refs.out b/test/message/test_runner_no_refs.out index 8db30eb..77c2687 100644 --- a/test/message/test_runner_no_refs.out +++ b/test/message/test_runner_no_refs.out @@ -7,6 +7,10 @@ TAP version 13 code: ERR_TEST_FAILURE stack: |- * + * + * + * + * ... 1..1 not ok 1 - does not keep event loop alive @@ -17,6 +21,9 @@ not ok 1 - does not keep event loop alive code: ERR_TEST_FAILURE stack: |- * + * + * + * ... 1..1 # tests 1 diff --git a/test/message/test_runner_output.js b/test/message/test_runner_output.js new file mode 100644 index 0000000..ef6ac9e --- /dev/null +++ b/test/message/test_runner_output.js @@ -0,0 +1,288 @@ +// https://github.com/nodejs/node/blob/432d1b50e0432daf7e81dea9a8d6dca64ecde6a4/test/message/test_runner_output.js +// Flags: --no-warnings + +'use strict' + +const assert = require('assert') +const test = require('../..') + +test('sync pass todo', t => { + t.todo() +}) + +test('sync pass todo with message', t => { + t.todo('this is a passing todo') +}) + +test('sync fail todo', t => { + t.todo() + throw new Error('thrown from sync fail todo') +}) + +test('sync fail todo with message', t => { + t.todo('this is a failing todo') + throw new Error('thrown from sync fail todo with message') +}) + +test('sync skip pass', t => { + t.skip() +}) + +test('sync skip pass with message', t => { + t.skip('this is skipped') +}) + +test('sync pass', t => { + t.diagnostic('this test should pass') +}) + +test('sync throw fail', () => { + throw new Error('thrown from sync throw fail') +}) + +test('async skip pass', async t => { + t.skip() +}) + +test('async pass', async () => {}) + +test('async throw fail', async () => { + throw new Error('thrown from async throw fail') +}) + +test('async skip fail', async t => { + t.skip() + throw new Error('thrown from async throw fail') +}) + +test('async assertion fail', async () => { + // Make sure the assert module is handled. + assert.strictEqual(true, false) +}) + +test('resolve pass', () => { + return Promise.resolve() +}) + +test('reject fail', () => { + return Promise.reject(new Error('rejected from reject fail')) +}) + +test('unhandled rejection - passes but warns', () => { + Promise.reject(new Error('rejected from unhandled rejection fail')) +}) + +test('async unhandled rejection - passes but warns', async () => { + Promise.reject(new Error('rejected from async unhandled rejection fail')) +}) + +test('immediate throw - passes but warns', () => { + setImmediate(() => { + throw new Error('thrown from immediate throw fail') + }) +}) + +test('immediate reject - passes but warns', () => { + setImmediate(() => { + Promise.reject(new Error('rejected from immediate reject fail')) + }) +}) + +test('immediate resolve pass', () => { + return new Promise(resolve => { + setImmediate(() => { + resolve() + }) + }) +}) + +test('subtest sync throw fail', async t => { + await t.test('+sync throw fail', t => { + t.diagnostic('this subtest should make its parent test fail') + throw new Error('thrown from subtest sync throw fail') + }) +}) + +test('sync throw non-error fail', async t => { + throw Symbol('thrown symbol from sync throw non-error fail') +}) + +test('level 0a', { concurrency: 4 }, async t => { + t.test('level 1a', async t => { + const p1a = new Promise(resolve => { + setTimeout(() => { + resolve() + }, 1000) + }) + + return p1a + }) + + t.test('level 1b', async t => { + const p1b = new Promise(resolve => { + resolve() + }) + + return p1b + }) + + t.test('level 1c', async t => { + const p1c = new Promise(resolve => { + setTimeout(() => { + resolve() + }, 2000) + }) + + return p1c + }) + + t.test('level 1d', async t => { + const p1c = new Promise(resolve => { + setTimeout(() => { + resolve() + }, 1500) + }) + + return p1c + }) + + const p0a = new Promise(resolve => { + setTimeout(() => { + resolve() + }, 3000) + }) + + return p0a +}) + +test('top level', { concurrency: 2 }, async t => { + t.test('+long running', async t => { + return new Promise((resolve, reject) => { + setTimeout(resolve, 3000).unref() + }) + }) + + t.test('+short running', async t => { + t.test('++short running', async t => {}) + }) +}) + +test('invalid subtest - pass but subtest fails', t => { + setImmediate(() => { + t.test('invalid subtest fail', () => { + throw new Error('this should not be thrown') + }) + }) +}) + +test('sync skip option', { skip: true }, t => { + throw new Error('this should not be executed') +}) + +test('sync skip option with message', { skip: 'this is skipped' }, t => { + throw new Error('this should not be executed') +}) + +test('sync skip option is false fail', { skip: false }, t => { + throw new Error('this should be executed') +}) + +// A test with no arguments provided. +test() + +// A test with only a named function provided. +test(function functionOnly () {}) + +// A test with only an anonymous function provided. +test(() => {}) + +// A test with only a name provided. +test('test with only a name provided') + +// A test with an empty string name. +test('') + +// A test with only options provided. +test({ skip: true }) + +// A test with only a name and options provided. +test('test with a name and options provided', { skip: true }) + +// A test with only options and a function provided. +test({ skip: true }, function functionAndOptions () {}) + +// A test whose description needs to be escaped. +test('escaped description \\ # \\#\\') + +// A test whose skip message needs to be escaped. +test('escaped skip message', { skip: '#skip' }) + +// A test whose todo message needs to be escaped. +test('escaped todo message', { todo: '#todo' }) + +// A test with a diagnostic message that needs to be escaped. +test('escaped diagnostic', t => { + t.diagnostic('#diagnostic') +}) + +test('callback pass', (t, done) => { + setImmediate(done) +}) + +test('callback fail', (t, done) => { + setImmediate(() => { + done(new Error('callback failure')) + }) +}) + +test('sync t is this in test', function (t) { + assert.strictEqual(this, t) +}) + +test('async t is this in test', async function (t) { + assert.strictEqual(this, t) +}) + +test('callback t is this in test', function (t, done) { + assert.strictEqual(this, t) + done() +}) + +test('callback also returns a Promise', async (t, done) => { + throw new Error('thrown from callback also returns a Promise') +}) + +test('callback throw', (t, done) => { + throw new Error('thrown from callback throw') +}) + +test('callback called twice', (t, done) => { + done() + done() +}) + +test('callback called twice in different ticks', (t, done) => { + setImmediate(done) + done() +}) + +test('callback called twice in future tick', (t, done) => { + setImmediate(() => { + done() + done() + }) +}) + +test('callback async throw', (t, done) => { + setImmediate(() => { + throw new Error('thrown from callback async throw') + }) +}) + +test('callback async throw after done', (t, done) => { + setImmediate(() => { + throw new Error('thrown from callback async throw after done') + }) + + done() +}) diff --git a/test/message/test_runner_output.out b/test/message/test_runner_output.out new file mode 100644 index 0000000..40925f0 --- /dev/null +++ b/test/message/test_runner_output.out @@ -0,0 +1,426 @@ +TAP version 13 +ok 1 - sync pass todo # TODO + --- + duration_ms: * + ... +ok 2 - sync pass todo with message # TODO this is a passing todo + --- + duration_ms: * + ... +not ok 3 - sync fail todo # TODO + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from sync fail todo' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + ... +not ok 4 - sync fail todo with message # TODO this is a failing todo + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from sync fail todo with message' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + * + * + ... +ok 5 - sync skip pass # SKIP + --- + duration_ms: * + ... +ok 6 - sync skip pass with message # SKIP this is skipped + --- + duration_ms: * + ... +ok 7 - sync pass + --- + duration_ms: * + ... +# this test should pass +not ok 8 - sync throw fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from sync throw fail' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + ... +ok 9 - async skip pass # SKIP + --- + duration_ms: * + ... +ok 10 - async pass + --- + duration_ms: * + ... +not ok 11 - async throw fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from async throw fail' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + ... +not ok 12 - async skip fail # SKIP + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from async throw fail' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + ... +not ok 13 - async assertion fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'Expected values to be strictly equal:\n\ntrue !== false\n' + code: ERR_ASSERTION + stack: |- + * + * + * + * + * + * + * + * + ... +ok 14 - resolve pass + --- + duration_ms: * + ... +not ok 15 - reject fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'rejected from reject fail' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + ... +ok 16 - unhandled rejection - passes but warns + --- + duration_ms: * + ... +ok 17 - async unhandled rejection - passes but warns + --- + duration_ms: * + ... +ok 18 - immediate throw - passes but warns + --- + duration_ms: * + ... +ok 19 - immediate reject - passes but warns + --- + duration_ms: * + ... +ok 20 - immediate resolve pass + --- + duration_ms: * + ... + not ok 1 - +sync throw fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from subtest sync throw fail' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + * + * + * + ... + # this subtest should make its parent test fail + 1..1 +not ok 21 - subtest sync throw fail + --- + duration_ms: * + failureType: 'subtestsFailed' + error: "'1 subtest failed'" + code: ERR_TEST_FAILURE + ... +not ok 22 - sync throw non-error fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'Symbol(thrown symbol from sync throw non-error fail)' + code: ERR_TEST_FAILURE + ... + ok 1 - level 1a + --- + duration_ms: * + ... + ok 2 - level 1b + --- + duration_ms: * + ... + ok 3 - level 1c + --- + duration_ms: * + ... + ok 4 - level 1d + --- + duration_ms: * + ... + 1..4 +ok 23 - level 0a + --- + duration_ms: * + ... + not ok 1 - +long running + --- + duration_ms: * + failureType: 'cancelledByParent' + error: "'test did not finish before its parent and was cancelled'" + code: ERR_TEST_FAILURE + ... + ok 1 - ++short running + --- + duration_ms: * + ... + 1..1 + ok 2 - +short running + --- + duration_ms: * + ... + 1..2 +not ok 24 - top level + --- + duration_ms: * + failureType: 'subtestsFailed' + error: "'1 subtest failed'" + code: ERR_TEST_FAILURE + ... +ok 25 - invalid subtest - pass but subtest fails + --- + duration_ms: * + ... +ok 26 - sync skip option # SKIP + --- + duration_ms: * + ... +ok 27 - sync skip option with message # SKIP this is skipped + --- + duration_ms: * + ... +not ok 28 - sync skip option is false fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'this should be executed' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + ... +ok 29 - + --- + duration_ms: * + ... +ok 30 - functionOnly + --- + duration_ms: * + ... +ok 31 - + --- + duration_ms: * + ... +ok 32 - test with only a name provided + --- + duration_ms: * + ... +ok 33 - + --- + duration_ms: * + ... +ok 34 - # SKIP + --- + duration_ms: * + ... +ok 35 - test with a name and options provided # SKIP + --- + duration_ms: * + ... +ok 36 - functionAndOptions # SKIP + --- + duration_ms: * + ... +ok 37 - escaped description \\ \# \\\#\\ + --- + duration_ms: * + ... +ok 38 - escaped skip message # SKIP \#skip + --- + duration_ms: * + ... +ok 39 - escaped todo message # TODO \#todo + --- + duration_ms: * + ... +ok 40 - escaped diagnostic + --- + duration_ms: * + ... +# \#diagnostic +ok 41 - callback pass + --- + duration_ms: * + ... +not ok 42 - callback fail + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'callback failure' + code: ERR_TEST_FAILURE + stack: |- + * + * + ... +ok 43 - sync t is this in test + --- + duration_ms: * + ... +ok 44 - async t is this in test + --- + duration_ms: * + ... +ok 45 - callback t is this in test + --- + duration_ms: * + ... +not ok 46 - callback also returns a Promise + --- + duration_ms: * + failureType: 'callbackAndPromisePresent' + error: "'passed a callback but also returned a Promise'" + code: ERR_TEST_FAILURE + ... +not ok 47 - callback throw + --- + duration_ms: * + failureType: 'testCodeFailure' + error: 'thrown from callback throw' + code: ERR_TEST_FAILURE + stack: |- + * + * + * + * + * + * + * + ... +not ok 48 - callback called twice + --- + duration_ms: * + failureType: 'multipleCallbackInvocations' + error: "'callback invoked multiple times'" + code: ERR_TEST_FAILURE + ... +ok 49 - callback called twice in different ticks + --- + duration_ms: * + ... +not ok 50 - callback called twice in future tick + --- + duration_ms: * + failureType: 'multipleCallbackInvocations' + error: "'callback invoked multiple times'" + code: ERR_TEST_FAILURE + stack: |- + * + ... +not ok 51 - callback async throw + --- + duration_ms: * + failureType: 'uncaughtException' + error: 'thrown from callback async throw' + code: ERR_TEST_FAILURE + stack: |- + * + ... +ok 52 - callback async throw after done + --- + duration_ms: * + ... +not ok 53 - invalid subtest fail + --- + duration_ms: * + failureType: 'parentAlreadyFinished' + error: "'test could not be started because its parent finished'" + code: ERR_TEST_FAILURE + stack: |- + * + ... +1..53 +# Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. +# Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. +# Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event. +# Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. +# Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: 'callback invoked multiple times'" and would have caused the test to fail, but instead triggered an uncaughtException event. +# Warning: Test "callback async throw after done" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from callback async throw after done" and would have caused the test to fail, but instead triggered an uncaughtException event. +# tests 53 +# pass 23 +# fail 15 +# skipped 10 +# todo 5 +# duration_ms * \ No newline at end of file