From 9cbae8a7e22567d30019e0cbc03c8597f03b4230 Mon Sep 17 00:00:00 2001 From: Joris van der Wel Date: Sun, 7 Jan 2024 17:50:12 +0100 Subject: [PATCH 1/4] [Fix] stack trace path parsing on windows Source files which are located in the current working directory, have a part of their path replaced by `path.sep + '$CWD'`. However, this causes the regular expression for stack trace lines to not match on windows. Example of a stack trace line, after replacement (`console.log(lineWithTokens)` in lib/test.js): ``` at Test.assert [as _assert] (\$CWD\example\my-test.js:483:11) ``` The part of the regexp that fails is `(?:\/|[a-zA-Z]:\\)`. I fixed this by allowing the path to start with a backslash. So instead of `\/`, the regexp uses `[/\\]`. This issue is already covered by existing test cases that are currently failing when they are ran on windows. For example: `.\node_modules\.bin\tap test/*.js` --- lib/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/test.js b/lib/test.js index 78076cdb..04ba31a3 100644 --- a/lib/test.js +++ b/lib/test.js @@ -518,9 +518,9 @@ Test.prototype._assert = function assert(ok, opts) { Last part captures file path plus line no (and optional column no). - /((?:\/|[a-zA-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)\)?/ + /((?:[/\\]|[a-zA-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)\)?/ */ - var re = /^(?:[^\s]*\s*\bat\s+)(?:(.*)\s+\()?((?:\/|[a-zA-Z]:\\)[^:)]+:(\d+)(?::(\d+))?)\)?$/; + var re = /^(?:[^\s]*\s*\bat\s+)(?:(.*)\s+\()?((?:[/\\]|[a-zA-Z]:\\)[^:)]+:(\d+)(?::(\d+))?)\)?$/; // first tokenize the PWD, then tokenize tape var lineWithTokens = $replace( $replace( From a2b74f97fe6ea14898b636f560291647bb747753 Mon Sep 17 00:00:00 2001 From: Joris van der Wel Date: Sun, 7 Jan 2024 19:53:10 +0100 Subject: [PATCH 2/4] [Fix] `bin/tape`: ignore options on windows The current version of `glob` returns paths always with forward slashes, even on windows. This causes the `dotignore` `Matcher` to never match the paths on windows, because it expects backslashes on windows. This means that the `--ignore` and `--ignore-pattern` options do not work properly on windows. This is fixed in a newer version of glob (not sure which specific version). However, we can not upgrade because it drops support for older node versions that we still want to support in tape. So instead, a workaround is to correct the slashes ourselves. This issue is already covered by existing test cases (test/ignore-pattern.js), that are currently failing when they are ran on windows. For example: `.\node_modules\.bin\tap test/*.js`. However, an additional fix is needed to make these tests pass (see next commit). --- bin/tape | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bin/tape b/bin/tape index 3b41be76..aa8cea32 100755 --- a/bin/tape +++ b/bin/tape @@ -2,6 +2,7 @@ 'use strict'; +var path = require('path'); var parseOpts = require('minimist'); var objectKeys = require('object-keys'); @@ -68,6 +69,19 @@ var files = opts._.reduce(function (result, arg) { throw new TypeError('unknown error: glob.sync("' + arg + '") did not return an array or throw. Please report this.'); } + // Workaround for glob v7 always replacing backslashes with forward slashes on windows + // This causes dotignore to not match the paths properly. + // This is fixed in newer version of glob, however we can not upgrade because it drops + // support for older node versions that we still want to support in tape. + // If glob is updated in the future this workaround can be removed, however note that + // the output of glob must then be sorted here because glob no longer does that. + // (also, backslashes and forward slashes should be ordered the same) + if (path.sep === '\\') { + globFiles = globFiles.map(function (globFile) { + return globFile.replace(/\//g, '\\'); + }); + } + return result.concat(globFiles); } return result.concat(arg); From 4a57fbe14db3eb342543c391f8c42fb83b4e8359 Mon Sep 17 00:00:00 2001 From: Joris van der Wel Date: Sun, 7 Jan 2024 20:43:39 +0100 Subject: [PATCH 3/4] [Tests] Spawn processes during tests using execPath so that the tests pass on windows In some parts of the code the `bin/tape` script was executed directly. This does not always work on windows, causing those tests to fail. So instead `process.execPath` is executed (which is the path to the node binary), and the script is passed as an argument. In other parts of the code, argv[0] was used. This has been made consistent so that execPath is used everywhere. --- test/ignore-pattern.js | 6 +++--- test/ignore_from_gitignore.js | 12 ++++++------ test/import.js | 2 +- test/require.js | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/ignore-pattern.js b/test/ignore-pattern.js index 9ad0952f..ea1811ba 100644 --- a/test/ignore-pattern.js +++ b/test/ignore-pattern.js @@ -8,7 +8,7 @@ var tapeBin = path.join(process.cwd(), 'bin/tape'); tap.test('should allow ignore file together with --ignore-pattern', function (tt) { tt.plan(1); - var proc = execFile(tapeBin, ['--ignore', '.ignore', '--ignore-pattern', 'fake_other_ignored_dir', '**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); + var proc = execFile(process.execPath, [tapeBin, '--ignore', '.ignore', '--ignore-pattern', 'fake_other_ignored_dir', '**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); proc.on('exit', function (code) { tt.equals(code, 0); @@ -17,7 +17,7 @@ tap.test('should allow ignore file together with --ignore-pattern', function (tt tap.test('should allow --ignore-pattern without ignore file', function (tt) { tt.plan(1); - var proc = execFile(tapeBin, ['--ignore-pattern', 'fake_*', '**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); + var proc = execFile(process.execPath, [tapeBin, '--ignore-pattern', 'fake_*', '**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); proc.on('exit', function (code) { tt.equals(code, 0); @@ -26,7 +26,7 @@ tap.test('should allow --ignore-pattern without ignore file', function (tt) { tap.test('should fail if not ignoring', function (tt) { tt.plan(1); - var proc = execFile(tapeBin, ['**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); + var proc = execFile(process.execPath, [tapeBin, '**/*.js'], { cwd: path.join(__dirname, 'ignore-pattern') }); proc.on('exit', function (code) { tt.equals(code, 1); diff --git a/test/ignore_from_gitignore.js b/test/ignore_from_gitignore.js index 3e46cdc5..b00af153 100644 --- a/test/ignore_from_gitignore.js +++ b/test/ignore_from_gitignore.js @@ -9,7 +9,7 @@ var stripFullStack = require('./common').stripFullStack; var tapeBin = path.join(process.cwd(), 'bin/tape'); -tap.test('Should pass with ignoring', { skip: process.platform === 'win32' }, function (tt) { +tap.test('Should pass with ignoring', function (tt) { tt.plan(2); var tc = function (rows) { @@ -38,14 +38,14 @@ tap.test('Should pass with ignoring', { skip: process.platform === 'win32' }, fu ]); }; - var ps = spawn(tapeBin, ['**/*.js', '-i', '.ignore'], { cwd: path.join(__dirname, 'ignore') }); + var ps = spawn(process.execPath, [tapeBin, '**/*.js', '-i', '.ignore'], { cwd: path.join(__dirname, 'ignore') }); ps.stdout.pipe(concat(tc)); ps.on('exit', function (code) { tt.equal(code, 0); // code 0 }); }); -tap.test('Should pass', { skip: process.platform === 'win32' }, function (tt) { +tap.test('Should pass', function (tt) { tt.plan(2); var tc = function (rows) { @@ -95,14 +95,14 @@ tap.test('Should pass', { skip: process.platform === 'win32' }, function (tt) { ]); }; - var ps = spawn(tapeBin, ['**/*.js'], { cwd: path.join(__dirname, 'ignore') }); + var ps = spawn(process.execPath, [tapeBin, '**/*.js'], { cwd: path.join(__dirname, 'ignore') }); ps.stdout.pipe(concat(tc)); ps.on('exit', function (code) { tt.equal(code, 1); }); }); -tap.test('Should fail when ignore file does not exist', { skip: process.platform === 'win32' }, function (tt) { +tap.test('Should fail when ignore file does not exist', function (tt) { tt.plan(3); var testStdout = function (rows) { @@ -113,7 +113,7 @@ tap.test('Should fail when ignore file does not exist', { skip: process.platform tt.ok((/^ENOENT[:,] no such file or directory,? (?:open )?'\$TEST\/ignore\/.gitignore'\n$/m).test(stripFullStack(rows.toString('utf8')).join('\n'))); }; - var ps = spawn(tapeBin, ['**/*.js', '-i'], { cwd: path.join(__dirname, 'ignore') }); + var ps = spawn(process.execPath, [tapeBin, '**/*.js', '-i'], { cwd: path.join(__dirname, 'ignore') }); ps.stdout.pipe(concat(testStdout)); ps.stderr.pipe(concat(testStderr)); ps.on('exit', function (code) { diff --git a/test/import.js b/test/import.js index 4f8a13ea..c86ed41c 100644 --- a/test/import.js +++ b/test/import.js @@ -9,7 +9,7 @@ var assign = require('object.assign'); function tape(args, options) { var bin = __dirname + '/../bin/tape'; - return spawn(process.argv[0], [bin].concat(args.split(' ')), assign({ cwd: __dirname }, options)); + return spawn(process.execPath, [bin].concat(args.split(' ')), assign({ cwd: __dirname }, options)); } tap.test('importing mjs files', function (t) { diff --git a/test/require.js b/test/require.js index 70334153..c6a93164 100644 --- a/test/require.js +++ b/test/require.js @@ -8,7 +8,7 @@ var stripFullStack = require('./common').stripFullStack; function tape(args) { var bin = __dirname + '/../bin/tape'; - return spawn('node', [bin].concat(args.split(' ')), { cwd: __dirname }); + return spawn(process.execPath, [bin].concat(args.split(' ')), { cwd: __dirname }); } tap.test('requiring a single module', function (t) { From bcf6ce793996acd4092bd60c1f99686a73ff048e Mon Sep 17 00:00:00 2001 From: Joris van der Wel Date: Mon, 8 Jan 2024 00:06:00 +0100 Subject: [PATCH 4/4] [Tests] fix `npm test` on windows The version of "nyc" (v9) that is being used does not support launching binaries from node_modules/.bin on windows. As a workaround the path to tap's run.js is specified. Newer version of nyc fix this issue, however those versions drop support for older node versions that we still want to support here. Also, the windows shell does not understand single quotes. --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 62ea4a7e..fc79f345 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "js-yaml": "^3.14.0", "npm-run-posix-or-windows": "^2.0.2", "npmignore": "^0.3.0", + "nyc": "^10.3.2", "safe-publish-latest": "^2.0.0", "tap": "^8.0.1", "tap-parser": "^5.4.0" @@ -80,9 +81,10 @@ "prelint": "npm-run-posix-or-windows eclint", "lint": "eslint --ext .js,.cjs,.mjs . bin/*", "pretest": "npm run lint", - "test": "npm run tests-only", + "test": "npm-run-posix-or-windows tests-only", "posttest": "aud --production", "tests-only": "nyc tap 'test/*.js'", + "tests-only:windows": "nyc node_modules\\tap\\bin\\run.js test/*.js", "test:example": "find example -name '*.js' | grep -v fail | grep -v static | xargs tap" }, "testling": {