From 43bee7c3edfd84f397ca924eb705ad68d50cd07c Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Wed, 12 Nov 2025 00:10:59 +0100 Subject: [PATCH 1/9] fix officerCode is null on login --- .../main/java/org/openimis/imispolicies/usecase/Login.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/openimis/imispolicies/usecase/Login.java b/app/src/main/java/org/openimis/imispolicies/usecase/Login.java index a142fc34..7c960b5c 100644 --- a/app/src/main/java/org/openimis/imispolicies/usecase/Login.java +++ b/app/src/main/java/org/openimis/imispolicies/usecase/Login.java @@ -53,7 +53,10 @@ public Login( @WorkerThread public void execute(@NonNull String username, @NonNull String password) throws Exception { - String officerCode = Global.getGlobal().getOfficerCode(); + String officerCode = (Global.getGlobal().getOfficerCode() != null) + ? Global.getGlobal().getOfficerCode() + : username; + if (officerCode == null) { throw new IllegalStateException("OfficerCode should not be null on login"); } From e5cc26341422c449a64eeac6c317baa57dfe58fa Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Wed, 12 Nov 2025 12:18:56 +0100 Subject: [PATCH 2/9] corrections --- .../java/org/openimis/imispolicies/usecase/Login.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/openimis/imispolicies/usecase/Login.java b/app/src/main/java/org/openimis/imispolicies/usecase/Login.java index 7c960b5c..260901b7 100644 --- a/app/src/main/java/org/openimis/imispolicies/usecase/Login.java +++ b/app/src/main/java/org/openimis/imispolicies/usecase/Login.java @@ -53,10 +53,10 @@ public Login( @WorkerThread public void execute(@NonNull String username, @NonNull String password) throws Exception { - String officerCode = (Global.getGlobal().getOfficerCode() != null) - ? Global.getGlobal().getOfficerCode() - : username; - + if (Global.getGlobal().getOfficerCode() == null) { + Global.getGlobal().setOfficerCode(username); + } + String officerCode = Global.getGlobal().getOfficerCode(); if (officerCode == null) { throw new IllegalStateException("OfficerCode should not be null on login"); } From c5d08136c677b064b820faf82f4c8092835efd37 Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Sat, 29 Nov 2025 00:24:39 +0100 Subject: [PATCH 3/9] set test infra --- .../java/org/openimis/imispolicies/imis/ExampleUnitTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java b/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java index 42be9bcc..f662e8a8 100644 --- a/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java +++ b/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java @@ -38,5 +38,6 @@ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); + assertEquals(5, 2 + 3); } } From 83be6812deff872e6787fc0aad7c60fa28e7df8c Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Tue, 9 Dec 2025 16:58:31 +0100 Subject: [PATCH 4/9] testing the creation of a new insuree --- app/build.gradle | 6 +- .../imispolicies/ClientAndroidInterface.java | 24 ++-- .../ClientAndroidInterfaceTest.java | 114 ++++++++++++++++++ 3 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java diff --git a/app/build.gradle b/app/build.gradle index 2135c835..ff8da71f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -233,7 +233,6 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - //noinspection GradleDependency implementation 'com.squareup.picasso:picasso:2.8' implementation 'commons-io:commons-io:2.11.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' @@ -244,5 +243,10 @@ dependencies { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) + + // Tests unitaires testImplementation 'junit:junit:4.13.2' + testImplementation 'org.mockito:mockito-core:5.5.0' + testImplementation 'org.robolectric:robolectric:4.11.1' } + diff --git a/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java b/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java index e06e4dfb..858635f6 100644 --- a/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java +++ b/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java @@ -136,7 +136,7 @@ public class ClientAndroidInterface { @NonNull private final Activity activity; @NonNull - private final SQLHandler sqlHandler; + protected final SQLHandler sqlHandler; @NonNull private final HashMap controls = new HashMap<>(); @NonNull @@ -144,7 +144,7 @@ public class ClientAndroidInterface { @NonNull private final ArrayList enrolMessages = new ArrayList<>(); @NonNull - private final Global global; + protected final Global global; @NonNull private final StorageManager storageManager; @NonNull @@ -167,6 +167,14 @@ public class ClientAndroidInterface { .build(); } + public ClientAndroidInterface(Activity activity, SQLHandler sqlHandler, Global global, Picasso picasso, StorageManager storageManager) { + this.activity = activity; + this.sqlHandler = sqlHandler; + this.global = global; + this.storageManager = storageManager; + this.picassoInstance = picasso; + } + @JavascriptInterface @SuppressWarnings("unused") public void SetUrl(String Url) { @@ -666,7 +674,7 @@ public String getHF(int DistrictId, String HFLevel) { return HFs.toString(); } - private HashMap jsonToTable(String jsonString) { + protected HashMap jsonToTable(String jsonString) { HashMap data = new HashMap<>(); try { JSONArray array = new JSONArray(jsonString); @@ -849,7 +857,7 @@ public void addOrUpdateFamilySms(int familyId, Boolean approve, String language) } } - private int isValidInsureeData(HashMap data) { + protected int isValidInsureeData(HashMap data) { int Result; String InsuranceNumber = data.get("txtInsuranceNumber"); @@ -1044,7 +1052,7 @@ else if (ExceedThreshold == 0) return rtInsureeId; } - private String copyImageFromGalleryToApplication(String selectedPath, String InsuranceNumber) { + protected String copyImageFromGalleryToApplication(String selectedPath, String InsuranceNumber) { String result = ""; try { @@ -5021,7 +5029,7 @@ public int getFamilyStat(int FamilyId) { return status; } - private int getFamilyStatus(int FamilyId) throws JSONException { + protected int getFamilyStatus(int FamilyId) throws JSONException { if (FamilyId < 0) return 0; @Language("SQL") String Query = "SELECT isOffline FROM tblFamilies WHERE FamilyId = " + FamilyId; @@ -5034,7 +5042,7 @@ private int getFamilyStatus(int FamilyId) throws JSONException { else return 0; } - private int getInsureeStatus(int InsureeId) throws JSONException {//herman + protected int getInsureeStatus(int InsureeId) throws JSONException {//herman if (InsureeId == 0) return 1; @Language("SQL") String Query = "SELECT isOffline FROM tblInsuree WHERE InsureeId = " + InsureeId; @@ -5252,7 +5260,7 @@ private int getNextAvailablePolicyId() { return getMaxIdFromTable("PolicyId", "tblPolicy"); } - private int getNextAvailableInsureeId() { + protected int getNextAvailableInsureeId() { return getMaxIdFromTable("InsureeId", "tblInsuree"); } diff --git a/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java b/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java new file mode 100644 index 00000000..5ff85f95 --- /dev/null +++ b/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java @@ -0,0 +1,114 @@ +package org.openimis.imispolicies; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import com.squareup.picasso.Picasso; +import org.openimis.imispolicies.tools.StorageManager; +import org.robolectric.RobolectricTestRunner; + +import android.app.Activity; +import android.content.res.Resources; + +import org.json.JSONArray; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.HashMap; + +@RunWith(RobolectricTestRunner.class) +public class ClientAndroidInterfaceTest { + + @Mock + SQLHandler sqlHandler; + + @Mock + Global global; + + @Mock + Activity activity; + + @Mock + Resources resources; + + @Mock + StorageManager storageManager; + + ClientAndroidInterface client; + + @Before + public void setup() { + MockitoAnnotations.openMocks(this); + + when(activity.getResources()).thenReturn(resources); + when(resources.getString(anyInt())).thenReturn("mockString"); + + client = new ClientAndroidInterface(activity, sqlHandler, global, null, storageManager); + + when(global.isNetworkAvailable()).thenReturn(true); + } + + @Test + public void testCreateNewInsuree_ShouldInsertInDatabase() throws Exception { + + String insureeJson = "{" + + "\"txtInsuranceNumber\":\"12345\"," + + "\"hfInsureeId\":\"0\"," + + "\"hfisHead\":\"1\"," + + "\"txtLastName\":\"Doe\"," + + "\"txtOtherNames\":\"John\"," + + "\"txtBirthDate\":\"1991-01-01\"," + + "\"ddlGender\":\"M\"," + + "\"txtPhoneNumber\":\"690000000\"" + + "\"hfNewPhotoPath\":\"\"" + + "\"hfImagePath\":\"/storage/emulated/0/DCIM/test.jpg\"" + + "}"; + + ClientAndroidInterface spyClient = spy(client); + + HashMap mockData = new HashMap<>(); + mockData.put("txtInsuranceNumber", "12345"); + mockData.put("hfInsureeId", "0"); + mockData.put("hfisHead", "1"); + mockData.put("txtLastName", "Doe"); + mockData.put("txtOtherNames", "John"); + mockData.put("txtBirthDate", "1991-01-01"); + mockData.put("ddlGender", "M"); + mockData.put("txtPhoneNumber", "690000000"); + mockData.put("hfNewPhotoPath", ""); + mockData.put("hfImagePath", "/storage/emulated/0/DCIM/test.jpg"); + + when(sqlHandler.getResult(anyString(), any(String[].class))).thenReturn(new JSONArray()); + doNothing().when(spyClient).SaveInsureePolicy(anyInt(), anyInt(), anyBoolean(), anyInt()); + doNothing().when(sqlHandler).insertData(anyString(), any()); + doNothing().when(sqlHandler).updateData(anyString(), any(), anyString(), any(String[].class)); + doReturn(mockData).when(spyClient).jsonToTable(anyString()); + doReturn(0).when(spyClient).isValidInsureeData(mockData); + doReturn(999).when(spyClient).getNextAvailableInsureeId(); + doReturn(0).when(spyClient).getFamilyStatus(anyInt()); + doReturn(0).when(spyClient).getInsureeStatus(anyInt()); + doNothing().when(spyClient).ShowDialog(anyString()); + doNothing().when(spyClient).ShowDialogYesNo(anyInt(), anyInt(), anyInt()); + doReturn("").when(spyClient).copyImageFromGalleryToApplication(anyString(), anyString()); + + doNothing().when(sqlHandler).insertData(anyString(), any()); + + int result = spyClient.SaveInsuree( + insureeJson, + 1, // FamilyId + 1, // isHead + 0, // ExceedThreshold + 0 // PolicyId + ); + + assertEquals(-999, result); + + verify(sqlHandler, times(1)).insertData(eq("tblInsuree"), any()); + } +} From cdfc36193bfff62fa9f5ea7bd7e1458563e1be18 Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Wed, 10 Dec 2025 10:40:48 +0100 Subject: [PATCH 5/9] corrections --- app/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ff8da71f..dc0cb43b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -233,6 +233,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + //noinspection GradleDependency implementation 'com.squareup.picasso:picasso:2.8' implementation 'commons-io:commons-io:2.11.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' @@ -244,7 +245,7 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) - // Tests unitaires + // unit tests testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-core:5.5.0' testImplementation 'org.robolectric:robolectric:4.11.1' From 481a713e0511399df3fad57861f6d2cba203379b Mon Sep 17 00:00:00 2001 From: Blue-B-code Date: Wed, 10 Dec 2025 13:19:30 +0100 Subject: [PATCH 6/9] Update ExampleUnitTest.java --- .../java/org/openimis/imispolicies/imis/ExampleUnitTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java b/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java index f662e8a8..42be9bcc 100644 --- a/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java +++ b/app/src/test/java/org/openimis/imispolicies/imis/ExampleUnitTest.java @@ -38,6 +38,5 @@ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); - assertEquals(5, 2 + 3); } } From 08e491fd1bfb09dc670b42b91fa41592743e86eb Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Wed, 10 Dec 2025 16:18:26 +0100 Subject: [PATCH 7/9] improve tests logging --- app/build.gradle | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index dc0cb43b..f87e9e8f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -218,6 +218,14 @@ apollo { ] } +tasks.withType(Test).configureEach { + testLogging { + events "passed", "skipped", "failed" + exceptionFormat "full" + showStandardStreams = false + } +} + dependencies { implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') implementation 'com.squareup.okhttp3:okhttp:4.11.0' From 348a3a36244d5670803775639a7ff0535ecdbd29 Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Thu, 11 Dec 2025 10:17:24 +0100 Subject: [PATCH 8/9] add pull_request on workflow --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e29e38e5..0d4188c4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,6 +6,10 @@ on: - '*' # tags: # - '!v*' + pull_request: + branches: + - '*' + types: [opened, synchronize, reopened] jobs: build: From 40bfdc822a462f8d00fe770778e38d04f5b71a22 Mon Sep 17 00:00:00 2001 From: paul sandjong Date: Wed, 14 Jan 2026 00:24:33 +0100 Subject: [PATCH 9/9] Unit tests for enrolment upload and improvements to enrolment tests --- .../imispolicies/ClientAndroidInterface.java | 12 +- .../ClientAndroidInterfaceTest.java | 443 +++++++++++++++--- 2 files changed, 393 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java b/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java index 858635f6..d98469ce 100644 --- a/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java +++ b/app/src/main/java/org/openimis/imispolicies/ClientAndroidInterface.java @@ -2546,10 +2546,14 @@ public int UpdatePolicy(int PolicyId, String PayDate, int policystatus) throws P return 1;//Update Success } + protected ProgressDialog createProgressDialog(String title, String message) { + return ProgressDialog.show(activity, title, message); + } + @JavascriptInterface @SuppressWarnings("unused") public void uploadEnrolment() throws Exception { - final ProgressDialog finalPd = ProgressDialog.show(activity, activity.getResources().getString(R.string.Sync), activity.getResources().getString(R.string.SyncProcessing)); + final ProgressDialog finalPd = createProgressDialog(activity.getResources().getString(R.string.Sync), activity.getResources().getString(R.string.SyncProcessing)); activity.runOnUiThread(() -> { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); }); @@ -2798,7 +2802,7 @@ public boolean VerifyPhoto(JSONArray insurees) throws JSONException { return result; } - private int Enrol(int CallerId) throws UserException, JSONException, IOException { + protected int Enrol(int CallerId) throws UserException, JSONException, IOException { ArrayList verifiedId = new ArrayList<>(); myList.clear(); int rtEnrolledId = 0; @@ -3129,7 +3133,7 @@ private int Enrol(int CallerId) throws UserException, JSONException, IOException return EnrolResult; } - private int uploadEnrols( + protected int uploadEnrols( @NonNull JSONArray familyArray, @NonNull JSONArray insureesArray, @NonNull JSONArray policiesArray, @@ -3578,7 +3582,7 @@ protected void onPostExecute(Boolean aBoolean) { } } - private void DeleteUploadedData(final int FamilyId, ArrayList FamilyIDs, int CallerId) { + protected void DeleteUploadedData(final int FamilyId, ArrayList FamilyIDs, int CallerId) { if (FamilyIDs.size() == 0) { FamilyIDs = new ArrayList<>() {{ add(String.valueOf(FamilyId)); diff --git a/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java b/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java index 5ff85f95..883170f7 100644 --- a/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java +++ b/app/src/test/java/org/openimis/imispolicies/ClientAndroidInterfaceTest.java @@ -1,114 +1,441 @@ package org.openimis.imispolicies; import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import com.squareup.picasso.Picasso; + import org.openimis.imispolicies.tools.StorageManager; import org.robolectric.RobolectricTestRunner; import android.app.Activity; import android.content.res.Resources; +import android.util.Pair; +import android.view.Window; import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import org.junit.Before; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; + import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.junit.MockitoJUnitRunner; + +import org.robolectric.shadows.ShadowLooper; + +import android.app.ProgressDialog; +import android.view.WindowManager; import java.util.HashMap; +import java.util.ArrayList; + @RunWith(RobolectricTestRunner.class) public class ClientAndroidInterfaceTest { - @Mock - SQLHandler sqlHandler; - - @Mock - Global global; - - @Mock - Activity activity; + @Mock SQLHandler sqlHandler; + @Mock Global global; + @Mock Activity activity; + @Mock Resources resources; + @Mock StorageManager storageManager; + @Mock ProgressDialog progressDialog; - @Mock - Resources resources; + ClientAndroidInterface client; - @Mock - StorageManager storageManager; + // ===== Global test data ===== + JSONArray familyArray; + JSONArray insureesArray; + JSONArray policiesArray; + JSONArray premiumsArray; + String insureeJson; + HashMap insureeMap; - ClientAndroidInterface client; @Before - public void setup() { + public void setup() throws JSONException { + MockitoAnnotations.openMocks(this); when(activity.getResources()).thenReturn(resources); when(resources.getString(anyInt())).thenReturn("mockString"); + when(global.isNetworkAvailable()).thenReturn(true); + when(activity.getWindow()).thenReturn(mock(Window.class)); - client = new ClientAndroidInterface(activity, sqlHandler, global, null, storageManager); + client = new ClientAndroidInterface( + activity, + sqlHandler, + global, + null, + storageManager + ); - when(global.isNetworkAvailable()).thenReturn(true); + familyArray = buildFamilyArray(); + insureesArray = buildInsureeArray(); + policiesArray = buildPolicyArray(); + premiumsArray = buildPremiumArray(); + insureeJson = buildInsureeJson(); + insureeMap = buildInsureeMap(); + } + + + @After + public void cleanUp() { + client = null; } + + // =================== uploadEnrolment =================== + @Test - public void testCreateNewInsuree_ShouldInsertInDatabase() throws Exception { + public void testUploadEnrolment_ShouldProcessSuccessfully() throws Exception { - String insureeJson = "{" - + "\"txtInsuranceNumber\":\"12345\"," - + "\"hfInsureeId\":\"0\"," - + "\"hfisHead\":\"1\"," - + "\"txtLastName\":\"Doe\"," - + "\"txtOtherNames\":\"John\"," - + "\"txtBirthDate\":\"1991-01-01\"," - + "\"ddlGender\":\"M\"," - + "\"txtPhoneNumber\":\"690000000\"" - + "\"hfNewPhotoPath\":\"\"" - + "\"hfImagePath\":\"/storage/emulated/0/DCIM/test.jpg\"" - + "}"; + ClientAndroidInterface spyClient = spy(client); + ProgressDialog mockDialog = mock(ProgressDialog.class); + + doReturn(mockDialog) + .when(spyClient) + .createProgressDialog(anyString(), anyString()); + + doReturn(1) + .when(spyClient) + .Enrol(1); + + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(activity).runOnUiThread(any(Runnable.class)); + + spyClient.uploadEnrolment(); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + verify(activity.getWindow()) + .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + verify(spyClient).Enrol(1); + verify(mockDialog).dismiss(); + } + + + @Test + public void testUploadEnrolment_ShouldHandleEnrolError() throws Exception { ClientAndroidInterface spyClient = spy(client); + ProgressDialog mockDialog = mock(ProgressDialog.class); + + doReturn(mockDialog) + .when(spyClient) + .createProgressDialog(anyString(), anyString()); + + doReturn(999) + .when(spyClient) + .Enrol(1); - HashMap mockData = new HashMap<>(); - mockData.put("txtInsuranceNumber", "12345"); - mockData.put("hfInsureeId", "0"); - mockData.put("hfisHead", "1"); - mockData.put("txtLastName", "Doe"); - mockData.put("txtOtherNames", "John"); - mockData.put("txtBirthDate", "1991-01-01"); - mockData.put("ddlGender", "M"); - mockData.put("txtPhoneNumber", "690000000"); - mockData.put("hfNewPhotoPath", ""); - mockData.put("hfImagePath", "/storage/emulated/0/DCIM/test.jpg"); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(activity).runOnUiThread(any(Runnable.class)); + + spyClient.uploadEnrolment(); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + verify(mockDialog).dismiss(); + } + + + // =================== Enrol =================== + + @Test + public void testEnrol_ShouldProcessSuccessfully() throws Exception { + + ClientAndroidInterface spyClient = spy(client); + + String queryInsurees = "SELECT I.InsureeUUID AS InsureeUUID, I.InsureeId AS InsureeId, I.FamilyId AS FamilyId, I.CHFID, I.LastName, I.OtherNames, I.DOB, I.Gender, NULLIF(I.Marital,'') Marital, I.isHead, NULLIF(I.IdentificationNumber,'null') IdentificationNumber, NULLIF(I.Phone,'null') Phone, REPLACE(I.PhotoPath, RTRIM(PhotoPath, REPLACE(PhotoPath, '/', '')), '') PhotoPath, NULLIF(I.CardIssued,'null') CardIssued, NULLIF(I.Relationship,'null') Relationship, NULLIF(I.Profession,'null') Profession, NULLIF(I.Education,'null') Education, NULLIF(I.Email,'null') Email, CASE WHEN I.TypeOfId='null' THEN null ELSE I.TypeOfId END TypeOfId, NULLIF(I.HFID,'null') HFID, NULLIF(I.CurrentAddress,'null') CurrentAddress, NULLIF(I.GeoLocation,'null') GeoLocation, NULLIF(I.CurVillage,'null') CurVillage,I.isOffline, I.Vulnerability FROM tblInsuree I WHERE "; + + String queryPolicies = + "SELECT p.PolicyId AS PolicyId, FamilyId AS FamilyId, EnrollDate, StartDate, " + + "NULLIF(EffectiveDate,'null') EffectiveDate, ExpiryDate, Policystatus, PolicyValue, " + + "ProdId, OfficerId, PolicyStage, isOffline, bcn.ControlNumber " + + "FROM tblPolicy p LEFT JOIN tblBulkControlNumbers bcn on p.PolicyId=bcn.PolicyId WHERE "; + + String queryPremiums = + "SELECT PR.PremiumId, PR.PolicyId, NULLIF(PR.PayerId,'null') PayerId, PR.Amount, " + + "PR.Receipt, PR.PayDate, PR.PayType, PR.isPhotoFee,PR.isOffline " + + "FROM tblPremium PR INNER JOIN tblPolicy PL ON PL.PolicyId = PR.PolicyId WHERE "; + + String queryFamilies = + "SELECT F.FamilyUUID as FamilyUUID, F.FamilyId AS FamilyId, F.InsureeId AS InsureeId, " + + "F.LocationId, I.CHFID AS HOFCHFID, NULLIF(F.Poverty,'null') Poverty, " + + "NULLIF(F.FamilyType,'null') FamilyType, NULLIF(F.FamilyAddress,'null') FamilyAddress, " + + "NULLIF(F.Ethnicity,'null') Ethnicity, NULLIF(F.ConfirmationNo,'null') ConfirmationNo, " + + "F.ConfirmationType ConfirmationType,F.isOffline isOffline " + + "FROM tblFamilies F INNER JOIN tblInsuree I ON I.InsureeId = F.InsureeId WHERE"; + + JSONArray mockFamilies = new JSONArray(); + JSONObject family1 = new JSONObject(); + family1.put("FamilyId", "1"); + family1.put("isOffline", "1"); + mockFamilies.put(family1); + + when(sqlHandler.getResult( + eq("SELECT FamilyId, isOffline FROM tblFamilies WHERE InsureeId != '' ORDER BY FamilyId"), + isNull() + )).thenReturn(mockFamilies); + + when(sqlHandler.getResult(contains(queryFamilies), any())).thenReturn(familyArray); + when(sqlHandler.getResult(contains(queryInsurees), any())).thenReturn(insureesArray); + when(sqlHandler.getResult(contains(queryPolicies), any())).thenReturn(policiesArray); + when(sqlHandler.getResult(contains(queryPremiums), any())).thenReturn(premiumsArray); + when(sqlHandler.getResult(anyString(), any(String[].class))).thenReturn(new JSONArray()); + + doReturn(true).when(spyClient).isPolicyRequired(); + doReturn(true).when(spyClient).isContributionRequired(); + doReturn(new Pair[0]).when(spyClient).FamilyPictures(any(JSONArray.class), eq(1)); + + doNothing().when(spyClient).DeleteImages(any(JSONArray.class), any(ArrayList.class), anyInt()); + doNothing().when(spyClient).DeleteUploadedData(anyInt(), any(ArrayList.class), anyInt()); + doReturn(1).when(spyClient).DeleteFamily(anyInt()); + + doNothing().when(spyClient).updatePolicyRecords(any(JSONArray.class)); + doNothing().when(spyClient).ShowErrorMessages(); + + when(activity.getString(anyInt())).thenReturn("mockString"); + + doReturn(0) + .when(spyClient) + .uploadEnrols(familyArray, insureesArray, policiesArray, premiumsArray, new Pair[0]); + + int result = spyClient.Enrol(1); + + assertEquals(result, 0); + } + + + // =================== SaveInsuree - Create =================== + + @Test + public void testCreateNewInsuree_ShouldInsertInDatabase() throws Exception { + + ClientAndroidInterface spyClient = spy(client); when(sqlHandler.getResult(anyString(), any(String[].class))).thenReturn(new JSONArray()); + doNothing().when(spyClient).SaveInsureePolicy(anyInt(), anyInt(), anyBoolean(), anyInt()); doNothing().when(sqlHandler).insertData(anyString(), any()); doNothing().when(sqlHandler).updateData(anyString(), any(), anyString(), any(String[].class)); - doReturn(mockData).when(spyClient).jsonToTable(anyString()); - doReturn(0).when(spyClient).isValidInsureeData(mockData); + + doAnswer(invocation -> { + String paramJson = invocation.getArgument(0); + assertEquals(insureeJson, paramJson); + + HashMap result = + (HashMap) invocation.callRealMethod(); + + assertEquals(insureeMap, result); + return result; + + }).when(spyClient).jsonToTable(anyString()); + doReturn(999).when(spyClient).getNextAvailableInsureeId(); - doReturn(0).when(spyClient).getFamilyStatus(anyInt()); - doReturn(0).when(spyClient).getInsureeStatus(anyInt()); + doReturn(0).when(spyClient).getFamilyStatus(1); + doNothing().when(spyClient).ShowDialog(anyString()); doNothing().when(spyClient).ShowDialogYesNo(anyInt(), anyInt(), anyInt()); - doReturn("").when(spyClient).copyImageFromGalleryToApplication(anyString(), anyString()); - doNothing().when(sqlHandler).insertData(anyString(), any()); + doReturn("") + .when(spyClient) + .copyImageFromGalleryToApplication( + insureeMap.get("hfNewPhotoPath"), + insureeMap.get("txtInsuranceNumber") + ); - int result = spyClient.SaveInsuree( - insureeJson, - 1, // FamilyId - 1, // isHead - 0, // ExceedThreshold - 0 // PolicyId - ); + int result = spyClient.SaveInsuree(insureeJson, 1, 1, 0, 0); assertEquals(-999, result); verify(sqlHandler, times(1)).insertData(eq("tblInsuree"), any()); + verify(spyClient, times(1)).jsonToTable(insureeJson); + verify(sqlHandler, times(1)).insertData(eq("tblInsuree"), any()); + verify(spyClient, times(1)).SaveInsureePolicy(999, 1, true, 0); + } + + + // =================== SaveInsuree - Modify =================== + + @Test + public void testModifyInsuree_ShouldUpdateInDatabase() throws Exception { + + ClientAndroidInterface spyClient = spy(client); + + when(sqlHandler.getResult(anyString(), any(String[].class))).thenReturn(new JSONArray()); + + doReturn(999).when(spyClient).getNextAvailableInsureeId(); + + HashMap testData = new HashMap<>(insureeMap); + testData.put("hfInsureeId", "10"); + + System.out.println(testData); + + doReturn(0).when(spyClient).getFamilyStatus(1); + doReturn(0).when(spyClient).getInsureeStatus(10); + doReturn("").when(spyClient).copyImageFromGalleryToApplication(anyString(), anyString()); + doReturn(testData).when(spyClient).jsonToTable(anyString()); + doReturn(0).when(spyClient).isValidInsureeData(any()); + + doNothing().when(spyClient).SaveInsureePolicy(anyInt(), anyInt(), anyBoolean(), anyInt()); + doNothing().when(spyClient).ShowDialog(anyString()); + + int result = spyClient.SaveInsuree(insureeJson, 1, 1, 0, 0); + + assertEquals(10, result); + verify(spyClient).isValidInsureeData(any()); + } + + + // =================== SaveInsuree - New Family =================== + + @Test + public void testCreateNewFamily_ShouldInsertInDatabase() throws Exception { + + ClientAndroidInterface spyClient = spy(client); + + when(sqlHandler.getResult(anyString(), any(String[].class))).thenReturn(new JSONArray()); + + doReturn(999).when(spyClient).getNextAvailableInsureeId(); + + HashMap testData = new HashMap<>(insureeMap); + System.out.println(testData); + + doReturn(1).when(spyClient).getFamilyStatus(1); + doReturn(0).when(spyClient).getInsureeStatus(10); + doReturn("").when(spyClient).copyImageFromGalleryToApplication(anyString(), anyString()); + doReturn(testData).when(spyClient).jsonToTable(anyString()); + doReturn(0).when(spyClient).isValidInsureeData(any()); + + doNothing().when(spyClient).SaveInsureePolicy(anyInt(), anyInt(), anyBoolean(), anyInt()); + doNothing().when(spyClient).ShowDialog(anyString()); + + int result = spyClient.SaveInsuree(insureeJson, 1, 1, 0, 0); + + assertEquals(999, result); + verify(spyClient).isValidInsureeData(any()); + } + + + // =================== Helpers =================== + + private JSONArray buildFamilyArray() throws JSONException { + + JSONArray array = new JSONArray(); + JSONObject family = new JSONObject(); + + family.put("FamilyId", 1); + family.put("InsureeId", 1); + family.put("CHFID", "CHF12345"); + family.put("isOffline", "true"); + family.put("FamilyType", "firstType"); + family.put("ConfirmationType", "firstType"); + family.put("ConfirmationDate", "2023-01-01"); + family.put("ConfirmationNumber", "12345"); + + array.put(family); + return array; + } + + + private JSONArray buildInsureeArray() throws JSONException { + + JSONArray array = new JSONArray(); + JSONObject insuree = new JSONObject(); + + insuree.put("InsureeId", 1); + insuree.put("FamilyId", 1); + insuree.put("CHFID", "CHF12345"); + insuree.put("LastName", "Doe"); + insuree.put("OtherNames", "John"); + insuree.put("DOB", "1990-01-01"); + insuree.put("Gender", "M"); + insuree.put("TypeOfId", "1"); + + array.put(insuree); + return array; + } + + + private JSONArray buildPolicyArray() throws JSONException { + + JSONArray array = new JSONArray(); + JSONObject policy = new JSONObject(); + + policy.put("PolicyId", 1); + policy.put("FamilyId", 1); + policy.put("ProdId", 1); + + array.put(policy); + return array; + } + + + private JSONArray buildPremiumArray() throws JSONException { + + JSONArray array = new JSONArray(); + JSONObject premium = new JSONObject(); + + premium.put("PremiumId", 1); + premium.put("PolicyId", 1); + premium.put("Amount", 1000); + premium.put("PayDate", "2023-01-01"); + + array.put(premium); + return array; + } + + + private String buildInsureeJson() throws JSONException { + + HashMap originalData = new HashMap<>(); + + originalData.put("txtInsuranceNumber", "12345"); + originalData.put("hfInsureeId", "0"); + originalData.put("hfisHead", "1"); + originalData.put("txtLastName", "Doe"); + originalData.put("txtOtherNames", "John"); + originalData.put("txtBirthDate", "1991-01-01"); + originalData.put("ddlGender", "M"); + originalData.put("txtPhoneNumber", "690000000"); + originalData.put("hfNewPhotoPath", ""); + originalData.put("hfImagePath", "/storage/emulated/0/DCIM/test.jpg"); + + JSONArray array = new JSONArray(); + + for (String key : originalData.keySet()) { + JSONObject obj = new JSONObject(); + obj.put("id", key); + obj.put("value", originalData.get(key)); + array.put(obj); + } + + return array.toString(); + } + + + private HashMap buildInsureeMap() { + + HashMap map = new HashMap<>(); + + map.put("txtInsuranceNumber", "12345"); + map.put("hfInsureeId", "0"); + map.put("hfisHead", "1"); + map.put("txtLastName", "Doe"); + map.put("txtOtherNames", "John"); + map.put("txtBirthDate", "1991-01-01"); + map.put("ddlGender", "M"); + map.put("txtPhoneNumber", "690000000"); + map.put("hfNewPhotoPath", ""); + map.put("hfImagePath", "/storage/emulated/0/DCIM/test.jpg"); + + return map; } }