Source code

Revision control

Copy as Markdown

Other Tools

const fs = require("fs-extra");
const path = require("path");
const readDirectory = async directoryPath => {
return new Promise((resolve, reject) => {
fs.readdir(directoryPath, (error, files) => {
if (error) {
reject(error);
}
resolve(files);
});
});
};
const makeDirectory = async directoryPath => {
return new Promise((resolve, reject) => {
fs.mkdir(directoryPath, error => {
if (error) {
reject(error);
}
resolve();
});
});
};
const readStats = async path => {
return new Promise((resolve, reject) => {
fs.stat(path, (error, stats) => {
if (error) {
resolve(null);
}
resolve(stats);
});
});
};
const readFile = async path => {
return new Promise((resolve, reject) => {
fs.readFile(
path,
{
encoding: "UTF-8"
},
(error, data) => {
if (error) {
reject(error);
}
resolve(data);
}
);
});
};
const writeFile = async (path, data) => {
return new Promise((resolve, reject) => {
fs.writeFile(path, data, error => {
if (error) {
reject(error);
}
resolve();
});
});
};
const parseFrontmatter = src => {
var start = src.indexOf("/*---");
var end = src.indexOf("---*/");
if (start === -1 || end === -1) return null;
var match,
includes = [],
flags = {},
negative = null;
var frontmatter = src.substring(start + 5, end);
match = frontmatter.match(/(?:^|\n)\s*includes:\s*\[([^\]]*)\]/);
if (match) {
includes = match[1].split(",").map(function f(s) {
return s.replace(/^\s+|\s+$/g, "");
});
} else {
match = frontmatter.match(/(?:^|\n)\s*includes:\s*\n(\s+-.*\n)/);
if (match) {
includes = match[1].split(",").map(function f(s) {
return s.replace(/^[\s\-]+|\s+$/g, "");
});
}
}
match = frontmatter.match(/(?:^|\n)\s*flags:\s*\[([^\]]*)\]/);
if (match) {
match[1]
.split(",")
.map(function f(s) {
return s.replace(/^\s+|\s+$/g, "");
})
.forEach(function(flag) {
switch (flag) {
case "onlyStrict":
if (flags.strict) {
console.error("flag conflict", src);
}
flags.strict = "always";
break;
case "noStrict":
if (flags.strict) {
console.error("flag conflict");
}
flags.strict = "never";
break;
case "module":
flags.module = true;
break;
case "raw":
flags.raw = true;
break;
case "async":
flags.async = true;
break;
case "generated":
case "non-deterministic":
case "CanBlockIsTrue":
case "CanBlockIsFalse":
break;
default:
console.error("unrecocognized flag: " + flag, frontmatter);
break;
}
});
}
match = frontmatter.match(/(?:^|\n)\s*negative:/);
if (match) {
var phase, type;
frontmatter
.substr(match.index + 9)
.split("\n")
.forEach(function(line) {
var match = line.match(/\s+phase:\s*(\S+)/);
if (match) {
phase = match[1];
}
match = line.match(/\s+type:\s*(\S+)/);
if (match) {
type = match[1];
}
});
if (!phase || !type) return null;
negative = {
phase: phase,
type: type
};
}
return {
includes: includes,
flags: flags,
negative: negative,
isDynamic: /dynamic-import/.test(frontmatter)
}; // lol, do better
};
const getOutputPath = ({ testsPath, currentPath, outputPath }) => {
return path.join(outputPath, path.relative(testsPath, currentPath));
};
// Tests that will freeze the runner
// ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js
// ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js
// ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js
// ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js
// ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js
const excludedTests = [
/15\.4\.4\.15-3-14\.js/,
/15\.4\.4\.18-3-14\.js/,
/15\.4\.4\.20-3-14\.js/,
/15\.4\.4\.21-3-14\.js/,
/15\.4\.4\.22-3-14\.js/
];
let testCount = 0;
const generateTest = async ({
testsPath,
outputPath,
currentPath,
templateContent,
iframeTemplateContent
}) => {
if (!currentPath) currentPath = testsPath;
let stats = await readStats(currentPath);
if (stats.isDirectory()) {
const outputDir = getOutputPath({
testsPath,
outputPath,
currentPath
});
if (!(await readStats(outputDir))) await makeDirectory(outputDir);
let files = await readDirectory(currentPath);
for (let file of files) {
await generateTest({
currentPath: path.join(currentPath, file),
outputPath,
testsPath,
templateContent,
iframeTemplateContent
});
}
} else {
if (
currentPath.indexOf(".js") === -1 ||
excludedTests.some(regex => regex.test(currentPath))
) {
return;
}
const jsRelativePath = path.relative(testsPath, currentPath);
const jsOutputPath = path.join(outputPath, jsRelativePath);
const htmlOutputPath = jsOutputPath.replace(".js", ".html");
const iframeHtmlOutputPath = jsOutputPath.replace(".js", ".iframe.html");
const jsSrc = await readFile(currentPath);
const meta = parseFrontmatter(jsSrc);
const includes = (meta && meta.includes) || [];
const testContent = replacePlaceholders(templateContent, {
jsRelativePath,
includes,
iframeTestPath: `/${iframeHtmlOutputPath}`
});
const iframeTestContent = replacePlaceholders(iframeTemplateContent, {
jsRelativePath,
includes,
iframeTestPath: `/${iframeHtmlOutputPath}`
});
await writeFile(htmlOutputPath, testContent);
await writeFile(iframeHtmlOutputPath, iframeTestContent);
await fs.copy(currentPath, jsOutputPath);
testCount++;
}
};
function replacePlaceholders(
content,
{ jsRelativePath, includes, iframeTestPath }
) {
content = content.replace(
"{{ TEST_URL }}",
"/ecmascript/tests/" + jsRelativePath
);
content = content.replace("{{ IFRAME_TEST_URL }}", iframeTestPath);
content = content.replace(
"{{ TEST_TITLE }}",
jsRelativePath.split("/").pop()
);
content = content.replace(
"{{ INCLUDES }}",
includes
.map(function(src) {
return "<script src='/ecmascript/harness/" + src + "'></script>";
})
.join("\n")
);
return content;
}
(async () => {
const ADAPTER_SCRIPT_NAME = "webplatform-adapter.js";
const HTML_TEMPLATE_NAME = path.join(__dirname, "test-template.html");
const IFRAME_HTML_TEMPLATE_NAME = path.join(
__dirname,
"test-template.iframe.html"
);
const DEFAULT_TEST_DIR = "./test262";
const DEFAULT_OUTPUT_DIR = ".";
const SUB_DIR_NAME = "ecmascript";
const testDir = process.argv[2] || DEFAULT_TEST_DIR;
const testsPath = path.join(testDir, "test");
const harnessDir = path.join(testDir, "harness");
let outputPath = process.argv[3] || DEFAULT_OUTPUT_DIR;
outputPath = path.join(outputPath, SUB_DIR_NAME);
const testsOutputPath = path.join(outputPath, "tests");
const harnessOutputDir = path.join(outputPath, "harness");
const adapterSourcePath = path.join(__dirname, ADAPTER_SCRIPT_NAME);
const adapterDestinationPath = path.join(outputPath, ADAPTER_SCRIPT_NAME);
if (!(await readStats(outputPath))) await makeDirectory(outputPath);
console.log("Reading test templates ...");
const templateContent = await readFile(HTML_TEMPLATE_NAME);
const iframeTemplateContent = await readFile(IFRAME_HTML_TEMPLATE_NAME);
console.log("Generating tests ...");
await generateTest({
testsPath,
outputPath: testsOutputPath,
templateContent,
iframeTemplateContent
});
await fs.copy(adapterSourcePath, adapterDestinationPath);
await fs.copy(harnessDir, harnessOutputDir);
console.log(
`Generated ${testCount} tests in directory ${outputPath} (${path.resolve(
outputPath
)})`
);
})();