package http import ( "context" "errors" "net/http" "net/http/httptest" "testing" "primaya-api/cpone-middleware/internal/repository" ) type fakeLabResultRepository struct { outcome repository.LabResultOutcome err error labNumber string } func (f *fakeLabResultRepository) GetLabResult(_ context.Context, labNumber string) (repository.LabResultOutcome, error) { f.labNumber = labNumber return f.outcome, f.err } func TestGetLabResultResponseParity(t *testing.T) { verifiedAt := "2026-08-19 10:00:00" name := "Hemoglobin" result := "14.2" reference := "13.0 - 17.0" unit := "g/dL" groupID := "HEMATOLOGI" groupName := "Hematologi" repo := &fakeLabResultRepository{outcome: repository.LabResultOutcome{ HTTPStatus: http.StatusOK, Success: true, Status: "lab_result_found", Message: "Hasil laboratorium ditemukan", Data: &repository.LabResultData{ Lab: repository.LabResultHeader{ LabNumber: "CPLAB2608190001", TrxDepartemenID: 6103991, Status: "authorized", VerifiedAt: &verifiedAt, }, Groups: []repository.LabResultGroup{{ GroupID: &groupID, GroupName: &groupName, Items: []repository.LabResultItem{{ TrxLayananID: 123456, ServiceID: "HB", Name: &name, Result: &result, ReferenceValue: &reference, Unit: &unit, CriticalFlag: "", }}, }}, }, }} handler := Handler{labResultRepo: repo} request := httptest.NewRequest(http.MethodGet, "/api/cpone/patients/lab-results/cplab2608190001", nil) request.SetPathValue("labNumber", "cplab2608190001") recorder := httptest.NewRecorder() handler.GetLabResult(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String()) } if repo.labNumber != "CPLAB2608190001" { t.Fatalf("lab number=%q", repo.labNumber) } const expected = `{"success":true,"status":"lab_result_found","message":"Hasil laboratorium ditemukan","data":{"lab":{"lab_number":"CPLAB2608190001","trx_departemen_id":6103991,"registration_id":null,"tanggal":null,"status":"authorized","verified_at":"2026-08-19 10:00:00","authorized_at":null,"catatan":null},"patient":{"medrec_id":null,"nama":null,"tanggal_lahir":null,"jenis_kelamin":null},"doctor":{"penanggung_jawab":null,"pengirim":null},"groups":[{"group_id":"HEMATOLOGI","group_name":"Hematologi","items":[{"trx_layanan_id":123456,"service_id":"HB","service_code":null,"name":"Hemoglobin","result":"14.2","reference_value":"13.0 - 17.0","unit":"g/dL","critical_flag":"","value_type":null,"note":null}]}]}}` + "\n" if recorder.Body.String() != expected { t.Fatalf("body mismatch\n got: %s\nwant: %s", recorder.Body.String(), expected) } } func TestGetLabResultValidationParity(t *testing.T) { tests := []struct { name, labNumber, message string }{ {name: "invalid characters", labNumber: "CPLAB_260819", message: "Nomor laboratorium hanya boleh berisi huruf, angka, dan tanda hubung"}, {name: "too long", labNumber: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNO", message: "Nomor laboratorium maksimal 50 karakter"}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { handler := Handler{labResultRepo: &fakeLabResultRepository{}} request := httptest.NewRequest(http.MethodGet, "/api/cpone/patients/lab-results/"+test.labNumber, nil) request.SetPathValue("labNumber", test.labNumber) recorder := httptest.NewRecorder() handler.GetLabResult(recorder, request) if recorder.Code != http.StatusUnprocessableEntity { t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String()) } expected := `{"success":false,"status":"validation_error","message":` + strconvQuote(test.message) + `,"data":null}` + "\n" if recorder.Body.String() != expected { t.Fatalf("body mismatch\n got: %s\nwant: %s", recorder.Body.String(), expected) } }) } } func TestGetLabResultForwardsDomainAndDatabaseOutcomes(t *testing.T) { tests := []struct { name string repo *fakeLabResultRepository statusCode int expected string }{ { name: "not found", repo: &fakeLabResultRepository{outcome: repository.LabResultOutcome{HTTPStatus: 404, Status: "lab_result_not_found", Message: "Hasil laboratorium tidak ditemukan"}}, statusCode: 404, expected: `{"success":false,"status":"lab_result_not_found","message":"Hasil laboratorium tidak ditemukan","data":null}` + "\n", }, { name: "database error", repo: &fakeLabResultRepository{err: errors.New("database unavailable")}, statusCode: 500, expected: `{"success":false,"status":"error","message":"database unavailable","data":null}` + "\n", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { handler := Handler{labResultRepo: test.repo} request := httptest.NewRequest(http.MethodGet, "/api/cpone/patients/lab-results/CPLAB2608190001", nil) request.SetPathValue("labNumber", "CPLAB2608190001") recorder := httptest.NewRecorder() handler.GetLabResult(recorder, request) if recorder.Code != test.statusCode || recorder.Body.String() != test.expected { t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String()) } }) } }