From 957efe2c6c8ed81a32c8da1ef305354e9a43fb05 Mon Sep 17 00:00:00 2001
From: Philipp Nowak <10376534+PhilippNowak96@users.noreply.github.com>
Date: Mon, 4 Jan 2021 19:45:34 +0100
Subject: [PATCH] Fix sorting of persons and places to be case insensitive for
 names (EXPOSUREAPP-4488)(closes #2012) (#2017)

* Fix sorting of persons and places to be case insensitive for names and add some unit tests for both parts (#2012)

* Address code review comments (EXPOSUREAPP-4488) (#2012)

Co-authored-by: Matthias Urhahn <matthias.urhahn@sap.com>
---
 .../model/ContactDiaryLocation.kt             |  3 +-
 .../model/ContactDiaryLocationVisit.kt        |  8 +-
 .../contactdiary/model/ContactDiaryPerson.kt  |  3 +-
 .../model/ContactDiaryPersonEncounter.kt      |  8 +-
 .../util/ContactDiaryExtensionsTest.kt        | 77 +++++++++++++++++++
 5 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt
index c5315a986..d4192af04 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.contactdiary.model
 
 import de.rki.coronawarnapp.util.lists.HasStableId
+import java.util.Locale
 
 interface ContactDiaryLocation : HasStableId {
     val locationId: Long
@@ -8,4 +9,4 @@ interface ContactDiaryLocation : HasStableId {
 }
 
 fun List<ContactDiaryLocation>.sortByNameAndIdASC(): List<ContactDiaryLocation> =
-    this.sortedWith(compareBy({ it.locationName }, { it.locationId }))
+    this.sortedWith(compareBy({ it.locationName.toLowerCase(Locale.ROOT) }, { it.locationId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt
index a1f4061d7..2d477bcee 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.contactdiary.model
 
 import org.joda.time.LocalDate
+import java.util.Locale
 
 interface ContactDiaryLocationVisit {
     val id: Long
@@ -9,4 +10,9 @@ interface ContactDiaryLocationVisit {
 }
 
 fun List<ContactDiaryLocationVisit>.sortByNameAndIdASC(): List<ContactDiaryLocationVisit> =
-    this.sortedWith(compareBy({ it.contactDiaryLocation.locationName }, { it.contactDiaryLocation.locationId }))
+    this.sortedWith(
+        compareBy(
+            { it.contactDiaryLocation.locationName.toLowerCase(Locale.ROOT) },
+            { it.contactDiaryLocation.locationId }
+        )
+    )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt
index 95badab55..de391152b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.contactdiary.model
 
 import de.rki.coronawarnapp.util.lists.HasStableId
+import java.util.Locale
 
 interface ContactDiaryPerson : HasStableId {
     val personId: Long
@@ -8,4 +9,4 @@ interface ContactDiaryPerson : HasStableId {
 }
 
 fun List<ContactDiaryPerson>.sortByNameAndIdASC(): List<ContactDiaryPerson> =
-    this.sortedWith(compareBy({ it.fullName }, { it.personId }))
+    this.sortedWith(compareBy({ it.fullName.toLowerCase(Locale.ROOT) }, { it.personId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt
index 60bf3887a..47975a267 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.contactdiary.model
 
 import org.joda.time.LocalDate
+import java.util.Locale
 
 interface ContactDiaryPersonEncounter {
     val id: Long
@@ -9,4 +10,9 @@ interface ContactDiaryPersonEncounter {
 }
 
 fun List<ContactDiaryPersonEncounter>.sortByNameAndIdASC(): List<ContactDiaryPersonEncounter> =
-    this.sortedWith(compareBy({ it.contactDiaryPerson.fullName }, { it.contactDiaryPerson.personId }))
+    this.sortedWith(
+        compareBy(
+            { it.contactDiaryPerson.fullName.toLowerCase(Locale.ROOT) },
+            { it.contactDiaryPerson.personId }
+        )
+    )
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensionsTest.kt
index ea4feec33..ee98a610d 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensionsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/util/ContactDiaryExtensionsTest.kt
@@ -1,5 +1,8 @@
 package de.rki.coronawarnapp.contactdiary.util
 
+import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocation
+import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryPerson
+import de.rki.coronawarnapp.contactdiary.model.sortByNameAndIdASC
 import org.junit.Assert
 import org.junit.jupiter.api.Test
 
@@ -12,4 +15,78 @@ class ContactDiaryExtensionsTest {
         Assert.assertEquals("Granny   ".formatContactDiaryNameField(5), "Grann")
         Assert.assertEquals("    ".formatContactDiaryNameField(2), "  ")
     }
+
+    @Test
+    fun `upper and lowercase mix sorting for names`() {
+        val testList = listOf(
+            DefaultContactDiaryPerson(1, "Max Mustermann"),
+            DefaultContactDiaryPerson(2, "Erika Musterfrau"),
+            DefaultContactDiaryPerson(3, "erika musterfrau2"),
+        )
+
+        val expectedResult = listOf(
+            DefaultContactDiaryPerson(2, "Erika Musterfrau"),
+            DefaultContactDiaryPerson(3, "erika musterfrau2"),
+            DefaultContactDiaryPerson(1, "Max Mustermann"),
+        )
+
+        // Test that lowercase "erika musterfrau2" is sorted to the 2nd position instead of the end
+        Assert.assertEquals(expectedResult, testList.sortByNameAndIdASC())
+    }
+
+    @Test
+    fun `sort by id when names are equal for names`() {
+        val testList = listOf(
+            DefaultContactDiaryPerson(1, "Max Mustermann"),
+            DefaultContactDiaryPerson(3, "Erika Musterfrau"),
+            DefaultContactDiaryPerson(2, "Erika Musterfrau"),
+        )
+
+        val expectedResult = listOf(
+            DefaultContactDiaryPerson(2, "Erika Musterfrau"),
+            DefaultContactDiaryPerson(3, "Erika Musterfrau"),
+            DefaultContactDiaryPerson(1, "Max Mustermann"),
+        )
+
+        // Test that "Erika Musterfrau" with lower personId comes before the other one, even though it was
+        // added as the last entry to the testList
+        Assert.assertEquals(expectedResult, testList.sortByNameAndIdASC())
+    }
+
+    @Test
+    fun `upper and lowercase mix sorting for places`() {
+        val testList = listOf(
+            DefaultContactDiaryLocation(1, "Berlin"),
+            DefaultContactDiaryLocation(2, "At home"),
+            DefaultContactDiaryLocation(3, "at home"),
+        )
+
+        val expectedResult = listOf(
+            DefaultContactDiaryLocation(2, "At home"),
+            DefaultContactDiaryLocation(3, "at home"),
+            DefaultContactDiaryLocation(1, "Berlin"),
+        )
+
+        // Test that lowercase "at home" is sorted to the 2nd position instead of the end
+        Assert.assertEquals(expectedResult, testList.sortByNameAndIdASC())
+    }
+
+    @Test
+    fun `sort by id when names are equal for places`() {
+        val testList = listOf(
+            DefaultContactDiaryLocation(1, "Berlin"),
+            DefaultContactDiaryLocation(3, "At home"),
+            DefaultContactDiaryLocation(2, "At home"),
+        )
+
+        val expectedResult = listOf(
+            DefaultContactDiaryLocation(2, "At home"),
+            DefaultContactDiaryLocation(3, "At home"),
+            DefaultContactDiaryLocation(1, "Berlin"),
+        )
+
+        // Test that "At home" with lower locationId comes before the other one, even though it was
+        // added as the last entry to the testList
+        Assert.assertEquals(expectedResult, testList.sortByNameAndIdASC())
+    }
 }
-- 
GitLab