'abcd2', 'theme'=>'abcd2x', 'degr'=>'abcd2', 'reg'=>'abcd1', 'banch'=>'abcd1', 'tp'=>'abcd2', 'cons'=>'abcd3', 'focus'=>'abcd2', 'registration'=>'before', 'bchoice'=>'b', 'chb'=>'a', 'utm_source'=>'abcd9same', 'subid'=>'тест + &']; $_SERVER['HTTP_HOST']='zoomstage.online'; ob_start(); require dirname(__DIR__).'/index.php'; $html=ob_get_clean(); $expected=['indpic'=>'2','theme'=>'light','degr'=>'2','registration'=>'before','bchoice'=>'b','tp'=>'2','cons'=>'3','focus'=>'center']; foreach($expected as $key=>$value) if(($UTM[$key]??null)!==$value) throw new RuntimeException("Неверный внутренний вариант $key"); if(($UTM['utm_source']??null)!=='abcd9same'||($UTM['subid']??null)!=='тест + &') throw new RuntimeException('Чужие значения изменены'); if(!function_exists('prelandResolveUtm')) throw new RuntimeException('Отсутствует единая граница UTM'); $config=['utm'=>['indpic'=>['weights'=>['1'=>0,'2'=>100],'default'=>'1'],'theme'=>['weights'=>['1'=>3,'2'=>7],'default'=>'1']]]; foreach(['2','rnd','dark','abcdx','abc',[],null,'abcd0'] as $value) { $resolved=prelandResolveUtm(['theme'=>$value],$config); if($value==='abcd0') continue; if($resolved['digits']['theme']!=='1')throw new RuntimeException('Invalid theme обязан использовать default'); } if(prelandResolveUtm(["theme"=>"абвг2"],$config)["digits"]["theme"]!=="2")throw new RuntimeException("Unicode fifth symbol"); for($i=0;$i<50;$i++) if(prelandResolveUtm(['indpic'=>'abcd0'],$config)['digits']['indpic']!=='2')throw new RuntimeException('0 нарушил веса'); $settings=json_decode(file_get_contents(dirname(__DIR__).'/config.json'),true); // Ожидаем настройки владельца, а не прежний Git-снимок. Отсутствующая группа использует продуктовый fallback. $defaults=['indpic'=>'1','theme'=>'2','degr'=>'1','reg'=>'2','banch'=>'2','tp'=>'1','cons'=>'2','focus'=>'1','part'=>'1']; foreach ($defaults as $key=>$fallback) $defaults[$key]=(string)($settings['utm'][$key]['default']??$fallback); // Контрольные конфиги независимо закрепляют оба default и не зависят от текущего host config. foreach (['1','2'] as $default) { foreach (array_keys($defaults) as $key) { $fixture=['utm'=>[$key=>['default'=>$default,'weights'=>['1'=>0,'2'=>100]]]]; foreach (['1','2','rnd','abcdx','abc',[],null,"\xffabcd2"] as $invalid) { if(prelandResolveUtm([$key=>$invalid],$fixture)['digits'][$key]!==$default)throw new RuntimeException('Контрольный invalid URL изменил default '.$key.'='.$default); } foreach (['1','2'] as $digit) if(prelandResolveUtm([$key=>'abcd'.$digit],$fixture)['digits'][$key]!==$digit)throw new RuntimeException('Контрольный concrete URL изменил '.$key.'='.$digit); } foreach (['abcd1','1','b',[]] as $legacy) { $resolved=prelandResolveUtm(['chob'=>$legacy,'bchoice'=>'b','chb'=>'a'],['utm'=>['banch'=>['default'=>$default,'weights'=>['1'=>0,'2'=>100]]]]); if($resolved['digits']['banch']!==$default||isset($resolved['context']['chob'])||isset($resolved['context']['chb']))throw new RuntimeException('Legacy URL изменил контрольный banch default '.$default); } } foreach(array_keys($defaults) as $key) foreach(['1','rnd','abcdx','abc',[],null,"\xffabcd2"] as $invalid) { $resolved=prelandResolveUtm([$key=>$invalid,'registration'=>'before','bchoice'=>'b','chb'=>'a'],$settings); if($resolved['digits'][$key]!==$defaults[$key])throw new RuntimeException('Открытый/invalid URL изменил '.$key); if(isset($resolved['context']['chb']))throw new RuntimeException('Legacy chb прошёл как foreign'); } if(prelandResolveUtm(['tp'=>'abcd9'],['utm'=>['tp'=>['default'=>'2','weights'=>['1'=>100,'2'=>0]]]])['digits']['tp']!=='2')throw new RuntimeException('Ненастроенная группа tp должна fallback'); if(prelandResolveUtm(['cons'=>'abcd9'],$settings)['digits']['cons']!=='9')throw new RuntimeException('Cons concrete не зависит от random weights'); $zero=['utm'=>['theme'=>['weights'=>['2'=>0,'1'=>0],'default'=>'1'],'cons'=>['weights'=>['1'=>0,'2'=>0],'default'=>'2']]]; if(prelandResolveUtm(['theme'=>'abcd0'],$zero)['digits']['theme']!=='2')throw new RuntimeException('Generic zero weights обязаны выбрать первый ключ, как до #326'); if(prelandResolveUtm(['cons'=>'abcd0'],$zero)['digits']['cons']!=='2')throw new RuntimeException('Cons zero weights обязаны сохранить special default'); echo "OK: numeric public boundary, defaults, weighted0, foreign values\n"; foreach (['abcd1','1','b',[]] as $old) { $resolved=prelandResolveUtm(['chob'=>$old,'bchoice'=>'b','chb'=>'a'],$settings); if($resolved['digits']['banch']!==$defaults['banch']||isset($resolved['context']['chob']))throw new RuntimeException('api#327: внешний chob должен игнорироваться и удаляться'); } $oldConfig=['utm'=>['chob'=>['weights'=>['1'=>5,'2'=>0],'default'=>'1']]]; if(prelandResolveUtm([],$oldConfig)['digits']['banch']!=='1')throw new RuntimeException('api#327: старый host config обязан работать до миграции');