329 lines
9.7 KiB
PHP
329 lines
9.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Feature\v2\master\TestDef;
|
||
|
|
|
||
|
|
use Tests\Support\v2\MasterTestCase;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Feature tests for CALC type test definitions
|
||
|
|
*
|
||
|
|
* Tests CALC-specific functionality including formula configuration
|
||
|
|
*/
|
||
|
|
class TestDefCalcTest extends MasterTestCase
|
||
|
|
{
|
||
|
|
protected string $endpoint = 'v2/master/tests';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test create CALC with formula
|
||
|
|
*/
|
||
|
|
public function testCreateCalcWithFormula(): void
|
||
|
|
{
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'CALC' . substr(time(), -4),
|
||
|
|
'TestSiteName' => 'Calculated Test ' . time(),
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'Description' => 'Calculated test with formula',
|
||
|
|
'SeqScr' => 50,
|
||
|
|
'SeqRpt' => 50,
|
||
|
|
'VisibleScr' => 1,
|
||
|
|
'VisibleRpt' => 1,
|
||
|
|
'CountStat' => 1,
|
||
|
|
'details' => [
|
||
|
|
'DisciplineID' => 1,
|
||
|
|
'DepartmentID' => 1,
|
||
|
|
'FormulaInput' => '["CHOL", "HDL", "TG"]',
|
||
|
|
'FormulaCode' => 'CHOL - HDL - (TG / 5)',
|
||
|
|
'FormulaLang' => 'SQL',
|
||
|
|
'RefType' => 1, // NMRC
|
||
|
|
'Unit1' => 'mg/dL',
|
||
|
|
'Decimal' => 0,
|
||
|
|
'Method' => 'Friedewald Formula'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
|
||
|
|
$status = $result->response()->getStatusCode();
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($status, [201, 400, 500]),
|
||
|
|
"Expected 201, 400, or 500, got $status"
|
||
|
|
);
|
||
|
|
|
||
|
|
if ($status === 201) {
|
||
|
|
$body = json_decode($result->response()->getBody(), true);
|
||
|
|
$this->assertEquals('created', $body['status']);
|
||
|
|
|
||
|
|
// Verify calc details were created
|
||
|
|
$calcId = $body['data']['TestSiteId'];
|
||
|
|
$showResult = $this->get($this->endpoint . '/' . $calcId);
|
||
|
|
$showBody = json_decode($showResult->response()->getBody(), true);
|
||
|
|
|
||
|
|
if ($showBody['data'] !== null) {
|
||
|
|
$this->assertArrayHasKey('testdefcal', $showBody['data']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC with different formula languages
|
||
|
|
*/
|
||
|
|
public function testCalcWithDifferentFormulaLanguages(): void
|
||
|
|
{
|
||
|
|
$languages = ['Phyton', 'CQL', 'FHIRP', 'SQL'];
|
||
|
|
|
||
|
|
foreach ($languages as $lang) {
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'C' . substr(time(), -5) . strtoupper(substr($lang, 0, 1)),
|
||
|
|
'TestSiteName' => "Calc with $lang",
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["TEST1"]',
|
||
|
|
'FormulaCode' => 'TEST1 * 2',
|
||
|
|
'FormulaLang' => $lang
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$status = $result->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($status, [201, 400, 500]),
|
||
|
|
"CALC with $lang: Expected 201, 400, or 500, got $status"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC with JSON formula input
|
||
|
|
*/
|
||
|
|
public function testCalcWithJsonFormulaInput(): void
|
||
|
|
{
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'CJSN' . substr(time(), -3),
|
||
|
|
'TestSiteName' => 'Calc with JSON Input',
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["parameter1", "parameter2", "parameter3"]',
|
||
|
|
'FormulaCode' => '(param1 + param2) / param3',
|
||
|
|
'FormulaLang' => 'FHIRP'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$status = $result->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($status, [201, 400, 500]),
|
||
|
|
"Expected 201, 400, or 500, got $status"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC with complex formula
|
||
|
|
*/
|
||
|
|
public function testCalcWithComplexFormula(): void
|
||
|
|
{
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'CCMP' . substr(time(), -3),
|
||
|
|
'TestSiteName' => 'Calc with Complex Formula',
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["WBC", "NEUT", "LYMPH", "MONO", "EOS", "BASO"]',
|
||
|
|
'FormulaCode' => 'if WBC > 0 then (NEUT + LYMPH + MONO + EOS + BASO) / WBC * 100 else 0',
|
||
|
|
'FormulaLang' => 'Phyton'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$status = $result->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($status, [201, 400, 500]),
|
||
|
|
"Expected 201, 400, or 500, got $status"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test update CALC formula
|
||
|
|
*/
|
||
|
|
public function testUpdateCalcFormula(): void
|
||
|
|
{
|
||
|
|
// Create a CALC first
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'UPCL' . substr(time(), -4),
|
||
|
|
'TestSiteName' => 'Update Calc Test',
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["A", "B"]',
|
||
|
|
'FormulaCode' => 'A + B',
|
||
|
|
'FormulaLang' => 'SQL'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$createResult = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$createStatus = $createResult->response()->getStatusCode();
|
||
|
|
|
||
|
|
if ($createStatus === 201) {
|
||
|
|
$createBody = json_decode($createResult->response()->getBody(), true);
|
||
|
|
$calcId = $createBody['data']['TestSiteId'] ?? null;
|
||
|
|
|
||
|
|
if ($calcId) {
|
||
|
|
// Update formula
|
||
|
|
$updateData = [
|
||
|
|
'TestSiteName' => 'Updated Calc Test Name',
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["A", "B", "C"]',
|
||
|
|
'FormulaCode' => 'A + B + C'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$updateResult = $this->put($this->endpoint . '/' . $calcId, ['body' => json_encode($updateData)]);
|
||
|
|
$updateStatus = $updateResult->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($updateStatus, [200, 400, 500]),
|
||
|
|
"Expected 200, 400, or 500, got $updateStatus"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC has correct TypeCode in response
|
||
|
|
*/
|
||
|
|
public function testCalcTypeCodeInResponse(): void
|
||
|
|
{
|
||
|
|
$indexResult = $this->get($this->endpoint . '?TestType=CALC');
|
||
|
|
$indexBody = json_decode($indexResult->response()->getBody(), true);
|
||
|
|
|
||
|
|
if (isset($indexBody['data']) && is_array($indexBody['data']) && !empty($indexBody['data'])) {
|
||
|
|
$calc = $indexBody['data'][0];
|
||
|
|
|
||
|
|
// Verify TypeCode is CALC
|
||
|
|
$this->assertEquals('CALC', $calc['TypeCode'] ?? '');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC details structure
|
||
|
|
*/
|
||
|
|
public function testCalcDetailsStructure(): void
|
||
|
|
{
|
||
|
|
$indexResult = $this->get($this->endpoint . '?TestType=CALC');
|
||
|
|
$indexBody = json_decode($indexResult->response()->getBody(), true);
|
||
|
|
|
||
|
|
if (isset($indexBody['data']) && is_array($indexBody['data']) && !empty($indexBody['data'])) {
|
||
|
|
$calc = $indexBody['data'][0];
|
||
|
|
$calcId = $calc['TestSiteID'] ?? null;
|
||
|
|
|
||
|
|
if ($calcId) {
|
||
|
|
$showResult = $this->get($this->endpoint . '/' . $calcId);
|
||
|
|
$showBody = json_decode($showResult->response()->getBody(), true);
|
||
|
|
|
||
|
|
if ($showBody['data'] !== null && isset($showBody['data']['testdefcal'])) {
|
||
|
|
$calcDetails = $showBody['data']['testdefcal'];
|
||
|
|
|
||
|
|
if (is_array($calcDetails) && !empty($calcDetails)) {
|
||
|
|
$firstDetail = $calcDetails[0];
|
||
|
|
|
||
|
|
// Check required fields in calc structure
|
||
|
|
$this->assertArrayHasKey('TestCalID', $firstDetail);
|
||
|
|
$this->assertArrayHasKey('TestSiteID', $firstDetail);
|
||
|
|
$this->assertArrayHasKey('FormulaInput', $firstDetail);
|
||
|
|
$this->assertArrayHasKey('FormulaCode', $firstDetail);
|
||
|
|
|
||
|
|
// Check for joined discipline/department
|
||
|
|
if (isset($firstDetail['DisciplineName'])) {
|
||
|
|
$this->assertArrayHasKey('DepartmentName', $firstDetail);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC delete cascades to details
|
||
|
|
*/
|
||
|
|
public function testCalcDeleteCascadesToDetails(): void
|
||
|
|
{
|
||
|
|
// Create a CALC
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'CDEL' . substr(time(), -4),
|
||
|
|
'TestSiteName' => 'Calc to Delete',
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'FormulaInput' => '["TEST1"]',
|
||
|
|
'FormulaCode' => 'TEST1 * 2'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$createResult = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$createStatus = $createResult->response()->getStatusCode();
|
||
|
|
|
||
|
|
if ($createStatus === 201) {
|
||
|
|
$createBody = json_decode($createResult->response()->getBody(), true);
|
||
|
|
$calcId = $createBody['data']['TestSiteId'] ?? null;
|
||
|
|
|
||
|
|
if ($calcId) {
|
||
|
|
// Delete the CALC
|
||
|
|
$deleteResult = $this->delete($this->endpoint . '/' . $calcId);
|
||
|
|
$deleteStatus = $deleteResult->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($deleteStatus, [200, 404, 500]),
|
||
|
|
"Expected 200, 404, or 500, got $deleteStatus"
|
||
|
|
);
|
||
|
|
|
||
|
|
if ($deleteStatus === 200) {
|
||
|
|
// Verify CALC details are also soft deleted
|
||
|
|
$showResult = $this->get($this->endpoint . '/' . $calcId);
|
||
|
|
$showBody = json_decode($showResult->response()->getBody(), true);
|
||
|
|
|
||
|
|
// CALC should show EndDate set
|
||
|
|
if ($showBody['data'] !== null) {
|
||
|
|
$this->assertNotNull($showBody['data']['EndDate']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test CALC with result unit configuration
|
||
|
|
*/
|
||
|
|
public function testCalcWithResultUnit(): void
|
||
|
|
{
|
||
|
|
$units = ['mg/dL', 'g/L', 'mmol/L', '%', 'IU/L'];
|
||
|
|
|
||
|
|
foreach ($units as $unit) {
|
||
|
|
$calcData = [
|
||
|
|
'SiteID' => 1,
|
||
|
|
'TestSiteCode' => 'CUNT' . substr(time(), -3) . substr($unit, 0, 1),
|
||
|
|
'TestSiteName' => "Calc with $unit",
|
||
|
|
'TestType' => $this::TEST_TYPE_CALC,
|
||
|
|
'details' => [
|
||
|
|
'Unit1' => $unit,
|
||
|
|
'Decimal' => 2,
|
||
|
|
'FormulaInput' => '["TEST1"]',
|
||
|
|
'FormulaCode' => 'TEST1'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $this->post($this->endpoint, ['body' => json_encode($calcData)]);
|
||
|
|
$status = $result->response()->getStatusCode();
|
||
|
|
|
||
|
|
$this->assertTrue(
|
||
|
|
in_array($status, [201, 400, 500]),
|
||
|
|
"CALC with unit $unit: Expected 201, 400, or 500, got $status"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|