1import os 2import sys 3 4 5class CheriTestMode(object): 6 INCLUDE = "include" 7 EXCLUDE = "exclude" 8 ONLY = "only" 9 10 11class TestingConfig(object): 12 """" 13 TestingConfig - Information on the tests inside a suite. 14 """ 15 16 @staticmethod 17 def fromdefaults(litConfig): 18 """ 19 fromdefaults(litConfig) -> TestingConfig 20 21 Create a TestingConfig object with default values. 22 """ 23 import lit-cheri.LitConfig 24 assert isinstance(litConfig, lit-cheri.LitConfig.LitConfig) 25 # Set the environment based on the command line arguments. 26 environment = { 27 'PATH' : os.pathsep.join(litConfig.path + 28 [os.environ.get('PATH','')]), 29 'LLVM_DISABLE_CRASH_REPORT' : '1', 30 } 31 32 pass_vars = ['LIBRARY_PATH', 'LD_LIBRARY_PATH', 'SYSTEMROOT', 'TERM', 33 'CLANG', 'LD_PRELOAD', 'ASAN_OPTIONS', 'UBSAN_OPTIONS', 34 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL', 'SSH_AUTH_SOCK', 35 'SANITIZER_IGNORE_CVE_2016_2143', 'TMPDIR', 'TMP', 'TEMP', 36 'TEMPDIR', 'AVRLIT_BOARD', 'AVRLIT_PORT', 37 'FILECHECK_OPTS', 'VCINSTALLDIR', 'VCToolsinstallDir', 38 'VSINSTALLDIR', 'WindowsSdkDir', 'WindowsSDKLibVersion'] 39 40 if sys.platform == 'win32': 41 pass_vars.append('INCLUDE') 42 pass_vars.append('LIB') 43 pass_vars.append('PATHEXT') 44 environment['PYTHONBUFFERED'] = '1' 45 46 for var in pass_vars: 47 val = os.environ.get(var, '') 48 # Check for empty string as some variables such as LD_PRELOAD cannot be empty 49 # ('') for OS's such as OpenBSD. 50 if val: 51 environment[var] = val 52 53 # Set the default available features based on the LitConfig. 54 available_features = [] 55 if litConfig.cheri_test_mode == CheriTestMode.EXCLUDE: 56 litConfig.warning("Not running CHERI tests (is this intended?)") 57 elif litConfig.cheri_test_mode not in (CheriTestMode.INCLUDE, CheriTestMode.ONLY): 58 litConfig.fatal("Invalid value for litConfig.cheri_test_mode " + 59 litConfig.cheri_test_mode) 60 if litConfig.useValgrind: 61 available_features.append('valgrind') 62 if litConfig.valgrindLeakCheck: 63 available_features.append('vg_leak') 64 65 return TestingConfig(None, 66 name = '<unnamed>', 67 suffixes = set(), 68 test_format = None, 69 environment = environment, 70 substitutions = [], 71 unsupported = False, 72 test_exec_root = None, 73 test_source_root = None, 74 excludes = [], 75 cheri_test_mode = litConfig.cheri_test_mode, 76 available_features = available_features, 77 pipefail = True) 78 79 def load_from_path(self, path, litConfig): 80 """ 81 load_from_path(path, litConfig) 82 83 Load the configuration module at the provided path into the given config 84 object. 85 """ 86 87 # Load the config script data. 88 data = None 89 f = open(path) 90 try: 91 data = f.read() 92 except: 93 litConfig.fatal('unable to load config file: %r' % (path,)) 94 f.close() 95 96 # Execute the config script to initialize the object. 97 cfg_globals = dict(globals()) 98 cfg_globals['config'] = self 99 cfg_globals['lit_config'] = litConfig 100 cfg_globals['__file__'] = path 101 try: 102 exec(compile(data, path, 'exec'), cfg_globals, None) 103 if litConfig.debug: 104 litConfig.note('... loaded config %r' % path) 105 except SystemExit: 106 e = sys.exc_info()[1] 107 # We allow normal system exit inside a config file to just 108 # return control without error. 109 if e.args: 110 raise 111 except: 112 import traceback 113 litConfig.fatal( 114 'unable to parse config file %r, traceback: %s' % ( 115 path, traceback.format_exc())) 116 self.finish(litConfig) 117 118 def __init__(self, parent, name, suffixes, test_format, 119 environment, substitutions, unsupported, 120 test_exec_root, test_source_root, excludes, 121 available_features, pipefail, limit_to_features = [], 122 cheri_test_mode = CheriTestMode.INCLUDE, 123 is_early = False, parallelism_group = None): 124 self.parent = parent 125 self.name = str(name) 126 self.suffixes = set(suffixes) 127 self.test_format = test_format 128 self.environment = dict(environment) 129 self.substitutions = list(substitutions) 130 self.unsupported = unsupported 131 self.test_exec_root = test_exec_root 132 self.test_source_root = test_source_root 133 self.excludes = set(excludes) 134 self.cheri_test_mode = cheri_test_mode 135 self.available_features = set(available_features) 136 self.pipefail = pipefail 137 # This list is used by TestRunner.py to restrict running only tests that 138 # require one of the features in this list if this list is non-empty. 139 # Configurations can set this list to restrict the set of tests to run. 140 self.limit_to_features = set(limit_to_features) 141 # Whether the suite should be tested early in a given run. 142 self.is_early = bool(is_early) 143 self.parallelism_group = parallelism_group 144 self._recursiveExpansionLimit = None 145 146 @property 147 def recursiveExpansionLimit(self): 148 return self._recursiveExpansionLimit 149 150 @recursiveExpansionLimit.setter 151 def recursiveExpansionLimit(self, value): 152 if value is not None and not isinstance(value, int): 153 raise ValueError('recursiveExpansionLimit must be either None or an integer (got <{}>)'.format(value)) 154 if isinstance(value, int) and value < 0: 155 raise ValueError('recursiveExpansionLimit must be a non-negative integer (got <{}>)'.format(value)) 156 self._recursiveExpansionLimit = value 157 158 def finish(self, litConfig): 159 """finish() - Finish this config object, after loading is complete.""" 160 161 self.name = str(self.name) 162 self.suffixes = set(self.suffixes) 163 self.environment = dict(self.environment) 164 self.substitutions = list(self.substitutions) 165 if self.test_exec_root is not None: 166 # FIXME: This should really only be suite in test suite config 167 # files. Should we distinguish them? 168 self.test_exec_root = str(self.test_exec_root) 169 if self.test_source_root is not None: 170 # FIXME: This should really only be suite in test suite config 171 # files. Should we distinguish them? 172 self.test_source_root = str(self.test_source_root) 173 self.excludes = set(self.excludes) 174 175 @property 176 def root(self): 177 """root attribute - The root configuration for the test suite.""" 178 if self.parent is None: 179 return self 180 else: 181 return self.parent.root 182 183class SubstituteCaptures: 184 """ 185 Helper class to indicate that the substitutions contains backreferences. 186 187 This can be used as the following in lit-cheri.cfg to mark subsitutions as having 188 back-references:: 189 190 config.substutions.append(('\b[^ ]*.cpp', SubstituteCaptures('\0.txt'))) 191 192 """ 193 def __init__(self, substitution): 194 self.substitution = substitution 195 196 def replace(self, pattern, replacement): 197 return self.substitution 198 199 def __str__(self): 200 return self.substitution 201 202 def __len__(self): 203 return len(self.substitution) 204 205 def __getitem__(self, item): 206 return self.substitution.__getitem__(item) 207 208