1# Copyright 2013 the V8 project authors. All rights reserved. 2# Redistribution and use in source and binary forms, with or without 3# modification, are permitted provided that the following conditions are 4# met: 5# 6# * Redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer. 8# * Redistributions in binary form must reproduce the above 9# copyright notice, this list of conditions and the following 10# disclaimer in the documentation and/or other materials provided 11# with the distribution. 12# * Neither the name of Google Inc. nor the names of its 13# contributors may be used to endorse or promote products derived 14# from this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28import itertools 29import os 30import re 31 32from testrunner.local import testsuite 33from testrunner.objects import testcase 34 35FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") 36FILES_PATTERN = re.compile(r"//\s+Files:(.*)") 37SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME") 38 39 40# TODO (machenbach): Share commonalities with mjstest. 41class WebkitTestSuite(testsuite.TestSuite): 42 43 def __init__(self, name, root): 44 super(WebkitTestSuite, self).__init__(name, root) 45 46 def ListTests(self, context): 47 tests = [] 48 for dirname, dirs, files in os.walk(self.root): 49 for dotted in [x for x in dirs if x.startswith('.')]: 50 dirs.remove(dotted) 51 if 'resources' in dirs: 52 dirs.remove('resources') 53 54 dirs.sort() 55 files.sort() 56 for filename in files: 57 if filename.endswith(".js"): 58 fullpath = os.path.join(dirname, filename) 59 relpath = fullpath[len(self.root) + 1 : -3] 60 testname = relpath.replace(os.path.sep, "/") 61 test = testcase.TestCase(self, testname) 62 tests.append(test) 63 return tests 64 65 def GetFlagsForTestCase(self, testcase, context): 66 source = self.GetSourceForTest(testcase) 67 flags = [] + context.mode_flags 68 flags_match = re.findall(FLAGS_PATTERN, source) 69 for match in flags_match: 70 flags += match.strip().split() 71 72 files_list = [] # List of file names to append to command arguments. 73 files_match = FILES_PATTERN.search(source); 74 # Accept several lines of 'Files:'. 75 while True: 76 if files_match: 77 files_list += files_match.group(1).strip().split() 78 files_match = FILES_PATTERN.search(source, files_match.end()) 79 else: 80 break 81 files = [ os.path.normpath(os.path.join(self.root, '..', '..', f)) 82 for f in files_list ] 83 testfilename = os.path.join(self.root, testcase.path + self.suffix()) 84 if SELF_SCRIPT_PATTERN.search(source): 85 env = ["-e", "TEST_FILE_NAME=\"%s\"" % testfilename.replace("\\", "\\\\")] 86 files = env + files 87 files.append(os.path.join(self.root, "resources/standalone-pre.js")) 88 files.append(testfilename) 89 files.append(os.path.join(self.root, "resources/standalone-post.js")) 90 91 flags += files 92 if context.isolates: 93 flags.append("--isolate") 94 flags += files 95 96 return testcase.flags + flags 97 98 def GetSourceForTest(self, testcase): 99 filename = os.path.join(self.root, testcase.path + self.suffix()) 100 with open(filename) as f: 101 return f.read() 102 103 # TODO(machenbach): Share with test/message/testcfg.py 104 def _IgnoreLine(self, string): 105 """Ignore empty lines, valgrind output and Android output.""" 106 if not string: return True 107 return (string.startswith("==") or string.startswith("**") or 108 string.startswith("ANDROID") or 109 # These five patterns appear in normal Native Client output. 110 string.startswith("DEBUG MODE ENABLED") or 111 string.startswith("tools/nacl-run.py") or 112 string.find("BYPASSING ALL ACL CHECKS") > 0 or 113 string.find("Native Client module will be loaded") > 0 or 114 string.find("NaClHostDescOpen:") > 0 or 115 # FIXME(machenbach): The test driver shouldn't try to use slow 116 # asserts if they weren't compiled. This fails in optdebug=2. 117 string == "Warning: unknown flag --enable-slow-asserts." or 118 string == "Try --help for options") 119 120 def IsFailureOutput(self, output, testpath): 121 if super(WebkitTestSuite, self).IsFailureOutput(output, testpath): 122 return True 123 file_name = os.path.join(self.root, testpath) + "-expected.txt" 124 with file(file_name, "r") as expected: 125 expected_lines = expected.readlines() 126 127 def ExpIterator(): 128 for line in expected_lines: 129 if line.startswith("#") or not line.strip(): continue 130 yield line.strip() 131 132 def ActIterator(lines): 133 for line in lines: 134 if self._IgnoreLine(line.strip()): continue 135 yield line.strip() 136 137 def ActBlockIterator(): 138 """Iterates over blocks of actual output lines.""" 139 lines = output.stdout.splitlines() 140 start_index = 0 141 found_eqeq = False 142 for index, line in enumerate(lines): 143 # If a stress test separator is found: 144 if line.startswith("=="): 145 # Iterate over all lines before a separator except the first. 146 if not found_eqeq: 147 found_eqeq = True 148 else: 149 yield ActIterator(lines[start_index:index]) 150 # The next block of ouput lines starts after the separator. 151 start_index = index + 1 152 # Iterate over complete output if no separator was found. 153 if not found_eqeq: 154 yield ActIterator(lines) 155 156 for act_iterator in ActBlockIterator(): 157 for (expected, actual) in itertools.izip_longest( 158 ExpIterator(), act_iterator, fillvalue=''): 159 if expected != actual: 160 return True 161 return False 162 163 164def GetSuite(name, root): 165 return WebkitTestSuite(name, root) 166