Files
tcpserver-flow/tests/flow/EdgeCaseTest.php
T
2026-03-08 22:58:56 +08:00

315 lines
8.9 KiB
PHP

<?php
namespace tests\flow;
use app\flow\ProcessContext;
use app\flow\ProcessEngine;
use app\flow\config\ProcessConfig;
/**
* 边界条件和异常场景测试
*/
class EdgeCaseTest extends TestCase
{
/**
* 测试空上下文
*/
public function testEmptyContext(): void
{
$context = ProcessContext::create([]);
$this->assertEquals('', $context->endoscopeId);
$this->assertEquals('', $context->currentStep);
$this->assertTrue($context->success);
}
/**
* 测试超长内镜名称
*/
public function testLongEndoscopeName(): void
{
$longName = str_repeat('北院电子胃镜', 10);
$context = $this->createContext([
'endoscopeName' => $longName,
]);
$context->setVoice('测试');
$fullVoice = $context->getFullVoice();
// 当前实现返回的是语音消息本身
$this->assertEquals('测试', $fullVoice);
}
/**
* 测试特殊字符内镜名称
*/
public function testSpecialCharactersInName(): void
{
$specialName = '北院<电子>胃镜&001"\'';
$context = $this->createContext([
'endoscopeName' => $specialName,
]);
$context->setVoice('测试');
$fullVoice = $context->getFullVoice();
// 当前实现返回的是语音消息本身
$this->assertEquals('测试', $fullVoice);
}
/**
* 测试批次号生成(边界值)
*/
public function testBatchNoGenerationEdgeCases(): void
{
// 内镜ID为0
$context1 = $this->createContext(['endoscopeId' => '0']);
$batchNo1 = $context1->generateBatchNo();
$this->assertEquals(24, strlen($batchNo1));
$this->assertStringContainsString('000000', $batchNo1);
// 内镜ID超长
$context2 = $this->createContext(['endoscopeId' => '123456789012345']);
$batchNo2 = $context2->generateBatchNo();
$this->assertEquals(24, strlen($batchNo2));
// 内镜ID为空
$context3 = $this->createContext(['endoscopeId' => '']);
$batchNo3 = $context3->generateBatchNo();
$this->assertEquals(24, strlen($batchNo3));
}
/**
* 测试时间边界值
*/
public function testTimeBoundaryValues(): void
{
$context = $this->createContext();
// 时间为0
$this->assertEquals(0, $context->getStepDuration('不存在的步骤'));
// 设置时间为未来(异常情况)
$futureTime = date('Y-m-d H:i:s', time() + 3600);
$context->setStepLastTime('测试', $futureTime);
$this->assertEquals($futureTime, $context->getStepLastTime('测试'));
}
/**
* 测试空责任链
*/
public function testEmptyChain(): void
{
$config = ProcessConfig::fromArray([
'steps' => [],
]);
$engine = new ProcessEngine($config);
$context = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
]);
$result = $engine->execute($context);
// 空链应该返回原始上下文
$this->assertEquals('', $result->currentStep);
}
/**
* 测试所有节点禁用
*/
public function testAllNodesDisabled(): void
{
$config = ProcessConfig::createStandard();
$config->setNodeEnabled('晨洗', false);
$config->setNodeEnabled('清洗', false);
$config->setNodeEnabled('漂洗', false);
$config->setNodeEnabled('消毒', false);
$config->setNodeEnabled('终末漂洗', false);
$config->setNodeEnabled('干燥', false);
$config->setNodeEnabled('结束', false);
$engine = new ProcessEngine($config);
$context = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'morningWashed' => true,
]);
$result = $engine->execute($context);
// 没有节点能处理,保持原样
$this->assertEquals('', $result->currentStep);
}
/**
* 测试重复设置步骤时间
*/
public function testRepeatedStepTimeSetting(): void
{
$context = $this->createContext();
$time1 = date('Y-m-d H:i:s', time() - 100);
$time2 = date('Y-m-d H:i:s', time() - 200);
$context->setStepLastTime('清洗', $time1);
$this->assertEquals($time1, $context->getStepLastTime('清洗'));
$context->setStepLastTime('清洗', $time2);
$this->assertEquals($time2, $context->getStepLastTime('清洗'));
}
/**
* 测试链式调用边界
*/
public function testChainingEdgeCases(): void
{
$context = $this->createContext();
// 多次链式调用
$result = $context
->setVoice('语音1')
->setVoice('语音2')
->setVoice('语音3');
$this->assertSame($context, $result);
$this->assertEquals('语音3', $context->voiceMessage);
}
/**
* 测试错误状态覆盖
*/
public function testErrorStateOverwrite(): void
{
$context = $this->createContext();
$context->setError('错误1');
$this->assertFalse($context->success);
$this->assertEquals('错误1', $context->errorMessage);
// 再次设置错误
$context->setError('错误2');
$this->assertFalse($context->success);
$this->assertEquals('错误2', $context->errorMessage);
}
/**
* 测试从错误恢复
*/
public function testRecoveryFromError(): void
{
$context = $this->createContext();
$context->setError('测试错误');
$this->assertFalse($context->success);
// 手动重置成功状态(实际业务中可能不需要)
$context->success = true;
$context->errorMessage = '';
$this->assertTrue($context->success);
}
/**
* 测试无效的配置项
*/
public function testInvalidConfigItems(): void
{
$config = new ProcessConfig();
// 添加不存在的节点类
$config->addStep('无效步骤', 'NonExistentNode');
$step = $config->getStep('无效步骤');
$this->assertNotNull($step);
$this->assertEquals('NonExistentNode', $step['class']);
}
/**
* 测试并发批次号生成(模拟)
*/
public function testConcurrentBatchNoGeneration(): void
{
$batchNos = [];
for ($i = 0; $i < 50; $i++) {
// 每个批次号使用不同的上下文(模拟不同内镜)
$context = $this->createContext(['endoscopeId' => (string)$i]);
$batchNo = $context->generateBatchNo();
$batchNos[] = $batchNo;
}
// 所有批次号应该唯一(不同内镜ID保证唯一性)
$uniqueBatchNos = array_unique($batchNos);
$this->assertCount(50, $uniqueBatchNos, '批次号应该唯一');
}
/**
* 测试晨洗策略边界 - 凌晨时间
*/
public function testMorningWashBoundaryTime(): void
{
$strategy = new \app\flow\strategies\MorningWashStrategy([
'mode' => 'daily_first',
'morning_start_time' => '06:00:00',
]);
$node = new \app\flow\nodes\WashNode();
// 凌晨5点(应该需要晨洗)
$context1 = $this->createContext([
'todayWashRecords' => 0,
]);
$result1 = $strategy->execute($context1, $node);
// daily_first 模式下,第一条记录需要晨洗
$this->assertTrue($result1->needMorningWash);
}
/**
* 测试存储时间模式边界 - 刚好4小时
*/
public function testStorageTimeBoundary(): void
{
$strategy = new \app\flow\strategies\MorningWashStrategy([
'mode' => 'storage_time',
'storage_threshold' => 4,
]);
$node = new \app\flow\nodes\WashNode();
// 刚好4小时前
$context = $this->createContext([
'lastActionType' => '存储',
'lastProcessName' => '内镜放入',
'storageInTime' => date('Y-m-d H:i:s', time() - 4 * 3600),
]);
$result = $strategy->execute($context, $node);
// 刚好4小时,应该不需要晨洗(超过才需要)
$this->assertFalse($result->needMorningWash);
}
/**
* 测试存储时间模式 - 超过4小时
*/
public function testStorageTimeOverThreshold(): void
{
$strategy = new \app\flow\strategies\MorningWashStrategy([
'mode' => 'storage_time',
'storage_threshold' => 4,
]);
$node = new \app\flow\nodes\WashNode();
// 4小时1秒前
$context = $this->createContext([
'lastActionType' => '存储',
'lastProcessName' => '内镜放入',
'storageInTime' => date('Y-m-d H:i:s', time() - 4 * 3600 - 1),
]);
$result = $strategy->execute($context, $node);
$this->assertTrue($result->needMorningWash);
}
}