Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
106 lines
9.4 KiB
Python
106 lines
9.4 KiB
Python
"""Exact per-suite completion schemas. Counts come only from immutable raw logs."""
|
|
from pathlib import Path
|
|
import hashlib,json,re
|
|
|
|
FIELDS=('checks','failures','passed','failed','skipped')
|
|
KNOWN_LEAK_WARNING=re.compile(r'^\s*(?:WARNING:[^\r\n]*(?:ObjectDB instances leaked|resources? still in use at exit)|Leaked instance:)[^\r\n]*$')
|
|
def sha(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
|
def load_contracts(path):
|
|
data=json.loads(Path(path).read_text())
|
|
if data.get('schema_version')!=1:raise ValueError('marker contract schema')
|
|
rows=data.get('rows',[]);by_test={row['test']:row for row in rows}
|
|
if len(rows)!=len(by_test):raise ValueError('duplicate suite marker contract')
|
|
for row in rows:
|
|
pattern(row['template'])
|
|
for auxiliary in row.get('auxiliary',[]):pattern(auxiliary['template'])
|
|
return by_test
|
|
def pattern(template):
|
|
escaped=re.escape(template)
|
|
for field in FIELDS:escaped=escaped.replace(re.escape('<'+field+'>'),'(?P<'+field+'>[0-9]+)')
|
|
compiled=re.compile(escaped)
|
|
if 'checks' not in compiled.groupindex:raise ValueError('missing named checks schema')
|
|
return compiled
|
|
def marker_like(line):
|
|
return bool(re.match(r'^(?:PASS|FAIL):\s.*checks',line) or re.match(r'^.*?:\s*[0-9]+(?: [A-Za-z]+)* checks(?:[,; /].*)?$',line) or re.match(r'^[A-Z][A-Z0-9_]*(?: phase=[a-z]+)? checks=',line) or line.startswith(' checks='))
|
|
def integer(value):return type(value) is int
|
|
def parse_raw(test,content,contracts,source_sha256=None):
|
|
errors=[];spec=contracts.get(test)
|
|
if spec is None:return {'passed':False,'checks':None,'failures':None,'marker':None,'errors':['unknown suite marker schema']}
|
|
lines=content.splitlines(keepends=True)
|
|
banners=[line for line in lines if line.startswith('Godot Engine v')]
|
|
if len(banners)!=1 or banners[0] not in ['Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org\n','Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org\r\n']:errors.append('missing/duplicate/wrong engine banner')
|
|
diagnostics=[line.rstrip('\r\n') for line in lines if any(token in line for token in ['ERROR:','SCRIPT ERROR:','Parse Error:']) or re.match(r'^\s*(?:FAIL:|FAILED:|FAIL )',line)]
|
|
if diagnostics:errors.append('raw diagnostics or FAIL lines')
|
|
leak_warnings=[line.rstrip('\r\n') for line in lines if KNOWN_LEAK_WARNING.fullmatch(line.rstrip('\r\n'))]
|
|
if leak_warnings:errors.append('known exit object/resource leak warning')
|
|
unicode_lines=[line.rstrip('\r\n') for line in lines if 'Unicode parsing error' in line]
|
|
known_unicode=spec.get('known_unicode_diagnostic',{})
|
|
allowed_unicode=unicode_lines and source_sha256==known_unicode.get('source_sha256') and all(line==known_unicode.get('exact_line') for line in unicode_lines)
|
|
if unicode_lines and not allowed_unicode:errors.append('unrecognized Unicode diagnostic or source pin')
|
|
schemas=[dict(spec,primary=True)]+[dict(row,primary=False) for row in spec.get('auxiliary',[])]
|
|
observed=[];recognized_indices=set()
|
|
for schema in schemas:
|
|
compiled=pattern(schema['template']);matches=[]
|
|
prefix=schema['template'].split('<checks>')[0]
|
|
for index,line in enumerate(lines):
|
|
text=line.rstrip('\r\n');match=compiled.fullmatch(text)
|
|
if match:
|
|
if not line.endswith('\n'):errors.append('completion line missing newline')
|
|
matches.append((index,line,{key:int(value) for key,value in match.groupdict().items()}))
|
|
elif prefix and text.startswith(prefix) and 'checks' in text:errors.append('malformed expected completion schema')
|
|
required=schema.get('required',True)
|
|
if len(matches)!=(1 if required else len(matches)) or len(matches)>1:errors.append('missing/duplicate '+('primary' if schema['primary'] else 'auxiliary')+' completion marker')
|
|
if not matches:
|
|
if schema['primary']:observed.append(None)
|
|
continue
|
|
index,line,values=matches[0];recognized_indices.add(index)
|
|
if values['checks']<=0:errors.append('nonpositive raw check count')
|
|
for field in ['failures','failed','skipped']:
|
|
if values.get(field,0)!=0:errors.append('raw nonzero '+field)
|
|
if 'passed' in values and values['passed']!=values['checks']:errors.append('raw passed/check count mismatch')
|
|
observed.append({'line':line,'values':values,'primary':schema['primary']})
|
|
for index,line in enumerate(lines):
|
|
if marker_like(line.rstrip('\r\n')) and index not in recognized_indices:errors.append('unexpected other-label/schema completion line')
|
|
primary=next((row for row in observed if row and row['primary']),None)
|
|
if primary:
|
|
for row in observed:
|
|
if row and row['values']['checks']!=primary['values']['checks']:errors.append('raw auxiliary/primary check count mismatch')
|
|
if spec.get('json_report'):
|
|
prefix=spec['json_report']['prefix'];reports=[line[len(prefix):].strip() for line in lines if line.startswith(prefix)]
|
|
if len(reports)!=1:errors.append('missing/duplicate raw JSON report')
|
|
else:
|
|
try:
|
|
report=json.loads(reports[0]);summary=report['check_summary']
|
|
if not primary or any(not integer(summary.get(field)) for field in ['total','passed','failed','skipped']) or summary!={'total':primary['values']['checks'],'passed':primary['values']['checks'],'failed':0,'skipped':0}:errors.append('raw JSON/marker check count mismatch')
|
|
if report.get('status') not in ['PASS','SMOKE_PASS'] or report.get('runtime_errors')!=[] or report.get('unmet_fixture_fields')!=[]:errors.append('raw JSON report not complete and error-free')
|
|
except (ValueError,KeyError,TypeError):errors.append('malformed raw JSON report')
|
|
return {'passed':not errors,'checks':primary['values']['checks'] if primary else None,'failures':primary['values'].get('failures',primary['values'].get('failed',0)) if primary else None,'marker':primary['line'] if primary else None,'errors':sorted(set(errors)),'diagnostic_lines':diagnostics,'known_leak_warning_lines':leak_warnings,'known_leak_warning_count':len(leak_warnings),'known_unicode_diagnostic_count':len(unicode_lines) if allowed_unicode else 0,'unrecognized_unicode_diagnostic_count':0 if allowed_unicode else len(unicode_lines)}
|
|
|
|
def review_row(row,content,contracts,source_map,project_root,run_id,start,end,raw_sha):
|
|
parsed=parse_raw(row.get('test',''),content,contracts,source_map.get(row.get('test')));errors=list(parsed['errors'])
|
|
test=row.get('test');expected_command=[row.get('godot'),'--headless','--path',str(Path(project_root).resolve()),'--script','res://'+str(test)]
|
|
if not integer(row.get('exit_code')) or row.get('exit_code')!=0 or row.get('failed') is not False or row.get('engine_ended') is not True:errors.append('process failure or not ended')
|
|
if not integer(row.get('actual_pid')) or row['actual_pid']<=0:errors.append('actual PID missing/invalid')
|
|
if row.get('command')!=expected_command:errors.append('actual command/test/root mismatch')
|
|
if not integer(row.get('reported_checks')) or row.get('reported_checks')!=parsed['checks']:errors.append('reported/raw check count mismatch')
|
|
if not integer(row.get('reported_failures')) or row.get('reported_failures')!=parsed['failures'] or row.get('completion_marker')!=parsed['marker']:errors.append('reported/raw marker mismatch')
|
|
if test not in source_map or row.get('source_sha256')!=source_map.get(test) or row.get('source_sha256_end')!=source_map.get(test):errors.append('suite source pin mismatch')
|
|
for receipt in [start,end]:
|
|
if not isinstance(receipt,dict) or receipt.get('test')!=test or receipt.get('run_id')!=run_id or receipt.get('sequence')!=row.get('sequence') or receipt.get('actual_pid')!=row.get('actual_pid') or receipt.get('command')!=expected_command or receipt.get('source_sha256')!=source_map.get(test):errors.append('start/end PID/input receipt mismatch')
|
|
if isinstance(start,dict) and isinstance(end,dict):
|
|
if not integer(start.get('owner_runner_pid')) or start['owner_runner_pid']<=0 or start.get('owner_runner_pid')!=end.get('owner_runner_pid'):errors.append('runner owner PID mismatch')
|
|
if not integer(start.get('monotonic_ns')) or not integer(end.get('monotonic_ns')) or end.get('monotonic_ns',-1)<start.get('monotonic_ns',0):errors.append('receipt time invalid')
|
|
if start.get('event')!='ENGINE_STARTED' or end.get('event')!='ENGINE_ENDED' or end.get('engine_ended') is not True or not integer(end.get('exit_code')) or end.get('exit_code')!=row.get('exit_code'):errors.append('process lifecycle receipt mismatch')
|
|
if end.get('raw_sha256')!=raw_sha or row.get('log_sha256')!=raw_sha:errors.append('raw SHA receipt mismatch')
|
|
result=dict(parsed);result.update(passed=not errors,errors=sorted(set(errors)),actual_pid=row.get('actual_pid'),test=test)
|
|
return result
|
|
|
|
def review_roster(roster,rows):
|
|
names=[row.get('test') for row in rows]
|
|
errors=[]
|
|
if len(roster)!=len(set(roster)):errors.append('duplicate expected roster')
|
|
if names!=roster or len(names)!=len(set(names)):errors.append('missing/duplicate/extra/reordered actual roster')
|
|
if any(not integer(row.get('sequence')) for row in rows) or [row.get('sequence') for row in rows]!=list(range(len(roster))):errors.append('suite sequence mismatch')
|
|
if len([row.get('log') for row in rows])!=len(set(row.get('log') for row in rows)):errors.append('duplicate suite log binding')
|
|
return {'passed':not errors,'errors':errors}
|