|
@@ -1,16 +1,48 @@
|
|
|
+/**
|
|
|
+ * Nextcloud Android client application
|
|
|
+ *
|
|
|
+ * @author Chris Narkiewicz
|
|
|
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
|
|
+ *
|
|
|
+ * This program is free software: you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU Affero General Public License
|
|
|
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
+ */
|
|
|
package com.nextcloud.client.files
|
|
|
|
|
|
+import android.net.Uri
|
|
|
+import com.nextcloud.client.account.Server
|
|
|
+import com.nextcloud.client.account.User
|
|
|
+import com.nextcloud.client.account.UserAccountManager
|
|
|
+import com.nhaarman.mockitokotlin2.mock
|
|
|
+import com.nhaarman.mockitokotlin2.whenever
|
|
|
+import com.owncloud.android.lib.resources.status.OwnCloudVersion
|
|
|
import org.junit.Assert.assertEquals
|
|
|
import org.junit.Assert.assertNotNull
|
|
|
+import org.junit.Assert.assertNull
|
|
|
+import org.junit.Assert.assertSame
|
|
|
import org.junit.Before
|
|
|
import org.junit.Test
|
|
|
import org.junit.runner.RunWith
|
|
|
import org.junit.runners.Parameterized
|
|
|
import org.junit.runners.Suite
|
|
|
+import org.mockito.Mock
|
|
|
+import org.mockito.MockitoAnnotations
|
|
|
+import java.net.URI
|
|
|
|
|
|
@RunWith(Suite::class)
|
|
|
@Suite.SuiteClasses(
|
|
|
- DeepLinkHandlerTest.DeepLinkPattern::class
|
|
|
+ DeepLinkHandlerTest.DeepLinkPattern::class,
|
|
|
+ DeepLinkHandlerTest.FileDeepLink::class
|
|
|
)
|
|
|
class DeepLinkHandlerTest {
|
|
|
|
|
@@ -39,8 +71,7 @@ class DeepLinkHandlerTest {
|
|
|
fun urls(): Array<Array<Any>> {
|
|
|
val testInput = mutableListOf<Array<Any>>()
|
|
|
SERVER_BASE_URLS.forEach { baseUrl ->
|
|
|
- INDEX_PHP_PATH.forEach {
|
|
|
- indexPath ->
|
|
|
+ INDEX_PHP_PATH.forEach { indexPath ->
|
|
|
val url = "$baseUrl$indexPath/f/$FILE_ID"
|
|
|
testInput.add(arrayOf(baseUrl, indexPath, "$FILE_ID", url))
|
|
|
}
|
|
@@ -70,5 +101,135 @@ class DeepLinkHandlerTest {
|
|
|
assertEquals(fileId, match?.groupValues?.get(DeepLinkHandler.FILE_ID_GROUP_INDEX))
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ fun no_trailing_path_allowed_after_file_id() {
|
|
|
+ val invalidUrl = "$url/"
|
|
|
+ val match = DeepLinkHandler.DEEP_LINK_PATTERN.matchEntire(invalidUrl)
|
|
|
+ assertNull(match)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class FileDeepLink {
|
|
|
+
|
|
|
+ companion object {
|
|
|
+ const val OTHER_SERVER_BASE_URL = "https://someotherserver.net"
|
|
|
+ const val SERVER_BASE_URL = "https://server.net"
|
|
|
+ const val FILE_ID = "1234567890"
|
|
|
+ val DEEP_LINK = Uri.parse("$SERVER_BASE_URL/index.php/f/$FILE_ID")
|
|
|
+
|
|
|
+ fun createMockUser(serverBaseUrl: String): User {
|
|
|
+ val user = mock<User>()
|
|
|
+ val uri = URI.create(serverBaseUrl)
|
|
|
+ val server = Server(uri = uri, version = OwnCloudVersion.nextcloud_19)
|
|
|
+ whenever(user.server).thenReturn(server)
|
|
|
+ return user
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ lateinit var userAccountManager: UserAccountManager
|
|
|
+ lateinit var allUsers: List<User>
|
|
|
+ lateinit var handler: DeepLinkHandler
|
|
|
+
|
|
|
+ @Before
|
|
|
+ fun setUp() {
|
|
|
+ MockitoAnnotations.initMocks(this)
|
|
|
+ whenever(userAccountManager.allUsers).thenAnswer { allUsers }
|
|
|
+ allUsers = emptyList()
|
|
|
+ handler = DeepLinkHandler(userAccountManager)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ fun no_user_can_open_file() {
|
|
|
+ // GIVEN
|
|
|
+ // no user capable of opening the file
|
|
|
+ allUsers = listOf(
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL),
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL)
|
|
|
+ )
|
|
|
+
|
|
|
+ // WHEN
|
|
|
+ // deep link is parsed
|
|
|
+ val match = handler.parseDeepLink(DEEP_LINK)
|
|
|
+
|
|
|
+ // THEN
|
|
|
+ // link is valid
|
|
|
+ // no user can open the file
|
|
|
+ assertNotNull(match)
|
|
|
+ assertEquals(0, match?.users?.size)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ fun single_user_can_open_file() {
|
|
|
+ // GIVEN
|
|
|
+ // multiple users registered
|
|
|
+ // one user capable of opening the link
|
|
|
+ val matchingUser = createMockUser(SERVER_BASE_URL)
|
|
|
+ allUsers = listOf(
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL),
|
|
|
+ matchingUser,
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL)
|
|
|
+ )
|
|
|
+
|
|
|
+ // WHEN
|
|
|
+ // deep link is parsed
|
|
|
+ val match = handler.parseDeepLink(DEEP_LINK)
|
|
|
+
|
|
|
+ // THEN
|
|
|
+ // link can be opened by single user
|
|
|
+ assertNotNull(match)
|
|
|
+ assertSame(matchingUser, match?.users?.get(0))
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ fun multiple_users_can_open_file() {
|
|
|
+ // GIVEN
|
|
|
+ // mutltiple users registered
|
|
|
+ // multiple users capable of opening the link
|
|
|
+ val matchingUsers = setOf(
|
|
|
+ createMockUser(SERVER_BASE_URL),
|
|
|
+ createMockUser(SERVER_BASE_URL)
|
|
|
+ )
|
|
|
+ val otherUsers = setOf(
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL),
|
|
|
+ createMockUser(OTHER_SERVER_BASE_URL)
|
|
|
+ )
|
|
|
+ allUsers = listOf(matchingUsers, otherUsers).flatten()
|
|
|
+
|
|
|
+ // WHEN
|
|
|
+ // deep link is parsed
|
|
|
+ val match = handler.parseDeepLink(DEEP_LINK)
|
|
|
+
|
|
|
+ // THEN
|
|
|
+ // link can be opened by multiple matching users
|
|
|
+ assertNotNull(match)
|
|
|
+ assertEquals(matchingUsers, match?.users?.toSet())
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ fun match_contains_extracted_file_id() {
|
|
|
+ // WHEN
|
|
|
+ // valid deep file link is parsed
|
|
|
+ val match = handler.parseDeepLink(DEEP_LINK)
|
|
|
+
|
|
|
+ // THEN
|
|
|
+ // file id is returned
|
|
|
+ assertEquals(FILE_ID, match?.fileId)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ fun no_match_for_invalid_link() {
|
|
|
+ // GIVEN
|
|
|
+ // invalid deep link
|
|
|
+ val invalidLink = Uri.parse("http://www.dodgylink.com/index.php")
|
|
|
+
|
|
|
+ // WHEN
|
|
|
+ // deep link is parsed
|
|
|
+ val match = handler.parseDeepLink(invalidLink)
|
|
|
+
|
|
|
+ // THEN
|
|
|
+ // no match
|
|
|
+ assertNull(match)
|
|
|
+ }
|
|
|
}
|
|
|
}
|