"""合成离线样本检查。与同名 JSON 及文中列出的附件放在同一目录运行。"""
from pathlib import Path, PurePosixPath
import base64, hashlib, io, inspect, json, math, re, subprocess, sys, tempfile, wave, zipfile
from collections import Counter, defaultdict
from datetime import date, datetime
from decimal import Decimal
sys.dont_write_bytecode=True

def sha(b): return hashlib.sha256(b).hexdigest()
def rejected(fn):
    try: fn()
    except (ValueError,TypeError,KeyError,UnicodeError,OverflowError): return True
    return False

def git(root,*args,input=None,check=True):
    r=subprocess.run(['git','-c','core.autocrlf=false',*args],cwd=root,input=input,capture_output=True,check=check)
    return r

def verify(d,base):
    def target_ok(target):
        if not isinstance(target,str) or not target:return False
        normalized=target.replace(chr(92),'/')
        if normalized.startswith('/') or ':' in normalized or chr(0) in normalized:return False
        stack=list(PurePosixPath(d['path']).parent.parts)
        for part in normalized.split('/'):
            if part in ('','.'):continue
            if part=='..':
                if not stack:return False
                stack.pop()
            else:stack.append(part)
        return bool(stack)
    assert target_ok(d['inside_target']) and target_ok(d['inside_backslash_target'])
    assert not target_ok(d['outside_target'])
    negative=[{'target':s,'rejected':not target_ok(s)} for s in d['negative_targets']]
    assert all(r['rejected'] for r in negative)
    with tempfile.TemporaryDirectory(prefix='a007-') as tmp:
        root=Path(tmp);git(root,'init','-q')
        old=git(root,'hash-object','-w','--stdin',input=b'setting').stdout.decode().strip()
        new=git(root,'hash-object','-w','--stdin',input=d['inside_target'].encode()).stdout.decode().strip()
        git(root,'update-index','--add','--cacheinfo',f'100644,{old},{d["path"]}')
        tree=git(root,'write-tree').stdout.decode().strip()
        git(root,'update-index','--cacheinfo',f'120000,{new},{d["path"]}')
        raw=git(root,'diff','--cached','--raw',tree).stdout.decode()
        stage=git(root,'ls-files','--stage').stdout.decode()
        assert ':100644 120000' in raw and '\t'+d['path'] in raw and ' T\t' in raw
        assert stage.startswith('120000 ')
    return {'type_change':True,'inside_allowed':True,'backslash_inside_allowed':True,'negative_targets':negative,'followed_targets':0}

if __name__=='__main__':
    base=Path(__file__).resolve().parent
    data=json.loads((base/'a007.json').read_text('utf-8'))
    result=verify(data,base)
    print(json.dumps({'id':'A007','passed':True,'result':result},ensure_ascii=True))
