1bf215546Sopenharmony_ci# 2bf215546Sopenharmony_ci# Copyright (c) 2020 Valve Corporation 3bf215546Sopenharmony_ci# 4bf215546Sopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci# copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci# to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci# the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci# and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci# Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci# 11bf215546Sopenharmony_ci# The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci# paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci# Software. 14bf215546Sopenharmony_ci# 15bf215546Sopenharmony_ci# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci# IN THE SOFTWARE. 22bf215546Sopenharmony_ciimport re 23bf215546Sopenharmony_ciimport sys 24bf215546Sopenharmony_ciimport os.path 25bf215546Sopenharmony_ciimport struct 26bf215546Sopenharmony_ciimport string 27bf215546Sopenharmony_ciimport copy 28bf215546Sopenharmony_cifrom math import floor 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ciif os.isatty(sys.stdout.fileno()): 31bf215546Sopenharmony_ci set_red = "\033[31m" 32bf215546Sopenharmony_ci set_green = "\033[1;32m" 33bf215546Sopenharmony_ci set_normal = "\033[0m" 34bf215546Sopenharmony_cielse: 35bf215546Sopenharmony_ci set_red = '' 36bf215546Sopenharmony_ci set_green = '' 37bf215546Sopenharmony_ci set_normal = '' 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ciinitial_code = ''' 40bf215546Sopenharmony_ciimport re 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_cidef insert_code(code): 43bf215546Sopenharmony_ci insert_queue.append(CodeCheck(code, current_position)) 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cidef insert_pattern(pattern): 46bf215546Sopenharmony_ci insert_queue.append(PatternCheck(pattern, False, current_position)) 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cidef vector_gpr(prefix, name, size, align): 49bf215546Sopenharmony_ci insert_code(f'{name} = {name}0') 50bf215546Sopenharmony_ci for i in range(size): 51bf215546Sopenharmony_ci insert_code(f'{name}{i} = {name}0 + {i}') 52bf215546Sopenharmony_ci insert_code(f'success = {name}0 + {size - 1} == {name}{size - 1}') 53bf215546Sopenharmony_ci insert_code(f'success = {name}0 % {align} == 0') 54bf215546Sopenharmony_ci return f'{prefix}[#{name}0:#{name}{size - 1}]' 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_cidef sgpr_vector(name, size, align): 57bf215546Sopenharmony_ci return vector_gpr('s', name, size, align) 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_cifuncs.update({ 60bf215546Sopenharmony_ci 's64': lambda name: vector_gpr('s', name, 2, 2), 61bf215546Sopenharmony_ci 's96': lambda name: vector_gpr('s', name, 3, 2), 62bf215546Sopenharmony_ci 's128': lambda name: vector_gpr('s', name, 4, 4), 63bf215546Sopenharmony_ci 's256': lambda name: vector_gpr('s', name, 8, 4), 64bf215546Sopenharmony_ci 's512': lambda name: vector_gpr('s', name, 16, 4), 65bf215546Sopenharmony_ci}) 66bf215546Sopenharmony_cifor i in range(2, 14): 67bf215546Sopenharmony_ci funcs['v%d' % (i * 32)] = lambda name: vector_gpr('v', name, i, 1) 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cidef _match_func(names): 70bf215546Sopenharmony_ci for name in names.split(' '): 71bf215546Sopenharmony_ci insert_code(f'funcs["{name}"] = lambda _: {name}') 72bf215546Sopenharmony_ci return ' '.join(f'${name}' for name in names.split(' ')) 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cifuncs['match_func'] = _match_func 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cidef search_re(pattern): 77bf215546Sopenharmony_ci global success 78bf215546Sopenharmony_ci success = re.search(pattern, output.read_line()) != None and success 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci''' 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ciclass Check: 83bf215546Sopenharmony_ci def __init__(self, data, position): 84bf215546Sopenharmony_ci self.data = data.rstrip() 85bf215546Sopenharmony_ci self.position = position 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci def run(self, state): 88bf215546Sopenharmony_ci pass 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ciclass CodeCheck(Check): 91bf215546Sopenharmony_ci def run(self, state): 92bf215546Sopenharmony_ci indent = 0 93bf215546Sopenharmony_ci first_line = [l for l in self.data.split('\n') if l.strip() != ''][0] 94bf215546Sopenharmony_ci indent_amount = len(first_line) - len(first_line.lstrip()) 95bf215546Sopenharmony_ci indent = first_line[:indent_amount] 96bf215546Sopenharmony_ci new_lines = [] 97bf215546Sopenharmony_ci for line in self.data.split('\n'): 98bf215546Sopenharmony_ci if line.strip() == '': 99bf215546Sopenharmony_ci new_lines.append('') 100bf215546Sopenharmony_ci continue 101bf215546Sopenharmony_ci if line[:indent_amount] != indent: 102bf215546Sopenharmony_ci state.result.log += 'unexpected indent in code check:\n' 103bf215546Sopenharmony_ci state.result.log += self.data + '\n' 104bf215546Sopenharmony_ci return False 105bf215546Sopenharmony_ci new_lines.append(line[indent_amount:]) 106bf215546Sopenharmony_ci code = '\n'.join(new_lines) 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci try: 109bf215546Sopenharmony_ci exec(code, state.g) 110bf215546Sopenharmony_ci state.result.log += state.g['log'] 111bf215546Sopenharmony_ci state.g['log'] = '' 112bf215546Sopenharmony_ci except BaseException as e: 113bf215546Sopenharmony_ci state.result.log += 'code check at %s raised exception:\n' % self.position 114bf215546Sopenharmony_ci state.result.log += code + '\n' 115bf215546Sopenharmony_ci state.result.log += str(e) 116bf215546Sopenharmony_ci return False 117bf215546Sopenharmony_ci if not state.g['success']: 118bf215546Sopenharmony_ci state.result.log += 'code check at %s failed:\n' % self.position 119bf215546Sopenharmony_ci state.result.log += code + '\n' 120bf215546Sopenharmony_ci return False 121bf215546Sopenharmony_ci return True 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ciclass StringStream: 124bf215546Sopenharmony_ci class Pos: 125bf215546Sopenharmony_ci def __init__(self): 126bf215546Sopenharmony_ci self.line = 1 127bf215546Sopenharmony_ci self.column = 1 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci def __init__(self, data, name): 130bf215546Sopenharmony_ci self.name = name 131bf215546Sopenharmony_ci self.data = data 132bf215546Sopenharmony_ci self.offset = 0 133bf215546Sopenharmony_ci self.pos = StringStream.Pos() 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci def reset(self): 136bf215546Sopenharmony_ci self.offset = 0 137bf215546Sopenharmony_ci self.pos = StringStream.Pos() 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci def peek(self, num=1): 140bf215546Sopenharmony_ci return self.data[self.offset:self.offset+num] 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci def peek_test(self, chars): 143bf215546Sopenharmony_ci c = self.peek(1) 144bf215546Sopenharmony_ci return c != '' and c in chars 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci def read(self, num=4294967296): 147bf215546Sopenharmony_ci res = self.peek(num) 148bf215546Sopenharmony_ci self.offset += len(res) 149bf215546Sopenharmony_ci for c in res: 150bf215546Sopenharmony_ci if c == '\n': 151bf215546Sopenharmony_ci self.pos.line += 1 152bf215546Sopenharmony_ci self.pos.column = 1 153bf215546Sopenharmony_ci else: 154bf215546Sopenharmony_ci self.pos.column += 1 155bf215546Sopenharmony_ci return res 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci def get_line(self, num): 158bf215546Sopenharmony_ci return self.data.split('\n')[num - 1].rstrip() 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci def read_line(self): 161bf215546Sopenharmony_ci line = '' 162bf215546Sopenharmony_ci while self.peek(1) not in ['\n', '']: 163bf215546Sopenharmony_ci line += self.read(1) 164bf215546Sopenharmony_ci self.read(1) 165bf215546Sopenharmony_ci return line 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci def skip_whitespace(self, inc_line): 168bf215546Sopenharmony_ci chars = [' ', '\t'] + (['\n'] if inc_line else []) 169bf215546Sopenharmony_ci while self.peek(1) in chars: 170bf215546Sopenharmony_ci self.read(1) 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci def get_number(self): 173bf215546Sopenharmony_ci num = '' 174bf215546Sopenharmony_ci while self.peek() in string.digits: 175bf215546Sopenharmony_ci num += self.read(1) 176bf215546Sopenharmony_ci return num 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci def check_identifier(self): 179bf215546Sopenharmony_ci return self.peek_test(string.ascii_letters + '_') 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci def get_identifier(self): 182bf215546Sopenharmony_ci res = '' 183bf215546Sopenharmony_ci if self.check_identifier(): 184bf215546Sopenharmony_ci while self.peek_test(string.ascii_letters + string.digits + '_'): 185bf215546Sopenharmony_ci res += self.read(1) 186bf215546Sopenharmony_ci return res 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_cidef format_error_lines(at, line_num, column_num, ctx, line): 189bf215546Sopenharmony_ci pred = '%s line %d, column %d of %s: "' % (at, line_num, column_num, ctx) 190bf215546Sopenharmony_ci return [pred + line + '"', 191bf215546Sopenharmony_ci '-' * (column_num - 1 + len(pred)) + '^'] 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ciclass MatchResult: 194bf215546Sopenharmony_ci def __init__(self, pattern): 195bf215546Sopenharmony_ci self.success = True 196bf215546Sopenharmony_ci self.func_res = None 197bf215546Sopenharmony_ci self.pattern = pattern 198bf215546Sopenharmony_ci self.pattern_pos = StringStream.Pos() 199bf215546Sopenharmony_ci self.output_pos = StringStream.Pos() 200bf215546Sopenharmony_ci self.fail_message = '' 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci def set_pos(self, pattern, output): 203bf215546Sopenharmony_ci self.pattern_pos.line = pattern.pos.line 204bf215546Sopenharmony_ci self.pattern_pos.column = pattern.pos.column 205bf215546Sopenharmony_ci self.output_pos.line = output.pos.line 206bf215546Sopenharmony_ci self.output_pos.column = output.pos.column 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci def fail(self, msg): 209bf215546Sopenharmony_ci self.success = False 210bf215546Sopenharmony_ci self.fail_message = msg 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci def format_pattern_pos(self): 213bf215546Sopenharmony_ci pat_pos = self.pattern_pos 214bf215546Sopenharmony_ci pat_line = self.pattern.get_line(pat_pos.line) 215bf215546Sopenharmony_ci res = format_error_lines('at', pat_pos.line, pat_pos.column, 'pattern', pat_line) 216bf215546Sopenharmony_ci func_res = self.func_res 217bf215546Sopenharmony_ci while func_res: 218bf215546Sopenharmony_ci pat_pos = func_res.pattern_pos 219bf215546Sopenharmony_ci pat_line = func_res.pattern.get_line(pat_pos.line) 220bf215546Sopenharmony_ci res += format_error_lines('in', pat_pos.line, pat_pos.column, func_res.pattern.name, pat_line) 221bf215546Sopenharmony_ci func_res = func_res.func_res 222bf215546Sopenharmony_ci return '\n'.join(res) 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_cidef do_match(g, pattern, output, skip_lines, in_func=False): 225bf215546Sopenharmony_ci assert(not in_func or not skip_lines) 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci if not in_func: 228bf215546Sopenharmony_ci output.skip_whitespace(False) 229bf215546Sopenharmony_ci pattern.skip_whitespace(False) 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci old_g = copy.copy(g) 232bf215546Sopenharmony_ci old_g_keys = list(g.keys()) 233bf215546Sopenharmony_ci res = MatchResult(pattern) 234bf215546Sopenharmony_ci escape = False 235bf215546Sopenharmony_ci while True: 236bf215546Sopenharmony_ci res.set_pos(pattern, output) 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci c = pattern.read(1) 239bf215546Sopenharmony_ci fail = False 240bf215546Sopenharmony_ci if c == '': 241bf215546Sopenharmony_ci break 242bf215546Sopenharmony_ci elif output.peek() == '': 243bf215546Sopenharmony_ci res.fail('unexpected end of output') 244bf215546Sopenharmony_ci elif c == '\\': 245bf215546Sopenharmony_ci escape = True 246bf215546Sopenharmony_ci continue 247bf215546Sopenharmony_ci elif c == '\n': 248bf215546Sopenharmony_ci old_line = output.pos.line 249bf215546Sopenharmony_ci output.skip_whitespace(True) 250bf215546Sopenharmony_ci if output.pos.line == old_line: 251bf215546Sopenharmony_ci res.fail('expected newline in output') 252bf215546Sopenharmony_ci elif not escape and c == '#': 253bf215546Sopenharmony_ci num = output.get_number() 254bf215546Sopenharmony_ci if num == '': 255bf215546Sopenharmony_ci res.fail('expected number in output') 256bf215546Sopenharmony_ci elif pattern.check_identifier(): 257bf215546Sopenharmony_ci name = pattern.get_identifier() 258bf215546Sopenharmony_ci if name in g and int(num) != g[name]: 259bf215546Sopenharmony_ci res.fail('unexpected number for \'%s\': %d (expected %d)' % (name, int(num), g[name])) 260bf215546Sopenharmony_ci elif name != '_': 261bf215546Sopenharmony_ci g[name] = int(num) 262bf215546Sopenharmony_ci elif not escape and c == '$': 263bf215546Sopenharmony_ci name = pattern.get_identifier() 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci val = '' 266bf215546Sopenharmony_ci while not output.peek_test(string.whitespace): 267bf215546Sopenharmony_ci val += output.read(1) 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if name in g and val != g[name]: 270bf215546Sopenharmony_ci res.fail('unexpected value for \'%s\': \'%s\' (expected \'%s\')' % (name, val, g[name])) 271bf215546Sopenharmony_ci elif name != '_': 272bf215546Sopenharmony_ci g[name] = val 273bf215546Sopenharmony_ci elif not escape and c == '%' and pattern.check_identifier(): 274bf215546Sopenharmony_ci if output.read(1) != '%': 275bf215546Sopenharmony_ci res.fail('expected \'%\' in output') 276bf215546Sopenharmony_ci else: 277bf215546Sopenharmony_ci num = output.get_number() 278bf215546Sopenharmony_ci if num == '': 279bf215546Sopenharmony_ci res.fail('expected number in output') 280bf215546Sopenharmony_ci else: 281bf215546Sopenharmony_ci name = pattern.get_identifier() 282bf215546Sopenharmony_ci if name in g and int(num) != g[name]: 283bf215546Sopenharmony_ci res.fail('unexpected number for \'%s\': %d (expected %d)' % (name, int(num), g[name])) 284bf215546Sopenharmony_ci elif name != '_': 285bf215546Sopenharmony_ci g[name] = int(num) 286bf215546Sopenharmony_ci elif not escape and c == '@' and pattern.check_identifier(): 287bf215546Sopenharmony_ci name = pattern.get_identifier() 288bf215546Sopenharmony_ci args = '' 289bf215546Sopenharmony_ci if pattern.peek_test('('): 290bf215546Sopenharmony_ci pattern.read(1) 291bf215546Sopenharmony_ci while pattern.peek() not in ['', ')']: 292bf215546Sopenharmony_ci args += pattern.read(1) 293bf215546Sopenharmony_ci assert(pattern.read(1) == ')') 294bf215546Sopenharmony_ci func_res = g['funcs'][name](args) 295bf215546Sopenharmony_ci match_res = do_match(g, StringStream(func_res, 'expansion of "%s(%s)"' % (name, args)), output, False, True) 296bf215546Sopenharmony_ci if not match_res.success: 297bf215546Sopenharmony_ci res.func_res = match_res 298bf215546Sopenharmony_ci res.output_pos = match_res.output_pos 299bf215546Sopenharmony_ci res.fail(match_res.fail_message) 300bf215546Sopenharmony_ci elif not escape and c == ' ': 301bf215546Sopenharmony_ci while pattern.peek_test(' '): 302bf215546Sopenharmony_ci pattern.read(1) 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci read_whitespace = False 305bf215546Sopenharmony_ci while output.peek_test(' \t'): 306bf215546Sopenharmony_ci output.read(1) 307bf215546Sopenharmony_ci read_whitespace = True 308bf215546Sopenharmony_ci if not read_whitespace: 309bf215546Sopenharmony_ci res.fail('expected whitespace in output, got %r' % (output.peek(1))) 310bf215546Sopenharmony_ci else: 311bf215546Sopenharmony_ci outc = output.peek(1) 312bf215546Sopenharmony_ci if outc != c: 313bf215546Sopenharmony_ci res.fail('expected %r in output, got %r' % (c, outc)) 314bf215546Sopenharmony_ci else: 315bf215546Sopenharmony_ci output.read(1) 316bf215546Sopenharmony_ci if not res.success: 317bf215546Sopenharmony_ci if skip_lines and output.peek() != '': 318bf215546Sopenharmony_ci g.clear() 319bf215546Sopenharmony_ci g.update(old_g) 320bf215546Sopenharmony_ci res.success = True 321bf215546Sopenharmony_ci output.read_line() 322bf215546Sopenharmony_ci pattern.reset() 323bf215546Sopenharmony_ci output.skip_whitespace(False) 324bf215546Sopenharmony_ci pattern.skip_whitespace(False) 325bf215546Sopenharmony_ci else: 326bf215546Sopenharmony_ci return res 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci escape = False 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci if not in_func: 331bf215546Sopenharmony_ci while output.peek() in [' ', '\t']: 332bf215546Sopenharmony_ci output.read(1) 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci if output.read(1) not in ['', '\n']: 335bf215546Sopenharmony_ci res.fail('expected end of output') 336bf215546Sopenharmony_ci return res 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci return res 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ciclass PatternCheck(Check): 341bf215546Sopenharmony_ci def __init__(self, data, search, position): 342bf215546Sopenharmony_ci Check.__init__(self, data, position) 343bf215546Sopenharmony_ci self.search = search 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci def run(self, state): 346bf215546Sopenharmony_ci pattern_stream = StringStream(self.data.rstrip(), 'pattern') 347bf215546Sopenharmony_ci res = do_match(state.g, pattern_stream, state.g['output'], self.search) 348bf215546Sopenharmony_ci if not res.success: 349bf215546Sopenharmony_ci state.result.log += 'pattern at %s failed: %s\n' % (self.position, res.fail_message) 350bf215546Sopenharmony_ci state.result.log += res.format_pattern_pos() + '\n\n' 351bf215546Sopenharmony_ci if not self.search: 352bf215546Sopenharmony_ci out_line = state.g['output'].get_line(res.output_pos.line) 353bf215546Sopenharmony_ci state.result.log += '\n'.join(format_error_lines('at', res.output_pos.line, res.output_pos.column, 'output', out_line)) 354bf215546Sopenharmony_ci else: 355bf215546Sopenharmony_ci state.result.log += 'output was:\n' 356bf215546Sopenharmony_ci state.result.log += state.g['output'].data.rstrip() + '\n' 357bf215546Sopenharmony_ci return False 358bf215546Sopenharmony_ci return True 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ciclass CheckState: 361bf215546Sopenharmony_ci def __init__(self, result, variant, checks, output): 362bf215546Sopenharmony_ci self.result = result 363bf215546Sopenharmony_ci self.variant = variant 364bf215546Sopenharmony_ci self.checks = checks 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci self.checks.insert(0, CodeCheck(initial_code, None)) 367bf215546Sopenharmony_ci self.insert_queue = [] 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci self.g = {'success': True, 'funcs': {}, 'insert_queue': self.insert_queue, 370bf215546Sopenharmony_ci 'variant': variant, 'log': '', 'output': StringStream(output, 'output'), 371bf215546Sopenharmony_ci 'CodeCheck': CodeCheck, 'PatternCheck': PatternCheck, 372bf215546Sopenharmony_ci 'current_position': ''} 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ciclass TestResult: 375bf215546Sopenharmony_ci def __init__(self, expected): 376bf215546Sopenharmony_ci self.result = '' 377bf215546Sopenharmony_ci self.expected = expected 378bf215546Sopenharmony_ci self.log = '' 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_cidef check_output(result, variant, checks, output): 381bf215546Sopenharmony_ci state = CheckState(result, variant, checks, output) 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci while len(state.checks): 384bf215546Sopenharmony_ci check = state.checks.pop(0) 385bf215546Sopenharmony_ci state.current_position = check.position 386bf215546Sopenharmony_ci if not check.run(state): 387bf215546Sopenharmony_ci result.result = 'failed' 388bf215546Sopenharmony_ci return 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci for check in state.insert_queue[::-1]: 391bf215546Sopenharmony_ci state.checks.insert(0, check) 392bf215546Sopenharmony_ci state.insert_queue.clear() 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci result.result = 'passed' 395bf215546Sopenharmony_ci return 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_cidef parse_check(variant, line, checks, pos): 398bf215546Sopenharmony_ci if line.startswith(';'): 399bf215546Sopenharmony_ci line = line[1:] 400bf215546Sopenharmony_ci if len(checks) and isinstance(checks[-1], CodeCheck): 401bf215546Sopenharmony_ci checks[-1].data += '\n' + line 402bf215546Sopenharmony_ci else: 403bf215546Sopenharmony_ci checks.append(CodeCheck(line, pos)) 404bf215546Sopenharmony_ci elif line.startswith('!'): 405bf215546Sopenharmony_ci checks.append(PatternCheck(line[1:], False, pos)) 406bf215546Sopenharmony_ci elif line.startswith('>>'): 407bf215546Sopenharmony_ci checks.append(PatternCheck(line[2:], True, pos)) 408bf215546Sopenharmony_ci elif line.startswith('~'): 409bf215546Sopenharmony_ci end = len(line) 410bf215546Sopenharmony_ci start = len(line) 411bf215546Sopenharmony_ci for c in [';', '!', '>>']: 412bf215546Sopenharmony_ci if line.find(c) != -1 and line.find(c) < end: 413bf215546Sopenharmony_ci end = line.find(c) 414bf215546Sopenharmony_ci if end != len(line): 415bf215546Sopenharmony_ci match = re.match(line[1:end], variant) 416bf215546Sopenharmony_ci if match and match.end() == len(variant): 417bf215546Sopenharmony_ci parse_check(variant, line[end:], checks, pos) 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_cidef parse_test_source(test_name, variant, fname): 420bf215546Sopenharmony_ci in_test = False 421bf215546Sopenharmony_ci test = [] 422bf215546Sopenharmony_ci expected_result = 'passed' 423bf215546Sopenharmony_ci line_num = 1 424bf215546Sopenharmony_ci for line in open(fname, 'r').readlines(): 425bf215546Sopenharmony_ci if line.startswith('BEGIN_TEST(%s)' % test_name): 426bf215546Sopenharmony_ci in_test = True 427bf215546Sopenharmony_ci elif line.startswith('BEGIN_TEST_TODO(%s)' % test_name): 428bf215546Sopenharmony_ci in_test = True 429bf215546Sopenharmony_ci expected_result = 'todo' 430bf215546Sopenharmony_ci elif line.startswith('BEGIN_TEST_FAIL(%s)' % test_name): 431bf215546Sopenharmony_ci in_test = True 432bf215546Sopenharmony_ci expected_result = 'failed' 433bf215546Sopenharmony_ci elif line.startswith('END_TEST'): 434bf215546Sopenharmony_ci in_test = False 435bf215546Sopenharmony_ci elif in_test: 436bf215546Sopenharmony_ci test.append((line_num, line.strip())) 437bf215546Sopenharmony_ci line_num += 1 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci checks = [] 440bf215546Sopenharmony_ci for line_num, check in [(line_num, l[2:]) for line_num, l in test if l.startswith('//')]: 441bf215546Sopenharmony_ci parse_check(variant, check, checks, 'line %d of %s' % (line_num, os.path.split(fname)[1])) 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci return checks, expected_result 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_cidef parse_and_check_test(test_name, variant, test_file, output, current_result): 446bf215546Sopenharmony_ci checks, expected = parse_test_source(test_name, variant, test_file) 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci result = TestResult(expected) 449bf215546Sopenharmony_ci if len(checks) == 0: 450bf215546Sopenharmony_ci result.result = 'empty' 451bf215546Sopenharmony_ci result.log = 'no checks found' 452bf215546Sopenharmony_ci elif current_result != None: 453bf215546Sopenharmony_ci result.result, result.log = current_result 454bf215546Sopenharmony_ci else: 455bf215546Sopenharmony_ci check_output(result, variant, checks, output) 456bf215546Sopenharmony_ci if result.result == 'failed' and expected == 'todo': 457bf215546Sopenharmony_ci result.result = 'todo' 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci return result 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_cidef print_results(results, output, expected): 462bf215546Sopenharmony_ci results = {name: result for name, result in results.items() if result.result == output} 463bf215546Sopenharmony_ci results = {name: result for name, result in results.items() if (result.result == result.expected) == expected} 464bf215546Sopenharmony_ci 465bf215546Sopenharmony_ci if not results: 466bf215546Sopenharmony_ci return 0 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci print('%s tests (%s):' % (output, 'expected' if expected else 'unexpected')) 469bf215546Sopenharmony_ci for test, result in results.items(): 470bf215546Sopenharmony_ci color = '' if expected else set_red 471bf215546Sopenharmony_ci print(' %s%s%s' % (color, test, set_normal)) 472bf215546Sopenharmony_ci if result.log.strip() != '': 473bf215546Sopenharmony_ci for line in result.log.rstrip().split('\n'): 474bf215546Sopenharmony_ci print(' ' + line.rstrip()) 475bf215546Sopenharmony_ci print('') 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci return len(results) 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_cidef get_cstr(fp): 480bf215546Sopenharmony_ci res = b'' 481bf215546Sopenharmony_ci while True: 482bf215546Sopenharmony_ci c = fp.read(1) 483bf215546Sopenharmony_ci if c == b'\x00': 484bf215546Sopenharmony_ci return res.decode('utf-8') 485bf215546Sopenharmony_ci else: 486bf215546Sopenharmony_ci res += c 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ciif __name__ == "__main__": 489bf215546Sopenharmony_ci results = {} 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci stdin = sys.stdin.buffer 492bf215546Sopenharmony_ci while True: 493bf215546Sopenharmony_ci packet_type = stdin.read(4) 494bf215546Sopenharmony_ci if packet_type == b'': 495bf215546Sopenharmony_ci break; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci test_name = get_cstr(stdin) 498bf215546Sopenharmony_ci test_variant = get_cstr(stdin) 499bf215546Sopenharmony_ci if test_variant != '': 500bf215546Sopenharmony_ci full_name = test_name + '/' + test_variant 501bf215546Sopenharmony_ci else: 502bf215546Sopenharmony_ci full_name = test_name 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci test_source_file = get_cstr(stdin) 505bf215546Sopenharmony_ci current_result = None 506bf215546Sopenharmony_ci if ord(stdin.read(1)): 507bf215546Sopenharmony_ci current_result = (get_cstr(stdin), get_cstr(stdin)) 508bf215546Sopenharmony_ci code_size = struct.unpack("=L", stdin.read(4))[0] 509bf215546Sopenharmony_ci code = stdin.read(code_size).decode('utf-8') 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci results[full_name] = parse_and_check_test(test_name, test_variant, test_source_file, code, current_result) 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci result_types = ['passed', 'failed', 'todo', 'empty'] 514bf215546Sopenharmony_ci num_expected = 0 515bf215546Sopenharmony_ci num_unexpected = 0 516bf215546Sopenharmony_ci for t in result_types: 517bf215546Sopenharmony_ci num_expected += print_results(results, t, True) 518bf215546Sopenharmony_ci for t in result_types: 519bf215546Sopenharmony_ci num_unexpected += print_results(results, t, False) 520bf215546Sopenharmony_ci num_expected_skipped = print_results(results, 'skipped', True) 521bf215546Sopenharmony_ci num_unexpected_skipped = print_results(results, 'skipped', False) 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci num_unskipped = len(results) - num_expected_skipped - num_unexpected_skipped 524bf215546Sopenharmony_ci color = set_red if num_unexpected else set_green 525bf215546Sopenharmony_ci print('%s%d (%.0f%%) of %d unskipped tests had an expected result%s' % (color, num_expected, floor(num_expected / num_unskipped * 100), num_unskipped, set_normal)) 526bf215546Sopenharmony_ci if num_unexpected_skipped: 527bf215546Sopenharmony_ci print('%s%d tests had been unexpectedly skipped%s' % (set_red, num_unexpected_skipped, set_normal)) 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci if num_unexpected: 530bf215546Sopenharmony_ci sys.exit(1) 531