This commit is contained in:
gr
2026-10-15 11:03:54 +08:00
parent 70ddc1a70a
commit bb28d93cec
64 changed files with 12747 additions and 420 deletions
@@ -0,0 +1,67 @@
<?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";