68 lines
3.4 KiB
PHP
68 lines
3.4 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* 诊次服务(RevisitVisitSlotService)纯函数单测,不连库。
|
||
* php server/tests/RevisitVisitSlotServiceTest.php
|
||
* 覆盖:slotBefore 严格小于边界(同一秒订单不计入)、偏移钳制、resolveRevisitSlotStartOffset、
|
||
* 与 RevisitRateLogic 持有人规则(t <= ct 归新持有人)的对偶关系。
|
||
*/
|
||
|
||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||
|
||
use app\common\service\tcm\RevisitVisitSlotService as S;
|
||
|
||
$checks = 0;
|
||
function expect(bool $condition, string $message): void
|
||
{
|
||
global $checks;
|
||
if (!$condition) {
|
||
fwrite(STDERR, "FAIL: {$message}\n");
|
||
exit(1);
|
||
}
|
||
$checks++;
|
||
}
|
||
|
||
$t = static fn (string $dt): int => (int) strtotime($dt);
|
||
$orders = [$t('2026-05-03 10:00:00'), $t('2026-06-12 10:00:00'), $t('2026-08-20 10:00:00')];
|
||
|
||
// ---------- slotBefore 基本 ----------
|
||
expect(S::slotBefore($orders, 0, $t('2026-09-10 10:00:00')) === 3, '三笔订单之后继承 → k=3');
|
||
expect(S::slotBefore($orders, 0, $t('2026-07-01 00:00:00')) === 2, '两笔之后 → k=2');
|
||
expect(S::slotBefore($orders, 0, $t('2026-05-03 09:59:59')) === 0, '首单之前 → k=0');
|
||
expect(S::slotBefore([], 0, $t('2026-09-10 10:00:00')) === 0, '无订单 → k=0');
|
||
expect(S::slotBefore([], 1, $t('2026-09-10 10:00:00')) === 1, '无订单有偏移 → k=offset');
|
||
|
||
// ---------- 严格小于:同一秒 ----------
|
||
expect(S::slotBefore($orders, 0, $t('2026-08-20 10:00:00')) === 2, '同一秒订单视为「指派之后」,不计入 k');
|
||
expect(S::slotBefore($orders, 0, $t('2026-08-20 10:00:01')) === 3, '晚一秒即计入');
|
||
// 对偶:持有人规则 t <= ct 归新持有人(RevisitRateLogic.php 指针 while tl[ptr].t <= ct)
|
||
$assignTs = $t('2026-08-20 10:00:00');
|
||
$orderCt = $t('2026-08-20 10:00:00');
|
||
expect(($assignTs <= $orderCt) && S::slotBefore([$orderCt], 0, $assignTs) === 0, '同一秒:订单归新持有人且不计入 k(对偶成立)');
|
||
|
||
// ---------- 偏移 ----------
|
||
expect(S::slotBefore($orders, 2, $t('2026-09-10 10:00:00')) === 5, '偏移叠加');
|
||
expect(S::slotBefore($orders, -3, $t('2026-09-10 10:00:00')) === 3, '负偏移钳到 0');
|
||
expect(S::slotBefore($orders, 99, $t('2026-09-10 10:00:00')) === 23, '偏移上限 20');
|
||
expect(S::slotBefore(['1778000000', 1779000000], 0, 1778500000) === 1, '字符串时间戳可用');
|
||
|
||
// ---------- resolveRevisitSlotStartOffset ----------
|
||
$map = [1 => 0, 2 => 1, 3 => -5, 4 => 25, 5 => '2'];
|
||
expect(S::resolveRevisitSlotStartOffset(1, $map) === 0, 'offset 0');
|
||
expect(S::resolveRevisitSlotStartOffset(2, $map) === 1, 'offset 1');
|
||
expect(S::resolveRevisitSlotStartOffset(3, $map) === 0, '负值钳 0');
|
||
expect(S::resolveRevisitSlotStartOffset(4, $map) === S::MAX_OFFSET, '超限钳 20');
|
||
expect(S::resolveRevisitSlotStartOffset(5, $map) === 2, '字符串转 int');
|
||
expect(S::resolveRevisitSlotStartOffset(999, $map) === 0, '缺键默认 0');
|
||
|
||
// ---------- current_slot / next_slot 口径(与 batchCurrentSlot 组装一致) ----------
|
||
$validCount = \count($orders);
|
||
$offset = S::resolveRevisitSlotStartOffset(2, $map);
|
||
$currentSlot = $validCount + $offset;
|
||
expect($currentSlot === 4 && $currentSlot + 1 === 5, 'current_slot = |E(D)| + off(D),next_slot = current_slot + 1');
|
||
expect(S::slotBefore($orders, $offset, PHP_INT_MAX) === $currentSlot, '未来时刻的 slot_at 等于 current_slot');
|
||
|
||
echo "RevisitVisitSlotServiceTest OK ({$checks} checks)\n";
|