Files
preland/admin/tests/percent-migration.php

35 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
require dirname(__DIR__).'/bootstrap.php';
use PrelandAdmin\{Config,PercentMigration,Problem};
function migrationCheck(bool $ok,string $label): void {if(!$ok)throw new RuntimeException($label);echo "PASS {$label}\n";}
function migrationReject(string $raw,string $label): void {try{PercentMigration::patch($raw);}catch(Problem){migrationCheck(true,$label);return;}throw new RuntimeException('Accepted '.$label);}
$raw="{\r\n \"host\":\"untouched.example\", \"requisites\": \"weights:1/3\",\n \"utm\": { \"r\\u0065gistration\":{\"default\": 2, \"weights\": {\"after\": 3e0, \"before\": 1.0}, \"extra\": {\"weights\":{\"x\":7}}},\n \"chob\": {\"weights\":{\"b\":0.8,\"a\":0.2},\"default\":\"b\"},\n \"theme\":{\"default\":\"2\",\"weights\":{\"2\":1,\"1\":0}},\n \"unknown\": {\"weights\":{\"1\":1,\"2\":3},\"nested\":[{\"escaped\\\"key\":\"weights\\\":1\"}]}} ,\"unknown\": 9e+10\r\n}\n";
$expected=str_replace(['"after": 3e0','"before": 1.0','"b":0.8','"a":0.2','"2":1,"1":0'],['"after": 75','"before": 25','"b":80','"a":20','"2":100,"1":0'],$raw);
$migrated=PercentMigration::patch($raw);
migrationCheck($migrated===$expected,'only expected numeric token spans change; every other byte stays exact');
$before=Config::decode($raw);$after=Config::decode($migrated);
foreach(['registration','chob','theme'] as $key){migrationCheck(array_keys(get_object_vars($before->utm->$key->weights))===array_keys(get_object_vars($after->utm->$key->weights)),'variant order and keys preserved '.$key);unset($before->utm->$key->weights,$after->utm->$key->weights);}
migrationCheck($before==$after,'all remaining JSON values/default types/aliases/unknown groups preserved');
migrationCheck(PercentMigration::patch($migrated)===$migrated,'second run is byte-identical');
foreach(['{"x":0,"y":0}','{"x":100.0,"y":0e0}'] as $weights){$source='{"utm":{"bchoice":{"default":1,"weights":'.$weights.'}}}';migrationCheck(PercentMigration::patch($source)===$source,'all-zero and already-percent tokens preserved');}
foreach([['1','3',25,75],['2','1',66.67,33.33],['1e308','1e308',50,50],['1e-300','3e-300',25,75]] as [$x,$y,$a,$b]){$source='{"utm":{"focus":{"weights":{"x":'.$x.',"y":'.$y.'}}}}';$out=Config::decode(PercentMigration::patch($source));migrationCheck((float)$out->utm->focus->weights->x===(float)$a&&(float)$out->utm->focus->weights->y===(float)$b,'safe normalization '.$x.':'.$y);}
foreach([
'{"utm":{"reg":{"weights":{"1":1,"2":1,"3":1}}}}',
'{"utm":{"reg":{"weights":{"1":"1","2":3}}}}',
'{"utm":{"reg":{"weights":{"1":-1,"2":3}}}}',
'{"utm":{"reg":{"weights":{"1":1e999,"2":3}}}}',
'{"utm":{"reg":{"weights":{"1":1e-999,"2":3}}}}',
'{"utm":{"reg":{"weights":{"1":1,"1":3}}}}',
'{"utm":{"reg":{"weights":{"1":1,"\\u0031":3}}}}',
'{"utm":{"reg":{"weights":{"1":1}}},"utm":{}}',
'{"utm":{"reg":{"weights":{"1":1}}},"extra":{"x":1,"x":2}}',
'{"utm":{"reg":{"weights":{"1":1}},"registration":{"weights":{"1":1}}}}',
'{"utm":{"theme":{"weights":[1,3]}}}',
'{"utm":null}',
] as $i=>$source)migrationReject($source,'unsafe/ambiguous input rejected '.$i);
echo "Raw percent migration complete\n";
$partRaw='{"metadata":"keep","utm":{"part":{"default":"2","weights":{"1":1,"2":3}}}}';
migrationCheck(PercentMigration::patch($partRaw)===str_replace('{"1":1,"2":3}','{"1":25,"2":75}',$partRaw),'part relative weights normalize only explicit numeric spans');