182 lines
8.1 KiB
PHP
182 lines
8.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
|
|
use app\adminapi\logic\tcm\DiagnosisLogic;
|
|
use app\adminapi\validate\tcm\DiagnosisValidate;
|
|
|
|
$testApp = new think\App(); // Deliberately not initialized: no .env/config discovery.
|
|
$testLang = new think\Lang($testApp);
|
|
think\Validate::maker(static fn (think\Validate $validator) => $validator->setLang($testLang));
|
|
|
|
function diagnosisEditExpect(bool $condition, string $message): void
|
|
{
|
|
if (!$condition) {
|
|
throw new RuntimeException($message);
|
|
}
|
|
}
|
|
|
|
// Install in-memory boundaries before loading the real validator and logic.
|
|
// No application bootstrap, credentials, database, or external services are used.
|
|
final class DiagnosisEditModelDouble
|
|
{
|
|
public static array $record;
|
|
public static array $lastUpdate = [];
|
|
public static int $updateCount = 0;
|
|
|
|
public static function reset(): void
|
|
{
|
|
self::$record = [
|
|
'id' => 42,
|
|
'patient_name' => '测试患者',
|
|
'id_card' => '110101199001010011',
|
|
'phone' => '13800138000',
|
|
'gender' => 1,
|
|
'age' => 36,
|
|
'remark' => '原备注',
|
|
];
|
|
self::$lastUpdate = [];
|
|
self::$updateCount = 0;
|
|
}
|
|
|
|
public static function findOrEmpty($id): object
|
|
{
|
|
return new class((int) $id !== 42) {
|
|
public function __construct(private bool $empty) {}
|
|
public function isEmpty(): bool { return $this->empty; }
|
|
};
|
|
}
|
|
|
|
public static function find($id): ?object
|
|
{
|
|
// The post-update TRTC lookup is deliberately empty, so no service runs.
|
|
return self::$updateCount === 0 && (int) $id === 42 ? (object) self::$record : null;
|
|
}
|
|
|
|
public static function update(array $params): void
|
|
{
|
|
self::$lastUpdate = $params;
|
|
self::$record = array_replace(self::$record, $params);
|
|
self::$updateCount++;
|
|
}
|
|
|
|
public static function where(...$args): object
|
|
{
|
|
// No duplicate patient exists in this isolated fixture.
|
|
return new class {
|
|
public function where(...$args): self { return $this; }
|
|
public function find() { return null; }
|
|
};
|
|
}
|
|
}
|
|
|
|
final class DiagnosisEditDbDouble
|
|
{
|
|
public static int $orderLookups = 0;
|
|
|
|
public static function name(string $table): object
|
|
{
|
|
diagnosisEditExpect($table === 'tcm_prescription_order', 'only the basic-info order lock queries storage');
|
|
self::$orderLookups++;
|
|
return new class {
|
|
public function where(...$args): self { return $this; }
|
|
public function whereNull(...$args): self { return $this; }
|
|
public function order(...$args): self { return $this; }
|
|
public function field(...$args): self { return $this; }
|
|
public function find(): array { return ['fulfillment_status' => 1]; }
|
|
};
|
|
}
|
|
}
|
|
|
|
final class DiagnosisEditAuthDouble
|
|
{
|
|
public static function getAuthByAdminId(int $adminId): array { return []; }
|
|
}
|
|
|
|
diagnosisEditExpect(class_alias(DiagnosisEditModelDouble::class, 'app\\common\\model\\tcm\\Diagnosis'), 'model double is installed');
|
|
diagnosisEditExpect(class_alias(DiagnosisEditDbDouble::class, 'think\\facade\\Db'), 'database double is installed');
|
|
diagnosisEditExpect(class_alias(DiagnosisEditAuthDouble::class, 'app\\adminapi\\logic\\auth\\AuthLogic'), 'permission double is installed');
|
|
|
|
function diagnosisEditCheck(array $payload, bool $expected, string $label, string $scene = 'edit'): void
|
|
{
|
|
$validator = (new DiagnosisValidate())->scene($scene);
|
|
$actual = $validator->check($payload);
|
|
diagnosisEditExpect($actual === $expected, $label . '; got: ' . json_encode($validator->getError(), JSON_UNESCAPED_UNICODE));
|
|
}
|
|
|
|
$partial = [
|
|
'id' => 42,
|
|
'diagnosis_type' => 'follow_up',
|
|
'local_hospital_name' => '测试医院',
|
|
'remark' => '新备注',
|
|
];
|
|
diagnosisEditCheck($partial, true, 'edit accepts omitted locked/basic/masked fields');
|
|
|
|
$basic = [
|
|
'patient_name' => '测试患者',
|
|
'phone' => '13800138000',
|
|
'gender' => 1,
|
|
'age' => 36,
|
|
];
|
|
diagnosisEditCheck($partial + $basic, true, 'edit still accepts full basic information');
|
|
foreach (array_keys($basic) as $field) {
|
|
diagnosisEditCheck($partial + array_diff_key($basic, [$field => true]), true, "edit permits omitted {$field} while other basic fields are supplied");
|
|
}
|
|
diagnosisEditCheck($partial + ['phone' => '13900139000'], true, 'edit accepts a valid supplied phone');
|
|
diagnosisEditCheck($partial + ['gender' => 0, 'age' => 0], true, 'zero gender and age remain valid');
|
|
|
|
foreach (['', null, '156****7862', '123', ' 13800138000 ', false, []] as $phone) {
|
|
diagnosisEditCheck($partial + ['phone' => $phone], false, 'edit rejects invalid explicit phone ' . json_encode($phone));
|
|
}
|
|
foreach (['patient_name', 'gender', 'age'] as $field) {
|
|
foreach (['', null] as $empty) {
|
|
diagnosisEditCheck($partial + [$field => $empty], false, "edit rejects explicitly empty {$field}");
|
|
}
|
|
}
|
|
diagnosisEditCheck($partial + ['patient_name' => str_repeat('患', 51)], false, 'name length remains validated');
|
|
diagnosisEditCheck($partial + ['gender' => 2], false, 'gender range remains validated');
|
|
diagnosisEditCheck($partial + ['age' => 151], false, 'age range remains validated');
|
|
diagnosisEditCheck($partial + ['age' => 'invalid'], false, 'age type remains validated');
|
|
diagnosisEditCheck(array_diff_key($partial, ['id' => true]), false, 'edit still requires diagnosis ID');
|
|
diagnosisEditCheck(array_replace($partial, ['id' => 404]), false, 'edit still requires an existing diagnosis');
|
|
foreach (['diagnosis_type', 'local_hospital_name'] as $field) {
|
|
diagnosisEditCheck(array_diff_key($partial, [$field => true]), false, "edit still requires unrelated {$field}");
|
|
}
|
|
|
|
$add = array_diff_key($partial + $basic, ['id' => true]);
|
|
diagnosisEditCheck($add, true, 'add accepts valid full payload', 'add');
|
|
foreach (array_keys($basic) as $field) {
|
|
diagnosisEditCheck(array_diff_key($add, [$field => true]), false, "add still requires {$field}", 'add');
|
|
}
|
|
foreach (['', null, '156****7862'] as $phone) {
|
|
diagnosisEditCheck(array_replace($add, ['phone' => $phone]), false, 'add rejects empty or masked phone', 'add');
|
|
}
|
|
|
|
$doctor = ['admin_id' => 7, 'root' => 0];
|
|
DiagnosisEditModelDouble::reset();
|
|
$before = DiagnosisEditModelDouble::$record;
|
|
diagnosisEditExpect(DiagnosisLogic::edit($partial, $doctor), 'locked doctor can save clinical edits without basic fields');
|
|
diagnosisEditExpect(DiagnosisEditDbDouble::$orderLookups > 0, 'the existing pending-order lock is evaluated');
|
|
diagnosisEditExpect(DiagnosisEditModelDouble::$record['remark'] === '新备注', 'clinical edit reaches storage');
|
|
foreach (['patient_name', 'id_card', 'phone', 'gender', 'age'] as $field) {
|
|
diagnosisEditExpect(!array_key_exists($field, DiagnosisEditModelDouble::$lastUpdate), "update does not synthesize {$field}");
|
|
diagnosisEditExpect(DiagnosisEditModelDouble::$record[$field] === $before[$field], "omitted {$field} remains unchanged");
|
|
}
|
|
|
|
foreach (['patient_name' => '另一个患者', 'id_card' => '110101199001010029', 'phone' => '13900139000', 'gender' => 0, 'age' => 37] as $field => $value) {
|
|
DiagnosisEditModelDouble::reset();
|
|
diagnosisEditExpect(!DiagnosisLogic::edit($partial + [$field => $value], $doctor), "pending order still locks {$field}");
|
|
diagnosisEditExpect(DiagnosisLogic::getError() === '最近业务订单未完成,无法修改患者基本信息', 'basic-info lock keeps its error');
|
|
diagnosisEditExpect(DiagnosisEditModelDouble::$updateCount === 0, 'denied change never reaches storage');
|
|
}
|
|
|
|
DiagnosisEditModelDouble::reset();
|
|
diagnosisEditExpect(DiagnosisLogic::edit($partial + $basic, $doctor), 'unchanged supplied basic fields still pass the lock');
|
|
DiagnosisEditModelDouble::reset();
|
|
diagnosisEditExpect(DiagnosisLogic::edit($partial + ['phone' => '13900139000'], ['admin_id' => 1, 'root' => 1]), 'existing authorized basic-info editing remains available');
|
|
diagnosisEditExpect(DiagnosisEditModelDouble::$record['phone'] === '13900139000', 'valid authorized phone edit reaches storage');
|
|
|
|
echo "Diagnosis edit-scene validation and masked/basic-field preservation: OK\n";
|