diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 913b1bf371..1cd9a78e57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -326,17 +326,12 @@ jobs: run: ./scripts/prebuilt.js - name: Run tests - if: runner.os != 'Windows' run: node scripts/test.js -all - name: Run gentype tests if: runner.os != 'Windows' run: make -C tests/gentype_tests/typescript-react-example clean test - - name: Run tests (Windows) - if: runner.os == 'Windows' - run: node scripts/test.js -mocha -theme -format - - name: Build playground compiler if: matrix.build_playground run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 80ba6dbb4f..b144bb80c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ - Remove uncurried flag from bsb. https://github.com/rescript-lang/rescript-compiler/pull/7049 - Build runtime/stdlib files with rescript/bsb instead of ninja.js. https://github.com/rescript-lang/rescript-compiler/pull/7063 - Build tests with bsb and move them out of jscomp. https://github.com/rescript-lang/rescript-compiler/pull/7068 +- Run `build_tests` on Windows. https://github.com/rescript-lang/rescript-compiler/pull/7065 # 12.0.0-alpha.3 diff --git a/scripts/test.js b/scripts/test.js index c6c45ef840..ebba6688c9 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -2,7 +2,7 @@ const cp = require("child_process"); const path = require("path"); const fs = require("fs"); -var { rescript_exe } = require("#cli/bin_path"); +const { rescript_exe } = require("#cli/bin_path"); const duneBinDir = require("./dune").duneBinDir; @@ -50,9 +50,13 @@ async function runTests() { } if (ounitTest) { - cp.execSync(path.join(duneBinDir, "ounit_tests"), { - stdio: [0, 1, 2], - }); + if (process.platform === "win32") { + console.log("Skipping OUnit tests on Windows"); + } else { + cp.execSync(path.join(duneBinDir, "ounit_tests"), { + stdio: [0, 1, 2], + }); + } } if (mochaTest) { diff --git a/tests/build_tests/case/input.js b/tests/build_tests/case/input.js index 8e5cced399..b3cbcc4d85 100644 --- a/tests/build_tests/case/input.js +++ b/tests/build_tests/case/input.js @@ -1,14 +1,18 @@ var p = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); +var { normalizeNewlines } = require("../utils.js"); + var o = p.spawnSync(rescript_exe, { encoding: "utf8", cwd: __dirname }); if ( ![ `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src/demo vs src/Demo\n`, - // On linux files are parsed in different order + // Windows: path separator + `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src\\demo vs src\\Demo\n`, + // Linux: files are parsed in different order `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src/Demo vs src/demo\n`, - ].includes(o.stderr) + ].includes(normalizeNewlines(o.stderr)) ) { assert.fail(o.stderr); } diff --git a/tests/build_tests/case2/input.js b/tests/build_tests/case2/input.js index a4a3245189..421017507e 100644 --- a/tests/build_tests/case2/input.js +++ b/tests/build_tests/case2/input.js @@ -1,14 +1,18 @@ var p = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); +var { normalizeNewlines } = require("../utils.js"); + var o = p.spawnSync(rescript_exe, { encoding: "utf8", cwd: __dirname }); if ( ![ `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src/X vs src/x\n`, - // On linux files are parsed in different order + // Windows: path separator + `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src\\X vs src\\x\n`, + // Linux: files are parsed in different order `Error: Invalid bsconfig.json implementation and interface have different path names or different cases src/x vs src/X\n`, - ].includes(o.stderr) + ].includes(normalizeNewlines(o.stderr)) ) { assert.fail(o.stderr); } diff --git a/tests/build_tests/cli_compile_status/input.js b/tests/build_tests/cli_compile_status/input.js index 90f72542c3..48365fc321 100755 --- a/tests/build_tests/cli_compile_status/input.js +++ b/tests/build_tests/cli_compile_status/input.js @@ -1,27 +1,31 @@ // @ts-check const assert = require("assert"); +const path = require("path"); const child_process = require("child_process"); +const { normalizeNewlines } = require("../utils.js"); + +const rescriptPath = path.join(__dirname, "..", "..", "..", "rescript") // Shows compile time for `rescript build` command -let out = child_process.spawnSync(`../../../rescript`, ["build"], { +let out = child_process.spawnSync("node", [rescriptPath, "build"], { encoding: "utf8", cwd: __dirname, }); assert.match( - out.stdout, + normalizeNewlines(out.stdout), new RegExp(`>>>> Start compiling Dependency Finished >>>> Finish compiling \\d+ mseconds`), ); // Shows compile time for `rescript` command -out = child_process.spawnSync(`../../../rescript`, { +out = child_process.spawnSync("node", [rescriptPath], { encoding: "utf8", cwd: __dirname, }); assert.match( - out.stdout, + normalizeNewlines(out.stdout), new RegExp(`>>>> Start compiling Dependency Finished >>>> Finish compiling \\d+ mseconds`), @@ -31,13 +35,10 @@ Dependency Finished // Because we can't be sure that -verbose is a valid argument // And bsb won't fail with a usage message. // It works this way not only for -verbose, but any other arg, including -h/--help/-help -out = child_process.spawnSync(`../../../rescript`, ["build", "-verbose"], { +out = child_process.spawnSync("node", [rescriptPath, "build", "-verbose"], { encoding: "utf8", cwd: __dirname, }); -assert.match( - out.stdout, - new RegExp( - `Package stack: test \nDependency Finished\nninja.exe -C lib/bs \n`, - ), -); + +assert.match(normalizeNewlines(out.stdout), /Package stack: test \nDependency Finished\n/); +assert.match(normalizeNewlines(out.stdout), /ninja.exe"? -C lib[\\/]bs ?\n/); diff --git a/tests/build_tests/cli_help/input.js b/tests/build_tests/cli_help/input.js index 8fe5b9b9b4..7817c56450 100755 --- a/tests/build_tests/cli_help/input.js +++ b/tests/build_tests/cli_help/input.js @@ -1,7 +1,10 @@ // @ts-check const assert = require("assert"); -const { exec } = require("../utils.js"); +const path = require("path"); +const { exec, normalizeNewlines } = require("../utils.js"); + +const rescriptPath = path.join(__dirname, "..", "..", "..", "rescript") const cliHelp = "Usage: rescript \n" + @@ -61,184 +64,88 @@ const dumpHelp = "Usage: rescript dump [target]\n" + "`rescript dump` dumps the information for the target\n"; +/** + * @param {string[]} params + * @param {{ stdout: string; stderr: string; status: number; }} expected + */ +async function runTest(params, expected) { + const out = await exec("node", [rescriptPath, ...params], { + cwd: __dirname, + }); + + assert.equal(normalizeNewlines(out.stdout), expected.stdout); + assert.equal(normalizeNewlines(out.stderr), expected.stderr); + assert.equal(out.status, expected.status); +} + async function test() { - { // Shows build help with --help arg - const out = await exec(`../../../rescript`, ["build", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, buildHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - const out = await exec(`../../../rescript`, ["build", "-w", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, buildHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - const out = await exec(`../../../rescript`, ["-w", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cliHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows cli help with --help arg even if there are invalid arguments after it - const out = await exec(`../../../rescript`, ["--help", "-w"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cliHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows build help with -h arg - const out = await exec(`../../../rescript`, ["build", "-h"], { - cwd: __dirname, - }); - assert.equal(out.stdout, buildHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Exits with build help with unknown arg - const out = await exec(`../../../rescript`, ["build", "-foo"], { - cwd: __dirname, - }); - assert.equal(out.stdout, ""); - assert.equal(out.stderr, 'Error: Unknown option "-foo".\n' + buildHelp); - assert.equal(out.status, 2); - } - - { - // Shows cli help with --help arg - const out = await exec(`../../../rescript`, ["--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cliHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows cli help with -h arg - const out = await exec(`../../../rescript`, ["-h"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cliHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows cli help with -h arg - const out = await exec(`../../../rescript`, ["help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cliHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Exits with cli help with unknown command - const out = await exec(`../../../rescript`, ["built"], { - cwd: __dirname, - }); - assert.equal(out.stdout, ""); - assert.equal(out.stderr, `Error: Unknown command "built".\n` + cliHelp); - assert.equal(out.status, 2); - } - - { - // Exits with build help with unknown args - const out = await exec(`../../../rescript`, ["-foo"], { - cwd: __dirname, - }); - assert.equal(out.stdout, ""); - assert.equal(out.stderr, 'Error: Unknown option "-foo".\n' + buildHelp); - assert.equal(out.status, 2); - } - - { - // Shows clean help with --help arg - const out = await exec(`../../../rescript`, ["clean", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cleanHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows clean help with -h arg - const out = await exec(`../../../rescript`, ["clean", "-h"], { - cwd: __dirname, - }); - assert.equal(out.stdout, cleanHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Exits with clean help with unknown arg - const out = await exec(`../../../rescript`, ["clean", "-foo"], { - cwd: __dirname, - }); - assert.equal(out.stdout, ""); - assert.equal(out.stderr, 'Error: Unknown option "-foo".\n' + cleanHelp); - assert.equal(out.status, 2); - } - - { - // Shows format help with --help arg - const out = await exec(`../../../rescript`, ["format", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, formatHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows format help with -h arg - const out = await exec(`../../../rescript`, ["format", "-h"], { - cwd: __dirname, - }); - assert.equal(out.stdout, formatHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows dump help with --help arg - const out = await exec(`../../../rescript`, ["dump", "--help"], { - cwd: __dirname, - }); - assert.equal(out.stdout, dumpHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } - - { - // Shows dump help with -h arg - const out = await exec(`../../../rescript`, ["dump", "-h"], { - cwd: __dirname, - }); - assert.equal(out.stdout, dumpHelp); - assert.equal(out.stderr, ""); - assert.equal(out.status, 0); - } + await runTest(["build", "--help"], { stdout: buildHelp, stderr: "", status: 0 }); + + await runTest(["build", "-w", "--help"], { stdout: buildHelp, stderr: "", status: 0 }); + + await runTest(["-w", "--help"], { stdout: cliHelp, stderr: "", status: 0 }); + + // Shows cli help with --help arg even if there are invalid arguments after it + await runTest(["--help", "-w"], { stdout: cliHelp, stderr: "", status: 0 }); + + // Shows build help with -h arg + await runTest(["build", "-h"], { stdout: buildHelp, stderr: "", status: 0 }); + + // Exits with build help with unknown arg + await runTest(["build", "-foo"], { + stdout: "", + stderr: 'Error: Unknown option "-foo".\n' + buildHelp, + status: 2, + }); + + // Shows cli help with --help arg + await runTest(["--help"], { stdout: cliHelp, stderr: "", status: 0 }); + + // Shows cli help with -h arg + await runTest(["-h"], { stdout: cliHelp, stderr: "", status: 0 }); + + // Shows cli help with -h arg + await runTest(["help"], { stdout: cliHelp, stderr: "", status: 0 }); + + // Exits with cli help with unknown command + await runTest(["built"], { + stdout: "", + stderr: `Error: Unknown command "built".\n` + cliHelp, + status: 2, + }); + + // Exits with build help with unknown args + await runTest(["-foo"], { + stdout: "", + stderr: 'Error: Unknown option "-foo".\n' + buildHelp, + status: 2, + }); + + // Shows clean help with --help arg + await runTest(["clean", "--help"], { stdout: cleanHelp, stderr: "", status: 0 }); + + // Shows clean help with -h arg + await runTest(["clean", "-h"], { stdout: cleanHelp, stderr: "", status: 0 }); + + // Exits with clean help with unknown arg + await runTest(["clean", "-foo"], { + stdout: "", + stderr: 'Error: Unknown option "-foo".\n' + cleanHelp, + status: 2, + }); + + // Shows format help with --help arg + await runTest(["format", "--help"], { stdout: formatHelp, stderr: "", status: 0 }); + + // Shows format help with -h arg + await runTest(["format", "-h"], { stdout: formatHelp, stderr: "", status: 0 }); + + // Shows dump help with --help arg + await runTest(["dump", "--help"], { stdout: dumpHelp, stderr: "", status: 0 }); + + // Shows dump help with -h arg + await runTest(["dump", "-h"], { stdout: dumpHelp, stderr: "", status: 0 }); } void test(); diff --git a/tests/build_tests/duplicated_symlinked_packages/input.js b/tests/build_tests/duplicated_symlinked_packages/input.js index b4f70bfd6a..a80c90d0d5 100644 --- a/tests/build_tests/duplicated_symlinked_packages/input.js +++ b/tests/build_tests/duplicated_symlinked_packages/input.js @@ -12,7 +12,14 @@ function postProcessErrorOutput(output) { output = output.replace(new RegExp(__dirname, "gi"), "."); return output; } + +if (process.platform === "win32") { + console.log("Skipping test on Windows"); + process.exit(0); +} + child_process.execSync(`${rescript_exe} clean`, { cwd: __dirname }); + child_process.exec(rescript_exe, { cwd: __dirname }, (err, stdout, stderr) => { const actualErrorOutput = postProcessErrorOutput(stderr.toString()); if (updateTests) { diff --git a/tests/build_tests/post-build/input.js b/tests/build_tests/post-build/input.js index 9cb97455d0..8a9b223f42 100644 --- a/tests/build_tests/post-build/input.js +++ b/tests/build_tests/post-build/input.js @@ -2,6 +2,11 @@ var child_process = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); +if (process.platform === "win32") { + console.log("Skipping test on Windows"); + process.exit(0); +} + var out = child_process.spawnSync(rescript_exe, { encoding: "utf8" }); if (out.status !== 0) { diff --git a/tests/build_tests/rerror/input.js b/tests/build_tests/rerror/input.js index 18276be1cc..6f452f1331 100644 --- a/tests/build_tests/rerror/input.js +++ b/tests/build_tests/rerror/input.js @@ -1,10 +1,14 @@ +// @ts-check var child_process = require("child_process"); var assert = require("assert"); +var os = require("os"); var { rescript_exe } = require("#cli/bin_path"); + child_process.spawnSync(`${rescript_exe} clean`, { cwd: __dirname, encoding: "utf8", }); + var o = child_process.spawnSync(rescript_exe, { cwd: __dirname, encoding: "utf8", @@ -15,16 +19,15 @@ var o = child_process.spawnSync(rescript_exe, { var u = o.stdout.match(/=>/g); var lines = o.stdout - .split("\n") + .split(/\r?\n/) .map(x => x.trim()) .filter(Boolean); -// console.log(`lines: \n${lines}`) -// console.log(lines[4]) + var test = false; for (var i = 0; i < lines.length; ++i) { if (lines[i] === "We've found a bug for you!") { console.log(`line ${i} found`); - assert.ok(/src\/demo.res:1:21-23/.test(lines[i + 1])); + assert.ok(/src[\\/]demo.res:1:21-23/.test(lines[i + 1])); test = true; } } diff --git a/tests/build_tests/scoped_ppx/input.js b/tests/build_tests/scoped_ppx/input.js index 57815a9ef1..9d75560d0d 100644 --- a/tests/build_tests/scoped_ppx/input.js +++ b/tests/build_tests/scoped_ppx/input.js @@ -1,12 +1,19 @@ var cp = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); + +if (process.platform === "win32") { + console.log("Skipping test on Windows"); + process.exit(0); +} + cp.execSync(rescript_exe, { cwd: __dirname, encoding: "utf8" }); var output = cp.execSync(`${rescript_exe} build -- -t commands src/hello.ast`, { cwd: __dirname, encoding: "utf8", }); + assert( /-ppx '.*\/test\.js -hello' -ppx '.*\/test\.js -heyy' -ppx .*test\.js/.test( output, diff --git a/tests/build_tests/super_errors/input.js b/tests/build_tests/super_errors/input.js index 958a538c8c..f7375a9933 100644 --- a/tests/build_tests/super_errors/input.js +++ b/tests/build_tests/super_errors/input.js @@ -3,6 +3,7 @@ const path = require("path"); const child_process = require("child_process"); const { bsc_exe: bsc } = require("#cli/bin_path"); +const { normalizeNewlines } = require("../utils.js"); const expectedDir = path.join(__dirname, "expected"); @@ -15,13 +16,14 @@ const prefix = `${bsc} -w +A -bs-jsx 4 -bs-jsx-mode automatic`; const updateTests = process.argv[2] === "update"; + function postProcessErrorOutput(output) { output = output.trimRight(); output = output.replace( - /\/[^ ]+?tests\/build_tests\/super_errors\//g, - "/.../", + /(?:[A-Z]:)?[\\/][^ ]+?tests[\\/]build_tests[\\/]super_errors[\\/]([^:]+)/g, + (_match, path, _offset, _string) => "/.../" + path.replace("\\", "/"), ); - return output; + return normalizeNewlines(output); } let doneTasksCount = 0; @@ -30,7 +32,6 @@ let atLeastOneTaskFailed = false; fixtures.forEach(fileName => { const fullFilePath = path.join(__dirname, "fixtures", fileName); const command = `${prefix} -color always ${fullFilePath}`; - console.log(`running ${command}`); child_process.exec(command, (err, stdout, stderr) => { doneTasksCount++; // careful of: diff --git a/tests/build_tests/unboxed_bool_with_const/input.js b/tests/build_tests/unboxed_bool_with_const/input.js index 2f5c856668..59b01f8273 100644 --- a/tests/build_tests/unboxed_bool_with_const/input.js +++ b/tests/build_tests/unboxed_bool_with_const/input.js @@ -3,6 +3,7 @@ var cp = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); +var { normalizeNewlines } = require("../utils.js"); var out = cp.spawnSync(rescript_exe, { cwd: __dirname, @@ -10,7 +11,7 @@ var out = cp.spawnSync(rescript_exe, { }); assert.equal( - out.stdout.slice(out.stdout.indexOf("Main.res:3:3-14")), + normalizeNewlines(out.stdout.slice(out.stdout.indexOf("Main.res:3:3-14"))), `Main.res:3:3-14 1 │ @unboxed diff --git a/tests/build_tests/unicode/input.js b/tests/build_tests/unicode/input.js index 9208b96e34..2e7443629b 100644 --- a/tests/build_tests/unicode/input.js +++ b/tests/build_tests/unicode/input.js @@ -1,11 +1,17 @@ //@ts-check var child_process = require("child_process"); +var fs = require("fs"); +var path = require("path"); + var { rescript_exe } = require("#cli/bin_path"); +if (process.platform === "win32") { + console.log("Skipping test on Windows"); + process.exit(0); +} + console.log(child_process.execSync(rescript_exe, { encoding: "utf8" })); -var fs = require("fs"); -var path = require("path"); var content = "" + fs.readFileSync(path.join(__dirname, "lib", "bs", ".sourcedirs.json")); diff --git a/tests/build_tests/utils.js b/tests/build_tests/utils.js index ac97290156..d0715e907f 100644 --- a/tests/build_tests/utils.js +++ b/tests/build_tests/utils.js @@ -49,4 +49,12 @@ async function exec(command, args, options) { }); } +/** + * @param {string} s + */ +function normalizeNewlines(s) { + return s.replace(/\r\n/g, '\n'); +} + exports.exec = exec; +exports.normalizeNewlines = normalizeNewlines; diff --git a/tests/build_tests/weird_deps/input.js b/tests/build_tests/weird_deps/input.js index 30d0fdd927..9199a61968 100644 --- a/tests/build_tests/weird_deps/input.js +++ b/tests/build_tests/weird_deps/input.js @@ -3,6 +3,7 @@ var cp = require("child_process"); var assert = require("assert"); var { rescript_exe } = require("#cli/bin_path"); +var { normalizeNewlines } = require("../utils.js"); var out = cp.spawnSync(rescript_exe, { cwd: __dirname, @@ -13,7 +14,7 @@ if (out.stdout !== "") { assert.fail(out.stdout); } else { assert.equal( - out.stderr, + normalizeNewlines(out.stderr), [ 'File "bsconfig.json", line 1', "Error: package weird not found or built ", diff --git a/tests/build_tests/weird_devdeps/input.js b/tests/build_tests/weird_devdeps/input.js index 892b4bdf37..8bc6743ce5 100644 --- a/tests/build_tests/weird_devdeps/input.js +++ b/tests/build_tests/weird_devdeps/input.js @@ -2,6 +2,7 @@ var cp = require("child_process"); var assert = require("assert"); +var os = require("os"); var rescript_exe = require("#cli/bin_path").rescript_exe; var out = cp.spawnSync(rescript_exe, { @@ -19,6 +20,6 @@ if (out.stdout !== "") { "Error: package weird not found or built ", "- Did you install it?", "", - ].join("\n"), + ].join(os.EOL), ); }