diff --git a/app/src/androidTest/java/com/github/swent/echo/compose/components/EventInfoSheetTest.kt b/app/src/androidTest/java/com/github/swent/echo/compose/components/EventInfoSheetTest.kt index c9425c477..0c091cb7b 100644 --- a/app/src/androidTest/java/com/github/swent/echo/compose/components/EventInfoSheetTest.kt +++ b/app/src/androidTest/java/com/github/swent/echo/compose/components/EventInfoSheetTest.kt @@ -30,6 +30,7 @@ class EventInfoSheetTest { val event = Event( eventId = "1", + creatorId = "1", organizerId = "1", title = "Event Title", description = "Event Description", diff --git a/app/src/androidTest/java/com/github/swent/echo/compose/map/MapViewAndroidTest.kt b/app/src/androidTest/java/com/github/swent/echo/compose/map/MapViewAndroidTest.kt index 108500932..fb76a5e2d 100644 --- a/app/src/androidTest/java/com/github/swent/echo/compose/map/MapViewAndroidTest.kt +++ b/app/src/androidTest/java/com/github/swent/echo/compose/map/MapViewAndroidTest.kt @@ -34,6 +34,7 @@ class MapViewAndroidTest { listOf( Event( eventId = "a", + creatorId = "a", organizerId = "a", title = "Bowling Event", description = "", @@ -44,6 +45,7 @@ class MapViewAndroidTest { ), Event( eventId = "b", + creatorId = "a", organizerId = "a", title = "Swimming Event", description = "", diff --git a/app/src/androidTest/java/com/github/swent/echo/data/repository/datasources/SupabaseTest.kt b/app/src/androidTest/java/com/github/swent/echo/data/repository/datasources/SupabaseTest.kt new file mode 100644 index 000000000..5890cc1bb --- /dev/null +++ b/app/src/androidTest/java/com/github/swent/echo/data/repository/datasources/SupabaseTest.kt @@ -0,0 +1,150 @@ +package com.github.swent.echo.data.repository.datasources + +import com.github.swent.echo.data.model.Association +import com.github.swent.echo.data.model.Event +import com.github.swent.echo.data.model.Location +import com.github.swent.echo.data.model.Tag +import com.github.swent.echo.data.model.UserProfile +import com.github.swent.echo.data.repository.datasources.Supabase as SupabaseSource +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.createSupabaseClient +import io.github.jan.supabase.exceptions.UnauthorizedRestException +import io.github.jan.supabase.gotrue.Auth +import io.github.jan.supabase.postgrest.Postgrest +import java.util.Arrays +import java.util.Date +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.SerializationException +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.function.ThrowingRunnable + +class SupabaseTest { + private val supabaseUrl = "ulejnivguxeiibkbpwnb.supabase.co" + private val supabasePublicKey = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVsZWpuaXZndXhlaWlia2Jwd25iIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTA4MzgxODQsImV4cCI6MjAyNjQxNDE4NH0.9Hkj-Gox2XHcHfs_U2GyQFc9sZ_nu2Xs16-KYBri32g" + private lateinit var supabaseClient: SupabaseClient + private lateinit var source: SupabaseSource + + private val association = + Association( + "b0122e3e-82ed-4409-83f9-dbfb9761db20", + "Dummy Assoc", + "DO NOT DELETE/MODIFY: tests in repository.datasources.SupabaseTest will fail" + ) + private val tag = Tag("daba142a-a276-4b7e-824d-43ca088633ff", "Dummy Tag") + private val event = + Event( + "3bcf6f25-81d4-4a14-9caa-c05feb593da0", + "e65e9435-a9f2-4474-be11-9054305f1a54", + "b0122e3e-82ed-4409-83f9-dbfb9761db20", + "Dummy Event", + "blabla description", + Location("testLocation", 0.0, 0.0), + Date(0), + Date(1), + HashSet(Arrays.asList(tag)) + ) + private val userProfile = UserProfile("b0122e3e-82ed-4409-83f9-dbfb9761db20", "Dummy User") + + @Before + fun setUp() { + supabaseClient = + createSupabaseClient(supabaseUrl, supabasePublicKey) { + install(Auth) + install(Postgrest) + } + source = SupabaseSource(supabaseClient) + } + + @Test + fun getAssociationTest() { + assertThrows( + NoSuchElementException::class.java, + ThrowingRunnable { + runBlocking { source.getAssociation("b0122e3e-82ed-4409-83f9-dbfb9761db20") } + } + ) + } + + @Test + fun setAssociationTest() { + assertThrows( + UnauthorizedRestException::class.java, + ThrowingRunnable { runBlocking { source.setAssociation(association) } } + ) + } + + @Test + fun getAllAssociationsTest() { + val associations = runBlocking { source.getAllAssociations() } + assertNotNull(associations) + } + + @Test + fun getEventTest() { + assertThrows( + NoSuchElementException::class.java, + ThrowingRunnable { + runBlocking { source.getEvent("3bcf6f25-81d4-4a14-9caa-c05feb593da0") } + } + ) + } + + @Test + fun setEventTest() { + assertThrows( + SerializationException::class.java, + ThrowingRunnable { runBlocking { source.setEvent(event) } } + ) + } + + @Test + fun getAllEventsTest() { + val associations = runBlocking { source.getAllEvents() } + assertNotNull(associations) + } + + @Test + fun getTagTest() { + assertThrows( + NoSuchElementException::class.java, + ThrowingRunnable { + runBlocking { source.getTag("daba142a-a276-4b7e-824d-43ca088633ff") } + } + ) + } + + @Test + fun setTagTest() { + assertThrows( + UnauthorizedRestException::class.java, + ThrowingRunnable { runBlocking { source.setTag(tag) } } + ) + } + + @Test + fun getAllTagsTest() { + val associations = runBlocking { source.getAllTags() } + assertNotNull(associations) + } + + @Test + fun getUserProfileTest() { + assertThrows( + NoSuchElementException::class.java, + ThrowingRunnable { + runBlocking { source.getUserProfile("b0122e3e-82ed-4409-83f9-dbfb9761db20") } + } + ) + } + + @Test + fun setUserProfileTest() { + assertThrows( + UnauthorizedRestException::class.java, + ThrowingRunnable { runBlocking { source.setUserProfile(userProfile) } } + ) + } +} diff --git a/app/src/main/java/com/github/swent/echo/data/model/Association.kt b/app/src/main/java/com/github/swent/echo/data/model/Association.kt index cb3228153..bedf92e94 100644 --- a/app/src/main/java/com/github/swent/echo/data/model/Association.kt +++ b/app/src/main/java/com/github/swent/echo/data/model/Association.kt @@ -1,3 +1,6 @@ package com.github.swent.echo.data.model +import kotlinx.serialization.Serializable + +@Serializable data class Association(val associationId: String, val name: String, val description: String) diff --git a/app/src/main/java/com/github/swent/echo/data/model/Event.kt b/app/src/main/java/com/github/swent/echo/data/model/Event.kt index 10b3fbdae..d7b281eb6 100644 --- a/app/src/main/java/com/github/swent/echo/data/model/Event.kt +++ b/app/src/main/java/com/github/swent/echo/data/model/Event.kt @@ -1,14 +1,18 @@ package com.github.swent.echo.data.model import java.util.Date +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +@Serializable data class Event( val eventId: String, + val creatorId: String, val organizerId: String, val title: String, val description: String, val location: Location, - val startDate: Date, - val endDate: Date, + @Contextual val startDate: Date, + @Contextual val endDate: Date, val tags: Set ) diff --git a/app/src/main/java/com/github/swent/echo/data/model/Location.kt b/app/src/main/java/com/github/swent/echo/data/model/Location.kt index 66e363452..ecc3cea06 100644 --- a/app/src/main/java/com/github/swent/echo/data/model/Location.kt +++ b/app/src/main/java/com/github/swent/echo/data/model/Location.kt @@ -1,8 +1,10 @@ package com.github.swent.echo.data.model +import kotlinx.serialization.Serializable import org.maplibre.android.geometry.LatLng import org.osmdroid.util.GeoPoint +@Serializable data class Location(val name: String, val lat: Double, val long: Double) { constructor(name: String, point: GeoPoint) : this(name, point.latitude, point.longitude) diff --git a/app/src/main/java/com/github/swent/echo/data/model/Tag.kt b/app/src/main/java/com/github/swent/echo/data/model/Tag.kt index aea039ebe..01133ab96 100644 --- a/app/src/main/java/com/github/swent/echo/data/model/Tag.kt +++ b/app/src/main/java/com/github/swent/echo/data/model/Tag.kt @@ -1,3 +1,5 @@ package com.github.swent.echo.data.model -data class Tag(val tagId: String, val name: String) +import kotlinx.serialization.Serializable + +@Serializable data class Tag(val tagId: String, val name: String) diff --git a/app/src/main/java/com/github/swent/echo/data/model/User.kt b/app/src/main/java/com/github/swent/echo/data/model/User.kt deleted file mode 100644 index 383d8c839..000000000 --- a/app/src/main/java/com/github/swent/echo/data/model/User.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.swent.echo.data.model - -data class User(val userId: String, val userProfileId: UserProfile) diff --git a/app/src/main/java/com/github/swent/echo/data/model/UserProfile.kt b/app/src/main/java/com/github/swent/echo/data/model/UserProfile.kt index 615bfb103..eca3b3ff3 100644 --- a/app/src/main/java/com/github/swent/echo/data/model/UserProfile.kt +++ b/app/src/main/java/com/github/swent/echo/data/model/UserProfile.kt @@ -1,3 +1,5 @@ package com.github.swent.echo.data.model -data class UserProfile(val userId: String, val name: String) +import kotlinx.serialization.Serializable + +@Serializable data class UserProfile(val userId: String, val name: String) diff --git a/app/src/main/java/com/github/swent/echo/data/repository/Repository.kt b/app/src/main/java/com/github/swent/echo/data/repository/Repository.kt index 2eafa834b..699e0d8bc 100644 --- a/app/src/main/java/com/github/swent/echo/data/repository/Repository.kt +++ b/app/src/main/java/com/github/swent/echo/data/repository/Repository.kt @@ -3,7 +3,6 @@ package com.github.swent.echo.data.repository import com.github.swent.echo.data.model.Association import com.github.swent.echo.data.model.Event import com.github.swent.echo.data.model.Tag -import com.github.swent.echo.data.model.User import com.github.swent.echo.data.model.UserProfile interface Repository { @@ -25,10 +24,6 @@ interface Repository { suspend fun getAllTags(): List - suspend fun getUser(userId: String): User - - suspend fun setUser(user: User) - suspend fun getUserProfile(userId: String): UserProfile suspend fun setUserProfile(userProfile: UserProfile) diff --git a/app/src/main/java/com/github/swent/echo/data/repository/RepositoryImpl.kt b/app/src/main/java/com/github/swent/echo/data/repository/RepositoryImpl.kt new file mode 100644 index 000000000..e0fee6887 --- /dev/null +++ b/app/src/main/java/com/github/swent/echo/data/repository/RepositoryImpl.kt @@ -0,0 +1,53 @@ +package com.github.swent.echo.data.repository + +import com.github.swent.echo.data.model.Association +import com.github.swent.echo.data.model.Event +import com.github.swent.echo.data.model.Tag +import com.github.swent.echo.data.model.UserProfile +import com.github.swent.echo.data.repository.datasources.RemoteDataSource + +class RepositoryImpl(private val remoteDataSource: RemoteDataSource) : Repository { + override suspend fun getAssociation(associationId: String): Association { + return remoteDataSource.getAssociation(associationId) + } + + override suspend fun setAssociation(association: Association) { + return remoteDataSource.setAssociation(association) + } + + override suspend fun getAllAssociations(): List { + return remoteDataSource.getAllAssociations() + } + + override suspend fun getEvent(eventId: String): Event { + return remoteDataSource.getEvent(eventId) + } + + override suspend fun setEvent(event: Event) { + return remoteDataSource.setEvent(event) + } + + override suspend fun getAllEvents(): List { + return remoteDataSource.getAllEvents() + } + + override suspend fun getTag(tagId: String): Tag { + return remoteDataSource.getTag(tagId) + } + + override suspend fun setTag(tag: Tag) { + return remoteDataSource.setTag(tag) + } + + override suspend fun getAllTags(): List { + return remoteDataSource.getAllTags() + } + + override suspend fun getUserProfile(userId: String): UserProfile { + return remoteDataSource.getUserProfile(userId) + } + + override suspend fun setUserProfile(userProfile: UserProfile) { + return remoteDataSource.setUserProfile(userProfile) + } +} diff --git a/app/src/main/java/com/github/swent/echo/data/repository/datasources/RemoteDataSource.kt b/app/src/main/java/com/github/swent/echo/data/repository/datasources/RemoteDataSource.kt index a0a09f753..01159c50e 100644 --- a/app/src/main/java/com/github/swent/echo/data/repository/datasources/RemoteDataSource.kt +++ b/app/src/main/java/com/github/swent/echo/data/repository/datasources/RemoteDataSource.kt @@ -1,5 +1,30 @@ package com.github.swent.echo.data.repository.datasources +import com.github.swent.echo.data.model.Association +import com.github.swent.echo.data.model.Event +import com.github.swent.echo.data.model.Tag +import com.github.swent.echo.data.model.UserProfile + interface RemoteDataSource { - fun getData(): String + suspend fun getAssociation(associationId: String): Association + + suspend fun setAssociation(association: Association) + + suspend fun getAllAssociations(): List + + suspend fun getEvent(eventId: String): Event + + suspend fun setEvent(event: Event) + + suspend fun getAllEvents(): List + + suspend fun getTag(tagId: String): Tag + + suspend fun setTag(tag: Tag) + + suspend fun getAllTags(): List + + suspend fun getUserProfile(userId: String): UserProfile + + suspend fun setUserProfile(userProfile: UserProfile) } diff --git a/app/src/main/java/com/github/swent/echo/data/repository/datasources/Supabase.kt b/app/src/main/java/com/github/swent/echo/data/repository/datasources/Supabase.kt new file mode 100644 index 000000000..f5879609a --- /dev/null +++ b/app/src/main/java/com/github/swent/echo/data/repository/datasources/Supabase.kt @@ -0,0 +1,63 @@ +package com.github.swent.echo.data.repository.datasources + +import com.github.swent.echo.data.model.Association +import com.github.swent.echo.data.model.Event +import com.github.swent.echo.data.model.Tag +import com.github.swent.echo.data.model.UserProfile +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.postgrest.from + +class Supabase(supabaseClient: SupabaseClient) : RemoteDataSource { + + var supabase = supabaseClient + + override suspend fun getAssociation(associationId: String): Association { + return supabase + .from("associations") + .select() { filter { eq("associationId", associationId) } } + .decodeSingle() + } + + override suspend fun setAssociation(association: Association) { + supabase.from("associations").upsert(association, onConflict = "associationId") + } + + override suspend fun getAllAssociations(): List { + return supabase.from("associations").select().decodeList() + } + + override suspend fun getEvent(eventId: String): Event { + return supabase.from("events").select() { filter { eq("eventId", eventId) } }.decodeSingle() + } + + override suspend fun setEvent(event: Event) { + supabase.from("events").upsert(event, onConflict = "eventId") + } + + override suspend fun getAllEvents(): List { + return supabase.from("events").select().decodeList() + } + + override suspend fun getTag(tagId: String): Tag { + return supabase.from("tags").select() { filter { eq("tagId", tagId) } }.decodeSingle() + } + + override suspend fun setTag(tag: Tag) { + supabase.from("tags").upsert(tag, onConflict = "tagId") + } + + override suspend fun getAllTags(): List { + return supabase.from("tags").select().decodeList() + } + + override suspend fun getUserProfile(userId: String): UserProfile { + return supabase + .from("userProfiles") + .select() { filter { eq("userId", userId) } } + .decodeSingle() + } + + override suspend fun setUserProfile(userProfile: UserProfile) { + supabase.from("userProfiles").upsert(userProfile, onConflict = "userId") + } +} diff --git a/app/src/main/java/com/github/swent/echo/viewmodels/event/EventViewModel.kt b/app/src/main/java/com/github/swent/echo/viewmodels/event/EventViewModel.kt index 64b57237d..d58865ae2 100644 --- a/app/src/main/java/com/github/swent/echo/viewmodels/event/EventViewModel.kt +++ b/app/src/main/java/com/github/swent/echo/viewmodels/event/EventViewModel.kt @@ -18,6 +18,7 @@ class EventViewModel() : ViewModel() { "", "", "", + "", Location("", 0.0, 0.0), Date.from(Instant.now()), Date.from(Instant.now()), diff --git a/app/src/test/java/com/github/swent/echo/data/repository/RepositoryImplTest.kt b/app/src/test/java/com/github/swent/echo/data/repository/RepositoryImplTest.kt new file mode 100644 index 000000000..bdf509294 --- /dev/null +++ b/app/src/test/java/com/github/swent/echo/data/repository/RepositoryImplTest.kt @@ -0,0 +1,120 @@ +package com.github.swent.echo.data.repository + +import com.github.swent.echo.data.model.Association +import com.github.swent.echo.data.model.Event +import com.github.swent.echo.data.model.Location +import com.github.swent.echo.data.model.Tag +import com.github.swent.echo.data.model.UserProfile +import com.github.swent.echo.data.repository.datasources.RemoteDataSource +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import java.util.Arrays +import java.util.Date +import kotlinx.coroutines.runBlocking +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test + +class RepositoryImplTest { + private lateinit var mockedRemoteDataSource: RemoteDataSource + private lateinit var repositoryImpl: RepositoryImpl + + private val association = Association("testAssoc", "Dummy Assoc", "blabla description") + private val tag = Tag("testTag", "Dummy Tag") + private val event = + Event( + "testEvent", + "testCreator", + "testOrganizer", + "Dummy Event", + "blabla description", + Location("testLocation", 0.0, 0.0), + Date(0), + Date(1), + HashSet(Arrays.asList(tag)) + ) + private val userProfile = UserProfile("testUser", "Dummy User") + + @Before + fun setUp() { + mockedRemoteDataSource = mockk(relaxed = true) + repositoryImpl = RepositoryImpl(mockedRemoteDataSource) + } + + @Test + fun getAssociationTest() { + every { runBlocking { mockedRemoteDataSource.getAssociation("testAssoc") } } returns + association + val associationResult = runBlocking { repositoryImpl.getAssociation("testAssoc") } + assertEquals(association, associationResult) + } + + @Test + fun setAssociationTest() { + runBlocking { repositoryImpl.setAssociation(association) } + verify { runBlocking { repositoryImpl.setAssociation(association) } } + } + + @Test + fun getAllAssociationsTest() { + every { runBlocking { mockedRemoteDataSource.getAllAssociations() } } returns + Arrays.asList(association) + val associationsResult = runBlocking { repositoryImpl.getAllAssociations() } + assertEquals(Arrays.asList(association), associationsResult) + } + + @Test + fun getEventTest() { + every { runBlocking { mockedRemoteDataSource.getEvent("testEvent") } } returns event + val eventResult = runBlocking { repositoryImpl.getEvent("testEvent") } + assertEquals(event, eventResult) + } + + @Test + fun setEventTest() { + runBlocking { repositoryImpl.setEvent(event) } + verify { runBlocking { repositoryImpl.setEvent(event) } } + } + + @Test + fun getAllEventsTest() { + every { runBlocking { mockedRemoteDataSource.getAllEvents() } } returns Arrays.asList(event) + val eventsResult = runBlocking { repositoryImpl.getAllEvents() } + assertEquals(Arrays.asList(event), eventsResult) + } + + @Test + fun getTagTest() { + every { runBlocking { mockedRemoteDataSource.getTag("testTag") } } returns tag + val tagResult = runBlocking { repositoryImpl.getTag("testTag") } + assertEquals(tag, tagResult) + } + + @Test + fun setTagTest() { + runBlocking { repositoryImpl.setTag(tag) } + verify { runBlocking { repositoryImpl.setTag(tag) } } + } + + @Test + fun getAllTagsTest() { + every { runBlocking { mockedRemoteDataSource.getAllTags() } } returns Arrays.asList(tag) + val tagsResult = runBlocking { repositoryImpl.getAllTags() } + assertEquals(Arrays.asList(tag), tagsResult) + } + + @Test + fun getUserProfileTest() { + every { runBlocking { mockedRemoteDataSource.getUserProfile("testUser") } } returns + userProfile + val userProfileResult = runBlocking { repositoryImpl.getUserProfile("testUser") } + assertEquals(userProfile, userProfileResult) + } + + @Test + fun setUserProfileTest() { + runBlocking { repositoryImpl.setUserProfile(userProfile) } + verify { runBlocking { repositoryImpl.setUserProfile(userProfile) } } + } +} diff --git a/app/src/test/java/com/github/swent/echo/viewmodels/event/EventViewModelTest.kt b/app/src/test/java/com/github/swent/echo/viewmodels/event/EventViewModelTest.kt index 6674f5b49..f0fded051 100644 --- a/app/src/test/java/com/github/swent/echo/viewmodels/event/EventViewModelTest.kt +++ b/app/src/test/java/com/github/swent/echo/viewmodels/event/EventViewModelTest.kt @@ -19,6 +19,7 @@ class EventViewModelTest { private val TEST_EVENT = Event( eventId = "testid", + "testid", organizerId = "testid", title = "test title", description = "test description",