From 86028205e182b7cfe17508d75f757c21d48f9ed9 Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 21:52:06 +0200 Subject: [PATCH 1/6] chore(Association): Create base data class representing an association. --- app/src/main/java/com/android/unio/model/Association.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/src/main/java/com/android/unio/model/Association.kt diff --git a/app/src/main/java/com/android/unio/model/Association.kt b/app/src/main/java/com/android/unio/model/Association.kt new file mode 100644 index 000000000..e957f6d9e --- /dev/null +++ b/app/src/main/java/com/android/unio/model/Association.kt @@ -0,0 +1,9 @@ +package com.android.unio.model + +data class Association( + val uid: String, + val acronym: String, + val fullName: String, + val description: String, + val members: List +) From c7861da13c20c026e86e031d80398ad423eb7f15 Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 21:53:26 +0200 Subject: [PATCH 2/6] chore(AssociationRepository): Create the Association repository and its Firestore implementation. --- .../unio/model/AssociationRepository.kt | 5 +++ .../model/AssociationRepositoryFirestore.kt | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 app/src/main/java/com/android/unio/model/AssociationRepository.kt create mode 100644 app/src/main/java/com/android/unio/model/AssociationRepositoryFirestore.kt diff --git a/app/src/main/java/com/android/unio/model/AssociationRepository.kt b/app/src/main/java/com/android/unio/model/AssociationRepository.kt new file mode 100644 index 000000000..b711a0c75 --- /dev/null +++ b/app/src/main/java/com/android/unio/model/AssociationRepository.kt @@ -0,0 +1,5 @@ +package com.android.unio.model + +interface AssociationRepository { + fun getAssociations(onSuccess: (List) -> Unit, onFailure: (Exception) -> Unit) +} diff --git a/app/src/main/java/com/android/unio/model/AssociationRepositoryFirestore.kt b/app/src/main/java/com/android/unio/model/AssociationRepositoryFirestore.kt new file mode 100644 index 000000000..516b3f82f --- /dev/null +++ b/app/src/main/java/com/android/unio/model/AssociationRepositoryFirestore.kt @@ -0,0 +1,39 @@ +package com.android.unio.model + +import com.google.firebase.firestore.DocumentSnapshot +import com.google.firebase.firestore.FirebaseFirestore + +class AssociationRepositoryFirestore(private val db: FirebaseFirestore) : AssociationRepository { + + override fun getAssociations( + onSuccess: (List) -> Unit, + onFailure: (Exception) -> Unit + ) { + db.collection(ASSOCIATION_PATH) + .get() + .addOnSuccessListener { result -> + val associations = mutableListOf() + for (document in result) { + val association = hydrate(document) + + associations.add(association) + } + onSuccess(associations) + } + .addOnFailureListener { exception -> onFailure(exception) } + } + + fun hydrate(doc: DocumentSnapshot): Association { + return Association( + uid = doc.id, + acronym = doc.getString("acronym") ?: "", + fullName = doc.getString("fullName") ?: "", + description = doc.getString("description") ?: "", + members = doc.get("members") as? List ?: emptyList()) + } + + companion object { + private const val ASSOCIATION_PATH = "associations" + private const val USER_PATH = "users" + } +} From cc273b549d9e0d0e724ca28a53bd3f26b7aa898a Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 21:55:14 +0200 Subject: [PATCH 3/6] chore(User): Create the base data class representing a user. This was done in chore/association-model because associations depend on the User class. --- app/src/main/java/com/android/unio/model/User.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 app/src/main/java/com/android/unio/model/User.kt diff --git a/app/src/main/java/com/android/unio/model/User.kt b/app/src/main/java/com/android/unio/model/User.kt new file mode 100644 index 000000000..7e6b121e6 --- /dev/null +++ b/app/src/main/java/com/android/unio/model/User.kt @@ -0,0 +1,8 @@ +package com.android.unio.model + +data class User( + val id: String, + val name: String, + val email: String, + val followingAssociations: List +) From 80f2bdbb16e9b818ef708e5a4514a8e437af974d Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 21:57:35 +0200 Subject: [PATCH 4/6] test(User): Minimal test for the User data class. Other tests will be added to this file as user-related functionalities are added to the project. --- .../test/java/com/android/unio/model/UserTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 app/src/test/java/com/android/unio/model/UserTest.kt diff --git a/app/src/test/java/com/android/unio/model/UserTest.kt b/app/src/test/java/com/android/unio/model/UserTest.kt new file mode 100644 index 000000000..9f9a11fdc --- /dev/null +++ b/app/src/test/java/com/android/unio/model/UserTest.kt @@ -0,0 +1,15 @@ +package com.android.unio.model + +import junit.framework.TestCase.assertEquals +import org.junit.Test + +class UserTest { + @Test + fun testUser() { + val user = User("1", "John", "john@example.com", emptyList()) + assertEquals("1", user.id) + assertEquals("John", user.name) + assertEquals("john@example.com", user.email) + assertEquals(emptyList(), user.followingAssociations) + } +} \ No newline at end of file From c9c1f8ed770f3d0abfc36671340134abde4c7556 Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 21:59:28 +0200 Subject: [PATCH 5/6] test(AssociationRepositoryFirestore): Test the Firestore implementation of the AssociationRepository --- .../AssociationRepositoryFirestoreTest.kt | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt diff --git a/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt b/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt new file mode 100644 index 000000000..05ac16da7 --- /dev/null +++ b/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt @@ -0,0 +1,112 @@ +package com.android.unio.model + +import com.google.android.gms.tasks.OnSuccessListener +import com.google.android.gms.tasks.Task +import com.google.firebase.firestore.CollectionReference +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.QueryDocumentSnapshot +import com.google.firebase.firestore.QuerySnapshot +import junit.framework.TestCase.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.eq + +class AssociationRepositoryFirestoreTest { + @Mock private lateinit var db: FirebaseFirestore + @Mock private lateinit var collectionReference: CollectionReference + @Mock private lateinit var querySnapshot: QuerySnapshot + @Mock private lateinit var queryDocumentSnapshot1: QueryDocumentSnapshot + @Mock private lateinit var queryDocumentSnapshot2: QueryDocumentSnapshot + @Mock private lateinit var task: Task + + private lateinit var repository: AssociationRepositoryFirestore + + private val association1 = + Association( + uid = "1", + acronym = "ACM", + fullName = "Association for Computing Machinery", + description = "ACM is the world's largest educational and scientific computing society.", + members = mutableListOf("1", "2")) + + private val association2 = + Association( + uid = "2", + acronym = "IEEE", + fullName = "Institute of Electrical and Electronics Engineers", + description = + "IEEE is the world's largest technical professional organization dedicated to advancing technology for the benefit of humanity.", + members = mutableListOf("3", "4")) + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + + // When getting the collection, return the task + `when`(db.collection(eq("associations"))).thenReturn(collectionReference) + `when`(collectionReference.get()).thenReturn(task) + + // When the task is successful, return the query snapshot + `when`(task.addOnSuccessListener(any())).thenAnswer { invocation -> + val callback = invocation.arguments[0] as OnSuccessListener + callback.onSuccess(querySnapshot) + task + } + + // When the query snapshot is iterated, return the two query document snapshots + `when`(querySnapshot.iterator()) + .thenReturn(mutableListOf(queryDocumentSnapshot1, queryDocumentSnapshot2).iterator()) + + // When the query document snapshots are queried for specific fields, return the fields + `when`(queryDocumentSnapshot1.id).thenReturn(association1.uid) + `when`(queryDocumentSnapshot1.getString("acronym")).thenReturn(association1.acronym) + `when`(queryDocumentSnapshot1.getString("fullName")).thenReturn(association1.fullName) + `when`(queryDocumentSnapshot1.getString("description")).thenReturn(association1.description) + `when`(queryDocumentSnapshot1.get("members")).thenReturn(association1.members) + + repository = AssociationRepositoryFirestore(db) + } + + @Test + fun testGetAssociations() { + `when`(queryDocumentSnapshot2.id).thenReturn(association2.uid) + `when`(queryDocumentSnapshot2.getString("acronym")).thenReturn(association2.acronym) + `when`(queryDocumentSnapshot2.getString("fullName")).thenReturn(association2.fullName) + `when`(queryDocumentSnapshot2.getString("description")).thenReturn(association2.description) + `when`(queryDocumentSnapshot2.get("members")).thenReturn(association2.members) + + repository.getAssociations( + onSuccess = { associations -> + assertEquals(2, associations.size) + assertEquals(association1, associations[0]) + assertEquals(association2, associations[1]) + }, + onFailure = { exception -> assert(false) }) + } + + @Test + fun testGetAssociationsWithMissingFields() { + // Only set the ID for the second association, leaving the other fields as null + `when`(queryDocumentSnapshot2.id).thenReturn(association2.uid) + + repository.getAssociations( + onSuccess = { associations -> + assertEquals(2, associations.size) + assertEquals(association1, associations[0]) + assertEquals( + Association( + uid = association2.uid, + acronym = "", + fullName = "", + description = "", + members = emptyList()), + associations[1]) + }, + onFailure = { exception -> assert(false) }) + + } +} From fb4fc619fdd16a060db1c5ed28208877699e4a85 Mon Sep 17 00:00:00 2001 From: Oskar Codes Date: Fri, 4 Oct 2024 22:21:02 +0200 Subject: [PATCH 6/6] style(tests): Format test files using ktfmtFormat. --- .../android/unio/model/AssociationRepositoryFirestoreTest.kt | 1 - app/src/test/java/com/android/unio/model/UserTest.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt b/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt index 05ac16da7..cd41ecb88 100644 --- a/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt +++ b/app/src/test/java/com/android/unio/model/AssociationRepositoryFirestoreTest.kt @@ -107,6 +107,5 @@ class AssociationRepositoryFirestoreTest { associations[1]) }, onFailure = { exception -> assert(false) }) - } } diff --git a/app/src/test/java/com/android/unio/model/UserTest.kt b/app/src/test/java/com/android/unio/model/UserTest.kt index 9f9a11fdc..d00edc527 100644 --- a/app/src/test/java/com/android/unio/model/UserTest.kt +++ b/app/src/test/java/com/android/unio/model/UserTest.kt @@ -12,4 +12,4 @@ class UserTest { assertEquals("john@example.com", user.email) assertEquals(emptyList(), user.followingAssociations) } -} \ No newline at end of file +}