Make run-external-typescript-tests.js cross-platform (#2737)

The old version had quite a bit of code related to grouping errors,
showing the number of errors per group and saving the groups of errors
to different files. However, now there are only 12 bad tests so I didn't
bother porting that logic to the new version. Instead, the errors a
simply printed to stdout.
master
Simon Lydell 2017-09-03 15:59:19 +02:00 committed by GitHub
parent c4e5463514
commit f903ae45ed
2 changed files with 73 additions and 111 deletions

View File

@ -1,128 +1,89 @@
"use strict"; "use strict";
/**
* There's an issue with this script's assumption that each run of prettier
* will result in one output to stderr or stdout.
*
* On Mac this seems not to hold for stderr, where multiple errors are buffered
* into one emit on the stderr stream.
*
* If you have any ideas on how to fix this, please send a PR!
*/
if (process.platform !== "win32") {
console.log("Warning: this script may not work on macOS.");
}
const fs = require("fs"); const fs = require("fs");
const globby = require("globby");
const path = require("path"); const path = require("path");
const spawn = require("child_process").spawn; const format = require("../src/cli-util").format;
const rimraf = require("rimraf");
const tsRoot = path.resolve(__dirname, "../../TypeScript"); function tryFormat(content) {
const testsDir = path.relative(process.cwd(), path.join(tsRoot, "tests")); try {
const errorsPath = "./errors/"; format({ "debug-check": true }, content, { parser: "typescript" });
const fileGlob = path.join(testsDir, "**/*.ts"); } catch (error) {
return error;
if (!fs.existsSync(tsRoot) || !fs.existsSync(testsDir)) { }
console.error(`Error: TypeScript is not cloned at ../TypeScript`); return null;
process.exit(1);
} }
const badFiles = []; function runExternalTests(testsDir) {
const errorTypes = {}; const testFiles = globby.sync(path.join(testsDir, "**/*.ts"));
let good = 0;
let skipped = 0;
rimraf.sync(errorsPath); if (testFiles.length === 0) {
throw new Error(
const cp = spawn("node", [ [
"./bin/prettier.js", "Couldn't find any test files.",
"--parser", `Please make sure that \`${testsDir}\` exists and contains the TypeScript tests.`
"typescript", ].join("\n")
"--debug-check", );
fileGlob
]);
cp.stdout.on("data", () => {
good++;
printStatus();
});
cp.stderr.on("data", err => {
const error = err.toString();
const { file, errorType } = splitFileAndError(error);
if (errorType.startsWith("SyntaxError:")) {
skipped++;
} else {
badFiles.push({ file, errorType, error });
errorTypes[errorType] = (errorTypes[errorType] || 0) + 1;
} }
printStatus();
});
cp.on("close", () => { const results = {
const total = badFiles.length + good + skipped; good: [],
const percentNoError = (100 * (good + skipped) / total).toFixed(0); skipped: [],
console.log( bad: []
`\n${percentNoError}% of ${total} files processed without errors.\n`
);
Object.keys(errorTypes)
.sort((a, b) => errorTypes[b] - errorTypes[a])
.forEach(errorType => {
console.log(`${errorTypes[errorType]}\t${errorType}`);
});
console.log(`\nWriting errors to '${errorsPath}' directory`);
writeErrorsToFiles();
});
function printStatus() {
process.stdout.write(
`\r${good} good, ${skipped} skipped, ${badFiles.length} bad`
);
}
function splitFileAndError(err) {
const lines = err.split("\n");
const [file, ...rest] = lines[0].split(":");
if (rest.length) {
return {
file,
errorType: rest
.join(":")
.replace(/\(\d+:\d+\)/, "")
.replace(/(Comment )".*"/, '$1"<omitted>"')
.trim()
};
}
console.error("Could not process error:", err);
return {
file: "?",
errorType: err
}; };
}
function writeErrorsToFiles() { testFiles.forEach(file => {
const splitter = "@".repeat(80); const content = fs.readFileSync(file, "utf8");
fs.mkdirSync(errorsPath);
Object.keys(errorTypes).forEach(errorType => { const error = tryFormat(content);
const files = badFiles.filter(f => f.errorType === errorType);
const contents = files if (error instanceof SyntaxError) {
.map(({ file, error }) => { results.skipped.push({ file, error });
// Trim file name from error. } else if (error) {
if (error.startsWith(file)) { results.bad.push({ file, error });
error = error.substring(file.length); } else {
} results.good.push({ file });
return `\n\n${file}\n${error}\n${splitter}\n`; }
})
.join("\n"); process.stderr.write(
fs.writeFileSync( `\r${results.good.length} good, ${results.skipped
path.join(errorsPath, sanitize(errorType) + ".log"), .length} skipped, ${results.bad.length} bad`
contents
); );
}); });
return results;
} }
function sanitize(string) { function run(argv) {
return string.replace(/[^A-Z0-9_.() -]/gi, "_").replace(/\.$/, ""); if (argv.length !== 1) {
console.error(
[
"You must provide the path to a TypeScript tests directory!",
"Example: node scripts/run-external-typescript-tests.js ../TypeScript/tests/"
].join("\n")
);
return 1;
}
const testsDir = argv[0];
let results = null;
try {
results = runExternalTests(testsDir);
} catch (error) {
console.error(`Failed to run external tests.\n${error}`);
return 1;
}
console.log("");
console.log(
results.bad.map(data => `${data.file}\n${data.error}`).join("\n\n\n")
);
return 0;
}
if (require.main === module) {
const exitCode = run(process.argv.slice(2));
process.exit(exitCode);
} }

View File

@ -359,6 +359,7 @@ function formatFiles(argv, filepatterns) {
module.exports = { module.exports = {
resolveConfig, resolveConfig,
format,
formatStdin, formatStdin,
formatFiles formatFiles
}; };