[infra] Fork test262-harness

The external project is effectively abandoned. Fork and move it in-tree
for easier maintenance and Python 3 migration.

Bug: chromium:1296209
Change-Id: I4ff97749acb2895bd8433c08b2a4ff109c90cda2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3475086
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79240}
This commit is contained in:
Shu-yu Guo 2022-02-22 16:06:52 -08:00 committed by V8 LUCI CQ
parent 3d5d99ffd9
commit d7e6146bc6
28 changed files with 2826 additions and 10 deletions

2
.gitignore vendored
View File

@ -55,7 +55,6 @@
!/test/mjsunit/tools/*.log
/test/mozilla/data
/test/test262/data
/test/test262/harness
/test/wasm-js/data
/test/wasm-js/tests
/test/wasm-js/tests.tar.gz
@ -70,6 +69,7 @@
/third_party/colorama/src
!/third_party/googletest
/third_party/googletest/src
!/third_party/test262-harness
!/third_party/v8
!/third_party/wasm-api
/tools/clang

2
DEPS
View File

@ -140,8 +140,6 @@ deps = {
Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be',
'test/test262/data':
Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'e87b0048c402479df1d9cb391fb86620cf3200fd',
'test/test262/harness':
Var('chromium_url') + '/external/github.com/test262-utils/test262-harness-py.git' + '@' + '278bcfaed0dcaa13936831fb1769d15e7c1e3b2b',
'third_party/aemu-linux-x64': {
'packages': [
{

View File

@ -13,7 +13,7 @@ group("v8_test262") {
data = [
"data/",
"detachArrayBuffer.js",
"harness/",
"../../third_party/test262-harness/",
"harness-adapt.js",
"harness-adapt-donotevaluate.js",
"harness-agent.js",

View File

@ -69,16 +69,18 @@ SKIPPED_FEATURES = set([])
DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
BASE_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEST_262_HARNESS_FILES = ["sta.js", "assert.js"]
TEST_262_NATIVE_FILES = ["detachArrayBuffer.js"]
TEST_262_SUITE_PATH = ["data", "test"]
TEST_262_HARNESS_PATH = ["data", "harness"]
TEST_262_TOOLS_PATH = ["harness", "src"]
TEST_262_TOOLS_ABS_PATH = [BASE_DIR, "third_party", "test262-harness", "src"]
TEST_262_LOCAL_TESTS_PATH = ["local-tests", "test"]
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),
*TEST_262_TOOLS_PATH))
sys.path.append(os.path.join(*TEST_262_TOOLS_ABS_PATH))
class VariantsGenerator(testsuite.VariantsGenerator):
@ -139,15 +141,14 @@ class TestSuite(testsuite.TestSuite):
self.parse_test_record = self._load_parse_test_record()
def _load_parse_test_record(self):
root = os.path.join(self.root, *TEST_262_TOOLS_PATH)
root = os.path.join(*TEST_262_TOOLS_ABS_PATH)
f = None
try:
(f, pathname, description) = imp.find_module("parseTestRecord", [root])
module = imp.load_module("parseTestRecord", f, pathname, description)
return module.parseTestRecord
except:
print ('Cannot load parseTestRecord; '
'you may need to gclient sync for test262')
print('Cannot load parseTestRecord')
raise
finally:
if f:

28
third_party/test262-harness/LICENSE vendored Normal file
View File

@ -0,0 +1,28 @@
The << Software identified by reference to the Ecma Standard* (“Software)”>> is protected by copyright and is being
made available under the “BSD License”, included below. This Software may be subject to third party rights (rights
from parties other than Ecma International), including patent rights, and no licenses under such third party rights
are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA
CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
Copyright © <<2012>> <<Ecma International>>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
* Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports

2
third_party/test262-harness/OWNERS vendored Normal file
View File

@ -0,0 +1,2 @@
file:../../INFRA_OWNERS
syg@chromium.org

19
third_party/test262-harness/README.md vendored Normal file
View File

@ -0,0 +1,19 @@
# Test262 Python Harness
### Usage
Loaded as a module, this project defines a single function, `parseTestRecord`.
This function creates an object representation of the metadata encoded in the
"frontmatter" of the provided Test262 test source code.
`test262.py` is an executable designed to execute Test262 tests. It is exposed
for public use. For usage instructions, invoke this executable with the
`--help` flag, as in:
$ test262.py --help
### Tests
Run the following command from the root of this projcet:
$ python -m unittest discover test

15
third_party/test262-harness/README.v8 vendored Normal file
View File

@ -0,0 +1,15 @@
Name: test262-harness
Short Name: test262-harness
URL: https://github.com/test262-utils/test262-harness-py
Version: 0
Revision: 278bcfaed0dcaa13936831fb1769d15e7c1e3b2b
Date: 2022-02-18
License: BSD
License File: LICENSE
Security Critical: no
Description:
Provides the parseTestRecord function in Python for the test262 runner.
Local modifications:
src/_monkeyYaml.py was made Python 3 compatible

View File

@ -0,0 +1 @@
from src.parseTestRecord import parseTestRecord

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<excludeList>
</excludeList>

View File

View File

@ -0,0 +1,18 @@
# Copyright (c) 2012 Ecma International. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
#--Imports---------------------------------------------------------------------
import parseTestRecord
#--Stubs-----------------------------------------------------------------------
#--Globals---------------------------------------------------------------------
#--Helpers--------------------------------------------------------------------#
def convertDocString(docString):
envelope = parseTestRecord.parseTestRecord(docString, '')
envelope.pop('header', None)
envelope.pop('test', None)
return envelope

View File

@ -0,0 +1,147 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
# This code provides a fallback parser that can handle the subset of
# YAML used in test262 frontmatter
import re
mYamlKV = re.compile(r"(.*?):(.*)")
mYamlIntDigits = re.compile(r"^[-0-9]*$")
mYamlFloatDigits = re.compile(r"^[-.0-9eE]*$")
mYamlListPattern = re.compile(r"^\[(.*)\]$")
mYamlMultilineList = re.compile(r"^ *- (.*)$")
mYamlStringValue = re.compile(r"^('|\").*\1$")
def load(str):
return myReadDict(str.splitlines())[1]
def myReadDict(lines, indent=""):
dict = None
key = None
emptyLines = 0
while lines:
if not lines[0].startswith(indent):
break
line = lines.pop(0)
if myIsAllSpaces(line):
emptyLines += 1
continue
result = mYamlKV.match(line)
if result:
if not dict:
dict = {}
key = result.group(1).strip()
value = result.group(2).strip()
(lines, value) = myReadValue(lines, value, indent)
dict[key] = value
else:
if dict and key and key in dict:
c = " " if emptyLines == 0 else "\n" * emptyLines
dict[key] += c + line.strip()
else:
raise Exception("monkeyYaml is confused at " + line)
emptyLines = 0
return lines, dict
def myReadValue(lines, value, indent):
if value == ">" or value == "|":
(lines, value) = myMultiline(lines, value == "|")
value = value + "\n"
return (lines, value)
if lines and not value:
if myMaybeList(lines[0]):
return myMultilineList(lines, value)
indentMatch = re.match("(" + indent + r"\s+)", lines[0])
if indentMatch:
if ":" in lines[0]:
return myReadDict(lines, indentMatch.group(1))
return myMultiline(lines, False)
return lines, myReadOneLine(value)
def myMaybeList(value):
return mYamlMultilineList.match(value)
def myMultilineList(lines, value):
# assume no explcit indentor (otherwise have to parse value)
value = []
indent = 0
while lines:
line = lines.pop(0)
leading = myLeadingSpaces(line)
if myIsAllSpaces(line):
pass
elif leading < indent:
lines.insert(0, line)
break;
else:
indent = indent or leading
value += [myReadOneLine(myRemoveListHeader(indent, line))]
return (lines, value)
def myRemoveListHeader(indent, line):
line = line[indent:]
return mYamlMultilineList.match(line).group(1)
def myReadOneLine(value):
if mYamlListPattern.match(value):
return myFlowList(value)
elif mYamlIntDigits.match(value):
try:
value = int(value)
except ValueError:
pass
elif mYamlFloatDigits.match(value):
try:
value = float(value)
except ValueError:
pass
elif mYamlStringValue.match(value):
value = value[1:-1]
return value
def myFlowList(value):
result = mYamlListPattern.match(value)
values = result.group(1).split(",")
return [myReadOneLine(v.strip()) for v in values]
def myMultiline(lines, preserveNewlines=False):
# assume no explcit indentor (otherwise have to parse value)
value = ""
indent = myLeadingSpaces(lines[0])
wasEmpty = None
while lines:
line = lines.pop(0)
isEmpty = myIsAllSpaces(line)
if isEmpty:
if preserveNewlines:
value += "\n"
elif myLeadingSpaces(line) < indent:
lines.insert(0, line)
break;
else:
if preserveNewlines:
if wasEmpty != None:
value += "\n"
else:
if wasEmpty == False:
value += " "
elif wasEmpty == True:
value += "\n"
value += line[(indent):]
wasEmpty = isEmpty
return (lines, value)
def myIsAllSpaces(line):
return len(line.strip()) == 0
def myLeadingSpaces(line):
return len(line) - len(line.lstrip(' '))

View File

@ -0,0 +1,335 @@
# Copyright (c) 2012 Ecma International. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
#--Imports---------------------------------------------------------------------
import argparse
import os
import sys
import xml.dom.minidom
import base64
import datetime
import shutil
import re
import json
import stat
from _common import convertDocString
#--Stubs-----------------------------------------------------------------------
def generateHarness(harnessType, jsonFile, description):
pass
#------------------------------------------------------------------------------
from _packagerConfig import *
#--Globals---------------------------------------------------------------------
__parser = argparse.ArgumentParser(description= \
'Tool used to generate the test262 website')
__parser.add_argument('version', action='store',
help='Version of the test suite.')
__parser.add_argument('--type', action='store', default=DEFAULT_TESTCASE_TEMPLATE,
help='Type of test case runner to generate.')
__parser.add_argument('--console', action='store_true', default=False,
help='Type of test case runner to generate.')
ARGS = __parser.parse_args()
if not os.path.exists(EXCLUDED_FILENAME):
print "Cannot generate (JSON) test262 tests without a file," + \
" %s, showing which tests have been disabled!" % EXCLUDED_FILENAME
sys.exit(1)
EXCLUDE_LIST = xml.dom.minidom.parse(EXCLUDED_FILENAME)
EXCLUDE_LIST = EXCLUDE_LIST.getElementsByTagName("test")
EXCLUDE_LIST = [x.getAttribute("id") for x in EXCLUDE_LIST]
#a list of all ES5 test chapter directories
TEST_SUITE_SECTIONS = []
#total number of tests accross the entire set of tests.
TOTAL_TEST_COUNT = 0
#List of all *.json files containing encoded test cases
SECTIONS_LIST = []
#--Sanity checks--------------------------------------------------------------#
if not os.path.exists(TEST262_CASES_DIR):
print "Cannot generate (JSON) test262 tests when the path containing said tests, %s, does not exist!" % TEST262_CASES_DIR
sys.exit(1)
if not os.path.exists(TEST262_HARNESS_DIR):
print "Cannot copy the test harness from a path, %s, that does not exist!" % TEST262_HARNESS_DIR
sys.exit(1)
if not os.path.exists(TEST262_WEB_CASES_DIR):
os.mkdir(TEST262_WEB_CASES_DIR)
if not os.path.exists(TEST262_WEB_HARNESS_DIR):
os.mkdir(TEST262_WEB_HARNESS_DIR)
if not hasattr(ARGS, "version"):
print "A test262 suite version must be specified from the command-line to run this script!"
sys.exit(1)
#--Helpers--------------------------------------------------------------------#
def createDepDirs(dirName):
#base case
if dirName==os.path.dirname(dirName):
if not os.path.exists(dirName):
os.mkdir(dirName)
else:
if not os.path.exists(dirName):
createDepDirs(os.path.dirname(dirName))
os.mkdir(dirName)
def test262PathToConsoleFile(path):
stuff = os.path.join(TEST262_CONSOLE_CASES_DIR,
path.replace("/", os.path.sep))
createDepDirs(os.path.dirname(stuff))
return stuff
def getJSCount(dirName):
'''
Returns the total number of *.js files (recursively) under a given
directory, dirName.
'''
retVal = 0
if os.path.isfile(dirName) and dirName.endswith(".js"):
retVal = 1
elif os.path.isdir(dirName):
tempList = [os.path.join(dirName, x) for x in os.listdir(dirName)]
for x in tempList:
retVal += getJSCount(x)
#else:
# raise Exception("getJSCount: encountered a non-file/non-dir!")
return retVal
#------------------------------------------------------------------------------
def dirWalker(dirName):
'''
Populates TEST_SUITE_SECTIONS with ES5 test directories based
upon the number of test files per directory.
'''
global TEST_SUITE_SECTIONS
#First check to see if it has test files directly inside it
temp = [os.path.join(dirName, x) for x in os.listdir(dirName) \
if not os.path.isdir(os.path.join(dirName, x))]
if len(temp)!=0:
TEST_SUITE_SECTIONS.append(dirName)
return
#Next check to see if all *.js files under this directory exceed our max
#for a JSON file
temp = getJSCount(dirName)
if temp==0:
print "ERROR: expected there to be JavaScript tests under dirName!"
sys.exit(1)
#TODO - commenting out this elif/else clause seems to be causing *.json
#naming conflicts WRT Sputnik test dirs.
# elif temp < MAX_CASES_PER_JSON:
TEST_SUITE_SECTIONS.append(dirName)
return
#TODO else:
# #Max has been exceeded. We need to look at each subdir individually
# temp = os.listdir(dirName)
# for tempSubdir in temp:
# dirWalker(os.path.join(dirName, tempSubdir))
#------------------------------------------------------------------------------
def isTestStarted(line):
'''
Used to detect if we've gone past extraneous test comments in a test case.
Note this is a naive approach on the sense that "/*abc*/" could be on one
line. However, we know for a fact this is not the case in IE Test Center
or Sputnik tests.
'''
if re.search("^\s*//", line)!=None: #//blah
return False
elif ("//" in line) and ("Copyright " in line):
#BOM hack
return False
elif re.match("^\s*$", line)!=None: #newlines
return False
return True
#------------------------------------------------------------------------------
def getAllJSFiles(dirName):
retVal = []
for fullPath,dontCare,files in os.walk(dirName):
retVal += [os.path.join(fullPath,b) for b in files if b.endswith(".js")]
return retVal
#--MAIN------------------------------------------------------------------------
for temp in os.listdir(TEST262_CASES_DIR):
temp = os.path.join(TEST262_CASES_DIR, temp)
if not os.path.exists(temp):
print "The expected ES5 test directory,", temp, "did not exist!"
sys.exit(1)
if temp.find("/.") != -1:
# skip hidden files on Unix, such as ".DS_Store" on Mac
continue
if not ONE_JSON_PER_CHAPTER:
dirWalker(temp)
else:
TEST_SUITE_SECTIONS.append(temp)
for chapter in TEST_SUITE_SECTIONS:
chapterName = chapter.rsplit(os.path.sep, 1)[1]
print "Generating test cases for ES5 chapter:", chapterName
#create dictionaries for all our tests and a section
testsList = {}
sect = {}
sect["name"] = "Chapter - " + chapterName
#create an array for tests in a chapter
tests = []
sourceFiles = getAllJSFiles(chapter)
if len(sourceFiles)!=0:
excluded = 0
testCount = 0
for test in sourceFiles:
#TODO - use something other than the hard-coded 'TestCases' below
testPath = "TestCases" + \
test.split(TEST262_CASES_DIR, 1)[1].replace("\\", "/")
testName=test.rsplit(".", 1)[0]
testName=testName.rsplit(os.path.sep, 1)[1]
if EXCLUDE_LIST.count(testName)==0:
# dictionary for each test
testDict = {}
testDict["path"] = testPath
tempFile = open(test, "rb")
scriptCode = tempFile.readlines()
tempFile.close()
scriptCodeContent=""
#Rip out license headers that add unnecessary bytes to
#the JSON'ized test cases
inBeginning = True
#Hack to preserve the BOM
if "Copyright " in scriptCode[0]:
scriptCodeContent += scriptCode[0]
for line in scriptCode:
if inBeginning:
isStarted = isTestStarted(line)
if not isStarted:
continue
inBeginning = False
scriptCodeContent += line
if scriptCodeContent==scriptCode[0]:
print "WARNING (" + test + \
"): unable to strip comments/license header/etc."
scriptCodeContent = "".join(scriptCode)
scriptCodeContentB64 = base64.b64encode(scriptCodeContent)
#add the test encoded code node to our test dictionary
testDict["code"] = scriptCodeContentB64
#now close the dictionary for the test
#now get the metadata added.
tempDict = convertDocString("".join(scriptCode))
for tempKey in tempDict.keys():
#path is set from the file path above; the "@path" property
#in comments is redundant
if not (tempKey in ["path"]):
testDict[tempKey] = tempDict[tempKey]
#this adds the test to our tests array
tests.append(testDict)
if ARGS.console:
with open(test262PathToConsoleFile(testDict["path"]),
"w") as fConsole:
fConsole.write(scriptCodeContent)
with open(test262PathToConsoleFile(testDict["path"][:-3] + \
"_metadata.js"),
"w") as fConsoleMeta:
metaDict = testDict.copy()
del metaDict["code"]
fConsoleMeta.write("testDescrip = " + str(metaDict))
testCount += 1
else:
print "Excluded:", testName
excluded = excluded + 1
#we have completed our tests
# add section node, number of tests and the tests themselves.
sect["numTests"] = str(len(sourceFiles)-excluded)
sect["tests"] = tests
#create a node for the tests and add it to our testsLists
testsList["testsCollection"] = sect
with open(os.path.join(TEST262_WEB_CASES_DIR, chapterName + ".json"),
"w") as f:
json.dump(testsList, f, separators=(',',':'), sort_keys=True,
indent=0)
if TESTCASELIST_PER_JSON:
CHAPTER_TEST_CASES_JSON = {}
CHAPTER_TEST_CASES_JSON["numTests"] = int(sect["numTests"])
CHAPTER_TEST_CASES_JSON["testSuite"] = \
[WEBSITE_CASES_PATH + chapterName + ".json"]
with open(os.path.join(TEST262_WEB_CASES_DIR,
"testcases_%s.json" % chapterName),
"w") as f:
json.dump(CHAPTER_TEST_CASES_JSON, f, separators=(',',':'),
sort_keys=True, indent=0)
generateHarness(ARGS.type, "testcases_%s.json" % chapterName,
chapterName.replace("ch", "Chapter "))
#add the name of the chapter test to our complete list
tempBool = True
for tempRe in WEBSITE_EXCLUDE_RE_LIST:
if tempRe.search(chapterName)!=None:
tempBool = False
if tempBool:
SECTIONS_LIST.append(WEBSITE_CASES_PATH + chapterName + ".json")
TOTAL_TEST_COUNT += int(sect["numTests"])
#we now have the list of files for each chapter
#create a root node for our suite
TEST_CASES_JSON = {}
TEST_CASES_JSON["numTests"] = TOTAL_TEST_COUNT
TEST_CASES_JSON["testSuite"] = SECTIONS_LIST
with open(os.path.join(TEST262_WEB_CASES_DIR, "default.json"), "w") as f:
json.dump(TEST_CASES_JSON, f, separators=(',',':'), sort_keys=True, indent=0)
generateHarness(ARGS.type, "default.json", "Chapters 1-16")
#Overall description of this version of the test suite
SUITE_DESCRIP_JSON = {}
SUITE_DESCRIP_JSON["version"] = ARGS.version
SUITE_DESCRIP_JSON["date"] = str(datetime.datetime.now().date())
with open(os.path.join(TEST262_WEB_CASES_DIR, "suiteDescrip.json"), "w") as f:
json.dump(SUITE_DESCRIP_JSON, f, separators=(',',':'), sort_keys=True)
#Deploy test harness to website as well
print ""
print "Deploying test harness files to 'TEST262_WEB_HARNESS_DIR'..."
if TEST262_HARNESS_DIR!=TEST262_WEB_HARNESS_DIR:
for filename in [x for x in os.listdir(TEST262_HARNESS_DIR) \
if x.endswith(".js")]:
toFilenameList = [ os.path.join(TEST262_WEB_HARNESS_DIR, filename)]
if ARGS.console:
toFilenameList.append(os.path.join(TEST262_CONSOLE_HARNESS_DIR,
filename))
for toFilename in toFilenameList:
if not os.path.exists(os.path.dirname(toFilename)):
os.mkdir(os.path.dirname(toFilename))
fileExists = os.path.exists(toFilename)
if fileExists:
SC_HELPER.edit(toFilename)
shutil.copy(os.path.join(TEST262_HARNESS_DIR, filename),
toFilename)
if not fileExists:
SC_HELPER.add(toFilename)
print "Done."

View File

@ -0,0 +1,117 @@
# Copyright (c) 2012 Ecma International. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
#--Imports---------------------------------------------------------------------
import os
import subprocess
import stat
import re
#--Globals---------------------------------------------------------------------
MAX_CASES_PER_JSON = 1000
WEBSITE_SHORT_NAME = "website"
CONSOLE_SHORT_NAME = "console"
DEFAULT_TESTCASE_TEMPLATE="test262"
ONE_JSON_PER_CHAPTER = False
TESTCASELIST_PER_JSON = True
#Path to the root of the Hg repository (relative to this file's location)
TEST262_ROOT = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")
TEST262_ROOT = os.path.abspath(TEST262_ROOT)
#Directory full of test cases we want to port to the website's test
#harness runner
TEST262_CASES_DIR = os.path.join(TEST262_ROOT, "test")
#Directory containing test harness files to be ported over to the
#website. Note that only *.js files will be migrated from this dir.
TEST262_HARNESS_DIR = os.path.join(TEST262_ROOT, "harness")
#Directory full of website test cases (ported over from TEST262_CASES_DIR)
TEST262_WEB_CASES_DIR = os.path.join(TEST262_ROOT, WEBSITE_SHORT_NAME, "json")
TEST262_CONSOLE_CASES_DIR = os.path.join(TEST262_ROOT, CONSOLE_SHORT_NAME)
#Directory containing the website's test harness (ported over from
#TEST262_HARNESS_DIR)
TEST262_WEB_HARNESS_DIR = os.path.join(TEST262_ROOT, WEBSITE_SHORT_NAME,
"harness")
TEST262_CONSOLE_HARNESS_DIR = os.path.join(TEST262_ROOT, CONSOLE_SHORT_NAME,
"harness")
#Path to the ported test case files on the actual website as opposed
#to the Hg layout
WEBSITE_CASES_PATH = "json/"
#The name of a file which contains a list of tests which should be
#disabled in test262. These tests are either invalid as-per ES5 or
#have issues with the test262 web harness.
EXCLUDED_FILENAME = os.path.join(TEST262_ROOT, "excludelist.xml")
WEBSITE_EXCLUDE_RE_LIST = ["bestPractice", "intl402"]
WEBSITE_EXCLUDE_RE_LIST = [ re.compile(x) for x in WEBSITE_EXCLUDE_RE_LIST]
#------------------------------------------------------------------------------
TEMPLATE_LINES = None
__lastHarnessType = None
def generateHarness(harnessType, jsonName, title):
global TEMPLATE_LINES
global __lastHarnessType
#TODO: temp hack to make experimental internationalization tests work
if jsonName=="testcases_intl402.json":
harnessType = "intl402"
elif jsonName=="testcases_bestPractice.json":
harnessType = "bestPractice"
if TEMPLATE_LINES==None or harnessType!=__lastHarnessType:
__lastHarnessType = harnessType
TEMPLATE_LINES = []
with open(os.path.join(os.getcwd(), "templates",
"runner." + harnessType + ".html"), "r") as f:
TEMPLATE_LINES = f.readlines()
fileName = os.path.join(TEST262_ROOT, WEBSITE_SHORT_NAME,
jsonName.replace(".json", ".html"))
fileNameExists = False
if os.path.exists(fileName):
SC_HELPER.edit(fileName)
fileNameExists = True
with open(fileName, "w") as f:
for line in TEMPLATE_LINES:
if "var TEST_LIST_PATH =" in line:
f.write(" var TEST_LIST_PATH = \"json/" + jsonName + \
"\";" + os.linesep)
#elif "ECMAScript 5" in line:
# f.write(line.replace("ECMAScript 5",
# "ECMAScript 5: %s" % title))
else:
f.write(line)
if not fileNameExists:
SC_HELPER.add(fileName)
#------------------------------------------------------------------------------
class SCAbstraction(object):
'''
A class which abstracts working with source control systems in relation to
generated test262 files. Useful when test262 is also used internally by
browser implementors.
'''
def edit(self, filename):
'''
Source control edit of a file. For Mercurial, just make sure it's
writable.
'''
if not(os.stat(filename).st_mode & stat.S_IWRITE):
os.chmod(filename, stat.S_IWRITE)
def add(self, filename):
'''
Source control add of a file.
'''
subprocess.call(["git", "add", filename])
SC_HELPER = SCAbstraction()

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python
# Copyright 2011 by Google, Inc. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
# TODO: resolve differences with common.py and unify into one file.
from __future__ import print_function
import os
import re
import imp
from _monkeyYaml import load as yamlLoad
#def onerror(message):
# print(message)
# Matches trailing whitespace and any following blank lines.
_BLANK_LINES = r"([ \t]*[\r\n]{1,2})*"
# Matches the YAML frontmatter block.
_YAML_PATTERN = re.compile(r"/\*---(.*)---\*/" + _BLANK_LINES, re.DOTALL)
# Matches all known variants for the license block.
# https://github.com/tc39/test262/blob/705d78299cf786c84fa4df473eff98374de7135a/tools/lint/lib/checks/license.py
_LICENSE_PATTERN = re.compile(
r'// Copyright( \([C]\))? (\w+) .+\. {1,2}All rights reserved\.[\r\n]{1,2}' +
r'(' +
r'// This code is governed by the( BSD)? license found in the LICENSE file\.' +
r'|' +
r'// See LICENSE for details.' +
r'|' +
r'// Use of this source code is governed by a BSD-style license that can be[\r\n]{1,2}' +
r'// found in the LICENSE file\.' +
r'|' +
r'// See LICENSE or https://github\.com/tc39/test262/blob/(master|HEAD)/LICENSE' +
r')' + _BLANK_LINES, re.IGNORECASE)
def yamlAttrParser(testRecord, attrs, name, onerror = print):
parsed = yamlLoad(attrs)
if parsed is None:
onerror("Failed to parse yaml in name %s" % name)
return
for key in parsed:
value = parsed[key]
if key == "info":
key = "commentary"
testRecord[key] = value
if 'flags' in testRecord:
for flag in testRecord['flags']:
testRecord[flag] = ""
def findLicense(src):
match = _LICENSE_PATTERN.search(src)
if not match:
return None
return match.group(0)
def findAttrs(src):
match = _YAML_PATTERN.search(src)
if not match:
return (None, None)
return (match.group(0), match.group(1).strip())
def parseTestRecord(src, name, onerror = print):
# Find the license block.
header = findLicense(src)
# Find the YAML frontmatter.
(frontmatter, attrs) = findAttrs(src)
# YAML frontmatter is required for all tests.
if frontmatter is None:
onerror("Missing frontmatter: %s" % name)
# The license shuold be placed before the frontmatter and there shouldn't be
# any extra content between the license and the frontmatter.
if header is not None and frontmatter is not None:
headerIdx = src.index(header)
frontmatterIdx = src.index(frontmatter)
if headerIdx > frontmatterIdx:
onerror("Unexpected license after frontmatter: %s" % name)
# Search for any extra test content, but ignore whitespace only or comment lines.
extra = src[headerIdx + len(header) : frontmatterIdx]
if extra and any(line.strip() and not line.lstrip().startswith("//") for line in extra.split("\n")):
onerror("Unexpected test content between license and frontmatter: %s" % name)
# Remove the license and YAML parts from the actual test content.
test = src
if frontmatter is not None:
test = test.replace(frontmatter, '')
if header is not None:
test = test.replace(header, '')
testRecord = {}
testRecord['header'] = header.strip() if header else ''
testRecord['test'] = test
if attrs:
yamlAttrParser(testRecord, attrs, name, onerror)
# Report if the license block is missing in non-generated tests.
if header is None and "generated" not in testRecord and "hashbang" not in name:
onerror("No license found in: %s" % name)
return testRecord

View File

@ -0,0 +1,170 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript" src="scripts/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="scripts/sections.js"></script>
<script type="text/javascript">
//Globals
var STANDARD = "ECMA-262";
var TEST_LIST_PATH = "json/testcaseslist.json";
</script>
<script type="text/javascript" src="scripts/sth.js"></script>
<script type="text/javascript" src="harness/sta.js"></script>
<script type="text/javascript" src="scripts/lib/jqueryprogressbar.js"></script>
<script type="text/javascript" src="scripts/helper.js"></script>
<script type="text/javascript" src="scripts/lib/jquery.base64.js"></script>
<script type="text/javascript">
//To support all the browsers
$(window).resize(ResizeLoadIndicator);
$(window).load(ResizeLoadIndicator);
function ResizeLoadIndicator() {
$(".indicatorContainer .disabledBackground").css({ height: ($(window).height() - 20) + "px" });
}
$(".indicatorContainer").click(function(e) {
if (!e) { var e = window.event; }
e.cancelBubble = true;
if (e.stopPropagation) { e.stopPropagation(); }
});
</script>
<title>ECMAScript Best Practices test262</title>
<link href="styles/style.css" media="screen" rel="stylesheet" title="CSS" type="text/css" />
</head>
<body>
<div class="indicatorContainer">
<!--Blank div to disable back portion when indicator is shown-->
<div class="disabledBackground"></div>
<div id="loadingIndicator">
<div>
<img src="./images/spinner.gif" alt="Loading..." />
<span>Loading...</span>
</div>
</div>
</div>
<div class="wrapper">
<!-- This Container holds the main header -->
<div class="mainHeader">
<p><span id="ECMAscript">ECMA</span><span id="ecmaSCRIPT">Script</span> <strong>Best Practices</strong> test262
<a id="ecmascriptbacklink" href='javascript:void(window.open("http://www.ecmascript.org/"));'>ECMAScript.org</a></p>
</div>
<!-- This Container holds the Navigation -->
<div class="navBar">
<ul>
<li><a href="#" class="selected nav-link" id="home">Home</a></li>
<li><a href="#" class="nav-link" id="run">Run</a></li>
<li><a href="#" class="nav-link test-report-link" id="results">Results</a></li>
<li><a href="#" class="nav-link" id="development">Development</a></li>
</ul>
</div>
<div class="content-container" id="contentContainer">
<!-- This is the Main Content Container -->
<div class="content-home">
<p class="headers">What is test262 <i>Best Practices</i>?</p>
<p class="content"><i>test262 Best Practices</i> is a supplemental test suite to <a href="default.html">test262</a> containing test cases that are <b>not</b> required by the ECMAScript specification, but deemed best practices for JavaScript implementers by Ecma's TC-39 committee.</p>
<p class="headers">Running the Tests</p>
<p class="content">Click the “Run” tab at the top of this page for instructions and follow the instructions to run the tests.</p>
<a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'></a>
</div>
<div class="content-dev">
<p class="headers">Development</p>
<p class="content">Test262 is being developed by the members of Ecma TC39. Ecma's intellectual property policies, permit only Ecma
members to directly contribute code to the project. However, a <a href='javascript:void(window.open("http://mail.mozilla.org/pipermail/test262-discuss/"));'>public mailing list</a> is used to coordinate development of Test262. If you wish to participate in the discussion please <a href='javascript:void(window.open("http://mail.mozilla.org/listinfo/test262-discuss"));'>subscribe</a>. Bug reports and suggestions should be sent to the mailing list.
</p>
<p class="content">
Ecma members can find detailed instructions on Test262 development procedures at the <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id=test262:test262"));'>Test262 Wiki</a>.
</p>
</div>
<div class="content-tests">
<!-- This is the Main Content Container -->
<p class="content">Please click on the Run All button to run all the tests. Once you start the test you may pause the test anytime by clicking on the Pause button. You can click on the Results tab once the test is completed or after pausing the test. The Reset button is for restarting the test run. You may run individual tests by clicking the Run button next to the tests listed below. If you wish to run several chapters in sequence, but not the entire test suite, click the Select button for the chapters you wish to run and then click the Run Selected button.</p>
<!-- This is the Progress Bar Holder -->
<div class="progressBarHolder">
<div id="progressbar"></div>
<div class="progressBarButtons">
<!-- Loading: Run All, Run Selected -->
<!-- Loaded: Run All, Run Selected -->
<!-- Running: Pause -->
<!-- Paused: Resume, Reset -->
<img src="images/runall.png" alt="Run All" title="Run all tests." id="btnRunAll" />
<img src="images/runselected.png" alt="Run Selected Tests" title="Run the tests selected below." id="btnRunSelected" />
<img src="images/pause.png" alt="Pause" title="Pause the running tests." id="btnPause" />
<img src="images/resume.png" alt="Resume" title="Resume the running tests." id="btnResume" />
<img src="images/reset.png" alt="Reset" title="Reset testing status." id="btnReset" />
</div>
<div style="clear: both;"></div>
</div>
<p class="hide">
Timer Value(ms) : <input id="txtTimerValue" value="50" /> <input id="btnSetTimerValue" value="Set Timer Value" type="button"/>
</p>
<!-- This is the Results Text Holder -->
<div class="resultsHeader">
Tests to run: <strong><span class="teststorun-counter" id="testsToRun"></span></strong>&nbsp;<span class="separator">|</span>
Total tests ran: <strong><span class="total-counter" id="totalCounter"></span></strong> <span class="separator">|</span>
Pass: <span class="pass" id="Pass"></span> <span class="separator">|</span>
Fail: <span class="fail" id="Fail"></span> <span class="separator">|</span>
Failed to load: <span class="fail" id="failedToLoadCounter1"></span>
<p><span id="nextActivity"></span></p>
</div>
<!-- Test Chapter selector -->
<div id="chapterSelector">
<table width="100%" border="0" cellspacing="0" cellpadding="2"></table>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder" id="tableLoggerParent">
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="table-logger" id="tableLogger"></table>
</div>
<div>
Test suite version: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
</div>
<div class="content-results">
<div class="crumbContainer">
<div class="crumbs"></div>
<div style="float:right;"><a class="setBlue hide" id="backlinkDiv" href="#">&lt;&lt; back</a></div>
<div style="clear : both;"></div>
</div>
<div class="resultsHeader"> <strong>Total tests: <span class="totalCases"></span></strong><br />
Passed: <span class="passedCases"></span> <span class="separator">|</span> Failed: <span class="failedCases"></span> <span class="separator">|</span>
Failed to load: <strong><span id="failedToLoadCounter"></span></strong>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder">
<table width="100%" cellspacing="0" cellpadding="0" border="0" class="results-data-table"> </table>
<div id="resultMessage">Test results will be displayed after the tests are executed using the Run page.</div>
</div>
<div>
Test suite version: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
<div class="downloadLinks">
<p><a class="anchor-download-xml" id="ancGenXMLReport"><strong>Download results as XML</strong></a></p> <!--| <strong><a href="scripts/testcases.zip">Download Source</a></strong></p>-->
</div>
<div id="legend" class="hide">
<label class="reportGreen">Green:</label>&nbsp;100%&nbsp;
<label class="reportLightGreen">Green:</label>&nbsp;75% to 99.9%&nbsp;
<label class="reportYellow">Yellow:</label>&nbsp;50% to 75% &nbsp;
<label class="reportRed">Red:</label>&nbsp;less than 50%
</div>
</div>
</div>
</div>
<!-- This is the Footer -->
<div class="footer">
<!--<div class="Links"> <a href="">Privacy</a> | <a href="">Terms of Use</a> </div>-->
<div class="copyright"> &copy; <a href='javascript:void(window.open("http://www.ecma-international.org"));'>Ecma International</a> </div>
</div>
<iframe id="scriptLoader" class="hide"></iframe>
</body>
</html>

View File

@ -0,0 +1,192 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript" src="scripts/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="scripts/sections.js"></script>
<script type="text/javascript">
//Globals
var STANDARD = "ECMA-402";
var TEST_LIST_PATH = "json/testcaseslist.json";
</script>
<script type="text/javascript" src="scripts/sth.js"></script>
<script type="text/javascript" src="harness/sta.js"></script>
<script type="text/javascript" src="scripts/lib/jqueryprogressbar.js"></script>
<script type="text/javascript" src="scripts/helper.js"></script>
<script type="text/javascript" src="scripts/lib/jquery.base64.js"></script>
<script type="text/javascript">
//To support all the browsers
$(window).resize(ResizeLoadIndicator);
$(window).load(ResizeLoadIndicator);
function ResizeLoadIndicator() {
$(".indicatorContainer .disabledBackground").css({ height: ($(window).height() - 20) + "px" });
}
$(".indicatorContainer").click(function(e) {
if (!e) { var e = window.event; }
e.cancelBubble = true;
if (e.stopPropagation) { e.stopPropagation(); }
});
</script>
<title>ECMAScript Internationalization test402</title>
<link href="styles/style.css" media="screen" rel="stylesheet" title="CSS" type="text/css" />
</head>
<body>
<div class="indicatorContainer">
<!--Blank div to disable back portion when indicator is shown-->
<div class="disabledBackground"></div>
<div id="loadingIndicator">
<div>
<img src="./images/spinner.gif" alt="Loading..." />
<span>Loading...</span>
</div>
</div>
</div>
<div class="wrapper">
<!-- This Container holds the main header -->
<div class="mainHeader">
<p><span id="ECMAscript">ECMA</span><span id="ecmaSCRIPT">Script</span> <strong>Internationalization</strong> test402
<a id="ecmascriptbacklink" href='javascript:void(window.open("http://www.ecmascript.org/"));'>ECMAScript.org</a></p>
</div>
<!-- This Container holds the Navigation -->
<div class="navBar">
<ul>
<li><a href="#" class="selected nav-link" id="home">Home</a></li>
<li><a href="#" class="nav-link" id="run">Run</a></li>
<li><a href="#" class="nav-link test-report-link" id="results">Results</a></li>
<li><a href="#" class="nav-link" id="development">Development</a></li>
</ul>
</div>
<div class="content-container" id="contentContainer">
<!-- This is the Main Content Container -->
<div class="content-home">
<p class="headers">What is test402?</p>
<p class="content">test402 is a test suite intended to check agreement between JavaScript implementations and the ECMAScript Internationalization API Specification.
The test suite contains many individual tests, each of which tests some specific requirements of the ECMAScript Internationalization API Specification.</p>
<p class="headers">What is the ECMAScript Internationalization API?</p>
<p class="content">The ECMAScript Internationalization API is a complement to the ECMAScript Language Specification, 5.1 edition.
It enables internationalization of JavaScript applications by providing collation (string comparison), number formatting, and date and time formatting, and lets applications choose the language and tailor the functionality to their needs.
The ECMAScript Internationalization API Specification 1.0 was approved as an official Ecma standard by the Ecma General Assembly in December 2012.
The ECMAScript Internationalization 1.0 standard is available in
<a href='javascript:void(window.open("http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf"));'>PDF</a>,
<a href='javascript:void(window.open("http://www.ecma-international.org/ecma-402/1.0/"));'>HTML</a>, and
<a href='javascript:void(window.open("http://www.ecma-international.org/ecma-402/1.0/ECMA-402.epub"));'>EPUB</a>
versions from the Ecma International web site.</p>
<p class="headers">What is ECMAScript?</p>
<p class="content">"ECMAScript" is the name under which the language more commonly known as "JavaScript" is standardized. Development of the ECMAScript standard is the responsibility of <a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'>Technical Committee 39 (TC39)</a> of <a href='javascript:void(window.open("http://www.ecma-international.org/"));'>Ecma International</a>.
The ECMAScript Language Specification standard is officially known as ECMA-262.
ECMAScript 5.1 (or just ES5.1) is short hand for the "ECMA-262, 5.1 Edition ECMAScript Language Specification" the official name of the current edition of the standard.
ECMAScript 5.1 was approved as an official Ecma standard by the Ecma General Assembly in June 2011.
The ECMAScript 5.1 standard is available in <a href='javascript:void(window.open("http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf"));'>PDF</a> and <a href='javascript:void(window.open("http://ecma-international.org/ecma-262/5.1/"));'>HTML</a> versions from the Ecma International web site.</p>
<p class="headers">Who creates and maintains test402?</p>
<p class="content">Development of test402 is a project of Ecma TC39.
The testing framework and individual tests are created by member organizations of TC39 and contributed to Ecma for use in test402.
For more information about how test402 is developed and maintained click the “Development” tab at the top of this page.</p>
<p class="headers">What is the status of test402?</p>
<p class="content"><strong>test402 is very very very incomplete.
It is still undergoing active development.</strong></p>
<p class="headers">Where can I find out more?</p>
<p class="content">Please visit our <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id=test262:faq"));'>Frequently Asked Questions</a> section on the <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id="));'>ECMAScript Wiki</a>.</p>
<p class="headers">Running the Tests</p>
<p class="content">Click the “Run” tab at the top of this page for instructions and follow the instructions to run the tests.</p>
<a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'></a>
</div>
<div class="content-dev">
<p class="headers">Development</p>
<p class="content">Test402 is being developed by the members of Ecma TC39. Ecma's intellectual property policies permit only Ecma
members to directly contribute code to the project. However, a <a href='javascript:void(window.open("http://mail.mozilla.org/pipermail/test262-discuss/"));'>public mailing list</a> is used to coordinate development of test402 and its sibling test262. If you wish to participate in the discussion please <a href='javascript:void(window.open("http://mail.mozilla.org/listinfo/test262-discuss"));'>subscribe</a>. Bug reports and suggestions should be sent to the mailing list.
</p>
</div>
<div class="content-tests">
<!-- This is the Main Content Container -->
<p class="content">Please click on the Run All button to run all the tests. Once you start the test you may pause the test anytime by clicking on the Pause button. You can click on the Results tab once the test is completed or after pausing the test. The Reset button is for restarting the test run. You may run individual tests by clicking the Run button next to the tests listed below. If you wish to run several chapters in sequence, but not the entire test suite, click the Select button for the chapters you wish to run and then click the Run Selected button.</p>
<!-- This is the Progress Bar Holder -->
<div class="progressBarHolder">
<div id="progressbar"></div>
<div class="progressBarButtons">
<!-- Loading: Run All, Run Selected -->
<!-- Loaded: Run All, Run Selected -->
<!-- Running: Pause -->
<!-- Paused: Resume, Reset -->
<img src="images/runall.png" alt="Run All" title="Run all tests." id="btnRunAll" />
<img src="images/runselected.png" alt="Run Selected Tests" title="Run the tests selected below." id="btnRunSelected" />
<img src="images/pause.png" alt="Pause" title="Pause the running tests." id="btnPause" />
<img src="images/resume.png" alt="Resume" title="Resume the running tests." id="btnResume" />
<img src="images/reset.png" alt="Reset" title="Reset testing status." id="btnReset" />
</div>
<div style="clear: both;"></div>
</div>
<p class="hide">
Timer Value(ms) : <input id="txtTimerValue" value="50" /> <input id="btnSetTimerValue" value="Set Timer Value" type="button"/>
</p>
<!-- This is the Results Text Holder -->
<div class="resultsHeader">
Tests to run: <strong><span class="teststorun-counter" id="testsToRun"></span></strong>&nbsp;<span class="separator">|</span>
Total tests ran: <strong><span class="total-counter" id="totalCounter"></span></strong> <span class="separator">|</span>
Pass: <span class="pass" id="Pass"></span> <span class="separator">|</span>
Fail: <span class="fail" id="Fail"></span> <span class="separator">|</span>
Failed to load: <span class="fail" id="failedToLoadCounter1"></span>
<p><span id="nextActivity"></span></p>
</div>
<!-- Test Chapter selector -->
<div id="chapterSelector">
<table width="100%" border="0" cellspacing="0" cellpadding="2"></table>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder" id="tableLoggerParent">
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="table-logger" id="tableLogger"></table>
</div>
<div>
Test suite version: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
</div>
<div class="content-results">
<div class="crumbContainer">
<div class="crumbs"></div>
<div style="float:right;"><a class="setBlue hide" id="backlinkDiv" href="#">&lt;&lt; back</a></div>
<div style="clear : both;"></div>
</div>
<div class="resultsHeader"> <strong>Total tests: <span class="totalCases"></span></strong><br />
Passed: <span class="passedCases"></span> <span class="separator">|</span> Failed: <span class="failedCases"></span> <span class="separator">|</span>
Failed to load: <strong><span id="failedToLoadCounter"></span></strong>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder">
<table width="100%" cellspacing="0" cellpadding="0" border="0" class="results-data-table"> </table>
<div id="resultMessage">Test results will be displayed after the tests are executed using the Run page.</div>
</div>
<div>
Test suite version: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
<div class="downloadLinks">
<p><a class="anchor-download-xml" id="ancGenXMLReport"><strong>Download results as XML</strong></a></p> <!--| <strong><a href="scripts/testcases.zip">Download Source</a></strong></p>-->
</div>
<div id="legend" class="hide">
<label class="reportGreen">Green:</label>&nbsp;100%&nbsp;
<label class="reportLightGreen">Green:</label>&nbsp;75% to 99.9%&nbsp;
<label class="reportYellow">Yellow:</label>&nbsp;50% to 75% &nbsp;
<label class="reportRed">Red:</label>&nbsp;less than 50%
</div>
</div>
</div>
</div>
<!-- This is the Footer -->
<div class="footer">
<!--<div class="Links"> <a href="">Privacy</a> | <a href="">Terms of Use</a> </div>-->
<div class="copyright"> &copy; <a href='javascript:void(window.open("http://www.ecma-international.org"));'>Ecma International</a> </div>
</div>
<iframe id="scriptLoader" class="hide"></iframe>
</body>
</html>

View File

@ -0,0 +1,203 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript" src="scripts/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="scripts/sections.js"></script>
<script type="text/javascript">
//Globals
var STANDARD = "ECMA-262";
var TEST_LIST_PATH = "json/testcaseslist.json";
</script>
<script type="text/javascript" src="scripts/sth.js"></script>
<script type="text/javascript" src="harness/sta.js"></script>
<script type="text/javascript" src="scripts/lib/jqueryprogressbar.js"></script>
<script type="text/javascript" src="scripts/helper.js"></script>
<script type="text/javascript" src="scripts/lib/jquery.base64.js"></script>
<script type="text/javascript">
//To support all the browsers
$(window).resize(ResizeLoadIndicator);
$(window).load(ResizeLoadIndicator);
function ResizeLoadIndicator() {
$(".indicatorContainer .disabledBackground").css({ height: ($(window).height() - 20) + "px" });
}
$(".indicatorContainer").click(function(e) {
if (!e) { var e = window.event; }
e.cancelBubble = true;
if (e.stopPropagation) { e.stopPropagation(); }
});
</script>
<title>ECMAScript Language test262</title>
<link href="styles/style.css" media="screen" rel="stylesheet" title="CSS" type="text/css" />
</head>
<body>
<div class="indicatorContainer">
<!--Blank div to disable back portion when indicator is shown-->
<div class="disabledBackground"></div>
<div id="loadingIndicator">
<div>
<img src="./images/spinner.gif" alt="Loading..." />
<span>Loading...</span>
</div>
</div>
</div>
<div class="wrapper">
<!-- This Container holds the main header -->
<div class="mainHeader">
<p><span id="ECMAscript">ECMA</span><span id="ecmaSCRIPT">Script</span> <strong>Language</strong> test262
<a id="ecmascriptbacklink" href='javascript:void(window.open("http://www.ecmascript.org/"));'>ECMAScript.org</a></p>
</div>
<!-- This Container holds the Navigation -->
<div class="navBar">
<ul>
<li><a href="#" class="selected nav-link" id="home">Home</a></li>
<li><a href="#" class="nav-link" id="run">Run</a></li>
<li><a href="#" class="nav-link test-report-link" id="results">Results</a></li>
<li><a href="#" class="nav-link" id="development">Development</a></li>
</ul>
</div>
<div class="content-container" id="contentContainer">
<!-- This is the Main Content Container -->
<div class="content-home">
<p class="headers">What is test262?</p>
<p class="content">test262 is a test suite intended to check agreement between JavaScript implementations and ECMA-262, the ECMAScript Language Specification (currently 5.1 Edition).
The test suite contains thousands of individual tests, each of which tests some specific requirements of the ECMAScript Language Specification.</p>
<p class="headers">What is ECMAScript?</p>
<p class="content">"ECMAScript" is the name under which the language more commonly known as "JavaScript" is standardized. Development of the ECMAScript standard is the responsibility of <a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'>Technical Committee 39 (TC39)</a> of <a href='javascript:void(window.open("http://www.ecma-international.org/"));'>Ecma International</a>.
The ECMAScript Language Specification standard is officially known as ECMA-262.
ECMAScript 5.1 (or just ES5.1) is short hand for the "ECMA-262, 5.1 Edition ECMAScript Language Specification" the official name of the current edition of the standard.
ECMAScript 5.1 was approved as an official Ecma standard by the Ecma General Assembly in June 2011.
The ECMAScript 5.1 standard is available in <a href='javascript:void(window.open("http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf"));'>PDF</a> and <a href='javascript:void(window.open("http://ecma-international.org/ecma-262/5.1/"));'>HTML</a> versions from the Ecma International web site.</p>
<p class="headers">Who creates and maintains test262?</p>
<p class="content">
Development of test262 is a project of Ecma TC39. The
testing framework and individual tests are created by
developers all over the world and contributed to Ecma for
use in test262. For more information about how test262 is
developed and maintained, click the
&#8220;Development&#8221; tab at the top of this page.
</p>
<p class="headers">What is the status of test262?</p>
<p class="content"><strong>test262 is not yet complete. It is still undergoing active development.</strong> Some portions of the ES5 specification have very complete test coverage while other portions of the specification have only partial test coverage. Some tests may be invalid or may yield false positive or false negative results. A perfect passing score on test262 does not guarantee that a JavaScript implementation perfectly supports ES5. Because tests are being actively added and modified, tests results from different days or times may not be directly comparable. Click the “Development” tab at the top of this page for instructions for reporting test262 bugs.</p>
<p class="headers">Where can I find out more?</p>
<p class="content">Please visit our <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id=test262:faq"));'>Frequently Asked Questions</a> section on the <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id="));'>ECMAScript Wiki</a>.</p>
<p class="headers">Running the Tests</p>
<p class="content">Click the “Run” tab at the top of this page for instructions and follow the instructions to run the tests.</p>
<a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'></a>
</div>
<div class="content-dev">
<p class="headers">Development</p>
<p class="content">
Test262 is being developed as an open source project and
the maintainers are accepting patches from the community.
The project is maintained using <a
href='javascript:void(window.open("https://git-scm.com/"));'>the
git version control system</a> and is <a
href='javascript:void(window.open("https://github.com/tc39/test262"));'>currently
hosted on GitHub.com</a>. Bug reports and patches may be
submitted to the GitHub repository.
</p>
<p class="content">
A <a
href='javascript:void(window.open("http://mail.mozilla.org/pipermail/test262-discuss/"));'>public
mailing list</a> is used to coordinate development of
test262. If you wish to participate in the discussion,
please <a
href='javascript:void(window.open("http://mail.mozilla.org/listinfo/test262-discuss"));'>subscribe</a>.
</p>
</div>
<div class="content-tests">
<!-- This is the Main Content Container -->
<p class="content">Please click on the Run All button to run all the tests. Once you start the test you may pause the test anytime by clicking on the Pause button. You can click on the Results tab once the test is completed or after pausing the test. The Reset button is for restarting the test run. You may run individual tests by clicking the Run button next to the tests listed below. If you wish to run several chapters in sequence, but not the entire test suite, click the Select button for the chapters you wish to run and then click the Run Selected button.</p>
<!-- This is the Progress Bar Holder -->
<div class="progressBarHolder">
<div id="progressbar"></div>
<div class="progressBarButtons">
<!-- Loading: Run All, Run Selected -->
<!-- Loaded: Run All, Run Selected -->
<!-- Running: Pause -->
<!-- Paused: Resume, Reset -->
<img src="images/runall.png" alt="Run All" title="Run all tests." id="btnRunAll" />
<img src="images/runselected.png" alt="Run Selected Tests" title="Run the tests selected below." id="btnRunSelected" />
<img src="images/pause.png" alt="Pause" title="Pause the running tests." id="btnPause" />
<img src="images/resume.png" alt="Resume" title="Resume the running tests." id="btnResume" />
<img src="images/reset.png" alt="Reset" title="Reset testing status." id="btnReset" />
</div>
<div style="clear: both;"></div>
</div>
<p class="hide">
Timer Value(ms) : <input id="txtTimerValue" value="50" /> <input id="btnSetTimerValue" value="Set Timer Value" type="button"/>
</p>
<!-- This is the Results Text Holder -->
<div class="resultsHeader">
Tests To run: <strong><span class="teststorun-counter" id="testsToRun"></span></strong>&nbsp;<span class="separator">|</span>
Total tests ran: <strong><span class="total-counter" id="totalCounter"></span></strong> <span class="separator">|</span>
Pass: <span class="pass" id="Pass"></span> <span class="separator">|</span>
Fail: <span class="fail" id="Fail"></span> <span class="separator">|</span>
Failed to load: <span class="fail" id="failedToLoadCounter1"></span>
<p><span id="nextActivity"></span></p>
</div>
<!-- Test Chapter selector -->
<div id="chapterSelector">
<table width="100%" border="0" cellspacing="0" cellpadding="2"></table>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder" id="tableLoggerParent">
<table width="100%" border="0" cellspacing="0" cellpadding="0" class="table-logger" id="tableLogger"></table>
</div>
<div>
Test suite version: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
</div>
<div class="content-results">
<div class="crumbContainer">
<div class="crumbs"></div>
<div style="float:right;"><a class="setBlue hide" id="backlinkDiv" href="#">&lt;&lt; back</a></div>
<div style="clear : both;"></div>
</div>
<div class="resultsHeader"> <strong>Total tests: <span class="totalCases"></span></strong><br />
Passed: <span class="passedCases"></span> <span class="separator">|</span> Failed: <span class="failedCases"></span> <span class="separator">|</span>
Failed to load: <strong><span id="failedToLoadCounter"></span></strong>
</div>
<!-- This is the Table -->
<div class="resultsTableHolder">
<table width="100%" cellspacing="0" cellpadding="0" border="0" class="results-data-table"> </table>
<div id="resultMessage">Test results will be displayed after the tests are executed using the Run page.</div>
</div>
<div>
Test suite version.: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test suite date: <span class="targetTestSuiteDate"></span>
</div>
<div class="downloadLinks">
<p><a class="anchor-download-xml" id="ancGenXMLReport"><strong>Download results as XML</strong></a></p> <!--| <strong><a href="scripts/testcases.zip">Download Source</a></strong></p>-->
</div>
<div id="legend" class="hide">
<label class="reportGreen">Green:</label>&nbsp;100%&nbsp;
<label class="reportLightGreen">Green:</label>&nbsp;75% to 99.9%&nbsp;
<label class="reportYellow">Yellow:</label>&nbsp;50% to 75% &nbsp;
<label class="reportRed">Red:</label>&nbsp;less than 50%
</div>
</div>
</div>
</div>
<!-- This is the Footer -->
<div class="footer">
<!--<div class="Links"> <a href="">Privacy</a> | <a href="">Terms of Use</a> </div>-->
<div class="copyright"> &copy; <a href='javascript:void(window.open("http://www.ecma-international.org"));'>Ecma International</a> </div>
</div>
<iframe id="scriptLoader" class="hide"></iframe>
</body>
</html>

664
third_party/test262-harness/src/test262.py vendored Executable file
View File

@ -0,0 +1,664 @@
#!/usr/bin/env python
# Copyright 2009 the Sputnik authors. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
# This is derived from sputnik.py, the Sputnik console test runner,
# with elements from packager.py, which is separately
# copyrighted. TODO: Refactor so there is less duplication between
# test262.py and packager.py.
import logging
import optparse
import os
from os import path
import platform
import re
import subprocess
import sys
import tempfile
import time
import xml.dom.minidom
import datetime
import shutil
import json
import stat
import xml.etree.ElementTree as xmlj
import unicodedata
from collections import Counter
from parseTestRecord import parseTestRecord, stripHeader
from _packagerConfig import *
class Test262Error(Exception):
def __init__(self, message):
self.message = message
def ReportError(s):
raise Test262Error(s)
if not os.path.exists(EXCLUDED_FILENAME):
print "Cannot generate (JSON) test262 tests without a file," + \
" %s, showing which tests have been disabled!" % EXCLUDED_FILENAME
sys.exit(1)
EXCLUDE_LIST = xml.dom.minidom.parse(EXCLUDED_FILENAME)
EXCLUDE_REASON = EXCLUDE_LIST.getElementsByTagName("reason")
EXCLUDE_LIST = EXCLUDE_LIST.getElementsByTagName("test")
EXCLUDE_LIST = [x.getAttribute("id") for x in EXCLUDE_LIST]
def BuildOptions():
result = optparse.OptionParser()
result.add_option("--command", default=None, help="The command-line to run")
result.add_option("--tests", default=path.abspath('.'),
help="Path to the tests")
result.add_option("--cat", default=False, action="store_true",
help="Print packaged test code that would be run")
result.add_option("--summary", default=False, action="store_true",
help="Print summary after running tests")
result.add_option("--full-summary", default=False, action="store_true",
help="Print summary and test output after running tests")
result.add_option("--strict_only", default=False, action="store_true",
help="Test only strict mode")
result.add_option("--non_strict_only", default=False, action="store_true",
help="Test only non-strict mode")
result.add_option("--unmarked_default", default="both",
help="default mode for tests of unspecified strictness")
result.add_option("--logname", help="Filename to save stdout to")
result.add_option("--junitname", help="Filename to save test results in JUnit XML format")
result.add_option("--loglevel", default="warning",
help="sets log level to debug, info, warning, error, or critical")
result.add_option("--print-handle", default="print", help="Command to print from console")
result.add_option("--list-includes", default=False, action="store_true",
help="List includes required by tests")
return result
def ValidateOptions(options):
if not options.command:
ReportError("A --command must be specified.")
if not path.exists(options.tests):
ReportError("Couldn't find test path '%s'" % options.tests)
placeHolderPattern = re.compile(r"\{\{(\w+)\}\}")
def IsWindows():
p = platform.system()
return (p == 'Windows') or (p == 'Microsoft')
class TempFile(object):
def __init__(self, suffix="", prefix="tmp", text=False):
self.suffix = suffix
self.prefix = prefix
self.text = text
self.fd = None
self.name = None
self.is_closed = False
self.Open()
def Open(self):
(self.fd, self.name) = tempfile.mkstemp(
suffix = self.suffix,
prefix = self.prefix,
text = self.text)
def Write(self, str):
os.write(self.fd, str)
def Read(self):
f = file(self.name)
result = f.read()
f.close()
return result
def Close(self):
if not self.is_closed:
self.is_closed = True
os.close(self.fd)
def Dispose(self):
try:
self.Close()
os.unlink(self.name)
except OSError, e:
logging.error("Error disposing temp file: %s", str(e))
class TestResult(object):
def __init__(self, exit_code, stdout, stderr, case):
self.exit_code = exit_code
self.stdout = stdout
self.stderr = stderr
self.case = case
def ReportOutcome(self, long_format):
name = self.case.GetName()
mode = self.case.GetMode()
if self.HasUnexpectedOutcome():
if self.case.IsNegative():
print "=== %s was expected to fail in %s, but didn't ===" % (name, mode)
print "--- expected error: %s ---\n" % self.case.GetNegativeType()
else:
if long_format:
print "=== %s failed in %s ===" % (name, mode)
else:
print "%s in %s: " % (name, mode)
self.WriteOutput(sys.stdout)
if long_format:
print "==="
elif self.case.IsNegative():
print "%s failed in %s as expected" % (name, mode)
else:
print "%s passed in %s" % (name, mode)
def WriteOutput(self, target):
out = self.stdout.strip()
if len(out) > 0:
target.write("--- output --- \n %s" % out)
err = self.stderr.strip()
if len(err) > 0:
target.write("--- errors --- \n %s" % err)
# This is a way to make the output from the "whitespace" tests into valid XML
def SafeFormat(self, msg):
try:
msg = msg.encode(encoding='ascii', errors='strict')
msg = msg.replace('\u000Bx', '?')
msg = msg.replace('\u000Cx', '?')
except:
return 'Output contained invalid characters'
def XmlAssemble(self, result):
test_name = self.case.GetName()
test_mode = self.case.GetMode()
testCaseElement = xmlj.Element("testcase")
testpath = self.TestPathManipulation(test_name)
testCaseElement.attrib["classname"] = "%s.%s" % (testpath[0] , testpath[1])
testCaseElement.attrib["name"] = "%s %s" % (testpath[2].replace('.','_') , test_mode)
if self.HasUnexpectedOutcome():
failureElement = xmlj.Element("failure")
out = self.stdout.strip().decode('utf-8')
err = self.stderr.strip().decode('utf-8')
if len(out) > 0:
failureElement.text = self.SafeFormat(out)
if len(err) > 0:
failureElement.text = self.SafeFormat(err)
testCaseElement.append(failureElement)
return testCaseElement
def TestPathManipulation(self, test_name):
testdirlist = test_name.split('/')
testcase = testdirlist.pop()
testclass = testdirlist.pop()
testclass = testclass.replace('.','_')
if len(testdirlist) >= 1:
testpackage = testdirlist.pop(0)
else:
testpackage = testclass
return(testpackage,testclass,testcase)
def HasFailed(self):
return self.exit_code != 0
def AsyncHasFailed(self):
return 'Test262:AsyncTestComplete' not in self.stdout
def HasUnexpectedOutcome(self):
if self.case.IsAsyncTest():
return self.AsyncHasFailed() or self.HasFailed()
elif self.case.IsNegative():
return not (self.HasFailed() and self.case.NegativeMatch(self.GetErrorOutput()))
else:
return self.HasFailed()
def GetErrorOutput(self):
if len(self.stderr) != 0:
return self.stderr
return self.stdout
class TestCase(object):
def __init__(self, suite, name, full_path, strict_mode):
self.suite = suite
self.name = name
self.full_path = full_path
self.strict_mode = strict_mode
f = open(self.full_path)
self.contents = f.read()
f.close()
testRecord = parseTestRecord(self.contents, name)
self.test = testRecord["test"]
del testRecord["test"]
del testRecord["header"]
testRecord.pop("commentary", None) # do not throw if missing
self.testRecord = testRecord;
self.validate()
def NegativeMatch(self, stderr):
neg = re.compile(self.GetNegativeType())
return re.search(neg, stderr)
def GetNegative(self):
if not self.IsNegative():
return None
return self.testRecord["negative"]
def GetNegativeType(self):
negative = self.GetNegative()
return negative and negative["type"]
def GetNegativePhase(self):
negative = self.GetNegative()
return negative and negative["phase"]
def GetName(self):
return path.join(*self.name)
def GetMode(self):
if self.strict_mode:
return "strict mode"
else:
return "non-strict mode"
def GetPath(self):
return self.name
def IsNegative(self):
return 'negative' in self.testRecord
def IsOnlyStrict(self):
return 'onlyStrict' in self.testRecord
def IsNoStrict(self):
return 'noStrict' in self.testRecord or self.IsRaw()
def IsRaw(self):
return 'raw' in self.testRecord
def IsAsyncTest(self):
return 'async' in self.testRecord
def GetIncludeList(self):
if self.testRecord.get('includes'):
return self.testRecord['includes']
return []
def GetAdditionalIncludes(self):
return '\n'.join([self.suite.GetInclude(include) for include in self.GetIncludeList()])
def GetSource(self):
if self.IsRaw():
return self.test
source = self.suite.GetInclude("sta.js") + \
self.suite.GetInclude("cth.js") + \
self.suite.GetInclude("assert.js")
if self.IsAsyncTest():
source = source + \
self.suite.GetInclude("timer.js") + \
self.suite.GetInclude("doneprintHandle.js").replace('print', self.suite.print_handle)
source = source + \
self.GetAdditionalIncludes() + \
self.test + '\n'
if self.GetNegativePhase() == "early":
source = ("throw 'Expected an early error, but code was executed.';\n" +
source)
if self.strict_mode:
source = '"use strict";\nvar strict_mode = true;\n' + source
else:
# add comment line so line numbers match in both strict and non-strict version
source = '//"no strict";\nvar strict_mode = false;\n' + source
return source
def InstantiateTemplate(self, template, params):
def GetParameter(match):
key = match.group(1)
return params.get(key, match.group(0))
return placeHolderPattern.sub(GetParameter, template)
def Execute(self, command):
if IsWindows():
args = '%s' % command
else:
args = command.split(" ")
stdout = TempFile(prefix="test262-out-")
stderr = TempFile(prefix="test262-err-")
try:
logging.info("exec: %s", str(args))
process = subprocess.Popen(
args,
shell = IsWindows(),
stdout = stdout.fd,
stderr = stderr.fd
)
code = process.wait()
out = stdout.Read()
err = stderr.Read()
finally:
stdout.Dispose()
stderr.Dispose()
return (code, out, err)
def RunTestIn(self, command_template, tmp):
tmp.Write(self.GetSource())
tmp.Close()
command = self.InstantiateTemplate(command_template, {
'path': tmp.name
})
(code, out, err) = self.Execute(command)
return TestResult(code, out, err, self)
def Run(self, command_template):
tmp = TempFile(suffix=".js", prefix="test262-", text=True)
try:
result = self.RunTestIn(command_template, tmp)
finally:
tmp.Dispose()
return result
def Print(self):
print self.GetSource()
def validate(self):
flags = self.testRecord.get("flags")
phase = self.GetNegativePhase()
if phase not in [None, "early", "runtime"]:
raise TypeError("Invalid value for negative phase: " + phase)
if not flags:
return
if 'raw' in flags:
if 'noStrict' in flags:
raise TypeError("The `raw` flag implies the `noStrict` flag")
elif 'onlyStrict' in flags:
raise TypeError(
"The `raw` flag is incompatible with the `onlyStrict` flag")
elif len(self.GetIncludeList()) > 0:
raise TypeError(
"The `raw` flag is incompatible with the `includes` tag")
class ProgressIndicator(object):
def __init__(self, count):
self.count = count
self.succeeded = 0
self.failed = 0
self.failed_tests = []
def HasRun(self, result):
result.ReportOutcome(True)
if result.HasUnexpectedOutcome():
self.failed += 1
self.failed_tests.append(result)
else:
self.succeeded += 1
def MakePlural(n):
if (n == 1):
return (n, "")
else:
return (n, "s")
def PercentFormat(partial, total):
return "%i test%s (%.1f%%)" % (MakePlural(partial) +
((100.0 * partial)/total,))
class TestSuite(object):
def __init__(self, root, strict_only, non_strict_only, unmarked_default, print_handle):
# TODO: derive from packagerConfig.py
self.test_root = path.join(root, 'test')
self.lib_root = path.join(root, 'harness')
self.strict_only = strict_only
self.non_strict_only = non_strict_only
self.unmarked_default = unmarked_default
self.print_handle = print_handle
self.include_cache = { }
def Validate(self):
if not path.exists(self.test_root):
ReportError("No test repository found")
if not path.exists(self.lib_root):
ReportError("No test library found")
def IsHidden(self, path):
return path.startswith('.') or path == 'CVS'
def IsTestCase(self, path):
return path.endswith('.js')
def ShouldRun(self, rel_path, tests):
if len(tests) == 0:
return True
for test in tests:
if test in rel_path:
return True
return False
def GetInclude(self, name):
if not name in self.include_cache:
static = path.join(self.lib_root, name)
if path.exists(static):
f = open(static)
contents = stripHeader(f.read())
contents = re.sub(r'\r\n', '\n', contents)
self.include_cache[name] = contents + "\n"
f.close()
else:
ReportError("Can't find: " + static)
return self.include_cache[name]
def EnumerateTests(self, tests):
logging.info("Listing tests in %s", self.test_root)
cases = []
for root, dirs, files in os.walk(self.test_root):
for f in [x for x in dirs if self.IsHidden(x)]:
dirs.remove(f)
dirs.sort()
for f in sorted(files):
if self.IsTestCase(f):
full_path = path.join(root, f)
if full_path.startswith(self.test_root):
rel_path = full_path[len(self.test_root)+1:]
else:
logging.warning("Unexpected path %s", full_path)
rel_path = full_path
if self.ShouldRun(rel_path, tests):
basename = path.basename(full_path)[:-3]
name = rel_path.split(path.sep)[:-1] + [basename]
if EXCLUDE_LIST.count(basename) >= 1:
print 'Excluded: ' + basename
else:
if not self.non_strict_only:
strict_case = TestCase(self, name, full_path, True)
if not strict_case.IsNoStrict():
if strict_case.IsOnlyStrict() or \
self.unmarked_default in ['both', 'strict']:
cases.append(strict_case)
if not self.strict_only:
non_strict_case = TestCase(self, name, full_path, False)
if not non_strict_case.IsOnlyStrict():
if non_strict_case.IsNoStrict() or \
self.unmarked_default in ['both', 'non_strict']:
cases.append(non_strict_case)
logging.info("Done listing tests")
return cases
def PrintSummary(self, progress, logfile):
def write(s):
if logfile:
self.logf.write(s + "\n")
print s
print
write("=== Summary ===");
count = progress.count
succeeded = progress.succeeded
failed = progress.failed
write(" - Ran %i test%s" % MakePlural(count))
if progress.failed == 0:
write(" - All tests succeeded")
else:
write(" - Passed " + PercentFormat(succeeded, count))
write(" - Failed " + PercentFormat(failed, count))
positive = [c for c in progress.failed_tests if not c.case.IsNegative()]
negative = [c for c in progress.failed_tests if c.case.IsNegative()]
if len(positive) > 0:
print
write("Failed Tests")
for result in positive:
write(" %s in %s" % (result.case.GetName(), result.case.GetMode()))
if len(negative) > 0:
print
write("Expected to fail but passed ---")
for result in negative:
write(" %s in %s" % (result.case.GetName(), result.case.GetMode()))
def PrintFailureOutput(self, progress, logfile):
for result in progress.failed_tests:
if logfile:
self.WriteLog(result)
print
result.ReportOutcome(False)
def Run(self, command_template, tests, print_summary, full_summary, logname, junitfile):
if not "{{path}}" in command_template:
command_template += " {{path}}"
cases = self.EnumerateTests(tests)
if len(cases) == 0:
ReportError("No tests to run")
progress = ProgressIndicator(len(cases))
if logname:
self.logf = open(logname, "w")
if junitfile:
self.outfile = open(junitfile, "w")
TestSuitesElement = xmlj.Element("testsuites")
TestSuiteElement = xmlj.Element("testsuite")
TestSuitesElement.append(TestSuiteElement)
TestSuiteElement.attrib["name "] = "test262"
for x in range(len(EXCLUDE_LIST)):
if self.ShouldRun (unicode(EXCLUDE_LIST[x].encode('utf-8','ignore')), tests):
SkipCaseElement = xmlj.Element("testcase")
SkipCaseElement.attrib["classname"] = unicode(EXCLUDE_LIST[x]).encode('utf-8','ignore')
SkipCaseElement.attrib["name"] = unicode(EXCLUDE_LIST[x]).encode('utf-8','ignore')
SkipElement = xmlj.Element("skipped")
SkipElement.attrib["message"] = unicode(EXCLUDE_REASON[x].firstChild.nodeValue)
SkipCaseElement.append(SkipElement)
TestSuiteElement.append(SkipCaseElement)
for case in cases:
result = case.Run(command_template)
if junitfile:
TestCaseElement = result.XmlAssemble(result)
TestSuiteElement.append(TestCaseElement)
if case == cases[len(cases)-1]:
xmlj.ElementTree(TestSuitesElement).write(junitfile, "UTF-8")
if logname:
self.WriteLog(result)
progress.HasRun(result)
if print_summary:
self.PrintSummary(progress, logname)
if full_summary:
self.PrintFailureOutput(progress, logname)
else:
print
print "Use --full-summary to see output from failed tests"
print
return progress.failed
def WriteLog(self, result):
name = result.case.GetName()
mode = result.case.GetMode()
if result.HasUnexpectedOutcome():
if result.case.IsNegative():
self.logf.write("=== %s was expected to fail in %s, but didn't === \n" % (name, mode))
self.logf.write("--- expected error: %s ---\n" % result.case.GetNegativeType())
result.WriteOutput(self.logf)
else:
self.logf.write("=== %s failed in %s === \n" % (name, mode))
result.WriteOutput(self.logf)
self.logf.write("===\n")
elif result.case.IsNegative():
self.logf.write("%s failed in %s as expected \n" % (name, mode))
else:
self.logf.write("%s passed in %s \n" % (name, mode))
def Print(self, tests):
cases = self.EnumerateTests(tests)
if len(cases) > 0:
cases[0].Print()
def ListIncludes(self, tests):
cases = self.EnumerateTests(tests)
includes_dict = Counter()
for case in cases:
includes = case.GetIncludeList()
includes_dict.update(includes)
print includes_dict
def Main():
code = 0
parser = BuildOptions()
(options, args) = parser.parse_args()
ValidateOptions(options)
test_suite = TestSuite(options.tests,
options.strict_only,
options.non_strict_only,
options.unmarked_default,
options.print_handle)
test_suite.Validate()
if options.loglevel == 'debug':
logging.basicConfig(level=logging.DEBUG)
elif options.loglevel == 'info':
logging.basicConfig(level=logging.INFO)
elif options.loglevel == 'warning':
logging.basicConfig(level=logging.WARNING)
elif options.loglevel == 'error':
logging.basicConfig(level=logging.ERROR)
elif options.loglevel == 'critical':
logging.basicConfig(level=logging.CRITICAL)
if options.cat:
test_suite.Print(args)
elif options.list_includes:
test_suite.ListIncludes(args)
else:
code = test_suite.Run(options.command, args,
options.summary or options.full_summary,
options.full_summary,
options.logname,
options.junitname)
return code
if __name__ == '__main__':
try:
code = Main()
sys.exit(code)
except Test262Error, e:
print "Error: %s" % e.message
sys.exit(1)

View File

@ -0,0 +1,11 @@
# Unit tests for python packaging tools
This directory holds tests for the python code, not tests of EMCAScript
## Running tests
````
$ cd tools/packaging/test
$ for x in test*.py; do python $x; done
````

View File

@ -0,0 +1,11 @@
// fake copyright comment
/*---
info: >
Sample test info
description: Sample test description
negative:
phase: early
type: SyntaxError
---*/
???

View File

@ -0,0 +1,19 @@
// Copyright 2009 the Sputnik authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/**
* The production Block { } in strict code can't contain function
* declaration;
*
* @path bestPractice/Sbp_A1_T1.js
* @description Trying to declare function at the Block statement
* @onlyStrict
* @negative SyntaxError
* @bestPractice http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls
*/
"use strict";
{
function __func(){}
}

View File

@ -0,0 +1,18 @@
// Copyright 2009 the Sputnik authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
info: >
The production Block { } in strict code can't contain function
declaration;
description: Trying to declare function at the Block statement
negative: SyntaxError
bestPractice: "http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls"
flags: [onlyStrict]
---*/
"use strict";
{
function __func(){}
}

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
import unittest
import os
# add parent dir to search path
import sys
sys.path.append("src")
from _common import *
def slurpFile(name):
with open('test/' + name) as f:
contents = f.read()
return contents
class TestOldParsing(unittest.TestCase):
def test_test(self):
pass
def test_overview(self):
name = 'fixtures/test262-old-headers.js'
contents = slurpFile(name)
record = convertDocString(contents)
self.assertEqual("""The production Block { } in strict code can't contain function
declaration;""", record['commentary'])
self.assertEqual("bestPractice/Sbp_A1_T1.js", record['path'])
self.assertEqual("Trying to declare function at the Block statement",
record['description'])
self.assertEqual("", record['onlyStrict'])
self.assertEqual("SyntaxError", record['negative'])
self.assertEqual("http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls",
record['bestPractice'])
class TestYAMLParsing(unittest.TestCase):
def test_overview(self):
name = 'fixtures/test262-yaml-headers.js'
contents = slurpFile(name)
record = convertDocString(contents)
self.assertEqual("The production Block { } in strict code can't contain function declaration;\n", record['commentary'])
self.assertEqual("Trying to declare function at the Block statement",
record['description'])
self.assertEqual(['onlyStrict'], record['flags'])
self.assertEqual("", record['onlyStrict'])
self.assertEqual("SyntaxError", record['negative'])
self.assertEqual("http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls",
record['bestPractice'])
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,210 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
import unittest
import os
import yaml
import imp
# add parent dir to search path
import sys
sys.path.append("src")
import _monkeyYaml as monkeyYaml
class TestMonkeyYAMLParsing(unittest.TestCase):
def test_empty(self):
self.assertEqual(monkeyYaml.load(""), yaml.load(""))
def test_newline(self):
self.assertEqual(monkeyYaml.load("\n"), yaml.load("\n"))
def test_oneline(self):
y = "foo: bar"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_twolines(self):
y = "foo: bar\nbaz_bletch : blith:er"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_multiLine(self):
y = "foo: >\n bar\nbaz: 3"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_es5id(self):
y = "es5id: 15.2.3.6-4-102"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_Multiline_1(self):
lines = [" foo"]
value = ">"
y = "\n".join([value] + lines)
(lines, value) = monkeyYaml.myMultiline(lines, value)
self.assertEqual(lines, [])
self.assertEqual(value, yaml.load(y))
def test_Multiline_2(self):
lines = [" foo", " bar"]
y = "\n".join([">"] + lines)
(lines, value) = monkeyYaml.myMultiline(lines)
self.assertEqual(lines, [])
self.assertEqual(value, yaml.load(y))
def test_Multiline_3(self):
lines = [" foo", " bar"]
y = "\n".join([">"] + lines)
(lines, value) = monkeyYaml.myMultiline(lines)
self.assertEqual(lines, [])
self.assertEqual(value, yaml.load(y))
def test_Multiline_4(self):
lines = [" foo", " bar", " other: 42"]
(lines, value) = monkeyYaml.myMultiline(lines)
self.assertEqual(lines, [" other: 42"])
self.assertEqual(value, "foo bar")
def test_myLeading(self):
self.assertEqual(2, monkeyYaml.myLeadingSpaces(" foo"))
self.assertEqual(2, monkeyYaml.myLeadingSpaces(" "))
self.assertEqual(0, monkeyYaml.myLeadingSpaces("\t "))
def test_includes_flow(self):
y = "includes: [a.js,b.js, c_with_wings.js]\n"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_myFlowList_1(self):
y = "[a.js,b.js, c_with_wings.js, 3, 4.12]"
self.assertEqual(monkeyYaml.myFlowList(y), ['a.js', 'b.js', 'c_with_wings.js', 3, 4.12])
def test_multiline_list_1(self):
y = "foo:\n - bar\n - baz"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_multiline_list2(self):
self.assertEqual(monkeyYaml.myRemoveListHeader(2, " - foo"), "foo")
def test_multiline_list3(self):
(lines, value) = monkeyYaml.myMultilineList([" - foo", " - bar", "baz: bletch"], "")
self.assertEqual(lines, ["baz: bletch"])
self.assertEqual(value, ["foo", "bar"])
def test_multiline_list_carriage_return(self):
y = "foo:\r\n - bar\r\n - baz"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_oneline_indented(self):
y = " foo: bar\n baz: baf\n"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_indentation_215(self):
self.maxDiff = None
y = """
description: >
The method should exist on the Array prototype, and it should be writable
and configurable, but not enumerable.
includes: [propertyHelper.js]
es6id: 22.1.3.13
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_indentation_215_2(self):
self.maxDiff = None
y = """
description: >
The method should exist
includes: [propertyHelper.js]
es6id: 22.1.3.13
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_line_folding(self):
self.maxDiff = None
y = """
description: aaa
bbb
es6id: 19.1.2.1
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_line_folding_2(self):
self.maxDiff = None
y = """
description: ccc
ddd
es6id: 19.1.2.1
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_line_folding_3(self):
self.maxDiff = None
y = """
description: eee
fff
es6id: 19.1.2.1
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_line_folding_4(self):
self.maxDiff = None
y = """
description: ggg
hhh
iii
jjj
es6id: 19.1.2.1
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_no_folding(self):
y = """
description: |
This is text that, naively parsed, would appear
to: have
nested: data
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_value_multiline(self):
y = """
description:
This is a multi-line value
whose trailing newline should be stripped
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_nested_1(self):
y = """
es61d: 19.1.2.1
negative:
stage: early
type: ReferenceError
description: foo
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_nested_2(self):
y = """
es61d: 19.1.2.1
first:
second_a:
third: 1
second_b: 3
description: foo
"""
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,183 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
import unittest
import os
import yaml
# add parent dir to search path
import sys
sys.path.append("src")
from parseTestRecord import *
def slurpFile(name):
with open('test/' + name) as f:
contents = f.read()
return contents
class TestOldParsing(unittest.TestCase):
def test_test(self):
self.assertTrue(True)
def test_overview(self):
name = 'fixtures/test262-old-headers.js'
contents = slurpFile(name)
record = parseTestRecord(contents, name)
self.assertEqual("""// Copyright 2009 the Sputnik authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.""",
record['header'])
self.assertEqual("""The production Block { } in strict code can't contain function
declaration;""", record['commentary'])
self.assertEqual("bestPractice/Sbp_A1_T1.js", record['path'])
self.assertEqual("Trying to declare function at the Block statement",
record['description'])
self.assertEqual("", record['onlyStrict'])
self.assertEqual("SyntaxError", record['negative'])
self.assertEqual("http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls",
record['bestPractice'])
self.assertEqual(""""use strict";
{
function __func(){}
}
""", record['test'])
@unittest.expectedFailure
def test_nomatch(self):
with self.assertRaisesRegexp(Exception, "unrecognized"):
parseTestRecord("#!/usr/bin/env python", "random.py")
def test_duplicate(self):
with self.assertRaisesRegexp(Exception, "duplicate: foo"):
parseTestRecord("""
// Copyright
/**
* @foo bar
* @foo bar
*/
1;
"""
, "name")
def test_malformed(self):
with self.assertRaisesRegexp(Exception, 'Malformed "@" attribute: name'):
parseTestRecord("""
// Copyright
/**
* @ baz
* @foo bar
*/
1;
"""
, "name")
def test_stripStars(self):
self.assertEqual("", stripStars(""))
self.assertEqual("foo", stripStars("\n* foo"))
self.assertEqual("@foo bar", stripStars("\n* @foo bar"))
self.assertEqual("@foo bar", stripStars("\n *@foo bar"))
class TestYAMLParsing(unittest.TestCase):
def test_test(self):
self.assertTrue(True)
def test_split(self):
name = 'fixtures/test262-yaml-headers.js'
contents = slurpFile(name)
self.assertTrue('---' in contents)
match = matchParts(contents, name)
self.assertEqual("""---
info: >
The production Block { } in strict code can't contain function
declaration;
description: Trying to declare function at the Block statement
negative: SyntaxError
bestPractice: "http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls"
flags: [onlyStrict]
---""", match.group(2))
def test_yamlParse(self):
text = """
info: >
The production Block { } in strict code can't contain function
declaration;
description: Trying to declare function at the Block statement
negative: SyntaxError
bestPractice: "http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls"
flags: [onlyStrict]"""
parsed = yaml.load(text)
self.assertEqual("Trying to declare function at the Block statement",
parsed['description'])
self.assertEqual("SyntaxError", parsed['negative'])
self.assertEqual('http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls', parsed['bestPractice'])
self.assertEqual(["onlyStrict"], parsed['flags'])
self.assertEqual("The production Block { } in strict code can't contain function declaration;\n", parsed['info'])
def test_hasYAML(self):
self.assertTrue(hasYAML("---\n some: yaml\n\n---"))
self.assertFalse(hasYAML("\n* Test description\n *\n * @foo bar\n* @noStrict\n"))
def test_fixturehasYAML(self):
name = 'fixtures/test262-yaml-headers.js'
contents = slurpFile(name)
self.assertTrue('---' in contents)
match = matchParts(contents, name)
self.assertTrue(hasYAML(match.group(2)))
def test_missingKeys(self):
result = {}
yamlAttrParser(result, """---
info: some info (note no flags or includes)
---""", "")
self.assertEqual("some info (note no flags or includes)", result['commentary'])
def test_overview(self):
name = 'fixtures/test262-yaml-headers.js'
contents = slurpFile(name)
record = parseTestRecord(contents, name)
self.assertEqual("""// Copyright 2009 the Sputnik authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.""",
record['header'])
self.assertEqual("The production Block { } in strict code can't contain function declaration;\n", record['commentary'])
self.assertEqual("Trying to declare function at the Block statement",
record['description'])
self.assertEqual(['onlyStrict'], record['flags'])
self.assertEqual("", record['onlyStrict'])
self.assertEqual("SyntaxError", record['negative'])
self.assertEqual("http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls",
record['bestPractice'])
self.assertEqual(""""use strict";
{
function __func(){}
}
""", record['test'])
def test_negative(self):
name = 'fixtures/negative.js'
contents = slurpFile(name)
record = parseTestRecord(contents, name)
self.assertEqual('early', record['negative']['phase'])
self.assertEqual('SyntaxError', record['negative']['type'])
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,274 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
import unittest
import sys
import os
import cStringIO
from functools import wraps
sys.path.append("src")
import test262
class TestTest262(unittest.TestCase):
def test_that_tests_run(self):
self.assertEqual(1 + 2, 3)
class MockTest(object):
def __init__(self, name, negative):
self.name = name
self.negative = negative if negative else False
self.strict_mode = False
def GetName(self):
return self.name
def IsNegative(self):
return self.negative
def GetMode(self):
if self.strict_mode:
return "strict mode"
return "non-strict mode"
class MockResult(object):
def __init__(self, case):
self.case = case
class TestTestSuite(unittest.TestCase):
def test_that_tests_run(self):
self.assertEqual(1 + 2, 3)
def test_create_test_suite(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
self.assertNotEqual(test_suite, None)
def test_summary(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
progress = test262.ProgressIndicator(100)
progress.succeeded = 98
progress.failed = 2
result = mute(True)(test_suite.PrintSummary)(progress, None)
self.assertEqual("""
=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
""", result)
def test_summary_logfile(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
progress = test262.ProgressIndicator(100)
progress.succeeded = 98
progress.failed = 2
fake_log = cStringIO.StringIO()
test_suite.logf = fake_log
result = mute(True)(test_suite.PrintSummary)(progress, True)
expected_out = """
=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
"""
expected_log = """=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
"""
self.assertEqual(expected_out, result)
self.assertEqual(expected_log, fake_log.getvalue())
def test_summary_withfails(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
progress = test262.ProgressIndicator(100)
progress.succeeded = 98
progress.failed = 2
progress.failed_tests = [
MockResult(MockTest("foo", False)),
MockResult(MockTest("bar", True))
]
result = mute(True)(test_suite.PrintSummary)(progress, None)
self.assertEqual("""
=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
Failed Tests
foo in non-strict mode
Expected to fail but passed ---
bar in non-strict mode
""", result)
def test_summary_withfails_andlog(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
progress = test262.ProgressIndicator(100)
progress.succeeded = 98
progress.failed = 2
progress.failed_tests = [
MockResult(MockTest("foo", False)),
MockResult(MockTest("bar", True))
]
fake_log = cStringIO.StringIO()
test_suite.logf = fake_log
expected_out = """
=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
Failed Tests
foo in non-strict mode
Expected to fail but passed ---
bar in non-strict mode
"""
expected_log = """=== Summary ===
- Ran 100 tests
- Passed 98 tests (98.0%)
- Failed 2 tests (2.0%)
Failed Tests
foo in non-strict mode
Expected to fail but passed ---
bar in non-strict mode
"""
result = mute(True)(test_suite.PrintSummary)(progress, True)
self.assertEqual(expected_out, result)
self.assertEqual(expected_log, fake_log.getvalue())
def test_summary_success_logfile(self):
test_suite = test262.TestSuite(".",
False,
False,
False,
None)
progress = test262.ProgressIndicator(100)
progress.succeeded = 100
progress.failed = 0
fake_log = cStringIO.StringIO()
test_suite.logf = fake_log
result = mute(True)(test_suite.PrintSummary)(progress, True)
expected_out = """
=== Summary ===
- Ran 100 tests
- All tests succeeded
"""
expected_log = """=== Summary ===
- Ran 100 tests
- All tests succeeded
"""
self.assertEqual(expected_out, result)
self.assertEqual(expected_log, fake_log.getvalue())
def test_percent_format(self):
self.assertEqual(test262.PercentFormat(1, 100), "1 test (1.0%)")
self.assertEqual(test262.PercentFormat(0, 100), "0 tests (0.0%)")
self.assertEqual(test262.PercentFormat(99, 100), "99 tests (99.0%)")
# module level utility functions
# copied from https://stackoverflow.com/questions/2828953/silence-the-stdout-of-a-function-in-python-without-trashing-sys-stdout-and-resto
def mute(returns_output=False):
"""
Decorate a function that prints to stdout, intercepting the output.
If "returns_output" is True, the function will return a generator
yielding the printed lines instead of the return values.
The decorator litterally hijack sys.stdout during each function
execution for ALL THE THREADS, so be careful with what you apply it to
and in which context.
>>> def numbers():
print "42"
print "1984"
...
>>> numbers()
42
1984
>>> mute()(numbers)()
>>> list(mute(True)(numbers)())
['42', '1984']
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
saved_stdout = sys.stdout
sys.stdout = cStringIO.StringIO()
try:
out = func(*args, **kwargs)
if returns_output:
out = sys.stdout.getvalue()
finally:
sys.stdout = saved_stdout
return out
return wrapper
return decorator
if __name__ == '__main__':
unittest.main()