11cb0ef41Sopenharmony_ci# Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci# Redistribution and use in source and binary forms, with or without 31cb0ef41Sopenharmony_ci# modification, are permitted provided that the following conditions are 41cb0ef41Sopenharmony_ci# met: 51cb0ef41Sopenharmony_ci# 61cb0ef41Sopenharmony_ci# * Redistributions of source code must retain the above copyright 71cb0ef41Sopenharmony_ci# notice, this list of conditions and the following disclaimer. 81cb0ef41Sopenharmony_ci# * Redistributions in binary form must reproduce the above 91cb0ef41Sopenharmony_ci# copyright notice, this list of conditions and the following 101cb0ef41Sopenharmony_ci# disclaimer in the documentation and/or other materials provided 111cb0ef41Sopenharmony_ci# with the distribution. 121cb0ef41Sopenharmony_ci# * Neither the name of Google Inc. nor the names of its 131cb0ef41Sopenharmony_ci# contributors may be used to endorse or promote products derived 141cb0ef41Sopenharmony_ci# from this software without specific prior written permission. 151cb0ef41Sopenharmony_ci# 161cb0ef41Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171cb0ef41Sopenharmony_ci# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181cb0ef41Sopenharmony_ci# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191cb0ef41Sopenharmony_ci# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201cb0ef41Sopenharmony_ci# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211cb0ef41Sopenharmony_ci# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221cb0ef41Sopenharmony_ci# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231cb0ef41Sopenharmony_ci# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241cb0ef41Sopenharmony_ci# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251cb0ef41Sopenharmony_ci# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261cb0ef41Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciimport fnmatch 301cb0ef41Sopenharmony_ciimport imp 311cb0ef41Sopenharmony_ciimport itertools 321cb0ef41Sopenharmony_ciimport os 331cb0ef41Sopenharmony_cifrom contextlib import contextmanager 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_cifrom . import command 361cb0ef41Sopenharmony_cifrom . import statusfile 371cb0ef41Sopenharmony_cifrom . import utils 381cb0ef41Sopenharmony_cifrom ..objects.testcase import TestCase 391cb0ef41Sopenharmony_cifrom .variants import ALL_VARIANTS, ALL_VARIANT_FLAGS 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciSTANDARD_VARIANT = set(["default"]) 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciclass VariantsGenerator(object): 461cb0ef41Sopenharmony_ci def __init__(self, variants): 471cb0ef41Sopenharmony_ci self._all_variants = [v for v in variants if v in ALL_VARIANTS] 481cb0ef41Sopenharmony_ci self._standard_variant = [v for v in variants if v in STANDARD_VARIANT] 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci def gen(self, test): 511cb0ef41Sopenharmony_ci """Generator producing (variant, flags, procid suffix) tuples.""" 521cb0ef41Sopenharmony_ci flags_set = self._get_flags_set(test) 531cb0ef41Sopenharmony_ci for n, variant in enumerate(self._get_variants(test)): 541cb0ef41Sopenharmony_ci yield (variant, flags_set[variant][0], n) 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci def _get_flags_set(self, test): 571cb0ef41Sopenharmony_ci return ALL_VARIANT_FLAGS 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci def _get_variants(self, test): 601cb0ef41Sopenharmony_ci if test.only_standard_variant: 611cb0ef41Sopenharmony_ci return self._standard_variant 621cb0ef41Sopenharmony_ci return self._all_variants 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciclass TestCombiner(object): 661cb0ef41Sopenharmony_ci def get_group_key(self, test): 671cb0ef41Sopenharmony_ci """To indicate what tests can be combined with each other we define a group 681cb0ef41Sopenharmony_ci key for each test. Tests with the same group key can be combined. Test 691cb0ef41Sopenharmony_ci without a group key (None) is not combinable with any other test. 701cb0ef41Sopenharmony_ci """ 711cb0ef41Sopenharmony_ci raise NotImplementedError() 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci def combine(self, name, tests): 741cb0ef41Sopenharmony_ci """Returns test combined from `tests`. Since we identify tests by their 751cb0ef41Sopenharmony_ci suite and name, `name` parameter should be unique within one suite. 761cb0ef41Sopenharmony_ci """ 771cb0ef41Sopenharmony_ci return self._combined_test_class()(name, tests) 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci def _combined_test_class(self): 801cb0ef41Sopenharmony_ci raise NotImplementedError() 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ciclass TestLoader(object): 841cb0ef41Sopenharmony_ci """Base class for loading TestSuite tests after applying test suite 851cb0ef41Sopenharmony_ci transformations.""" 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci def __init__(self, suite, test_class, test_config, test_root): 881cb0ef41Sopenharmony_ci self.suite = suite 891cb0ef41Sopenharmony_ci self.test_class = test_class 901cb0ef41Sopenharmony_ci self.test_config = test_config 911cb0ef41Sopenharmony_ci self.test_root = test_root 921cb0ef41Sopenharmony_ci self.test_count_estimation = len(list(self._list_test_filenames())) 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci def _list_test_filenames(self): 951cb0ef41Sopenharmony_ci """Implemented by the subclassed TestLoaders to list filenames. 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci Filenames are expected to be sorted and are deterministic.""" 981cb0ef41Sopenharmony_ci raise NotImplementedError 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci def _should_filter_by_name(self, name): 1011cb0ef41Sopenharmony_ci return False 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci def _should_filter_by_test(self, test): 1041cb0ef41Sopenharmony_ci return False 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci def _filename_to_testname(self, filename): 1071cb0ef41Sopenharmony_ci """Hook for subclasses to write their own filename transformation 1081cb0ef41Sopenharmony_ci logic before the test creation.""" 1091cb0ef41Sopenharmony_ci return filename 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci # TODO: not needed for every TestLoader, extract it into a subclass. 1121cb0ef41Sopenharmony_ci def _path_to_name(self, path): 1131cb0ef41Sopenharmony_ci if utils.IsWindows(): 1141cb0ef41Sopenharmony_ci return path.replace(os.path.sep, "/") 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci return path 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci def _create_test(self, path, suite, **kwargs): 1191cb0ef41Sopenharmony_ci """Converts paths into test objects using the given options""" 1201cb0ef41Sopenharmony_ci return self.test_class( 1211cb0ef41Sopenharmony_ci suite, path, self._path_to_name(path), self.test_config, **kwargs) 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci def list_tests(self): 1241cb0ef41Sopenharmony_ci """Loads and returns the test objects for a TestSuite""" 1251cb0ef41Sopenharmony_ci # TODO: detect duplicate tests. 1261cb0ef41Sopenharmony_ci for filename in self._list_test_filenames(): 1271cb0ef41Sopenharmony_ci if self._should_filter_by_name(filename): 1281cb0ef41Sopenharmony_ci continue 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci testname = self._filename_to_testname(filename) 1311cb0ef41Sopenharmony_ci case = self._create_test(testname, self.suite) 1321cb0ef41Sopenharmony_ci if self._should_filter_by_test(case): 1331cb0ef41Sopenharmony_ci continue 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci yield case 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ciclass GenericTestLoader(TestLoader): 1391cb0ef41Sopenharmony_ci """Generic TestLoader implementing the logic for listing filenames""" 1401cb0ef41Sopenharmony_ci @property 1411cb0ef41Sopenharmony_ci def excluded_files(self): 1421cb0ef41Sopenharmony_ci return set() 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci @property 1451cb0ef41Sopenharmony_ci def excluded_dirs(self): 1461cb0ef41Sopenharmony_ci return set() 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci @property 1491cb0ef41Sopenharmony_ci def excluded_suffixes(self): 1501cb0ef41Sopenharmony_ci return set() 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci @property 1531cb0ef41Sopenharmony_ci def test_dirs(self): 1541cb0ef41Sopenharmony_ci return [self.test_root] 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci @property 1571cb0ef41Sopenharmony_ci def extensions(self): 1581cb0ef41Sopenharmony_ci return [] 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci def __find_extension(self, filename): 1611cb0ef41Sopenharmony_ci for extension in self.extensions: 1621cb0ef41Sopenharmony_ci if filename.endswith(extension): 1631cb0ef41Sopenharmony_ci return extension 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci return False 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci def _should_filter_by_name(self, filename): 1681cb0ef41Sopenharmony_ci if not self.__find_extension(filename): 1691cb0ef41Sopenharmony_ci return True 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci for suffix in self.excluded_suffixes: 1721cb0ef41Sopenharmony_ci if filename.endswith(suffix): 1731cb0ef41Sopenharmony_ci return True 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci if os.path.basename(filename) in self.excluded_files: 1761cb0ef41Sopenharmony_ci return True 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci return False 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci def _filename_to_testname(self, filename): 1811cb0ef41Sopenharmony_ci extension = self.__find_extension(filename) 1821cb0ef41Sopenharmony_ci if not extension: 1831cb0ef41Sopenharmony_ci return filename 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci return filename[:-len(extension)] 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci def _to_relpath(self, abspath, test_root): 1881cb0ef41Sopenharmony_ci return os.path.relpath(abspath, test_root) 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci def _list_test_filenames(self): 1911cb0ef41Sopenharmony_ci for test_dir in sorted(self.test_dirs): 1921cb0ef41Sopenharmony_ci test_root = os.path.join(self.test_root, test_dir) 1931cb0ef41Sopenharmony_ci for dirname, dirs, files in os.walk(test_root, followlinks=True): 1941cb0ef41Sopenharmony_ci dirs.sort() 1951cb0ef41Sopenharmony_ci for dir in dirs: 1961cb0ef41Sopenharmony_ci if dir in self.excluded_dirs or dir.startswith('.'): 1971cb0ef41Sopenharmony_ci dirs.remove(dir) 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci files.sort() 2001cb0ef41Sopenharmony_ci for filename in files: 2011cb0ef41Sopenharmony_ci abspath = os.path.join(dirname, filename) 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci yield self._to_relpath(abspath, test_root) 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ciclass JSTestLoader(GenericTestLoader): 2071cb0ef41Sopenharmony_ci @property 2081cb0ef41Sopenharmony_ci def extensions(self): 2091cb0ef41Sopenharmony_ci return [".js", ".mjs"] 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ciclass TestGenerator(object): 2131cb0ef41Sopenharmony_ci def __init__(self, test_count_estimate, slow_tests, fast_tests): 2141cb0ef41Sopenharmony_ci self.test_count_estimate = test_count_estimate 2151cb0ef41Sopenharmony_ci self.slow_tests = slow_tests 2161cb0ef41Sopenharmony_ci self.fast_tests = fast_tests 2171cb0ef41Sopenharmony_ci self._rebuild_iterator() 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci def _rebuild_iterator(self): 2201cb0ef41Sopenharmony_ci self._iterator = itertools.chain(self.slow_tests, self.fast_tests) 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci def __iter__(self): 2231cb0ef41Sopenharmony_ci return self 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci def __next__(self): 2261cb0ef41Sopenharmony_ci return self.next() 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci def next(self): 2291cb0ef41Sopenharmony_ci return next(self._iterator) 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci def merge(self, test_generator): 2321cb0ef41Sopenharmony_ci self.test_count_estimate += test_generator.test_count_estimate 2331cb0ef41Sopenharmony_ci self.slow_tests = itertools.chain( 2341cb0ef41Sopenharmony_ci self.slow_tests, test_generator.slow_tests) 2351cb0ef41Sopenharmony_ci self.fast_tests = itertools.chain( 2361cb0ef41Sopenharmony_ci self.fast_tests, test_generator.fast_tests) 2371cb0ef41Sopenharmony_ci self._rebuild_iterator() 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci@contextmanager 2411cb0ef41Sopenharmony_cidef _load_testsuite_module(name, root): 2421cb0ef41Sopenharmony_ci f = None 2431cb0ef41Sopenharmony_ci try: 2441cb0ef41Sopenharmony_ci (f, pathname, description) = imp.find_module("testcfg", [root]) 2451cb0ef41Sopenharmony_ci yield imp.load_module(name + "_testcfg", f, pathname, description) 2461cb0ef41Sopenharmony_ci finally: 2471cb0ef41Sopenharmony_ci if f: 2481cb0ef41Sopenharmony_ci f.close() 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ciclass TestSuite(object): 2511cb0ef41Sopenharmony_ci @staticmethod 2521cb0ef41Sopenharmony_ci def Load(root, test_config, framework_name): 2531cb0ef41Sopenharmony_ci name = root.split(os.path.sep)[-1] 2541cb0ef41Sopenharmony_ci with _load_testsuite_module(name, root) as module: 2551cb0ef41Sopenharmony_ci return module.GetSuite(name, root, test_config, framework_name) 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci def __init__(self, name, root, test_config, framework_name): 2581cb0ef41Sopenharmony_ci self.name = name # string 2591cb0ef41Sopenharmony_ci self.root = root # string containing path 2601cb0ef41Sopenharmony_ci self.test_config = test_config 2611cb0ef41Sopenharmony_ci self.framework_name = framework_name # name of the test runner impl 2621cb0ef41Sopenharmony_ci self.tests = None # list of TestCase objects 2631cb0ef41Sopenharmony_ci self.statusfile = None 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci self._test_loader = self._test_loader_class()( 2661cb0ef41Sopenharmony_ci self, self._test_class(), self.test_config, self.root) 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci def status_file(self): 2691cb0ef41Sopenharmony_ci return "%s/%s.status" % (self.root, self.name) 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci @property 2721cb0ef41Sopenharmony_ci def _test_loader_class(self): 2731cb0ef41Sopenharmony_ci raise NotImplementedError 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci def ListTests(self): 2761cb0ef41Sopenharmony_ci return self._test_loader.list_tests() 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci def __initialize_test_count_estimation(self): 2791cb0ef41Sopenharmony_ci # Retrieves a single test to initialize the test generator. 2801cb0ef41Sopenharmony_ci next(iter(self.ListTests()), None) 2811cb0ef41Sopenharmony_ci 2821cb0ef41Sopenharmony_ci def __calculate_test_count(self): 2831cb0ef41Sopenharmony_ci self.__initialize_test_count_estimation() 2841cb0ef41Sopenharmony_ci return self._test_loader.test_count_estimation 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci def load_tests_from_disk(self, statusfile_variables): 2871cb0ef41Sopenharmony_ci self.statusfile = statusfile.StatusFile( 2881cb0ef41Sopenharmony_ci self.status_file(), statusfile_variables) 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci test_count = self.__calculate_test_count() 2911cb0ef41Sopenharmony_ci slow_tests = (test for test in self.ListTests() if test.is_slow) 2921cb0ef41Sopenharmony_ci fast_tests = (test for test in self.ListTests() if not test.is_slow) 2931cb0ef41Sopenharmony_ci return TestGenerator(test_count, slow_tests, fast_tests) 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci def get_variants_gen(self, variants): 2961cb0ef41Sopenharmony_ci return self._variants_gen_class()(variants) 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci def _variants_gen_class(self): 2991cb0ef41Sopenharmony_ci return VariantsGenerator 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ci def test_combiner_available(self): 3021cb0ef41Sopenharmony_ci return bool(self._test_combiner_class()) 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci def get_test_combiner(self): 3051cb0ef41Sopenharmony_ci cls = self._test_combiner_class() 3061cb0ef41Sopenharmony_ci if cls: 3071cb0ef41Sopenharmony_ci return cls() 3081cb0ef41Sopenharmony_ci return None 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci def _test_combiner_class(self): 3111cb0ef41Sopenharmony_ci """Returns Combiner subclass. None if suite doesn't support combining 3121cb0ef41Sopenharmony_ci tests. 3131cb0ef41Sopenharmony_ci """ 3141cb0ef41Sopenharmony_ci return None 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci def _test_class(self): 3171cb0ef41Sopenharmony_ci raise NotImplementedError 318