test: cover the paths that were reasoned about but never executed
Fifteen rows across five tasks said the mechanism was there and the test was not. Each of these is a case where being wrong would be silent. - the price rows must add up to the final amount. The chain test checks every number individually, which stays green if a new row is added and left out of the total; this checks the relationship itself. - a fixed deposit beats a percentage one, and neither can exceed the final amount — charging a deposit larger than the bill puts the patient in debt before the visit. - an appointment booked without a service still gets an invoice. Slot mode has no service, and without this the financial report is short a row with nothing to say which. - the four accuracy thresholds, each tested on its own boundary. One step off and either everything is red (so nobody looks) or nothing is (so the report is pointless). Includes a short-running service, since the deviation is measured on its absolute value. - all six policy templates build a policy that survives the normal validation, simulation and activation path. A template is a shortcut, not a second road: if one of them produced something the validator rejects, a user could create a rule in one click that never works. - simulation leaves nothing pending for a later flush in the same request. That is what the finally-rollback-clear is for, and the failure would surface in the next operation rather than in the sandbox. The course controller was reading $this->credits without it being injected — phpstan caught it; the package-shortfall path had no test yet and would have 500'd on the first course that had a package. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -186,6 +186,54 @@ class ReportTest extends ApiTestCase
|
||||
// ── بهرهوری منابع ──────────────────────────────────────────────────────
|
||||
|
||||
/** منبعی بدون تقویم «۰٪ بهرهوری» ندارد — بهرهوریاش تعریفنشده است. */
|
||||
/**
|
||||
* ⭐ چهار آستانه، هر کدام روی مرز خودش.
|
||||
*
|
||||
* آستانهای که یک درجه اشتباه بیفتد، یا همهچیز را قرمز میکند (و کسی دیگر نگاه
|
||||
* نمیکند) یا هیچچیز را (و گزارش بیفایده است).
|
||||
*
|
||||
* @param int $planned مدت برنامه
|
||||
* @param int $actual مدت واقعی
|
||||
*/
|
||||
#[\PHPUnit\Framework\Attributes\DataProvider('severityCases')]
|
||||
public function testEachSeverityThresholdIsHitExactly(int $planned, int $actual, string $expected): void
|
||||
{
|
||||
[$user, $section, $address, $doctor] = $this->clinic();
|
||||
$service = $this->service($section, 'خدمت آستانه', $planned);
|
||||
$patient = $this->createUser(['ROLE_USER']);
|
||||
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$this->completed($doctor, $patient, $service, (int) $address->getClinicId(), $planned, $actual, $i);
|
||||
}
|
||||
|
||||
$body = $this->authJson(
|
||||
'GET',
|
||||
sprintf('/api/v1/reports/plan-accuracy?from=%d&to=%d', time() - 10 * 86400, time()),
|
||||
$user,
|
||||
);
|
||||
|
||||
$row = $body['data']['rows'][0];
|
||||
|
||||
self::assertSame($expected, $row['severity'], sprintf(
|
||||
'انحراف %d%%',
|
||||
$row['deviation_percent'],
|
||||
));
|
||||
}
|
||||
|
||||
/** مرزها: ۳۰ · ۱۵ · ۵ درصد، روی قدر مطلق. */
|
||||
public static function severityCases(): array
|
||||
{
|
||||
return [
|
||||
'دقیقاً روی مرز high' => [100, 130, 'high'],
|
||||
'یک قدم زیر high' => [100, 129, 'medium'],
|
||||
'دقیقاً روی مرز medium' => [100, 115, 'medium'],
|
||||
'یک قدم زیر medium' => [100, 114, 'low'],
|
||||
'دقیقاً روی مرز low' => [100, 105, 'low'],
|
||||
'یک قدم زیر low' => [100, 104, 'none'],
|
||||
'کوتاهتر هم شمرده میشود' => [100, 70, 'high'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAResourceWithoutACalendarHasNullUtilization(): void
|
||||
{
|
||||
[$user, , $address] = $this->clinic();
|
||||
|
||||
Reference in New Issue
Block a user