#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import math import os import re import shutil import sys import traceback from datetime import date from typing import Any, Optional
import yaml
# Skip all common files used to support tests for jstests # These files are listed in the README.txt
SUPPORT_FILES = set(
[ "browser.js", "shell.js", "template.js", "user.js", "js-test-driver-begin.js", "js-test-driver-end.js",
]
)
# Run once per subdirectory def findAndCopyIncludes(dirPath: str, baseDir: str, includeDir: str) -> "list[str]":
relPath = os.path.relpath(dirPath, baseDir)
includes: list[str] = ["sm/non262.js"]
os.makedirs(os.path.join(includeDir, "sm"), exist_ok=True)
# Recurse down all folders in the relative path until # we reach the base directory of shell.js include files. # Each directory will have a shell.js file to copy. while relPath: # find the shell.js
shellFile = os.path.join(baseDir, relPath, "shell.js")
# if the file exists and is not empty, include in includes if os.path.exists(shellFile) and os.path.getsize(shellFile) > 0: with open(shellFile, "rb") as f:
testSource = f.read()
if b"// SKIP test262 export"notin testSource: # create new shell.js file name
includeFileName = "sm/" + relPath.replace("/", "-") + "-shell.js"
includes.append(includeFileName)
def skipTest(source: bytes) -> Optional[bytes]: if b"This Source Code Form is subject to the terms of the Mozilla Public"in source: return b"MPL license" for c in UNSUPPORTED_CODE: if c in source: return c
# should capture conditions to skip
matchesSkip = re.search(r"skip-if\((.*)\)", reftest) if matchesSkip:
matches = matchesSkip.group(1).split("||") for match in matches: # captures a features list
dependsOnProp = re.search(
r"!this.hasOwnProperty\([\'\"](.*?)[\'\"]\)", match
) if dependsOnProp: if feature := featureFromReftest(dependsOnProp.group(1)):
features.append(feature) else:
print("# Can't parse the following skip-if rule: %s" % match)
# should capture the expected error
matchesError = re.search(r"error:\s*(\w*)", reftest) if matchesError: # The metadata from the reftests won't say if it's a runtime or an # early error. This specification is required for the frontmatter tags.
error = matchesError.group(1)
# just tells if it's a module
matchesModule = re.search(r"\bmodule\b", reftest) if matchesModule:
module = True
# captures any comments
matchesComments = re.search(r" -- (.*)", reftest) if matchesComments:
comments = matchesComments.group(1)
def parseHeader(source: bytes) -> "tuple[bytes, Optional[ReftestEntry]]": """
Parse the source to return it with the extracted the header """ from lib.manifest import TEST_HEADER_PATTERN_INLINE
# Bail early if we do not start with a single comment. ifnot source.startswith(b"//"): return (source, None)
# Extract the token.
part, _, rest = source.partition(b"\n")
part = part.decode("utf-8")
matches = TEST_HEADER_PATTERN_INLINE.match(part)
if matches and matches.group(0):
reftest = matches.group(0)
# Remove the found header from the source; # Fetch and return the reftest entries return (rest, fetchReftestEntries(reftest))
return (source, None)
## insertCopyrightLines
LICENSE_PATTERN = re.compile(
rb"// Copyright( \([C]\))? (\w+) .+\. {1,2}All rights reserved\.[\r\n]{1,2}"
+ rb"("
+ rb"// This code is governed by the( BSD)? license found in the LICENSE file\."
+ rb"|"
+ rb"// See LICENSE for details."
+ rb"|"
+ rb"// Use of this source code is governed by a BSD-style license that can be[\r\n]{1,2}"
+ rb"// found in the LICENSE file\."
+ rb"|"
+ rb"// See LICENSE or https://github\.com/tc39/test262/blob/HEAD/LICENSE"
+ rb")[\r\n]{1,2}",
re.IGNORECASE,
)
BSD_TEMPLATE = (
b"""\
// Copyright (C) %d Mozilla Corporation. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
def insertCopyrightLines(source: bytes) -> "tuple[bytes, bytes]": """
Insert the copyright lines into the file. """ if match := LICENSE_PATTERN.search(source):
start, end = match.span() return source[start:end], source[:start] + source[end:]
if (
match := PD_PATTERN1.search(source) or PD_PATTERN2.search(source) or PD_PATTERN3.search(source)
):
start, end = match.span() return PD_TEMPLATE, source[:start] + source[end:]
def extractMeta(source: bytes) -> "tuple[dict[str, Any], bytes]": """
Capture the frontmatter metadata as yaml if it exists.
Returns a new dict if it doesn't. """
match = FRONTMATTER_WRAPPER_PATTERN.search(source) ifnot match: return {}, source
yamlresult = yaml.safe_load(unindented) if isinstance(yamlresult, str):
result = {"info": yamlresult} else:
result = yamlresult
start, end = match.span() return result, source[:start] + source[end:]
## computeMeta
def translateHelpers(source: bytes) -> "tuple[bytes, list[str]]": """
Translate SpiderMonkey helper methods that have standard variants in test262.
This also returns a list of includes that are needed to use these variants in test262, if any. """
includes: list[str] = []
source, n = re.subn(rb"\bassertDeepEq\b", b"assert.deepEqual", source) if n:
includes.append("deepEqual.js")
source, n = re.subn(rb"\bassertEqArray\b", b"assert.compareArray", source) if n:
includes.append("compareArray.js")
# Only add the module flag if the value from reftest is truish if reftest.module:
frontmatter.setdefault("flags", []).append("module") if"noStrict"in frontmatter["flags"]:
frontmatter["flags"].remove("noStrict") if"onlyStrict"in frontmatter["flags"]:
frontmatter["flags"].remove("onlyStrict")
# Add any comments to the info tag if reftest.info:
info = reftest.info # Open some space in an existing info text if"info"in frontmatter and frontmatter["info"]:
frontmatter["info"] += "\n\n%s" % info else:
frontmatter["info"] = info
# Set the negative flags if reftest.error:
error = reftest.error if"negative"notin frontmatter:
frontmatter["negative"] = { # This code is assuming error tags are parse errors, but they # might be runtime errors as well. # From this point, this code can also print a warning asking to # specify the error phase in the generated code or fill the # phase with an empty string. "phase": "parse", "type": error,
} # Print a warning if the errors don't match elif frontmatter["negative"].get("type") != error:
print( "Warning: The reftest error doesn't match the existing "
+ "frontmatter error. %s != %s"
% (error, frontmatter["negative"]["type"])
)
return frontmatter
def cleanupMeta(meta: "dict[str, Any]") -> "dict[str, Any]": """
Clean up all the frontmatter meta tags. This isnot a lint tool, just a
simple cleanup to remove trailing spaces and duplicate entries from lists. """
# Trim values on each string tag for tag in ("description", "esid", "es5id", "es6id", "info", "author"): if tag in meta: ifnot meta[tag]: del meta[tag] else:
meta[tag] = meta[tag].strip() ifnot len(meta[tag]): del meta[tag]
# Populate required tags for tag in ("description", "esid"):
meta.setdefault(tag, "pending")
# Remove duplicate entries on each list tag for tag in ("features", "flags", "includes"): if tag in meta: ifnot meta[tag]: del meta[tag] else: # We need the list back for the yaml dump
meta[tag] = sorted(set(meta[tag])) ifnot len(meta[tag]): del meta[tag]
def insertMeta(source: bytes, frontmatter: "dict[str, Any]") -> bytes: """
Insert the formatted frontmatter into the file, use the current existing
space if any """
lines: list[bytes] = []
lines.append(b"/*---")
for key, value in frontmatter.items(): if key in ("description", "info"):
lines.append(b"%s: |" % key.encode("ascii"))
lines.append(
yaml.dump(
value,
encoding="utf8",
default_style="|",
default_flow_style=False,
allow_unicode=True,
)
.strip()
.replace(b"|-\n", b"")
) elif key == "includes":
lines.append(
b"includes: "
+ yaml.dump(
value, encoding="utf8", default_flow_style=True, width=math.inf
).strip()
) else:
lines.append(
yaml.dump(
{key: value}, encoding="utf8", default_flow_style=False
).strip()
)
if frontmatter.get("negative", {}).get("phase", "") == "parse":
source += b"$DONOTEVALUATE();\n"
return source
def computeMeta(
source: bytes,
reftest: "Optional[ReftestEntry]",
frontmatter: "dict[str, Any]",
includes: "list[str]",
) -> "dict[str, Any]": """
Captures the reftest meta and a pre-existing meta if any and merge them
into a single dict. """
if source.startswith((b'"use strict"', b"'use strict'")):
frontmatter.setdefault("flags", []).append("onlyStrict")
if b"createIsHTMLDDA"in source:
frontmatter.setdefault("features", []).append("IsHTMLDDA")
# Merge the reftest and frontmatter
merged = mergeMeta(reftest, frontmatter, includes)
# Cleanup the metadata return cleanupMeta(merged)
## convertReportCompare
def convertReportCompare(source: bytes) -> bytes: """
Captures all the reportCompare and convert them accordingly.
Cases with reportCompare calls where the arguments are the same and one of
0, true, or null, will be discarded as they are not necessary for Test262.
Otherwise, reportCompare will be replaced withassert.sameValue, as the
equivalent in Test262 """
def exportTest262(
outDir: str, providedSrcs: "list[str]", includeShell: bool, baseDir: str
): # Create the output directory from scratch.
print(f"Generating output in {os.path.abspath(outDir)}") if os.path.isdir(outDir):
shutil.rmtree(outDir)
# only make the includes directory if requested
includeDir = os.path.join(outDir, "harness-includes") if includeShell:
os.makedirs(includeDir)
skipped = 0
skippedDirs = 0
# Go through each source path for providedSrc in providedSrcs:
src = os.path.abspath(providedSrc) ifnot os.path.isdir(src):
print(f"Did not find directory {src}") # the basename of the path will be used in case multiple "src" arguments # are passed in to create an output directory for each "src".
basename = os.path.basename(src)
# Process all test directories recursively. for dirPath, dirNames, fileNames in os.walk(src): # we need to make and get the unique set of includes for this filepath
includes = [] if includeShell:
includes = findAndCopyIncludes(dirPath, baseDir, includeDir)
# This is hacky, but we're unlikely to add anything new # that needs to be skipped this way. if relPath + "/" + fileName in UNSUPPORTED_PATHS:
print("SKIPPED %s" % testName)
skipped += 1 continue
# Copy non-test files as is. if"_FIXTURE"in fileName or os.path.splitext(fileName)[1] != ".js":
shutil.copyfile(filePath, os.path.join(currentOutDir, fileName))
print("C %s" % testName) continue
# Read the original test source and preprocess it for Test262 with open(filePath, "rb") as testFile:
testSource = testFile.read()
skip = skipTest(testSource) if skip isnotNone:
print(
f"SKIPPED {testName} because file contains {skip.decode('ascii')}"
)
skipped += 1 continue
try:
newSource = convertTestFile(testSource, includes) if newSource isNone:
print(f"SKIPPED {testName} due to disabled features")
skipped += 1 continue except Exception as e:
print(f"SKIPPED {testName} due to error {e}")
traceback.print_exc(file=sys.stdout)
skipped += 1 continue
with open(os.path.join(currentOutDir, fileName), "wb") as output:
output.write(newSource)
print("SAVED %s" % testName)
print(f"Skipped {skipped} tests and {skippedDirs} test directories")
if __name__ == "__main__": import argparse
# This script must be run from js/src/tests to work correctly. if"/".join(os.path.normpath(os.getcwd()).split(os.sep)[-3:]) != "js/src/tests": raise RuntimeError("%s must be run from js/src/tests" % sys.argv[0])
parser = argparse.ArgumentParser(
description="Export tests to match Test262 file compliance."
)
parser.add_argument( "--out",
default="test262/export",
help="Output directory. Any existing directory will be removed! " "(default: %(default)s)",
)
parser.add_argument( "--exportshellincludes",
action="store_true",
help="Optionally export shell.js files as includes in exported tests. " "Only use for testing, do not use for exporting to test262 (test262 tests " "should have as few dependencies as possible).",
)
parser.add_argument( "src", nargs="+", help="Source folder with test files to export"
)
args = parser.parse_args()
exportTest262(
os.path.abspath(args.out), args.src, args.exportshellincludes, os.getcwd()
)
Messung V0.5
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.