mirror of https://github.com/tc39/test262.git
336 lines
13 KiB
Python
336 lines
13 KiB
Python
# 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', required=True,
|
|
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."
|