test262/tools/packaging/packager.py

305 lines
12 KiB
Python
Raw Normal View History

# Copyright (c) 2011 Microsoft Corporation
2011-09-24 19:35:50 +02:00
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided
# that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice, this list of conditions and
# the following disclaimer.
# * 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.
# * Neither the name of Microsoft nor the names of its contributors may be used to
# endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
#--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
2011-09-24 19:35:50 +02:00
#--Stubs-----------------------------------------------------------------------
def generateHarness(harnessType, jsonFile, description):
pass
#------------------------------------------------------------------------------
from TestCasePackagerConfig 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='test262',
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
#global which states whether the test case we're currently processing is in
#the midst of a "/* ... */" style comment
IS_MULTILINE_COMMENT = False
#List of all *.json files containing encoded test cases
SECTIONS_LIST = []
ONE_JSON_PER_CHAPTER = False
TESTCASELIST_PER_JSON = False
#--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 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)
elif temp < MAX_CASES_PER_JSON:
TEST_SUITE_SECTIONS.append(dirName)
return
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.
'''
global IS_MULTILINE_COMMENT
#TODO
return True
2011-09-24 19:35:50 +02:00
if IS_MULTILINE_COMMENT and ("*/" in line): #End of a newline comment
IS_MULTILINE_COMMENT = False
return False
elif "/*" in line: #Beginning of a newline comment
IS_MULTILINE_COMMENT = True
return False
elif IS_MULTILINE_COMMENT: #//we're already in a multi-line comment that hasn't ended
return False
elif re.match("^\s*//", line)!=None: #//blah
return False
elif re.match("^\s*$", line)!=None: #newlines
return False
elif "ES5Harness" in line: #definitely start of the test!
return True
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 TEST_CONTRIB_DIRS:
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 not ONE_JSON_PER_CHAPTER:
dirWalker(temp)
else:
for tempSubdir in os.listdir(temp):
TEST_SUITE_SECTIONS.append(os.path.join(temp, tempSubdir))
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 = {}
#TODO
#testDict["id"] = testName
2011-09-24 19:35:50 +02:00
testDict["path"] = testPath.replace("/ietestcenter", "").replace("/sputnik_converted", "")
tempFile = open(test, "r")
scriptCode = tempFile.readlines()
tempFile.close()
scriptCodeContent=""
#Rip out license headers that add unnecessary bytes to the JSON'ized test cases
inBeginning = True
IS_MULTILINE_COMMENT = False
for line in scriptCode:
if inBeginning:
isStarted = isTestStarted(line)
if not isStarted:
continue
inBeginning = False
scriptCodeContent += line
if scriptCodeContent=="":
print "WARNING (" + test + "): unable to strip comments/license header/etc."
scriptCodeContent = "".join(scriptCode)
scriptCodeContent = base64.b64encode(scriptCodeContent)
#add the test encoded code node to our test dictionary
testDict["code"] = scriptCodeContent
#now close the dictionary for the test
#now get the metadata added.
tempDict = convertDocString("".join(scriptCode))
for tempKey in tempDict.keys():
#TODO - is this check really necessary?
if not (tempKey in ["path"]):
testDict[tempKey] = tempDict[tempKey]
2011-09-24 19:35:50 +02:00
#this adds the test to our tests array
tests.append(testDict)
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)
if TESTCASELIST_PER_JSON:
CHAPTER_TEST_CASES_JSON = {}
CHAPTER_TEST_CASES_JSON["numTests"] = int(sect["numTests"])
CHAPTER_TEST_CASES_JSON["version"] = ARGS.version
CHAPTER_TEST_CASES_JSON["date"] = str(datetime.datetime.now().date())
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)
generateHarness(ARGS.type, "testcases_%s.json" % chapterName, chapterName.replace("chapter", "Chapter "))
#add the name of the chapter test to our complete list
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["version"] = ARGS.version
TEST_CASES_JSON["date"] = str(datetime.datetime.now().date())
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)
generateHarness(ARGS.type, "default.json", "Chapters 1-16")
#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")]:
toFilename = os.path.join(TEST262_WEB_HARNESS_DIR, filename)
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."