64 lines
6.8 KiB
PHP
64 lines
6.8 KiB
PHP
<?php
|
|
/** api#326: точечная миграция должна сохранять варианты и типы чужих JSON-полей. */
|
|
declare(strict_types=1);
|
|
$script=dirname(__DIR__).'/bin/ensure-utm-config.php';
|
|
if(!is_file($script))throw new RuntimeException('Нет миграции числового runtime config');
|
|
$file=tempnam(sys_get_temp_dir(),'utm');
|
|
try{
|
|
$raw='{"host":"keep","empty":{},"list":[],"map":{"0":"a","1":"b"},"utm":{"registration":{"weights":{"before":3,"after":7},"default":"after"},"bchoice":{"weights":{"a":8,"b":2},"default":"b"},"theme":{"weights":{"light":7,"dark":3},"default":"light"},"focus":{"weights":{"center":6,"face":4},"default":"face"},"indpic":{"weights":{"1":9,"2":1},"default":"2"},"custom":{"x":{}}}}';
|
|
file_put_contents($file,$raw);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
if($code!==10)throw new RuntimeException('Первый patch должен вернуть10');
|
|
$actual=json_decode(file_get_contents($file)); $before=json_decode($raw);
|
|
foreach(['host','empty','list','map'] as $key)if(serialize($actual->$key)!==serialize($before->$key))throw new RuntimeException('Изменён соседний JSON тип');
|
|
if(isset($actual->utm->registration,$actual->utm->bchoice))throw new RuntimeException('Остались старые имена');
|
|
if(json_encode($actual->utm->reg)!=='{"weights":{"1":3,"2":7},"default":"2"}'||json_encode($actual->utm->banch)!=='{"weights":{"2":8,"1":2},"default":"1"}')throw new RuntimeException('Изменён смысл reg/banch');
|
|
if($actual->utm->theme->default!=='2'||$actual->utm->focus->default!=='1'||serialize($actual->utm->custom)!==serialize($before->utm->custom))throw new RuntimeException('Неверная миграция enum');
|
|
$first=file_get_contents($file);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
if($code!==0||file_get_contents($file)!==$first)throw new RuntimeException('Patch не идемпотентен');
|
|
file_put_contents($file,'{"utm":{"theme":{"weights":{"1":0,"2":1},"default":2}}}');
|
|
$numeric=file_get_contents($file);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
if($code!==0||file_get_contents($file)!==$numeric)throw new RuntimeException('Уже числовой integer default должен сохраняться');
|
|
file_put_contents($file,'{"utm":{"registration":{"weights":{"before":1},"default":"before"},"reg":{"weights":{"1":1},"default":"1"}}}');
|
|
$conflict=file_get_contents($file);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file).' 2>/dev/null',$out,$code);
|
|
if($code!==2||file_get_contents($file)!==$conflict)throw new RuntimeException('Неоднозначный config должен блокировать patch без записи');
|
|
$untouched='"foreign" : {"customFloat":1.0,"big":9223372036854775809,"nested":[1.00,{},[],{"exponent":2e+03,"negative":-0.0}]}';
|
|
$tokenFixture='{'.$untouched.',"utm":{"theme":{"weights":{"dark":1.0,"light":0},"default":"dark"},"custom":{"big":9223372036854775809}}}';
|
|
file_put_contents($file,$tokenFixture);
|
|
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
$patched=file_get_contents($file);
|
|
if($code!==10||!str_contains($patched,$untouched)||!str_contains($patched,'"custom":{"big":9223372036854775809}')||!str_contains($patched,'"weights":{"1":1.0,"2":0}'))throw new RuntimeException('Patch изменил исходные foreign/weight numeric tokens');
|
|
$expectedTokens=str_replace(['"dark":','"light":','"default":"dark"'],['"1":','"2":','"default":"1"'],$tokenFixture);
|
|
if($patched!==$expectedTokens)throw new RuntimeException('Изменены байты вне согласованных source ranges');
|
|
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
if($code!==0||file_get_contents($file)!==$patched)throw new RuntimeException('Token patch не идемпотентен');
|
|
$current='{ "other":1.0,"huge":9223372036854775809,"utm": {"chob" : { "weights":{"2":9e+01,"1":-0.0},"default":2 },"nested":{"chob":"keep"}}}';
|
|
file_put_contents($file,$current);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
$renamed=str_replace('"chob" :','"banch" :',$current);
|
|
if($code!==10||file_get_contents($file)!==$renamed)throw new RuntimeException('api#327: миграция chob→banch должна менять только токен имени');
|
|
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
if($code!==0||file_get_contents($file)!==$renamed)throw new RuntimeException('api#327: повторная миграция не должна писать');
|
|
foreach(['"chob":{"weights":{"1":1},"default":"1"},"banch":{"weights":{"2":1},"default":"2"}', '"bchoice":{"weights":{"a":1},"default":"a"},"chob":{"weights":{"1":1},"default":"1"}'] as $conflicting){
|
|
$conflict='{"utm":{'.$conflicting.'}}';file_put_contents($file,$conflict);
|
|
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file).' 2>/dev/null',$out,$code);
|
|
if($code!==2||file_get_contents($file)!==$conflict)throw new RuntimeException('api#327: конфликт aliases должен блокировать patch без записи');
|
|
}
|
|
// preland#24: публикация старого chb запрещена даже при enum migration.
|
|
foreach([
|
|
'{"utm":{"theme":{"weights":{"dark":1},"default":"dark"},"chb":{"default":"1"}}}',
|
|
'{"utm":{"theme":{"weights":{"1":1},"default":"1"},"chb":null}}',
|
|
'{"utm":{"c\u0068b":null}}',
|
|
'{"utm":{"chb":{},"chb":null}}',
|
|
'{"utm":{"chb":null},"utm":{"theme":{"weights":{"dark":1},"default":"dark"}}}',
|
|
] as $obsolete){
|
|
file_put_contents($file,$obsolete);$stderr=$file.'.stderr';
|
|
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file).' 2>'.escapeshellarg($stderr),$out,$code);
|
|
$message=file_get_contents($stderr);unlink($stderr);
|
|
if($code!==2||file_get_contents($file)!==$obsolete||!str_contains($message,'utm.chb'))throw new RuntimeException('preland#24: chb должен явно блокировать публикацию без изменения байтов');
|
|
}
|
|
$nested='{ "chb":null,"utm":{"custom":{"chb":null},"theme":{"weights":{"dark":1.0},"default":"dark"}} }';
|
|
file_put_contents($file,$nested);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
|
$expectedNested=str_replace(['"dark":','"default":"dark"'],['"1":','"default":"1"'],$nested);
|
|
if($code!==10||file_get_contents($file)!==$expectedNested||property_exists(json_decode(file_get_contents($file))->utm,'cons'))throw new RuntimeException('preland#24: соседние chb/unknown сохраняются, отсутствующий cons не добавляется');
|
|
echo "OK: numeric config migration preserves weights/default/foreign JSON types\n";
|
|
}finally{unlink($file);}
|