# 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."