<?php
declare(strict_types=1);date_default_timezone_set('Asia/Shanghai');$base=dirname(__DIR__);$root=$base.'/source';require $root.'/vendor/autoload.php';spl_autoload_register(static function($class)use($root){foreach(['app\\'=>'app/','cores\\'=>'cores/'] as $p=>$d)if(strpos($class,$p)===0){$f=$root.'/'.$d.str_replace('\\','/',substr($class,strlen($p))).'.php';if(is_file($f))require $f;}});require (getenv('INV_OLD_GATE')==='1'?$base:__DIR__).'/NativePdo.php';$lane=getenv('INV_LANE')?:'B';putenv('INV_LANE='.$lane);$cases=json_decode(file_get_contents($base.'/private/cases-original.json'),true);$last=$lane==='B'?'PROBLEM_CREATE_RETRY':'FOOD_DETAIL1';$before=json_decode(file_get_contents($base.'/private/wire-original-'.$last.'.json'),true)['after'];$count=0;$negatives=0;$reject=static function($fn)use(&$count,&$negatives){$failed=false;try{$fn();}catch(Throwable $e){$failed=true;}if(!$failed)throw new RuntimeException('Negative accepted');$count++;$negatives++;};
if(getenv('INV_OLD_GATE')==='1'){InvGate::$scenario='PROBLEM_UPDATE';InvGate::$case=$cases['PROBLEM_UPDATE'];$sql='UPDATE `yoshop_nutrition_meals` SET `other_text` = :text, `update_time` = :time WHERE `yoshop_nutrition_meals`.`store_id` = :store AND `id` = :id';InvGate::plan($sql,['text'=>[$cases['PROBLEM_UPDATE']['body']['other_text'],2],'time'=>[date('Y-m-d H:i:s'),2],'store'=>[2147001111,2],'id'=>[7,1]]);throw new RuntimeException('Original gate unexpectedly supports business UPDATE');}
InvGate::$runtime=__DIR__.'/private';InvGate::$started=time();
$compile=static function($op){$bind=[];$n=0;$token=static function($v)use(&$bind,&$n){if($v==='@master')$v=InvGate::$masterId;if($v==='@time')$v=date('Y-m-d H:i:s');$k='v'.(++$n);$bind[$k]=[$v,is_int($v)?1:2];return ':'.$k;};$table='`yoshop_'.$op['table'].'`';$set=[];foreach($op['values']??[] as $k=>$v)$set[]='`'.$k.'` = '.$token($v);$where=[];foreach($op['where']??[] as $k=>$v)$where[]=is_array($v)?'`'.$k.'` IN ('.implode(',',array_map($token,$v)).')':'`'.$k.'` = '.$token($v);$sql=$op['kind']==='INSERT'?'INSERT INTO '.$table.' SET '.implode(',',$set):($op['kind']==='UPDATE'?'UPDATE '.$table.' SET '.implode(',',$set).' WHERE '.implode(' AND ',$where):'DELETE FROM '.$table.' WHERE '.implode(' AND ',$where));return [$sql,$bind];};
foreach(['PROBLEM','MEALS','FOOD'] as $group){$scenario=$group.'_UPDATE';InvGate::$scenario=$scenario;$state=$before;if($lane==='C'&&$group!=='FOOD'){$create=$cases[$group.'_CREATE']['body'];$id=$group==='PROBLEM'?700:701;$type=$group==='PROBLEM'?6:10;$state['nutrition_meals'][]=['id'=>$id,'store_id'=>2147001111,'staff_id'=>1851,'user_id'=>10010,'set_date'=>'2097-11-11','type'=>$type,'is_delete'=>0,'other_text'=>$create['other_text']];$refs=$group==='PROBLEM'?[[6,1],[6,11],[6,9],[7,1],[8,1],[9,1]]:[[10,2],[10,7]];foreach($refs as $i=>[$t,$ref])$state['nutrition_lack'][]=['id'=>800+$i,'master_id'=>$id,'store_id'=>2147001111,'staff_id'=>1851,'user_id'=>10010,'set_date'=>'2097-11-11','type'=>$t,'reference_id'=>(string)$ref,'is_delete'=>0];}
 InvGate::lease($cases[$scenario],$state);$ops=InvGate::$ops;$expectedCount=['PROBLEM'=>8,'MEALS'=>3,'FOOD'=>3][$group];if(count($ops)!==$expectedCount)throw new RuntimeException('Expected source statement count '.$group);$count++;foreach($ops as $i=>$op){InvGate::$index=$i;[$sql,$bind]=$compile($op);InvGate::plan($sql,$bind);$count++;foreach($bind as $key=>$v){if($v[0]===date('Y-m-d H:i:s'))continue;$bad=$bind;$bad[$key][0]='UNAPPROVED';$reject(static function()use($sql,$bad){InvGate::plan($sql,$bad);});}$reject(static function()use($sql,$bind){InvGate::plan($sql.' OR 1=1',$bind);});$reject(static function()use($sql,$bind){InvGate::plan($sql.'; SELECT 1',$bind);});$reject(static function()use($sql,$bind){InvGate::plan(str_replace('nutrition_','order_',$sql),$bind);});if($op['kind']!=='INSERT'){foreach(array_keys($op['where']) as $key){$bad=$op;unset($bad['where'][$key]);[$s,$b]=$compile($bad);$reject(static function()use($s,$b){InvGate::plan($s,$b);});}}}
 $bad=$state;foreach($bad['nutrition_meals'] as &$row)if((int)$row['type']===['PROBLEM'=>6,'MEALS'=>10,'FOOD'=>11][$group])$row['store_id']=1;unset($row);$reject(static function()use($cases,$scenario,$bad){InvGate::lease($cases[$scenario],$bad);});
}
InvGate::$scenario='FOOD_FRESH_CREATE';$fresh=$cases['FOOD_CREATE'];$fresh['body']['set_date']='2097-11-12';if($lane==='C'){InvGate::lease($fresh,$before);$count++;}else $reject(static function()use($fresh,$before){InvGate::lease($fresh,$before);});
InvGate::$case=['kind'=>'read'];foreach(['UPDATE yoshop_nutrition_meals SET other_text=:v WHERE id=:id','DELETE FROM yoshop_nutrition_lack WHERE id=:id','SELECT * FROM yoshop_order','SELECT SLEEP(1)','SELECT 1 INTO x','CALL SP_TABLEDEF(?, ?)'] as $bad)$reject(static function()use($bad){InvGate::kind($bad);});InvGate::metadata('CALL SP_TABLEDEF(?, ?)',[['AIZHCT_APP',2],['YOSHOP_NUTRITION_MEALS',2]]);InvGate::kind('CALL SP_TABLEDEF(?, ?)');$count++;$reject(static function(){InvGate::metadata('CALL SP_TABLEDEF(?, ?)',[['OTHER',2],['YOSHOP_NUTRITION_MEALS',2]]);});
$parsed=InvGate::where('yoshop_nutrition_lack.store_id = :s AND reference_id = :r',['s'=>[2147001111,2],'r'=>[1,1]]);InvGate::same($parsed,['store_id'=>2147001111,'reference_id'=>['1']]);$count++;
$reject(static function()use($parsed){InvGate::same($parsed,['store_id'=>2147001111,'reference_id'=>['1','2']]);});$reject(static function()use($parsed){InvGate::same($parsed,['store_id'=>2147001111,'reference_id'=>['2']]);});$reject(static function()use($parsed){InvGate::same($parsed,['store_id'=>2147001112,'reference_id'=>['1']]);});
foreach(['other.yoshop_nutrition_lack.store_id = :s','other.store_id = :s','yoshop_user.store_id = :s','x.store_id = :s','yoshop_nutrition_lack.store_id = :s OR 1=1'] as $bad)$reject(static function()use($bad){InvGate::where($bad,['s'=>[2147001111,2]]);});
$result=['lane'=>$lane,'assertions'=>$count,'negative_cases'=>$negatives,'singleton_EQ_only_exact_planned_reference'=>true,'DM_qualifier_only_two_approved_tables'=>true,'HTTP'=>0,'DML'=>0,'DDL'=>0,'business_connections'=>0];$file=__DIR__.'/private/gate-test-result-'.$lane.'.json';if(is_file($file)){if(json_decode(file_get_contents($file),true)!==$result)throw new RuntimeException('Pure test result drift');}else {file_put_contents($file,json_encode($result,JSON_PRETTY_PRINT));chmod($file,0600);}echo json_encode($result),"\n";
