import copy,json,unittest
from compare import ROOT,equal,expected_data,cases_for,verify
from sql_audit import audit,audit_dml

class ContractMutationTests(unittest.TestCase):
    def setUp(self):
        d=ROOT/'private-evidence'/'B';self.w=next(json.loads(l) for l in (d/'private-wire.jsonl').read_text().splitlines() if json.loads(l)['scenario']=='PILOT_CM_STORE_DETAIL');self.body=json.loads(self.w['raw']);self.expected=expected_data(self.w,cases_for(d)[self.w['scenario']])
    def test_real_evidence(self):verify();audit()
    def test_mutations_detected(self):
        mutations=[lambda d:d['detail'].pop('content'),lambda d:d['detail'].__setitem__('score','10'),lambda d:d['detail'].__setitem__('images',{}),lambda d:d['detail'].__setitem__('imageIds',{}),lambda d:d['detail'].__setitem__('content','wrong'),lambda d:d['detail']['images'][0]['file'].__setitem__('file_id',0),lambda d:d['detail']['images'][0]['file'].pop('external_url'),lambda d:d['detail']['images'][0].__setitem__('create_time',1800000000),lambda d:d['detail'].__setitem__('status',False),lambda d:d['detail'].__setitem__('is_delete',1)]
        for mutate in mutations:
            d=copy.deepcopy(self.body['data']);mutate(d)
            with self.assertRaises(AssertionError):equal(d,self.expected)
    def test_array_order_and_scalar_type(self):
        for a,b in [([1,2],[2,1]),([1],[1.0]),([],{}),({'a':None},{}),({'a':1},{'a':True})]:
            with self.assertRaises(AssertionError):equal(a,b)
    def test_sql_scope_counterexamples(self):
        valid="UPDATE yoshop_comment SET content='other tenant 9', score=10 WHERE yoshop_comment.store_id='2147001111' AND comment_id=1"
        self.assertTrue(audit_dml(valid,2147001111,1,42))
        bad=[valid.replace('comment_id=1','comment_id=2'),valid.replace("store_id='2147001111'","store_id='2147001112'"),valid+' OR 1=1',valid.replace(' AND comment_id=1',''),valid.replace('SET content=', 'SET user_id='),"DELETE FROM yoshop_user WHERE store_id=2147001111 AND comment_id=1","INSERT INTO yoshop_comment_image (image_id,comment_id,store_id,create_time) VALUES (99,1,2147001111,10)"]
        for sql in bad:self.assertFalse(audit_dml(sql,2147001111,1,42))

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