diff --git a/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt b/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt index 1432b02ac..8a82398ec 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/util/MessageSearchHelper.kt @@ -41,6 +41,7 @@ class MessageSearchHelper( private var previousResults: List = emptyList() fun startMessageSearch(search: String): Observable { + resetCachedData() return doSearch(search) } @@ -56,7 +57,6 @@ class MessageSearchHelper( } private fun doSearch(search: String, cursor: Int = 0): Observable { - resetResultsIfNeeded(search) disposeIfPossible() return unifiedSearchRepository.searchMessages(user, search, cursor) .map { results -> @@ -76,12 +76,6 @@ class MessageSearchHelper( .doOnComplete(this::disposeIfPossible) } - private fun resetResultsIfNeeded(search: String) { - if (search != previousSearch) { - resetCachedData() - } - } - private fun resetCachedData() { previousSearch = null previousCursor = 0 diff --git a/app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt b/app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt new file mode 100644 index 000000000..6099a8e10 --- /dev/null +++ b/app/src/test/java/com/nextcloud/talk/controllers/util/MessageSearchHelperTest.kt @@ -0,0 +1,146 @@ +/* + * Nextcloud Talk application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.controllers.util + +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.models.domain.SearchMessageEntry +import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository +import com.nextcloud.talk.test.fakes.FakeUnifiedSearchRepository +import io.reactivex.Observable +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +class MessageSearchHelperTest { + + @Mock + lateinit var userEntity: UserEntity + + val repository = FakeUnifiedSearchRepository() + + @Suppress("LongParameterList") + private fun createMessageEntry( + searchTerm: String = "foo", + thumbnailURL: String = "foo", + title: String = "foo", + messageExcerpt: String = "foo", + conversationToken: String = "foo", + messageId: String? = "foo" + ) = SearchMessageEntry(searchTerm, thumbnailURL, title, messageExcerpt, conversationToken, messageId) + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + } + + @Test + fun emptySearch() { + repository.response = UnifiedSearchRepository.UnifiedSearchResults(0, false, emptyList()) + + val sut = MessageSearchHelper(userEntity, repository) + + val testObserver = sut.startMessageSearch("foo").test() + testObserver.assertComplete() + testObserver.assertValueCount(1) + val expected = MessageSearchHelper.MessageSearchResults(emptyList(), false) + testObserver.assertValue(expected) + } + + @Test + fun nonEmptySearch_withMoreResults() { + val entries = (1..5).map { createMessageEntry() } + repository.response = UnifiedSearchRepository.UnifiedSearchResults(5, true, entries) + + val sut = MessageSearchHelper(userEntity, repository) + + val observable = sut.startMessageSearch("foo") + val expected = MessageSearchHelper.MessageSearchResults(entries, true) + testCall(observable, expected) + } + + @Test + fun nonEmptySearch_withNoMoreResults() { + val entries = (1..2).map { createMessageEntry() } + repository.response = UnifiedSearchRepository.UnifiedSearchResults(2, false, entries) + + val sut = MessageSearchHelper(userEntity, repository) + + val observable = sut.startMessageSearch("foo") + val expected = MessageSearchHelper.MessageSearchResults(entries, false) + testCall(observable, expected) + } + + @Test + fun nonEmptySearch_consecutiveSearches_sameResult() { + val entries = (1..2).map { createMessageEntry() } + repository.response = UnifiedSearchRepository.UnifiedSearchResults(2, false, entries) + + val sut = MessageSearchHelper(userEntity, repository) + + repeat(5) { + val observable = sut.startMessageSearch("foo") + val expected = MessageSearchHelper.MessageSearchResults(entries, false) + testCall(observable, expected) + } + } + + @Test + fun loadMore_noPreviousResults() { + val sut = MessageSearchHelper(userEntity, repository) + Assert.assertEquals(null, sut.loadMore()) + } + + @Test + fun loadMore_previousResults_sameSearch() { + val sut = MessageSearchHelper(userEntity, repository) + + val firstPageEntries = (1..5).map { createMessageEntry() } + repository.response = UnifiedSearchRepository.UnifiedSearchResults(5, true, firstPageEntries) + + val firstPageObservable = sut.startMessageSearch("foo") + Assert.assertEquals(0, repository.lastRequestedCursor) + val firstPageExpected = MessageSearchHelper.MessageSearchResults(firstPageEntries, true) + testCall(firstPageObservable, firstPageExpected) + + val secondPageEntries = (1..5).map { createMessageEntry(title = "bar") } + repository.response = UnifiedSearchRepository.UnifiedSearchResults(10, false, secondPageEntries) + + val secondPageObservable = sut.loadMore() + Assert.assertEquals(5, repository.lastRequestedCursor) + Assert.assertNotNull(secondPageObservable) + val secondPageExpected = MessageSearchHelper.MessageSearchResults(firstPageEntries + secondPageEntries, false) + testCall(secondPageObservable!!, secondPageExpected) + } + + private fun testCall( + searchCall: Observable, + expectedResult: MessageSearchHelper.MessageSearchResults + ) { + val testObserver = searchCall.test() + testObserver.assertComplete() + testObserver.assertValueCount(1) + testObserver.assertValue(expectedResult) + testObserver.dispose() + } +} diff --git a/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt b/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt new file mode 100644 index 000000000..cf2827934 --- /dev/null +++ b/app/src/test/java/com/nextcloud/talk/test/fakes/FakeUnifiedSearchRepository.kt @@ -0,0 +1,47 @@ +/* + * Nextcloud Talk application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.test.fakes + +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.models.domain.SearchMessageEntry +import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository +import io.reactivex.Observable + +class FakeUnifiedSearchRepository : UnifiedSearchRepository { + + lateinit var response: UnifiedSearchRepository.UnifiedSearchResults + var lastRequestedCursor = -1 + + override fun searchMessages( + userEntity: UserEntity, + searchTerm: String, + cursor: Int, + limit: Int + ): Observable> { + lastRequestedCursor = cursor + return Observable.just(response) + } + + override fun searchInRoom(text: String, roomId: String): Observable> { + TODO("Not yet implemented") + } +}