• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2012 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
28
29import hashlib
30import imp
31import os
32import shutil
33import sys
34import tarfile
35
36
37from testrunner.local import statusfile
38from testrunner.local import testsuite
39from testrunner.local import utils
40from testrunner.objects import testcase
41
42DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
43ARCHIVE = DATA + ".tar"
44
45TEST_262_HARNESS_FILES = ["sta.js", "assert.js"]
46TEST_262_NATIVE_FILES = ["detachArrayBuffer.js"]
47
48TEST_262_SUITE_PATH = ["data", "test"]
49TEST_262_HARNESS_PATH = ["data", "harness"]
50TEST_262_TOOLS_PATH = ["data", "tools", "packaging"]
51
52ALL_VARIANT_FLAGS_STRICT = dict(
53    (v, [flags + ["--use-strict"] for flags in flag_sets])
54    for v, flag_sets in testsuite.ALL_VARIANT_FLAGS.iteritems()
55)
56
57FAST_VARIANT_FLAGS_STRICT = dict(
58    (v, [flags + ["--use-strict"] for flags in flag_sets])
59    for v, flag_sets in testsuite.FAST_VARIANT_FLAGS.iteritems()
60)
61
62ALL_VARIANT_FLAGS_BOTH = dict(
63    (v, [flags for flags in testsuite.ALL_VARIANT_FLAGS[v] +
64                            ALL_VARIANT_FLAGS_STRICT[v]])
65    for v in testsuite.ALL_VARIANT_FLAGS
66)
67
68FAST_VARIANT_FLAGS_BOTH = dict(
69    (v, [flags for flags in testsuite.FAST_VARIANT_FLAGS[v] +
70                            FAST_VARIANT_FLAGS_STRICT[v]])
71    for v in testsuite.FAST_VARIANT_FLAGS
72)
73
74ALL_VARIANTS = {
75  'nostrict': testsuite.ALL_VARIANT_FLAGS,
76  'strict': ALL_VARIANT_FLAGS_STRICT,
77  'both': ALL_VARIANT_FLAGS_BOTH,
78}
79
80FAST_VARIANTS = {
81  'nostrict': testsuite.FAST_VARIANT_FLAGS,
82  'strict': FAST_VARIANT_FLAGS_STRICT,
83  'both': FAST_VARIANT_FLAGS_BOTH,
84}
85
86class Test262VariantGenerator(testsuite.VariantGenerator):
87  def GetFlagSets(self, testcase, variant):
88    if testcase.outcomes and statusfile.OnlyFastVariants(testcase.outcomes):
89      variant_flags = FAST_VARIANTS
90    else:
91      variant_flags = ALL_VARIANTS
92
93    test_record = self.suite.GetTestRecord(testcase)
94    if "noStrict" in test_record:
95      return variant_flags["nostrict"][variant]
96    if "onlyStrict" in test_record:
97      return variant_flags["strict"][variant]
98    return variant_flags["both"][variant]
99
100
101class Test262TestSuite(testsuite.TestSuite):
102
103  def __init__(self, name, root):
104    super(Test262TestSuite, self).__init__(name, root)
105    self.testroot = os.path.join(self.root, *TEST_262_SUITE_PATH)
106    self.harnesspath = os.path.join(self.root, *TEST_262_HARNESS_PATH)
107    self.harness = [os.path.join(self.harnesspath, f)
108                    for f in TEST_262_HARNESS_FILES]
109    self.harness += [os.path.join(self.root, "harness-adapt.js")]
110    self.ParseTestRecord = None
111
112  def ListTests(self, context):
113    tests = []
114    for dirname, dirs, files in os.walk(self.testroot):
115      for dotted in [x for x in dirs if x.startswith(".")]:
116        dirs.remove(dotted)
117      if context.noi18n and "intl402" in dirs:
118        dirs.remove("intl402")
119      dirs.sort()
120      files.sort()
121      for filename in files:
122        if filename.endswith(".js"):
123          fullpath = os.path.join(dirname, filename)
124          relpath = fullpath[len(self.testroot) + 1 : -3]
125          testname = relpath.replace(os.path.sep, "/")
126          case = testcase.TestCase(self, testname)
127          tests.append(case)
128    return tests
129
130  def GetFlagsForTestCase(self, testcase, context):
131    return (testcase.flags + context.mode_flags + self.harness +
132            self.GetIncludesForTest(testcase) + ["--harmony"] +
133            (["--module"] if "module" in self.GetTestRecord(testcase) else []) +
134            [os.path.join(self.testroot, testcase.path + ".js")] +
135            (["--throws"] if "negative" in self.GetTestRecord(testcase)
136                          else []) +
137            (["--allow-natives-syntax"]
138             if "detachArrayBuffer.js" in
139                self.GetTestRecord(testcase).get("includes", [])
140             else []))
141
142  def _VariantGeneratorFactory(self):
143    return Test262VariantGenerator
144
145  def LoadParseTestRecord(self):
146    if not self.ParseTestRecord:
147      root = os.path.join(self.root, *TEST_262_TOOLS_PATH)
148      f = None
149      try:
150        (f, pathname, description) = imp.find_module("parseTestRecord", [root])
151        module = imp.load_module("parseTestRecord", f, pathname, description)
152        self.ParseTestRecord = module.parseTestRecord
153      except:
154        raise ImportError("Cannot load parseTestRecord; you may need to "
155                          "gclient sync for test262")
156      finally:
157        if f:
158          f.close()
159    return self.ParseTestRecord
160
161  def GetTestRecord(self, testcase):
162    if not hasattr(testcase, "test_record"):
163      ParseTestRecord = self.LoadParseTestRecord()
164      testcase.test_record = ParseTestRecord(self.GetSourceForTest(testcase),
165                                             testcase.path)
166    return testcase.test_record
167
168  def BasePath(self, filename):
169    return self.root if filename in TEST_262_NATIVE_FILES else self.harnesspath
170
171  def GetIncludesForTest(self, testcase):
172    test_record = self.GetTestRecord(testcase)
173    if "includes" in test_record:
174      return [os.path.join(self.BasePath(filename), filename)
175              for filename in test_record.get("includes", [])]
176    else:
177      includes = []
178    return includes
179
180  def GetSourceForTest(self, testcase):
181    filename = os.path.join(self.testroot, testcase.path + ".js")
182    with open(filename) as f:
183      return f.read()
184
185  def _ParseException(self, str):
186    for line in str.split("\n")[::-1]:
187      if line and not line[0].isspace() and ":" in line:
188        return line.split(":")[0]
189
190
191  def IsFailureOutput(self, testcase):
192    output = testcase.output
193    test_record = self.GetTestRecord(testcase)
194    if output.exit_code != 0:
195      return True
196    if "negative" in test_record:
197      if self._ParseException(output.stdout) != test_record["negative"]:
198        return True
199    return "FAILED!" in output.stdout
200
201  def HasUnexpectedOutput(self, testcase):
202    outcome = self.GetOutcome(testcase)
203    if (statusfile.FAIL_SLOPPY in testcase.outcomes and
204        "--use-strict" not in testcase.flags):
205      return outcome != statusfile.FAIL
206    return not outcome in (testcase.outcomes or [statusfile.PASS])
207
208  def DownloadData(self):
209    print "Test262 download is deprecated. It's part of DEPS."
210
211    # Clean up old directories and archive files.
212    directory_old_name = os.path.join(self.root, "data.old")
213    if os.path.exists(directory_old_name):
214      shutil.rmtree(directory_old_name)
215
216    archive_files = [f for f in os.listdir(self.root)
217                     if f.startswith("tc39-test262-")]
218    if len(archive_files) > 0:
219      print "Clobber outdated test archives ..."
220      for f in archive_files:
221        os.remove(os.path.join(self.root, f))
222
223    # The archive is created only on swarming. Local checkouts have the
224    # data folder.
225    if os.path.exists(ARCHIVE) and not os.path.exists(DATA):
226      print "Extracting archive..."
227      tar = tarfile.open(ARCHIVE)
228      tar.extractall(path=os.path.dirname(ARCHIVE))
229      tar.close()
230
231
232def GetSuite(name, root):
233  return Test262TestSuite(name, root)
234