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" ); } } }