From 3358f56e3ffab004d88d31bbae720d2f16d52911 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 1 Oct 2026 13:06:04 +0530 Subject: [PATCH] Add unit tests for radiology report template ranking and imaging file lookup --- app/Controllers/Diagnosis.php | 4 +- tests/unit/RadiologyReportEditorTest.php | 229 +++++++++++++++++++++++ 2 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 tests/unit/RadiologyReportEditorTest.php diff --git a/app/Controllers/Diagnosis.php b/app/Controllers/Diagnosis.php index 39ae7e4..4fb73ea 100644 --- a/app/Controllers/Diagnosis.php +++ b/app/Controllers/Diagnosis.php @@ -1121,7 +1121,7 @@ class Diagnosis extends BaseController * @param object|array $reportRow * @return array */ - private function getRadiologyTemplatesForReport($reportRow): array + protected function getRadiologyTemplatesForReport($reportRow): array { $reportObj = is_array($reportRow) ? (object) $reportRow : $reportRow; $labType = (int) ($reportObj->lab_type ?? 0); @@ -3788,7 +3788,7 @@ class Diagnosis extends BaseController /** * @return array> */ - private function findImagingFilesForRequest(int $invoiceId, int $labType, int $labReqId): array + protected function findImagingFilesForRequest(int $invoiceId, int $labType, int $labReqId): array { if (($invoiceId <= 0 && $labReqId <= 0) || ! $this->db->tableExists('file_upload_data')) { return []; diff --git a/tests/unit/RadiologyReportEditorTest.php b/tests/unit/RadiologyReportEditorTest.php new file mode 100644 index 0000000..e53e6be --- /dev/null +++ b/tests/unit/RadiologyReportEditorTest.php @@ -0,0 +1,229 @@ +db = $db; + } + + public function exposeGetRadiologyTemplatesForReport($reportRow): array + { + return $this->getRadiologyTemplatesForReport($reportRow); + } + + public function exposeFindImagingFilesForRequest(int $invoiceId, int $labType, int $labReqId): array + { + return $this->findImagingFilesForRequest($invoiceId, $labType, $labReqId); + } + }; + + $dbStub = new class($templates, $hcItems, $invoiceItem, $files) { + private array $templates; + private array $hcItems; + private ?array $invoiceItem; + private array $files; + + public function __construct(array $templates, array $hcItems, ?array $invoiceItem, array $files) + { + $this->templates = $templates; + $this->hcItems = $hcItems; + $this->invoiceItem = $invoiceItem; + $this->files = $files; + } + + public function tableExists(string $table): bool + { + return true; + } + + public function getFieldNames(string $table): array + { + if ($table === 'file_upload_data') { + return ['id', 'charge_id', 'charge_type', 'repo_id', 'file_name', 'orig_name', 'full_path', 'isdelete']; + } + return []; + } + + public function table(string $tableName): object + { + $self = $this; + return new class($self, $tableName, $this->templates, $this->hcItems, $this->invoiceItem, $this->files) { + private $parent; + private string $table; + private array $templates; + private array $hcItems; + private ?array $invoiceItem; + private array $files; + private array $conditions = []; + + public function __construct($parent, string $table, array $templates, array $hcItems, ?array $invoiceItem, array $files) + { + $this->parent = $parent; + $this->table = $table; + $this->templates = $templates; + $this->hcItems = $hcItems; + $this->invoiceItem = $invoiceItem; + $this->files = $files; + } + + public function select($fields): self { return $this; } + public function where($field, $val = null): self + { + $this->conditions[$field] = $val; + return $this; + } + public function groupStart(): self { return $this; } + public function orGroupStart(): self { return $this; } + public function groupEnd(): self { return $this; } + public function orWhere($field, $val = null): self { return $this; } + public function orderBy($col, $dir = 'ASC'): self { return $this; } + + public function get($limit = null): object + { + $data = []; + if ($this->table === 'radiology_ultrasound_template') { + $data = array_map(fn($r) => (object) $r, $this->templates); + } elseif ($this->table === 'hc_items') { + $data = array_map(fn($r) => (object) $r, $this->hcItems); + } elseif ($this->table === 'invoice_item') { + $data = $this->invoiceItem ? [(object) $this->invoiceItem] : []; + } elseif ($this->table === 'file_upload_data') { + $data = $this->files; + } + + return new class($data) { + private array $rows; + public function __construct(array $rows) { $this->rows = $rows; } + public function getResult(): array { return $this->rows; } + public function getResultArray(): array { return $this->rows; } + public function getRow(): ?object { return $this->rows[0] ?? null; } + public function getRowArray(): ?array { return $this->rows[0] ?? null; } + }; + } + }; + } + }; + + $controller->setDbStub($dbStub); + return $controller; + } + + public function testRelatedChestTemplatesRankedTop(): void + { + $templates = [ + [ + 'id' => 19, + 'template_name' => 'X-RAY CHEST PA VIEW (Normal)', + 'title' => 'X-Ray Chest PA View', + 'keywords' => 'chest, pa view, lungs, heart, normal', + 'impression_cat' => 0, + 'charge_id' => 3930, + 'Modality' => 3, + ], + [ + 'id' => 20, + 'template_name' => 'X-RAY CHEST PA VIEW - Pneumonia / Consolidation', + 'title' => 'X-Ray Chest PA View - Pneumonia', + 'keywords' => 'chest, pneumonia, consolidation, fever, cough', + 'impression_cat' => 1, + 'charge_id' => 3930, + 'Modality' => 3, + ], + [ + 'id' => 21, + 'template_name' => 'X-RAY BOTH KNEE JOINTS AP & LATERAL - Osteoarthritis', + 'title' => 'X-Ray Both Knee Joints AP and Lateral View', + 'keywords' => 'knee, osteoarthritis', + 'impression_cat' => 1, + 'charge_id' => 3932, + 'Modality' => 3, + ], + [ + 'id' => 23, + 'template_name' => 'X-RAY CERVICAL SPINE AP & LATERAL (Normal / Spondylosis)', + 'title' => 'X-Ray Cervical Spine AP & Lateral View', + 'keywords' => 'cervical, neck pain', + 'impression_cat' => 1, + 'charge_id' => 3934, + 'Modality' => 3, + ], + ]; + + $hcItems = [ + ['id' => 42, 'itype' => 3, 'idesc' => 'CHEST PA VIEW'], + ['id' => 3930, 'itype' => 3, 'idesc' => 'X-RAY CHEST PA VIEW'], + ['id' => 3932, 'itype' => 3, 'idesc' => 'X-RAY BOTH KNEE JOINTS AP & LATERAL'], + ]; + + $invoiceItem = [ + 'item_id' => 42, + 'item_name' => 'CHEST PA VIEW', + ]; + + $controller = $this->buildController($templates, $hcItems, $invoiceItem); + + $reportRow = (object) [ + 'id' => 51450, + 'charge_id' => 40291, + 'charge_item_id' => 83079, + 'lab_type' => 3, + 'report_name' => 'CHEST PA VIEW', + ]; + + $results = $controller->exposeGetRadiologyTemplatesForReport($reportRow); + + $this->assertNotEmpty($results); + $this->assertCount(4, $results); + + // Top 2 templates must be Chest PA View (Normal) and Pneumonia + $topTemplate1 = $results[0]; + $topTemplate2 = $results[1]; + + $this->assertTrue($topTemplate1->is_related); + $this->assertTrue($topTemplate2->is_related); + $this->assertContains($topTemplate1->id, [19, 20]); + $this->assertContains($topTemplate2->id, [19, 20]); + + // Knee and Cervical spine must have lower score and not be related + $this->assertFalse($results[2]->is_related); + $this->assertFalse($results[3]->is_related); + } + + public function testFindImagingFilesReturnsDicomFile(): void + { + $files = [ + [ + 'id' => 43143, + 'charge_id' => 40291, + 'charge_type' => 3, + 'repo_id' => 51450, + 'file_name' => 'diag_20261001_113444_955045f6.dcm', + 'orig_name' => 'instance-0001.dcm', + 'full_path' => '/uploads/diagnosis/2026/10/diag_20261001_113444_955045f6.dcm', + 'file_type' => 'application/octet-stream', + 'isdelete' => 0, + ], + ]; + + $controller = $this->buildController([], [], null, $files); + + $resultFiles = $controller->exposeFindImagingFilesForRequest(40291, 3, 51450); + + $this->assertCount(1, $resultFiles); + $this->assertEquals(43143, $resultFiles[0]['id']); + $this->assertEquals('instance-0001.dcm', $resultFiles[0]['orig_name']); + } +}