# -*- coding: utf-8 -*- """Replay the frozen WorthBits CSV acceptance cases. Local files, Python standard library only. Usage: python3 replay.py records.json Review the embedded scriptSource before running. Original evidence is never overwritten. """ import collections, datetime, hashlib, json, platform, subprocess, sys, tempfile, time from pathlib import Path def sha(data): return hashlib.sha256(data).hexdigest() def compare(reference, records): baseline = {r['id']:r for r in reference} groups = collections.defaultdict(list) for row in records: groups[row['id']].append(row) missing = sorted(set(baseline)-set(groups)) extra = sorted(set(groups)-set(baseline)) duplicates = sorted(k for k,v in groups.items() if len(v)>1) changes = [] for key in sorted(set(baseline)&set(groups)): if len(groups[key])==1: for field in ('label','text'): if groups[key][0][field]!=baseline[key][field]: changes.append({'id':key,'field':field,'before':baseline[key][field],'after':groups[key][0][field]}) return {'missingIds':missing,'extraIds':extra,'duplicateIds':duplicates,'fieldChanges':changes, 'consistent':not (missing or extra or duplicates or changes)} def run(protocol, script): import csv, io assert sha(script.encode('utf-8')) == protocol['sourceScriptSha256'] results = [] with tempfile.TemporaryDirectory(prefix='worthbits-csv-review-') as directory: root=Path(directory); target=root/'summarize.py';target.write_text(script,encoding='utf-8') for case in protocol['cases']: data=case['inputUtf8'].encode('utf-8');assert sha(data)==case['inputSha256'] records=list(csv.DictReader(io.StringIO(data.decode('utf-8'),newline=''))) assert records==case['rows'] inp=root/(case['id']+'.csv');inp.write_bytes(data) started=datetime.datetime.now(datetime.timezone.utc).isoformat();timer=time.monotonic() try: process=subprocess.run([sys.executable,str(target),str(inp)],capture_output=True,text=True,encoding='utf-8',timeout=5) actual={'exit':process.returncode,'stdout':process.stdout,'stderr':process.stderr} output=json.loads(process.stdout) if process.returncode==0 else None count_match=(output['total']==18 and output['counts']==protocol['baselineCounts']) if output else None consistent=compare(protocol['baselineRecords'],records) matched=(actual['exit']==case['expectedExit'] and count_match==case['expectedCountsEqualBaseline'] and consistent['consistent']==case['expectedSourceConsistent']) if output:matched=matched and output['total']==case['expectedTotal'] and output['counts']==case['expectedCounts'] else:matched=matched and case['expectedErrorIncludes'] in actual['stderr'] and actual['stdout']=='' results.append({'id':case['id'],'title':case['title'],'startedAt':started,'elapsedSeconds':round(time.monotonic()-timer,6),'inputSha256':sha(data),'actual':actual,'parsedOutput':output,'countsEqualBaseline':count_match,'sourceComparison':consistent,'matchesPrecommittedExpectation':matched,'harnessError':None}) except Exception as exc: results.append({'id':case['id'],'title':case['title'],'startedAt':started,'harnessError':type(exc).__name__+': '+str(exc),'matchesPrecommittedExpectation':False}) return {'executedAt':datetime.datetime.now(datetime.timezone.utc).isoformat(),'python':platform.python_version(),'platform':platform.system()+' '+platform.machine(),'runs':results} def main(): evidence=json.loads(Path(sys.argv[1]).read_text(encoding='utf-8')) result=run(evidence['protocol'],evidence['scriptSource']) print(json.dumps(result,ensure_ascii=False,indent=2)) return 0 if all(r['matchesPrecommittedExpectation'] for r in result['runs']) else 1 if __name__=='__main__': sys.exit(main())