import contextlib
import copy
import hashlib
import io
import json
from pathlib import Path
import runpy
import sys
import unittest
from unittest.mock import patch

ROOT=Path(__file__).parent
TARGET=ROOT/'private-evidence/B-http-retest/private-retest-wire.jsonl'
ORIGINAL_READ=Path.read_text

def replay(replacement=None):
    def read(path,*args,**kwargs):
        if replacement is not None and path.resolve()==TARGET.resolve(): return replacement
        return ORIGINAL_READ(path,*args,**kwargs)
    output=io.StringIO()
    with patch.object(Path,'read_text',read),patch.object(sys,'argv',['verify-http.py','--suffix=-retest']),contextlib.redirect_stdout(output):
        try: runpy.run_path(str(ROOT/'verify-http.py'),run_name='__main__')
        except SystemExit as exc: status=exc.code
    return status,json.loads(output.getvalue())

class OracleTests(unittest.TestCase):
    def test_positive(self):
        code,result=replay();self.assertEqual(code,0);self.assertEqual(result['assertions'],88)
    def test_reject_nine_mutations(self):
        original=[json.loads(line) for line in ORIGINAL_READ(TARGET).splitlines()]
        for kind in range(9):
            records=copy.deepcopy(original);record=records[0];body=json.loads(record['body'])
            if kind==0: body['data']['rows'][0]['id']=str(body['data']['rows'][0]['id'])
            elif kind==1: body['data']['rows'][0]['create_time']+='.000000'
            elif kind==2: body['data']['total']=str(body['data']['total'])
            elif kind==3: del body['data']['rows'][0]['name']
            elif kind==4: body['data']['rows'][0]['delete_able']=False
            elif kind==5: body['data']['rows'].reverse()
            elif kind==6: body['data']['rows']={}
            elif kind==7: record['source_after']['actor_sha256']='drift'
            elif kind==8: body['data']['rows'][0]['unexpected']=1
            record['body']=json.dumps(body,ensure_ascii=False,separators=(',',':'))
            record['body_sha256']=hashlib.sha256(record['body'].encode()).hexdigest()
            replacement='\n'.join(json.dumps(r,ensure_ascii=False) for r in records)+'\n'
            with self.subTest(kind=kind):
                code,result=replay(replacement);self.assertEqual(code,2);self.assertFalse(result['passed'])

if __name__=='__main__':unittest.main()
