added DEV version to repo

This commit is contained in:
Fr4nz D13trich 2025-09-18 18:43:03 +02:00
parent 1ef725ef20
commit 23e673bfdf
2135 changed files with 97033 additions and 21206 deletions

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2021 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client;

View file

@ -0,0 +1,59 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.GrantStoragePermissionRule.Companion.grant
import com.owncloud.android.AbstractIT
import com.owncloud.android.ui.activity.CommunityActivity
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
class CommunityActivityIT : AbstractIT() {
private val testClassName = "com.nextcloud.client.CommunityActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@get:Rule
var storagePermissionRule: TestRule = grant()
@Test
@UiThread
@ScreenshotTest
fun open() {
launchActivity<CommunityActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client;

View file

@ -3,26 +3,26 @@
*
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import android.app.Activity
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import com.nextcloud.test.RetryTestRule
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.R
@ -35,33 +35,39 @@ import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.operations.CreateFolderOperation
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.adapter.OCFileListItemViewHolder
import org.junit.Assert
import com.owncloud.android.utils.EspressoIdlingResource
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
class FileDisplayActivityIT : AbstractOnServerIT() {
@get:Rule
val activityRule = IntentsTestRule(
FileDisplayActivity::class.java,
true,
false
)
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@get:Rule
val retryRule = RetryTestRule() // showShares is flaky
// @ScreenshotTest // todo run without real server
@Suppress("DEPRECATION")
@Test
fun showShares() {
Assert.assertTrue(ExistenceCheckRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess)
Assert.assertTrue(CreateFolderRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess)
Assert.assertTrue(CreateFolderRemoteOperation("/shareToGroup/", true).execute(client).isSuccess)
Assert.assertTrue(CreateFolderRemoteOperation("/shareViaLink/", true).execute(client).isSuccess)
Assert.assertTrue(CreateFolderRemoteOperation("/noShare/", true).execute(client).isSuccess)
// assertTrue(new CreateFolderRemoteOperation("/shareToCircle/", true).execute(client).isSuccess());
assertTrue(ExistenceCheckRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess)
assertTrue(CreateFolderRemoteOperation("/shareToAdmin/", true).execute(client).isSuccess)
assertTrue(CreateFolderRemoteOperation("/shareToGroup/", true).execute(client).isSuccess)
assertTrue(CreateFolderRemoteOperation("/shareViaLink/", true).execute(client).isSuccess)
assertTrue(CreateFolderRemoteOperation("/noShare/", true).execute(client).isSuccess)
// share folder to user "admin"
Assert.assertTrue(
assertTrue(
CreateShareRemoteOperation(
"/shareToAdmin/",
ShareType.USER,
@ -73,7 +79,7 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
)
// share folder via public link
Assert.assertTrue(
assertTrue(
CreateShareRemoteOperation(
"/shareViaLink/",
ShareType.PUBLIC_LINK,
@ -85,7 +91,7 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
)
// share folder to group
Assert.assertTrue(
assertTrue(
CreateShareRemoteOperation(
"/shareToGroup/",
ShareType.GROUP,
@ -96,101 +102,53 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
).execute(client).isSuccess
)
// share folder to circle
// get share
// RemoteOperationResult searchResult = new GetShareesRemoteOperation("publicCircle", 1, 50).execute(client);
// assertTrue(searchResult.getLogMessage(), searchResult.isSuccess());
//
// JSONObject resultJson = (JSONObject) searchResult.getData().get(0);
// String circleId = resultJson.getJSONObject("value").getString("shareWith");
//
// assertTrue(new CreateShareRemoteOperation("/shareToCircle/",
// ShareType.CIRCLE,
// circleId,
// false,
// "",
// OCShare.DEFAULT_PERMISSION)
// .execute(client).isSuccess());
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// open drawer
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
val sut: Activity = activityRule.launchActivity(null)
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
// open drawer
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
// click "shared"
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_shared))
shortSleep()
shortSleep()
// screenshot(sut) // todo run without real server
// click "shared"
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_shared))
}
}
}
}
@Suppress("DEPRECATION")
@Test
fun allFiles() {
val sut = activityRule.launchActivity(null)
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
// given test folder
assertTrue(
CreateFolderOperation("/test/", user, targetContext, storageManager)
.execute(client)
.isSuccess
)
// given test folder
Assert.assertTrue(
CreateFolderOperation("/test/", user, targetContext, storageManager)
.execute(client)
.isSuccess
)
// navigate into it
val test = storageManager.getFileByPath("/test/")
sut.file = test
sut.startSyncFolderOperation(test, false)
assertEquals(storageManager.getFileByPath("/test/"), sut.currentDir)
EspressoIdlingResource.decrement()
// navigate into it
val test = storageManager.getFileByPath("/test/")
sut.file = test
sut.startSyncFolderOperation(test, false)
Assert.assertEquals(storageManager.getFileByPath("/test/"), sut.currentDir)
// open drawer
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
// open drawer
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
// click "all files"
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_all_files))
// click "all files"
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_all_files))
// then should be in root again
shortSleep()
Assert.assertEquals(storageManager.getFileByPath("/"), sut.currentDir)
}
@Test
fun checkToolbarTitleOnNavigation() {
// Create folder structure
val topFolder = "folder1"
val childFolder = "folder2"
CreateFolderOperation("/$topFolder/", user, targetContext, storageManager)
.execute(client)
CreateFolderOperation("/$topFolder/$childFolder/", user, targetContext, storageManager)
.execute(client)
activityRule.launchActivity(null)
shortSleep()
// go into "foo"
onView(withText(topFolder)).perform(click())
shortSleep()
// check title is right
checkToolbarTitle(topFolder)
// go into "bar"
onView(withText(childFolder)).perform(click())
shortSleep()
// check title is right
checkToolbarTitle(childFolder)
// browse back up, we should be back in "foo"
Espresso.pressBack()
shortSleep()
// check title is right
checkToolbarTitle(topFolder)
// then should be in root again
assertEquals(storageManager.getFileByPath("/"), sut.currentDir)
}
}
}
}
private fun checkToolbarTitle(childFolder: String) {
@ -203,8 +161,10 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
)
}
@Suppress("DEPRECATION")
@Test
fun browseFavoriteAndBack() {
EspressoIdlingResource.increment()
// Create folder structure
val topFolder = "folder1"
@ -212,52 +172,68 @@ class FileDisplayActivityIT : AbstractOnServerIT() {
.execute(client)
ToggleFavoriteRemoteOperation(true, "/$topFolder/")
.execute(client)
EspressoIdlingResource.decrement()
val sut = activityRule.launchActivity(null)
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// navigate to favorites
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_favorites))
// navigate to favorites
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
onView(withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_favorites))
shortSleep()
// check sort button is not shown, favorites are not sortable
onView(
withId(R.id.sort_button)
).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
// check sort button is not shown, favorites are not sortable
onView(withId(R.id.sort_button)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
// browse into folder
onView(withId(R.id.list_root))
.perform(closeSoftKeyboard())
.perform(
RecyclerViewActions.actionOnItemAtPosition<OCFileListItemViewHolder>(
0,
click()
)
)
checkToolbarTitle(topFolder)
// sort button should now be visible
onView(withId(R.id.sort_button)).check(matches(ViewMatchers.isDisplayed()))
// browse into folder
onView(withId(R.id.list_root))
.perform(closeSoftKeyboard())
.perform(
RecyclerViewActions.actionOnItemAtPosition<OCFileListItemViewHolder>(
0,
click()
)
)
shortSleep()
checkToolbarTitle(topFolder)
// sort button should now be visible
onView(withId(R.id.sort_button)).check(matches(ViewMatchers.isDisplayed()))
// browse back, should be back to All Files
Espresso.pressBack()
checkToolbarTitle(sut.getString(R.string.app_name))
onView(withId(R.id.sort_button)).check(matches(ViewMatchers.isDisplayed()))
// browse back, should be back to All Files
Espresso.pressBack()
checkToolbarTitle(sut.getString(R.string.app_name))
onView(withId(R.id.sort_button)).check(matches(ViewMatchers.isDisplayed()))
}
}
}
}
@Suppress("DEPRECATION")
@Test
fun switchToGridView() {
activityRule.launchActivity(null)
Assert.assertTrue(
CreateFolderOperation("/test/", user, targetContext, storageManager)
.execute(client)
.isSuccess
)
onView(withId(R.id.switch_grid_view_button)).perform(click())
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
assertTrue(
CreateFolderOperation("/test/", user, targetContext, storageManager)
.execute(client)
.isSuccess
)
onView(withId(R.id.switch_grid_view_button)).perform(click())
}
}
}
}
@Test
fun openAccountSwitcher() {
activityRule.launchActivity(null)
onView(withId(R.id.switch_account_button)).perform(click())
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(withId(R.id.switch_account_button)).perform(click())
}
}
}
}
}

View file

@ -1,35 +1,50 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import android.Manifest
import androidx.test.espresso.Espresso
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.rule.GrantPermissionRule
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.fragment.EmptyListState
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
class FileDisplayActivityScreenshotIT : AbstractIT() {
@get:Rule
val activityRule = IntentsTestRule(
FileDisplayActivity::class.java,
true,
false
)
private val testClassName = "com.nextcloud.client.FileDisplayActivityScreenshotIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@get:Rule
val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(
@ -41,82 +56,110 @@ class FileDisplayActivityScreenshotIT : AbstractIT() {
}
@Test
@UiThread
@ScreenshotTest
fun open() {
try {
val sut = activityRule.launchActivity(null)
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
shortSleep()
sut.runOnUiThread {
sut.listOfFilesFragment!!.setFabEnabled(false)
sut.resetScrolling(true)
sut.listOfFilesFragment!!.setEmptyListLoadingMessage()
sut.listOfFilesFragment!!.isLoading = false
sut.run {
listOfFilesFragment?.let {
it.setFabEnabled(false)
resetScrolling(true)
it.setEmptyListMessage(EmptyListState.LOADING)
it.isLoading = false
}
}
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
shortSleep()
waitForIdleSync()
screenshot(sut)
} catch (e: SecurityException) {
Log_OC.e(TAG, "Error caught at open $e")
}
}
@Test
@UiThread
@ScreenshotTest
fun showMediaThenAllFiles() {
try {
val fileDisplayActivity = activityRule.launchActivity(null)
val sut = fileDisplayActivity.listOfFilesFragment
Assert.assertNotNull(sut)
sut!!.setFabEnabled(false)
sut.setEmptyListLoadingMessage()
sut.isLoading = false
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val fragment = sut.listOfFilesFragment
Assert.assertNotNull(fragment)
fragment!!.setFabEnabled(false)
fragment.setEmptyListMessage(EmptyListState.LOADING)
fragment.isLoading = false
EspressoIdlingResource.decrement()
// open drawer
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
// click "all files"
Espresso.onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_gallery))
onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_gallery))
// wait
shortSleep()
onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_all_files))
// click "all files"
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
Espresso.onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.nav_all_files))
EspressoIdlingResource.increment()
fragment.setFabEnabled(false)
fragment.setEmptyListMessage(EmptyListState.LOADING)
fragment.isLoading = false
EspressoIdlingResource.decrement()
// then compare screenshot
shortSleep()
sut.setFabEnabled(false)
sut.setEmptyListLoadingMessage()
sut.isLoading = false
shortSleep()
screenshot(fileDisplayActivity)
val screenShotName = createName(testClassName + "_" + "showMediaThenAllFiles", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
} catch (e: SecurityException) {
Log_OC.e(TAG, "Error caught at open $e")
}
}
@Test
@UiThread
@ScreenshotTest
fun drawer() {
try {
val sut = activityRule.launchActivity(null)
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(ViewMatchers.withId(R.id.drawer_layout)).perform(DrawerActions.open())
shortSleep()
sut.runOnUiThread {
sut.hideInfoBox()
sut.resetScrolling(true)
sut.listOfFilesFragment!!.setFabEnabled(false)
sut.listOfFilesFragment!!.setEmptyListLoadingMessage()
sut.listOfFilesFragment!!.isLoading = false
EspressoIdlingResource.increment()
sut.run {
hideInfoBox()
resetScrolling(true)
listOfFilesFragment?.let {
it.setFabEnabled(false)
it.setEmptyListMessage(EmptyListState.LOADING)
it.isLoading = false
}
}
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "drawer", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
shortSleep()
waitForIdleSync()
screenshot(sut)
} catch (e: SecurityException) {
Log_OC.e(TAG, "Error caught at open $e")
}

View file

@ -0,0 +1,53 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.client.onboarding.FirstRunActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class FirstRunActivityIT : AbstractIT() {
private val testClassName = "com.nextcloud.client.FirstRunActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun open() {
launchActivity<FirstRunActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -1,71 +1,109 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import android.app.Activity
import android.content.Intent
import android.os.Looper
import androidx.test.espresso.intent.rule.IntentsTestRule
import com.nextcloud.test.GrantStoragePermissionRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.GrantStoragePermissionRule.Companion.grant
import com.owncloud.android.AbstractIT
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
import com.owncloud.android.ui.activity.RequestCredentialsActivity
import com.owncloud.android.ui.activity.SettingsActivity
import com.owncloud.android.utils.EncryptionUtils
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
@Suppress("FunctionNaming")
class SettingsActivityIT : AbstractIT() {
@get:Rule
val activityRule = IntentsTestRule(
SettingsActivity::class.java,
true,
false
)
private val testClassName = "com.nextcloud.client.SettingsActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@get:Rule
val permissionRule = GrantStoragePermissionRule.grant()
var storagePermissionRule: TestRule = grant()
@Test
@UiThread
@ScreenshotTest
fun open() {
val sut: Activity = activityRule.launchActivity(null)
screenshot(sut)
launchActivity<SettingsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun showMnemonic_Error() {
val sut = activityRule.launchActivity(null)
sut.handleMnemonicRequest(null)
shortSleep()
waitForIdleSync()
screenshot(sut)
launchActivity<SettingsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
sut.handleMnemonicRequest(null)
val screenShotName = createName(testClassName + "_" + "showMnemonic_Error", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Suppress("DEPRECATION")
@Test
@UiThread
fun showMnemonic() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val intent = Intent()
intent.putExtra(RequestCredentialsActivity.KEY_CHECK_RESULT, RequestCredentialsActivity.KEY_CHECK_RESULT_TRUE)
val arbitraryDataProvider = ArbitraryDataProviderImpl(targetContext)
arbitraryDataProvider.storeOrUpdateKeyValue(user.accountName, EncryptionUtils.MNEMONIC, "Secret mnemonic")
val sut = activityRule.launchActivity(null)
sut.runOnUiThread {
sut.handleMnemonicRequest(intent)
val intent = Intent().apply {
putExtra(RequestCredentialsActivity.KEY_CHECK_RESULT, RequestCredentialsActivity.KEY_CHECK_RESULT_TRUE)
}
Looper.myLooper()?.quitSafely()
Assert.assertTrue(true) // if we reach this, everything is ok
ArbitraryDataProviderImpl(targetContext).run {
storeOrUpdateKeyValue(user.accountName, EncryptionUtils.MNEMONIC, "Secret mnemonic")
}
launchActivity<SettingsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
sut.handleMnemonicRequest(intent)
onView(isRoot()).check(matches(isDisplayed()))
Looper.myLooper()?.quitSafely()
Assert.assertTrue(true)
}
}
}
}
}

View file

@ -0,0 +1,132 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import android.content.Intent
import android.os.Looper
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.client.preferences.SubFolderRule
import com.owncloud.android.AbstractIT
import com.owncloud.android.datamodel.MediaFolderType
import com.owncloud.android.datamodel.SyncedFolder
import com.owncloud.android.datamodel.SyncedFolderDisplayItem
import com.owncloud.android.ui.activity.SyncedFoldersActivity
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment.Companion.newInstance
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class SyncedFoldersActivityIT : AbstractIT() {
private val testClassName = "com.nextcloud.client.SyncedFoldersActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun open() {
launchActivity<SyncedFoldersActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.adapter.clear()
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.binding.emptyList.emptyListView, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testSyncedFolderDialog() {
val item = SyncedFolderDisplayItem(
1,
"/sdcard/DCIM/",
"/InstantUpload/",
true,
false,
false,
true,
"test@https://nextcloud.localhost",
0,
0,
true,
1000,
"Name",
MediaFolderType.IMAGE,
false,
SubFolderRule.YEAR_MONTH,
false,
SyncedFolder.NOT_SCANNED_YET
)
val fragment = newInstance(item, 0)
val intent = Intent(targetContext, SyncedFoldersActivity::class.java)
launchActivity<SyncedFoldersActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
fragment?.show(sut.supportFragmentManager, "")
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "testSyncedFolderDialog", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshot(fragment?.requireDialog()?.window?.decorView, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun showPowerCheckDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val intent = Intent(targetContext, SyncedFoldersActivity::class.java)
launchActivity<SyncedFoldersActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val dialog = sut.buildPowerCheckDialog()
dialog.show()
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "showPowerCheckDialog", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshot(dialog.window?.decorView, screenShotName)
}
}
}
}
}

View file

@ -4,7 +4,7 @@
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client

View file

@ -0,0 +1,58 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withId
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.ui.activity.UploadListActivity
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class UploadListActivityActivityIT : AbstractIT() {
private val testClassName = "com.nextcloud.client.UploadListActivityActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun openDrawer() {
launchActivity<UploadListActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(isRoot()).check(matches(isDisplayed()))
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
val screenShotName = createName(testClassName + "_" + "openDrawer", "")
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.account

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.account

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.account;

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.account
@ -12,7 +12,7 @@ import android.net.Uri
import android.os.Parcel
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.lib.common.OwnCloudBasicCredentials
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import com.owncloud.android.lib.resources.status.NextcloudVersion
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotSame
@ -31,7 +31,7 @@ class RegisteredUserTest {
val ownCloudAccount = OwnCloudAccount(uri, credentials)
val server = Server(
uri = URI(uri.toString()),
version = OwnCloudVersion.nextcloud_17
version = NextcloudVersion.nextcloud_31
)
return RegisteredUser(
account = account,

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2019-2023 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.account;

View file

@ -1,14 +1,15 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.assistant
import com.nextcloud.client.assistant.repository.AssistantRepository
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
import com.owncloud.android.lib.resources.status.NextcloudVersion
import org.junit.Assert.assertTrue
import org.junit.Before
@ -21,7 +22,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
@Before
fun setup() {
sut = AssistantRepository(nextcloudClient)
sut = AssistantRepository(nextcloudClient, capability)
}
@Test
@ -33,10 +34,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
}
val result = sut?.getTaskTypes()
assertTrue(result?.isSuccess == true)
val taskTypes = result?.resultData?.types
assertTrue(taskTypes?.isNotEmpty() == true)
assertTrue(result?.isNotEmpty() == true)
}
@Test
@ -48,10 +46,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
}
val result = sut?.getTaskList("assistant")
assertTrue(result?.isSuccess == true)
val taskList = result?.resultData?.tasks
assertTrue(taskList?.isEmpty() == true || (taskList?.size ?: 0) > 0)
assertTrue(result?.isEmpty() == true || (result?.size ?: 0) > 0)
}
@Test
@ -63,8 +58,14 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
}
val input = "Give me some random output for test purpose"
val type = "OCP\\TextProcessing\\FreePromptTaskType"
val result = sut?.createTask(input, type)
val taskType = TaskTypeData(
"core:text2text",
"Free text to text prompt",
"Runs an arbitrary prompt through a language model that returns a reply",
emptyMap(),
emptyMap()
)
val result = sut?.createTask(input, taskType)
assertTrue(result?.isSuccess == true)
}
@ -80,13 +81,11 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
sleep(120)
val resultOfTaskList = sut?.getTaskList("assistant")
assertTrue(resultOfTaskList?.isSuccess == true)
val taskList = sut?.getTaskList("assistant")
assertTrue(taskList != null)
sleep(120)
val taskList = resultOfTaskList?.resultData?.tasks
assert((taskList?.size ?: 0) > 0)
val result = sut?.deleteTask(taskList!!.first().id)

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.database.migrations

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.documentscan

View file

@ -3,39 +3,68 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.etm
import android.app.Activity
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class EtmActivityTest : AbstractIT() {
@get:Rule
var activityRule = IntentsTestRule(EtmActivity::class.java, true, false)
private val testClassName = "com.nextcloud.client.etm.EtmActivityTest"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun overview() {
val sut: Activity = activityRule.launchActivity(null)
waitForIdleSync()
screenshot(sut)
launchActivity<EtmActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "overview", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun accounts() {
val sut: EtmActivity = activityRule.launchActivity(null)
launchActivity<EtmActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.vm.onPageSelected(1)
EspressoIdlingResource.decrement()
UiThreadStatement.runOnUiThread { sut.vm.onPageSelected(1) }
screenshot(sut)
val screenShotName = createName(testClassName + "_" + "accounts", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.files
@ -37,8 +37,8 @@ class DeepLinkHandlerTest {
class DeepLinkPattern {
companion object {
val FILE_ID = 1234
val SERVER_BASE_URLS = listOf(
private const val FILE_ID = 1234
private val SERVER_BASE_URLS = listOf(
"http://hostname.net",
"https://hostname.net",
"http://hostname.net/subdir1",
@ -48,7 +48,7 @@ class DeepLinkHandlerTest {
"http://hostname.net/subdir1/subdir2/subdir3",
"https://hostname.net/subdir1/subdir2/subdir3"
)
val INDEX_PHP_PATH = listOf(
private val INDEX_PHP_PATH = listOf(
"",
"/index.php"
)
@ -102,12 +102,12 @@ class DeepLinkHandlerTest {
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")
val DEEP_LINK: Uri = 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)
val server = Server(uri = uri, version = OwnCloudVersion.nextcloud_20)
whenever(user.server).thenReturn(server)
return user
}
@ -115,8 +115,8 @@ class DeepLinkHandlerTest {
@Mock
lateinit var userAccountManager: UserAccountManager
lateinit var allUsers: List<User>
lateinit var handler: DeepLinkHandler
private lateinit var allUsers: List<User>
private lateinit var handler: DeepLinkHandler
@Before
fun setUp() {

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.files.download

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.files.download

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.files.download

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.files.download

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.integrations.deck
@ -65,9 +65,7 @@ class DeckApiTest {
companion object {
@Parameterized.Parameters
@JvmStatic
fun initParametrs(): Array<String> {
return DeckApiImpl.DECK_APP_PACKAGES
}
fun initParametrs(): Array<String> = DeckApiImpl.DECK_APP_PACKAGES
}
@Before

View file

@ -2,10 +2,11 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.jobs
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
@ -19,13 +20,19 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.nextcloud.client.account.User
import com.nextcloud.client.core.Clock
import com.nextcloud.utils.extensions.toByteArray
import com.owncloud.android.lib.common.utils.Log_OC
import org.apache.commons.io.FileUtils
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.Suite
import org.mockito.ArgumentMatcher
@ -37,6 +44,8 @@ import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.io.File
import java.io.IOException
import java.util.Date
import java.util.UUID
import java.util.concurrent.CountDownLatch
@ -82,9 +91,11 @@ class BackgroundJobManagerTest {
internal lateinit var workManager: WorkManager
internal lateinit var clock: Clock
internal lateinit var backgroundJobManager: BackgroundJobManagerImpl
internal lateinit var context: Context
@Before
fun setUpFixture() {
context = mock()
user = mock()
whenever(user.accountName).thenReturn(USER_ACCOUNT_NAME)
workManager = mock()
@ -302,16 +313,36 @@ class BackgroundJobManagerTest {
private lateinit var jobInfo: LiveData<JobInfo?>
private lateinit var request: OneTimeWorkRequest
@get:Rule
var folder: TemporaryFolder = TemporaryFolder()
@Before
fun setUp() {
var selectedContactsFile: File? = null
try {
selectedContactsFile = folder.newFile("hashset_cache.txt")
} catch (_: IOException) {
Log_OC.e("ImmediateContactsImport", "error creating temporary test file in ")
fail("hashset_cache cannot be found")
}
if (selectedContactsFile == null) {
fail("hashset_cache cannot be found")
}
val requestCaptor: KArgumentCaptor<OneTimeWorkRequest> = argumentCaptor()
workInfo = MutableLiveData()
whenever(workManager.getWorkInfoByIdLiveData(any())).thenReturn(workInfo)
val selectedContacts = intArrayOf(1, 2, 3)
val contractsAsByteArray = selectedContacts.toByteArray()
FileUtils.writeByteArrayToFile(selectedContactsFile, contractsAsByteArray)
jobInfo = backgroundJobManager.startImmediateContactsImport(
contactsAccountName = "name",
contactsAccountType = "type",
vCardFilePath = "/path/to/vcard/file",
selectedContacts = intArrayOf(1, 2, 3)
selectedContactsFilePath = selectedContactsFile!!.absolutePath
)
verify(workManager).enqueueUniqueWork(
any(),

View file

@ -1,8 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.client.jobs
@ -11,73 +10,120 @@ import android.Manifest
import androidx.test.rule.GrantPermissionRule
import androidx.work.WorkManager
import com.nextcloud.client.core.ClockImpl
import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.client.preferences.AppPreferencesImpl
import com.nextcloud.test.RetryTestRule
import com.owncloud.android.AbstractIT
import com.nextcloud.utils.extensions.toByteArray
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.operations.DownloadFileOperation
import ezvcard.Ezvcard
import ezvcard.VCard
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.apache.commons.io.FileUtils
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
class ContactsBackupIT : AbstractOnServerIT() {
val workmanager = WorkManager.getInstance(targetContext)
val preferences = AppPreferencesImpl.fromContext(targetContext)
private val backgroundJobManager = BackgroundJobManagerImpl(workmanager, ClockImpl(), preferences)
private val workManager = WorkManager.getInstance(targetContext)
private val preferences: AppPreferences = AppPreferencesImpl.fromContext(targetContext)
private val backgroundJobManager = BackgroundJobManagerImpl(workManager, ClockImpl(), preferences)
@get:Rule
val writeContactsRule = GrantPermissionRule.grant(Manifest.permission.WRITE_CONTACTS)
val writeContactsRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_CONTACTS)
@get:Rule
val readContactsRule = GrantPermissionRule.grant(Manifest.permission.READ_CONTACTS)
val readContactsRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_CONTACTS)
@get:Rule
val retryTestRule = RetryTestRule() // flaky test
@get:Rule
var folder: TemporaryFolder = TemporaryFolder()
private val vcard: String = "vcard.vcf"
private var selectedContactsFile: File? = null
@Before
fun setup() {
try {
selectedContactsFile = folder.newFile("hashset_cache.txt")
} catch (_: IOException) {
Log_OC.e("ContactsBackupIT", "error creating temporary test file in ")
}
}
@Test
fun importExport() {
val intArray = IntArray(1)
intArray[0] = 0
val intArray = intArrayOf(0)
if (selectedContactsFile == null) {
fail("hashset_cache cannot be found")
}
val contractsAsByteArray = intArray.toByteArray()
FileUtils.writeByteArrayToFile(selectedContactsFile, contractsAsByteArray)
// import file to local contacts
backgroundJobManager.startImmediateContactsImport(null, null, getFile(vcard).absolutePath, intArray)
shortSleep()
backgroundJobManager.startImmediateContactsImport(
null,
null,
getFile(vcard).absolutePath,
selectedContactsFile!!.absolutePath
)
longSleep()
// export contact
backgroundJobManager.startImmediateContactsBackup(user)
longSleep()
val backupFolder: String = targetContext.resources.getString(R.string.contacts_backup_folder) +
val folderPath: String = targetContext.resources.getString(R.string.contacts_backup_folder) +
OCFile.PATH_SEPARATOR
refreshFolder("/")
longSleep()
refreshFolder(backupFolder)
longSleep()
val backupOCFile = storageManager.getFolderContent(
storageManager.getFileByDecryptedRemotePath(backupFolder),
false
)[0]
refreshFolder(folderPath)
longSleep()
longSleep()
assertTrue(DownloadFileOperation(user, backupOCFile, AbstractIT.targetContext).execute(client).isSuccess)
if (folderPath.isEmpty()) {
fail("folderPath cannot be empty")
}
val folder = fileDataStorageManager.getFileByDecryptedRemotePath(folderPath)
if (folder == null) {
fail("folder cannot be null")
}
val ocFile = storageManager.getFolderContent(folder, false).firstOrNull()
if (ocFile == null) {
fail("ocFile cannot be null")
}
if (ocFile?.storagePath == null) {
fail("ocFile.storagePath cannot be null")
}
assertTrue(DownloadFileOperation(user, ocFile, targetContext).execute(client).isSuccess)
val file = ocFile?.storagePath?.let { File(it) }
if (file == null) {
fail("file cannot be null")
}
val backupFile = File(backupOCFile.storagePath)
val vcardInputStream = BufferedInputStream(FileInputStream(getFile(vcard)))
val backupFileInputStream = BufferedInputStream(FileInputStream(backupFile))
val backupFileInputStream = BufferedInputStream(FileInputStream(file))
// verify same
val originalCards: ArrayList<VCard> = ArrayList()
@ -87,6 +133,17 @@ class ContactsBackupIT : AbstractOnServerIT() {
backupCards.addAll(Ezvcard.parse(backupFileInputStream).all())
assertEquals(originalCards.size, backupCards.size)
assertEquals(originalCards[0].formattedName.toString(), backupCards[0].formattedName.toString())
val originalCardFormattedName = originalCards.firstOrNull()?.formattedName
if (originalCardFormattedName == null) {
fail("originalCardFormattedName cannot be null")
}
val backupCardFormattedName = backupCards.firstOrNull()?.formattedName
if (backupCardFormattedName == null) {
fail("backupCardFormattedName cannot be null")
}
assertEquals(originalCardFormattedName.toString(), backupCardFormattedName.toString())
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.migrations

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.migrations

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.migrations
@ -69,25 +69,16 @@ class MockSharedPreferences : SharedPreferences {
override fun getInt(key: String?, defValue: Int): Int = store.getOrDefault(key, defValue) as Int
override fun getAll(): MutableMap<String?, Any?> {
return HashMap(store)
}
override fun getAll(): MutableMap<String?, Any?> = HashMap(store)
override fun edit(): SharedPreferences.Editor {
return MockEditor(store)
}
override fun edit(): SharedPreferences.Editor = MockEditor(store)
override fun getLong(key: String?, defValue: Long): Long {
throw UnsupportedOperationException()
}
override fun getLong(key: String?, defValue: Long): Long = throw UnsupportedOperationException()
override fun getFloat(key: String?, defValue: Float): Float {
throw UnsupportedOperationException()
}
override fun getFloat(key: String?, defValue: Float): Float = throw UnsupportedOperationException()
override fun getStringSet(key: String?, defValues: MutableSet<String>?): MutableSet<String>? {
return store.getOrDefault(key, defValues) as MutableSet<String>?
}
override fun getStringSet(key: String?, defValues: MutableSet<String>?): MutableSet<String>? =
store.getOrDefault(key, defValues) as MutableSet<String>?
override fun registerOnSharedPreferenceChangeListener(
listener: SharedPreferences.OnSharedPreferenceChangeListener?

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.migrations

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.client.network

View file

@ -1,9 +1,9 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.extensions

View file

@ -1,9 +1,9 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.extensions

View file

@ -0,0 +1,176 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.extensions
import com.nextcloud.utils.extensions.isNotBlankAndEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import org.junit.Test
@Suppress("TooManyFunctions")
class StringExtensionTests {
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreNull() {
val str1: String? = null
val str2: String? = null
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenFirstStringIsNull() {
val str1: String? = null
val str2 = "hello"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenSecondStringIsNull() {
val str1 = "hello"
val str2: String? = null
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreEmpty() {
val str1 = ""
val str2 = ""
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenFirstStringIsEmpty() {
val str1 = ""
val str2 = "hello"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenSecondStringIsEmpty() {
val str1 = "hello"
val str2 = ""
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreWhitespaceOnly() {
val str1 = " "
val str2 = " \t "
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenFirstStringIsWhitespaceOnly() {
val str1 = " "
val str2 = "hello"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenSecondStringIsWhitespaceOnly() {
val str1 = "hello"
val str2 = " "
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenStringsAreDifferentButBothValid() {
val str1 = "hello"
val str2 = "world"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenStringsHaveDifferentCase() {
val str1 = "Hello"
val str2 = "hello"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenMixedCaseStrings() {
val str1 = "HeLLo WoRLd"
val str2 = "hello world"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenUppercaseStrings() {
val str1 = "HELLO"
val str2 = "hello"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalAndValid() {
val str1 = "hello"
val str2 = "hello"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpaces() {
val str1 = "hello world"
val str2 = "hello world"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalSingleCharacter() {
val str1 = "a"
val str2 = "A"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpecialCharacters() {
val str1 = "hello@world!123"
val str2 = "HELLO@WORLD!123"
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenOneHasLeadingWhitespaceAndOtherDoesNot() {
val str1 = " hello"
val str2 = "HELLO"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenOneHasTrailingWhitespaceAndOtherDoesNot() {
val str1 = "hello"
val str2 = "HELLO "
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenBothHaveIdenticalWhitespacePaddingDifferentCase() {
val str1 = " hello "
val str2 = " HELLO "
assertTrue(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenMixedWhitespaceCharacters() {
val str1 = "\t"
val str2 = "\n"
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsEmpty() {
val str1: String? = null
val str2 = ""
assertFalse(str1.isNotBlankAndEquals(str2))
}
@Test
fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsWhitespace() {
val str1: String? = null
val str2 = " "
assertFalse(str1.isNotBlankAndEquals(str2))
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2021 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.sso

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2021 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test
@ -13,9 +13,7 @@ object RandomStringGenerator {
@JvmOverloads
@JvmStatic
fun make(length: Int = DEFAULT_LENGTH): String {
return (1..length)
.map { ALLOWED_CHARACTERS.random() }
.joinToString("")
}
fun make(length: Int = DEFAULT_LENGTH): String = (1..length)
.map { ALLOWED_CHARACTERS.random() }
.joinToString("")
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test
@ -25,9 +25,7 @@ class RetryTestRule(val retryCount: Int = defaultRetryValue) : TestRule {
private val defaultRetryValue: Int = if (BuildConfig.CI) 5 else 1
}
override fun apply(base: Statement, description: Description): Statement {
return statement(base, description)
}
override fun apply(base: Statement, description: Description): Statement = statement(base, description)
@Suppress("TooGenericExceptionCaught") // and this exactly what we want here
private fun statement(base: Statement, description: Description): Statement {

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test

View file

@ -1,9 +1,9 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.test.model
@ -24,17 +24,11 @@ data class TestDataParcelable(val message: String) : Parcelable {
parcel.writeString(message)
}
override fun describeContents(): Int {
return 0
}
override fun describeContents(): Int = 0
companion object CREATOR : Parcelable.Creator<TestDataParcelable> {
override fun createFromParcel(parcel: Parcel): TestDataParcelable {
return TestDataParcelable(parcel)
}
override fun createFromParcel(parcel: Parcel): TestDataParcelable = TestDataParcelable(parcel)
override fun newArray(size: Int): Array<TestDataParcelable?> {
return arrayOfNulls(size)
}
override fun newArray(size: Int): Array<TestDataParcelable?> = arrayOfNulls(size)
}
}

View file

@ -1,124 +1,80 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2022 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.ui
import android.graphics.BitmapFactory
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.utils.BitmapUtils
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class BitmapIT : AbstractIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
private val testClassName = "com.nextcloud.ui.BitmapIT"
@Test
@ScreenshotTest
fun roundBitmap() {
val file = getFile("christine.jpg")
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
val activity = testActivityRule.launchActivity(null)
val imageView = ImageView(activity).apply {
setImageBitmap(bitmap)
}
val bitmap2 = BitmapFactory.decodeFile(file.absolutePath)
val imageView2 = ImageView(activity).apply {
setImageBitmap(BitmapUtils.roundBitmap(bitmap2))
}
val linearLayout = LinearLayout(activity).apply {
orientation = LinearLayout.VERTICAL
setBackgroundColor(context.getColor(R.color.grey_200))
}
linearLayout.addView(imageView, 200, 200)
linearLayout.addView(imageView2, 200, 200)
activity.addView(linearLayout)
screenshot(activity)
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
// @Test
// @ScreenshotTest
// fun glideSVG() {
// val activity = testActivityRule.launchActivity(null)
// val accountProvider = UserAccountManagerImpl.fromContext(activity)
// val clientFactory = ClientFactoryImpl(activity)
//
// val linearLayout = LinearLayout(activity).apply {
// orientation = LinearLayout.VERTICAL
// setBackgroundColor(context.getColor(R.color.grey_200))
// }
//
// val file = getFile("christine.jpg")
// val bitmap = BitmapFactory.decodeFile(file.absolutePath)
//
// ImageView(activity).apply {
// setImageBitmap(bitmap)
// linearLayout.addView(this, 50, 50)
// }
//
// downloadIcon(
// client.baseUri.toString() + "/apps/files/img/app.svg",
// activity,
// linearLayout,
// accountProvider,
// clientFactory
// )
//
// downloadIcon(
// client.baseUri.toString() + "/core/img/actions/group.svg",
// activity,
// linearLayout,
// accountProvider,
// clientFactory
// )
//
// activity.addView(linearLayout)
//
// longSleep()
//
// screenshot(activity)
// }
//
// private fun downloadIcon(
// url: String,
// activity: TestActivity,
// linearLayout: LinearLayout,
// accountProvider: UserAccountManager,
// clientFactory: ClientFactory
// ) {
// val view = ImageView(activity).apply {
// linearLayout.addView(this, 50, 50)
// }
// val target = object : SimpleTarget<Drawable>() {
// override fun onResourceReady(resource: Drawable?, glideAnimation: GlideAnimation<in Drawable>?) {
// view.setColorFilter(targetContext.getColor(R.color.dark), PorterDuff.Mode.SRC_ATOP)
// view.setImageDrawable(resource)
// }
// }
//
// testActivityRule.runOnUiThread {
// DisplayUtils.downloadIcon(
// accountProvider,
// clientFactory,
// activity,
// url,
// target,
// R.drawable.ic_user
// )
// }
// }
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun roundBitmap() {
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val file = getFile("christine.jpg")
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
val imageView = ImageView(activity).apply {
setImageBitmap(bitmap)
}
val bitmap2 = BitmapFactory.decodeFile(file.absolutePath)
val imageView2 = ImageView(activity).apply {
setImageBitmap(BitmapUtils.roundBitmap(bitmap2))
}
val linearLayout = LinearLayout(activity).apply {
orientation = LinearLayout.VERTICAL
setBackgroundColor(context.getColor(R.color.grey_200))
}
linearLayout.addView(imageView, 200, 200)
linearLayout.addView(imageView2, 200, 200)
activity.addView(linearLayout)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "roundBitmap", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(activity, screenShotName)
}
}
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.ui
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.resources.users.Status
import com.owncloud.android.lib.resources.users.StatusType
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.utils.EspressoIdlingResource
import org.junit.After
import org.junit.Before
import org.junit.Test
class SetOnlineStatusBottomSheetIT : AbstractIT() {
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
fun open() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SetOnlineStatusBottomSheet(
Status(StatusType.DND, "Working hard…", "🤖", -1)
)
sut.show(activity.supportFragmentManager, "")
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
}
}
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.ui
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.resources.users.ClearAt
import com.owncloud.android.lib.resources.users.PredefinedStatus
import com.owncloud.android.lib.resources.users.Status
import com.owncloud.android.lib.resources.users.StatusType
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.utils.EspressoIdlingResource
import org.junit.After
import org.junit.Before
import org.junit.Test
class SetStatusMessageBottomSheetIT : AbstractIT() {
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
fun open() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SetStatusMessageBottomSheet(
user,
Status(StatusType.DND, "Working hard…", "🤖", -1)
)
sut.show(activity.supportFragmentManager, "")
val predefinedStatus: ArrayList<PredefinedStatus> = arrayListOf(
PredefinedStatus("meeting", "📅", "In a meeting", ClearAt("period", "3600")),
PredefinedStatus("commuting", "🚌", "Commuting", ClearAt("period", "1800")),
PredefinedStatus("be-right-back", "", "Be right back", ClearAt("period", "900")),
PredefinedStatus("remote-work", "🏡", "Working remotely", ClearAt("end-of", "day")),
PredefinedStatus("sick-leave", "🤒", "Out sick", ClearAt("end-of", "day")),
PredefinedStatus("vacationing", "🌴", "Vacationing", null)
)
sut.setPredefinedStatus(predefinedStatus)
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
}
}
}
}
}

View file

@ -0,0 +1,241 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.utils
import com.nextcloud.utils.autoRename.AutoRename
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedFile
import com.owncloud.android.lib.resources.status.NextcloudVersion
import com.owncloud.android.lib.resources.status.OCCapability
import org.junit.Before
import org.junit.Test
@Suppress("TooManyFunctions")
class AutoRenameTests : AbstractOnServerIT() {
private var capability: OCCapability = fileDataStorageManager.getCapability(account.name)
private val forbiddenFilenameExtension = "."
private val forbiddenFilenameCharacter = ">"
@Before
fun setup() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
capability = capability.apply {
forbiddenFilenameExtensionJson = listOf(
"""[" ",".",".part",".part"]""",
"""[".",".part",".part"," "]""",
"""[".",".part"," ", ".part"]""",
"""[".part"," ", ".part","."]""",
"""[" ",".",".PART",".PART"]""",
"""[".",".PART",".PART"," "]""",
"""[".",".PART"," ", ".PART"]""",
"""[".PART"," ", ".PART","."]"""
).random()
forbiddenFilenameCharactersJson = """["<", ">", ":", "\\\\", "/", "|", "?", "*", "&"]"""
}
}
@Test
fun testInvalidChar() {
val filename = "file${forbiddenFilenameCharacter}file.txt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "file_file.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testInvalidExtension() {
val filename = "file$forbiddenFilenameExtension"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "file_"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testMultipleInvalidChars() {
val filename = "file|name?<>.txt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "file_name___.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testStartEndInvalidExtensions() {
val filename = " .file.part "
val result = AutoRename.rename(filename, capability)
val expectedFilename = "_file_part"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testStartInvalidExtension() {
val filename = " .file.part"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "_file_part"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testEndInvalidExtension() {
val filename = ".file.part "
val result = AutoRename.rename(filename, capability)
val expectedFilename = "_file_part"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testMiddleNonPrintableChar() {
val filename = "file\u0001name.txt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "filename.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testStartNonPrintableChar() {
val filename = "\u0001filename.txt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "filename.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testEndNonPrintableChar() {
val filename = "filename.txt\u0001"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "filename.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testExtensionNonPrintableChar() {
val filename = "filename.t\u0001xt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "filename.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testMiddleInvalidFolderChar() {
val folderPath = "abc/def/kg$forbiddenFilenameCharacter/lmo/pp/"
val result = AutoRename.rename(folderPath, capability)
val expectedFolderName = "abc/def/kg_/lmo/pp/"
assert(result == expectedFolderName) { "Expected $expectedFolderName but got $result" }
}
@Test
fun testEndInvalidFolderChar() {
val folderPath = "abc/def/kg/lmo/pp$forbiddenFilenameCharacter/"
val result = AutoRename.rename(folderPath, capability)
val expectedFolderName = "abc/def/kg/lmo/pp_/"
assert(result == expectedFolderName) { "Expected $expectedFolderName but got $result" }
}
@Test
fun testStartInvalidFolderChar() {
val folderPath = "${forbiddenFilenameCharacter}abc/def/kg/lmo/pp/"
val result = AutoRename.rename(folderPath, capability)
val expectedFolderName = "_abc/def/kg/lmo/pp/"
assert(result == expectedFolderName) { "Expected $expectedFolderName but got $result" }
}
@Test
fun testMixedInvalidChar() {
val filename = " file\u0001na${forbiddenFilenameCharacter}me.txt "
val result = AutoRename.rename(filename, capability)
val expectedFilename = "filena_me.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testStartsWithPathSeparator() {
val folderPath = "/abc/def/kg/lmo/pp$forbiddenFilenameCharacter/file.txt/"
val result = AutoRename.rename(folderPath, capability)
val expectedFolderName = "/abc/def/kg/lmo/pp_/file.txt/"
assert(result == expectedFolderName) { "Expected $expectedFolderName but got $result" }
}
@Test
fun testStartsWithPathSeparatorAndValidFilepath() {
val folderPath = "/COm02/2569.webp/"
val result = AutoRename.rename(folderPath, capability)
val expectedFolderName = "/COm02/2569.webp/"
assert(result == expectedFolderName) { "Expected $expectedFolderName but got $result" }
}
@Test
fun testValidFilename() {
val filename = ".file.TXT"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "_file.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testRenameExtensionForFolder() {
val filename = "/Pictures/@User/SubDir/08.16.07 Ka Yel/"
val result = AutoRename.rename(filename, capability)
assert(result == filename) { "Expected $filename but got $result" }
}
@Test
fun testRenameExtensionForFile() {
val filename = "/Pictures/@User/SubDir/08.16.07 Ka Yel.TXT"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "/Pictures/@User/SubDir/08.16.07 Ka Yel.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testE2EEFile() {
val decryptedFile = DecryptedFile(
authenticationTag = "HQlWBdm+gYC5kZwWnqXR1Q==",
filename = "a:a.jpg",
nonce = "sigyys8SfPZSScDJ860vYw==",
mimetype = "image/jpeg",
key = "sigyys8SfPZSScDJ860vYw=="
)
val result = AutoRename.rename(decryptedFile.filename, capability)
val expectedFilename = "a_a.jpg"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testRemovingLeadingWhitespace() {
val filename = " readme.txt"
val result = AutoRename.rename(filename, capability)
val expectedFilename = "readme.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testRemovingTrailingWhitespace() {
val filename = "readme.txt "
val result = AutoRename.rename(filename, capability)
val expectedFilename = "readme.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testRemovingTrailingAndLeadingWhitespace() {
val filename = " readme.txt "
val result = AutoRename.rename(filename, capability)
val expectedFilename = "readme.txt"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
@Test
fun testFolderNameLowercase() {
val filename = "Foo.Bar.Baz"
val result = AutoRename.rename(filename, capability, isFolderPath = true)
val expectedFilename = "Foo.Bar.Baz"
assert(result == expectedFilename) { "Expected $expectedFilename but got $result" }
}
}

View file

@ -0,0 +1,45 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.utils
import androidx.test.platform.app.InstrumentationRegistry
import com.google.gson.Gson
import com.owncloud.android.datamodel.Credentials
import com.owncloud.android.ui.dialog.setupEncryption.CertificateValidator
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.io.InputStreamReader
class CertificateValidatorTests {
private var sut: CertificateValidator? = null
@Before
fun setup() {
sut = CertificateValidator()
}
@After
fun destroy() {
sut = null
}
@Test
fun testValidateWhenGivenValidServerKeyAndCertificateShouldReturnTrue() {
val inputStream =
InstrumentationRegistry.getInstrumentation().context.assets.open("credentials.json")
val credentials = InputStreamReader(inputStream).use { reader ->
Gson().fromJson(reader, Credentials::class.java)
}
val isCertificateValid = sut?.validate(credentials.publicKey, credentials.certificate) ?: false
assert(isCertificateValid)
}
}

View file

@ -0,0 +1,231 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.utils
import com.nextcloud.utils.fileNameValidator.FileNameValidator
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.R
import com.owncloud.android.lib.resources.status.NextcloudVersion
import com.owncloud.android.lib.resources.status.OCCapability
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@Suppress("TooManyFunctions")
class FileNameValidatorTests : AbstractOnServerIT() {
private var capability: OCCapability = fileDataStorageManager.getCapability(account.name)
@Before
fun setup() {
capability = capability.apply {
forbiddenFilenamesJson = """[".htaccess",".htaccess"]"""
forbiddenFilenameBaseNamesJson = """
["con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4",
"com5", "com6", "com7", "com8", "com9", "com¹", "com²", "com³",
"lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7",
"lpt8", "lpt9", "lpt¹", "lpt²", "lpt³"]
"""
forbiddenFilenameExtensionJson = """[" ",".",".part",".part"]"""
forbiddenFilenameCharactersJson = """["<", ">", ":", "\\\\", "/", "|", "?", "*", "&"]"""
}
}
@Test
fun testInvalidCharacter() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val result = FileNameValidator.checkFileName("file<name", capability, targetContext)
assertEquals(
String.format(targetContext.getString(R.string.file_name_validator_error_invalid_character), "<"),
result
)
}
@Test
fun testReservedName() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val result = FileNameValidator.checkFileName("CON", capability, targetContext)
assertEquals(targetContext.getString(R.string.file_name_validator_error_reserved_names, "con"), result)
}
@Test
fun testForbiddenFilenameExtension() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val result = FileNameValidator.checkFileName("my_fav_file.part", capability, targetContext)
assertEquals(
targetContext.getString(R.string.file_name_validator_error_forbidden_file_extensions, ".part"),
result
)
}
@Test
fun testEndsWithSpaceOrPeriod() {
val firstFilename = "test "
val secondFilename = "test."
val result = FileNameValidator.checkFileName(firstFilename, capability, targetContext)
val result2 = FileNameValidator.checkFileName(secondFilename, capability, targetContext)
if (capability.version.isOlderThan(NextcloudVersion.nextcloud_30)) {
assertEquals(null, result)
assertEquals(null, result2)
} else {
assertEquals(
targetContext.getString(R.string.file_name_validator_error_forbidden_space_character_extensions),
result
)
assertEquals(
targetContext.getString(R.string.file_name_validator_error_forbidden_file_extensions, "."),
result2
)
}
}
@Test
fun testEmptyFileName() {
val result = FileNameValidator.checkFileName("", capability, targetContext)
assertEquals(targetContext.getString(R.string.filename_empty), result)
}
@Test
fun testBlankFileName() {
val result = FileNameValidator.checkFileName(" ", capability, targetContext)
assertEquals(targetContext.getString(R.string.filename_empty), result)
}
@Test
fun testFileAlreadyExists() {
val existingFiles = setOf("existingFile")
val result = FileNameValidator.checkFileName("existingFile", capability, targetContext, existingFiles)
assertEquals(targetContext.getString(R.string.file_already_exists), result)
}
@Test
fun testValidFileName() {
val result = FileNameValidator.checkFileName("validFileName", capability, targetContext)
assertNull(result)
}
@Test
fun testIsFileHidden() {
assertTrue(FileNameValidator.isFileHidden(".hiddenFile"))
assertFalse(FileNameValidator.isFileHidden("visibleFile"))
}
@Test
fun testIsFileNameAlreadyExist() {
val existingFiles = setOf("existingFile")
assertTrue(FileNameValidator.isFileNameAlreadyExist("existingFile", existingFiles))
assertFalse(FileNameValidator.isFileNameAlreadyExist("newFile", existingFiles))
}
@Test
fun testValidFolderAndFilePaths() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertTrue(result)
}
@Test
fun testFolderPathWithReservedName() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "CON"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathWithReservedName() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "PRN.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFolderPathWithInvalidCharacter() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "invalid<Folder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathWithInvalidCharacter() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file|2.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFolderPathEndingWithSpace() {
val folderPath = "folderWithSpace "
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertEquals(capability.version.isOlderThan(NextcloudVersion.nextcloud_30), result)
}
@Test
fun testFilePathEndingWithPeriod() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertEquals(capability.version.isOlderThan(NextcloudVersion.nextcloud_30), result)
}
@Test
fun testFilePathWithNestedFolder() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "validFolder\\secondValidFolder\\CON"
val filePaths = listOf("file1.txt", "file2.doc", "file3.")
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testOnlyFolderPath() {
val folderPath = "/A1/Aaaww/W/C2/"
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, listOf(), capability, targetContext)
assertTrue(result)
}
@Test
fun testOnlyFolderPathWithOneReservedName() {
testOnlyOnServer(NextcloudVersion.nextcloud_30)
val folderPath = "/A1/Aaaww/CON/W/C2/"
val result = FileNameValidator.checkFolderAndFilePaths(folderPath, listOf(), capability, targetContext)
assertFalse(result)
}
}

View file

@ -0,0 +1,272 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.utils
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType
import com.owncloud.android.lib.resources.shares.OCShare
import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.lib.resources.shares.extensions.isAllowDownloadAndSyncEnabled
import com.owncloud.android.lib.resources.shares.extensions.toggleAllowDownloadAndSync
import com.owncloud.android.ui.fragment.util.SharePermissionManager
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import org.junit.Test
@Suppress("TooManyFunctions")
class SharePermissionManagerTest {
private fun createShare(sharePermission: Int, isFolder: Boolean = false, attributesJson: String? = null): OCShare =
if (isFolder) {
OCShare("/test")
.apply {
permissions = sharePermission
attributes = attributesJson
shareType = ShareType.INTERNAL
sharedDate = 1188206955
shareWith = "User 1"
sharedWithDisplayName = "User 1"
}
} else {
OCShare("/test.png")
.apply {
permissions = sharePermission
attributes = attributesJson
shareType = ShareType.INTERNAL
sharedDate = 1188206955
shareWith = "User 1"
sharedWithDisplayName = "User 1"
}
}.apply {
this.isFolder = isFolder
}
// region Permission change tests
@Test
fun testTogglePermissionShouldAddPermissionFlagWhenChecked() {
val initialPermission = OCShare.READ_PERMISSION_FLAG
val updatedPermission =
SharePermissionManager.togglePermission(true, initialPermission, OCShare.UPDATE_PERMISSION_FLAG)
val updatedShare = createShare(updatedPermission)
assertTrue(SharePermissionManager.isCustomPermission(updatedShare))
}
@Test
fun testTogglePermissionShouldRemovePermissionFlagWhenUnchecked() {
val initialPermission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
val updatedPermission =
SharePermissionManager.togglePermission(false, initialPermission, OCShare.UPDATE_PERMISSION_FLAG)
val updatedShare = createShare(updatedPermission)
assertTrue(SharePermissionManager.isViewOnly(updatedShare))
}
// endregion
// region HasPermissions tests
@Test
fun testHasPermissionShouldReturnTrueIfPermissionPresent() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
assertTrue(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG))
}
@Test
fun testHasPermissionShouldReturnFalseIfPermissionNotPresent() {
val permission = OCShare.READ_PERMISSION_FLAG
assertFalse(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG))
}
// endregion
// region Helper Method Tests
@Test
fun testCanEditShouldReturnTrueIfAllPermissionsPresent() {
val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, isFolder = true)
assertTrue(SharePermissionManager.canEdit(share))
}
@Test
fun testCanEditShouldReturnFalseIfPermissionsAreInsufficient() {
val share = createShare(OCShare.READ_PERMISSION_FLAG)
assertFalse(SharePermissionManager.canEdit(share))
}
@Test
fun testIsViewOnlyShouldReturnTrueIfOnlyReadPermissionSet() {
val share = createShare(OCShare.READ_PERMISSION_FLAG)
assertTrue(SharePermissionManager.isViewOnly(share))
}
@Test
fun testIsFileRequestShouldReturnTrueIfOnlyCreatePermissionSetOnFolder() {
val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true)
assertTrue(SharePermissionManager.isFileRequest(share))
}
@Test
fun testIsFileRequestShouldReturnFalseIfOnlyCreatePermissionSetOnFile() {
val share = createShare(OCShare.CREATE_PERMISSION_FLAG)
assertFalse(SharePermissionManager.isFileRequest(share))
}
@Test
fun testIsSecureFileDropShouldReturnTrueIfReadAndCreatePermissionsPresent() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
val share = createShare(permission)
assertTrue(SharePermissionManager.isSecureFileDrop(share))
}
@Test
fun testCanReshareShouldReturnTrueIfSharePermissionIsPresent() {
val share = createShare(OCShare.SHARE_PERMISSION_FLAG)
assertTrue(SharePermissionManager.canReshare(share))
}
@Test
fun testGetMaximumPermissionForFolder() {
assertEquals(
OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER,
SharePermissionManager.getMaximumPermission(isFolder = true)
)
}
@Test
fun testGetMaximumPermissionForFile() {
assertEquals(
OCShare.MAXIMUM_PERMISSIONS_FOR_FILE,
SharePermissionManager.getMaximumPermission(isFolder = false)
)
}
// endregion
// region GetSelectedTypeTests
@Test
fun testGetSelectedTypeShouldReturnCanEditWhenFullPermissionsGiven() {
val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FILE)
assertEquals(QuickPermissionType.CAN_EDIT, SharePermissionManager.getSelectedType(share, encrypted = false))
}
@Test
fun testGetSelectedTypeShouldReturnSecureFileDropWhenEncryptedAndReadCreateGiven() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
val share = createShare(permission)
assertEquals(
QuickPermissionType.SECURE_FILE_DROP,
SharePermissionManager.getSelectedType(share, encrypted = true)
)
}
@Test
fun testGetSelectedTypeShouldReturnFileRequestWhenCreatePermissionGiven() {
val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true)
assertEquals(QuickPermissionType.FILE_REQUEST, SharePermissionManager.getSelectedType(share, encrypted = false))
}
@Test
fun testGetSelectedTypeShouldReturnViewOnlyWhenReadPermissionGiven() {
val share = createShare(OCShare.READ_PERMISSION_FLAG)
assertEquals(QuickPermissionType.VIEW_ONLY, SharePermissionManager.getSelectedType(share, encrypted = false))
}
@Test
fun testGetSelectedTypeShouldReturnCustomPermissionOnlyWhenCustomPermissionGiven() {
val share = createShare(OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG)
assertEquals(
QuickPermissionType.CUSTOM_PERMISSIONS,
SharePermissionManager.getSelectedType(share, encrypted = false)
)
}
@Test
fun testGetSelectedTypeShouldReturnNoneOnlyWhenNoPermissionGiven() {
val share = createShare(OCShare.NO_PERMISSION)
assertEquals(
QuickPermissionType.NONE,
SharePermissionManager.getSelectedType(share, encrypted = false)
)
}
// endregion
// region CustomPermissions Tests
@Test
fun testIsCustomPermissionShouldReturnFalseWhenNoPermissionsGiven() {
val permission = OCShare.NO_PERMISSION
val share = createShare(permission, isFolder = false)
assertFalse(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnFalseWhenNoReadPermissionsGiven() {
val permission = OCShare.SHARE_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertFalse(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnTrueWhenUpdatePermissionsGivenOnFile() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertTrue(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnTrueWhenUpdateAndSharePermissionsGivenOnFile() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + OCShare.SHARE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertTrue(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnFalseWhenCreatePermissionsGivenOnFile() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertFalse(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnFalseWhenDeletePermissionsGivenOnFile() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.DELETE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertFalse(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnTrueWhenCreatePermissionsGivenOnFolder() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
val share = createShare(permission, isFolder = true)
assertTrue(SharePermissionManager.isCustomPermission(share))
}
@Test
fun testIsCustomPermissionShouldReturnTrueWhenMixedPermissionsOnFile() {
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
val share = createShare(permission, isFolder = false)
assertTrue(SharePermissionManager.isCustomPermission(share))
}
// endregion
// region Attributes Tests
@Test
fun testToggleAllowDownloadAndSyncShouldCreateAttributeJsonIfNoneExists() {
val ocShare = OCShare().apply {
isFolder = true
shareType = ShareType.USER
permissions = 17
}
ocShare.attributes = toggleAllowDownloadAndSync(
ocShare.attributes,
isChecked = true,
useV2DownloadAttributes = false
)
assertTrue(ocShare.isAllowDownloadAndSyncEnabled(false))
}
@Test
fun testIsAllowDownloadAndSyncEnabledShouldReturnFalseIfAttributeIsMissing() {
val share = createShare(OCShare.READ_PERMISSION_FLAG, attributesJson = null)
assertFalse(share.isAllowDownloadAndSyncEnabled(false))
}
// endregion
}

View file

@ -2,51 +2,76 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2023 TSI-mc
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nmc.android.ui
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import org.junit.Rule
import com.owncloud.android.utils.EspressoIdlingResource
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class LauncherActivityIT : AbstractIT() {
@get:Rule
val activityRule = ActivityScenarioRule(LauncherActivity::class.java)
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@Test
fun testSplashScreenWithEmptyTitlesShouldHideTitles() {
waitForIdleSync()
onView(withId(R.id.ivSplash)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.splashScreenBold)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
onView(withId(R.id.splashScreenNormal)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
fun testSplashScreenWithTitlesShouldShowTitles() {
waitForIdleSync()
onView(withId(R.id.ivSplash)).check(matches(isCompletelyDisplayed()))
activityRule.scenario.onActivity {
it.setSplashTitles("Example", "Cloud")
@UiThread
fun testSplashScreenWithEmptyTitlesShouldHideTitles() {
launchActivity<LauncherActivity>().use { scenario ->
scenario.onActivity { _ ->
onIdleSync {
onView(withId(R.id.ivSplash)).check(matches(isCompletelyDisplayed()))
onView(
withId(R.id.splashScreenBold)
).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
onView(
withId(R.id.splashScreenNormal)
).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
}
}
}
}
val onePercentArea = ViewMatchers.isDisplayingAtLeast(1)
onView(withId(R.id.splashScreenBold)).check(matches(onePercentArea))
onView(withId(R.id.splashScreenNormal)).check(matches(onePercentArea))
@Test
@UiThread
fun testSplashScreenWithTitlesShouldShowTitles() {
launchActivity<LauncherActivity>().use { scenario ->
scenario.onActivity {
onIdleSync {
onView(withId(R.id.ivSplash)).check(matches(isCompletelyDisplayed()))
EspressoIdlingResource.increment()
it.setSplashTitles("Example", "Cloud")
EspressoIdlingResource.decrement()
val onePercentArea = ViewMatchers.isDisplayingAtLeast(1)
onView(withId(R.id.splashScreenBold)).check(matches(onePercentArea))
onView(withId(R.id.splashScreenNormal)).check(matches(onePercentArea))
}
}
}
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android;
@ -22,6 +22,8 @@ import android.view.View;
import com.facebook.testing.screenshot.Screenshot;
import com.facebook.testing.screenshot.internal.TestNameDetector;
import com.nextcloud.android.common.ui.theme.MaterialSchemes;
import com.nextcloud.android.common.ui.theme.MaterialSchemesImpl;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.account.UserAccountManagerImpl;
@ -38,7 +40,6 @@ import com.nextcloud.test.RandomStringGenerator;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.db.OCUpload;
import com.owncloud.android.files.services.NameCollisionPolicy;
@ -54,6 +55,7 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.operations.UploadFileOperation;
import com.owncloud.android.utils.FileStorageUtils;
import com.owncloud.android.utils.theme.MaterialSchemesProvider;
import org.apache.commons.io.FileUtils;
import org.junit.After;
@ -182,7 +184,7 @@ public abstract class AbstractIT {
String darkModeParameter = arguments.getString("DARKMODE");
if (darkModeParameter != null) {
if (darkModeParameter.equalsIgnoreCase("dark")) {
if ("dark".equalsIgnoreCase(darkModeParameter)) {
DARK_MODE = "dark";
AppPreferencesImpl.fromContext(targetContext).setDarkThemeMode(DarkMode.DARK);
MainApp.setAppTheme(DarkMode.DARK);
@ -191,7 +193,7 @@ public abstract class AbstractIT {
}
}
if (DARK_MODE.equalsIgnoreCase("light") && COLOR.equalsIgnoreCase("blue")) {
if ("light".equalsIgnoreCase(DARK_MODE) && "blue".equalsIgnoreCase(COLOR)) {
// use already existing names
DARK_MODE = "";
COLOR = "";
@ -254,19 +256,12 @@ public abstract class AbstractIT {
file.mkdirs();
return file;
} else {
switch (name) {
case "empty.txt":
return createFile("empty.txt", 0);
case "nonEmpty.txt":
return createFile("nonEmpty.txt", 100);
case "chunkedFile.txt":
return createFile("chunkedFile.txt", 500000);
default:
return createFile(name, 0);
}
return switch (name) {
case "empty.txt" -> createFile("empty.txt", 0);
case "nonEmpty.txt" -> createFile("nonEmpty.txt", 100);
case "chunkedFile.txt" -> createFile("chunkedFile.txt", 500000);
default -> createFile(name, 0);
};
}
}
@ -301,7 +296,7 @@ public abstract class AbstractIT {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
protected void onIdleSync(Runnable recipient) {
public void onIdleSync(Runnable recipient) {
InstrumentationRegistry.getInstrumentation().waitForIdle(recipient);
}
@ -355,7 +350,7 @@ public abstract class AbstractIT {
}
}
public OCFile createFolder(String remotePath) {
public void createFolder(String remotePath) {
RemoteOperationResult check = new ExistenceCheckRemoteOperation(remotePath, false).execute(client);
if (!check.isSuccess()) {
@ -363,8 +358,6 @@ public abstract class AbstractIT {
.execute(client)
.isSuccess());
}
return getStorageManager().getFileByDecryptedRemotePath(remotePath.endsWith("/") ? remotePath : remotePath + "/");
}
public void uploadFile(File file, String remotePath) {
@ -375,6 +368,11 @@ public abstract class AbstractIT {
public void uploadOCUpload(OCUpload ocUpload) {
ConnectivityService connectivityServiceMock = new ConnectivityService() {
@Override
public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
}
@Override
public boolean isConnected() {
return false;
@ -457,12 +455,18 @@ public abstract class AbstractIT {
screenshot(view, "");
}
protected void screenshotViaName(Activity activity, String name) {
public void screenshotViaName(Activity activity, String name) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
Screenshot.snapActivity(activity).setName(name).record();
}
}
protected void screenshotViaName(View view, String name) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
Screenshot.snap(view).setName(name).record();
}
}
protected void screenshot(View view, String prefix) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
Screenshot.snap(view).setName(createName(prefix)).record();
@ -541,4 +545,38 @@ public abstract class AbstractIT {
protected static boolean removeAccount(Account account) {
return AccountManager.get(targetContext).removeAccountExplicitly(account);
}
protected MaterialSchemesProvider getMaterialSchemesProvider() {
return new MaterialSchemesProvider() {
@NonNull
@Override
public MaterialSchemes getMaterialSchemesForUser(@NonNull User user) {
return null;
}
@NonNull
@Override
public MaterialSchemes getMaterialSchemesForCapability(@NonNull OCCapability capability) {
return null;
}
@NonNull
@Override
public MaterialSchemes getMaterialSchemesForCurrentUser() {
return new MaterialSchemesImpl(R.color.primary, false);
}
@NonNull
@Override
public MaterialSchemes getDefaultMaterialSchemes() {
return null;
}
@NonNull
@Override
public MaterialSchemes getMaterialSchemesForPrimaryBackground() {
return null;
}
};
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android;
@ -13,7 +13,6 @@ import android.accounts.OperationCanceledException;
import android.content.ActivityNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.account.UserAccountManagerImpl;
@ -174,9 +173,7 @@ public abstract class AbstractOnServerIT extends AbstractIT {
Assert.fail("Server not ready!");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
@ -187,6 +184,11 @@ public abstract class AbstractOnServerIT extends AbstractIT {
public void uploadOCUpload(OCUpload ocUpload, int localBehaviour) {
ConnectivityService connectivityServiceMock = new ConnectivityService() {
@Override
public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
}
@Override
public boolean isConnected() {
return false;

View file

@ -4,7 +4,7 @@
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android;

View file

@ -1,8 +1,8 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android;
@ -106,8 +106,8 @@ public class FileIT extends AbstractOnServerIT {
assertTrue(new SynchronizeFolderOperation(targetContext,
folderPath,
user,
System.currentTimeMillis(),
fileDataStorageManager)
fileDataStorageManager,
false)
.execute(targetContext)
.isSuccess());

View file

@ -0,0 +1,183 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.activity.SettingsActivity
import com.owncloud.android.ui.activity.SyncedFoldersActivity
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.BeforeClass
import org.junit.ClassRule
import org.junit.Test
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
import tools.fastlane.screengrab.locale.LocaleTestRule
class ScreenshotsIT : AbstractIT() {
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun gridViewScreenshot() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
onView(withId(R.id.switch_grid_view_button)).perform(click())
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("01_gridView")
// Switch back
onView(withId(R.id.switch_grid_view_button)).perform(click())
assertTrue(true)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun listViewScreenshot() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val path = "/Camera/"
OCFile(path).apply {
storageManager.saveFile(this)
}
onView(withId(R.id.list_root)).perform(click())
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("02_listView")
assertTrue(true)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun drawerScreenshot() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("03_drawer")
onView(withId(R.id.drawer_layout)).perform(DrawerActions.close())
assertTrue(true)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun multipleAccountsScreenshot() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
onView(withId(R.id.switch_account_button)).perform(click())
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("04_accounts")
Espresso.pressBack()
assertTrue(true)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun autoUploadScreenshot() {
launchActivity<SyncedFoldersActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("05_autoUpload")
assertTrue(true)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun davdroidScreenshot() {
launchActivity<SettingsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
onView(withText(R.string.prefs_category_more)).perform(scrollTo())
EspressoIdlingResource.decrement()
onView(isRoot()).check(matches(isDisplayed()))
Screengrab.screenshot("06_davdroid")
assertTrue(true)
}
}
}
}
companion object {
@ClassRule
@JvmField
val localeTestRule: LocaleTestRule = LocaleTestRule()
@BeforeClass
@JvmStatic
fun beforeScreenshot() {
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
}
}
}

View file

@ -4,7 +4,7 @@
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android;
@ -56,6 +56,11 @@ public class UploadIT extends AbstractOnServerIT {
targetContext.getContentResolver());
private ConnectivityService connectivityServiceMock = new ConnectivityService() {
@Override
public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
}
@Override
public boolean isConnected() {
return false;
@ -274,6 +279,11 @@ public class UploadIT extends AbstractOnServerIT {
@Test
public void testUploadOnWifiOnlyButNoWifi() {
ConnectivityService connectivityServiceMock = new ConnectivityService() {
@Override
public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
}
@Override
public boolean isConnected() {
return false;
@ -358,6 +368,11 @@ public class UploadIT extends AbstractOnServerIT {
@Test
public void testUploadOnWifiOnlyButMeteredWifi() {
ConnectivityService connectivityServiceMock = new ConnectivityService() {
@Override
public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
}
@Override
public boolean isConnected() {
return false;
@ -452,7 +467,7 @@ public class UploadIT extends AbstractOnServerIT {
assertEquals(remotePath, ocFile.getRemotePath());
assertEquals(creationTimestamp, ocFile.getCreationTimestamp());
assertTrue(uploadTimestamp - 10 < ocFile.getUploadTimestamp() ||
assertTrue(uploadTimestamp - 10 < ocFile.getUploadTimestamp() &&
uploadTimestamp + 10 > ocFile.getUploadTimestamp());
}
@ -498,7 +513,7 @@ public class UploadIT extends AbstractOnServerIT {
OCFile ocFile = null;
for (OCFile f : files) {
if (f.getFileName().equals("metadata.jpg")) {
if ("metadata.jpg".equals(f.getFileName())) {
ocFile = f;
break;
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.authentication

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.authentication

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2021 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel
@ -43,7 +43,6 @@ class ContentResolverHelperIT {
}
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
fun contentResolver_onAndroid26_usesNewAPI() {
ContentResolverHelper
.queryResolver(resolver, URI, PROJECTION, SELECTION, null, SORT_COLUMN, SORT_DIRECTION, LIMIT)

View file

@ -0,0 +1,10 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android.datamodel
data class Credentials(val publicKey: String, val certificate: String)

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel;

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel;

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel

View file

@ -1,9 +1,9 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper_ozturk@proton.me>
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel

View file

@ -36,6 +36,7 @@ public class OCFileUnitTest {
private static final String STORAGE_PATH = "/mnt/sd/localpath/to/a/file.txt";
private static final String MIME_TYPE = "text/plain";
private static final long FILE_LENGTH = 9876543210L;
private static final long UPLOADED_TIMESTAMP = 8765431109L;
private static final long CREATION_TIMESTAMP = 8765432109L;
private static final long MODIFICATION_TIMESTAMP = 7654321098L;
private static final long MODIFICATION_TIMESTAMP_AT_LAST_SYNC_FOR_DATA = 6543210987L;
@ -63,6 +64,7 @@ public class OCFileUnitTest {
mFile.setStoragePath(STORAGE_PATH);
mFile.setMimeType(MIME_TYPE);
mFile.setFileLength(FILE_LENGTH);
mFile.setUploadTimestamp(UPLOADED_TIMESTAMP);
mFile.setCreationTimestamp(CREATION_TIMESTAMP);
mFile.setModificationTimestamp(MODIFICATION_TIMESTAMP);
mFile.setModificationTimestampAtLastSyncForData(MODIFICATION_TIMESTAMP_AT_LAST_SYNC_FOR_DATA);
@ -93,6 +95,7 @@ public class OCFileUnitTest {
assertThat(fileReadFromParcel.getStoragePath(), is(STORAGE_PATH));
assertThat(fileReadFromParcel.getMimeType(), is(MIME_TYPE));
assertThat(fileReadFromParcel.getFileLength(), is(FILE_LENGTH));
assertThat(fileReadFromParcel.getUploadTimestamp(), is(UPLOADED_TIMESTAMP));
assertThat(fileReadFromParcel.getCreationTimestamp(), is(CREATION_TIMESTAMP));
assertThat(fileReadFromParcel.getModificationTimestamp(), is(MODIFICATION_TIMESTAMP));
assertThat(

View file

@ -4,7 +4,7 @@
* SPDX-FileCopyrightText: 2017 JARP <jarp@customer-187-174-218-184.uninet-ide.com.mx
* SPDX-FileCopyrightText: 2019 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2021 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.datamodel;

View file

@ -0,0 +1,39 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android.extensions
import android.app.Activity
import android.content.Intent
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
inline fun <reified T : Activity> AbstractIT.launchAndCapture(
testClassName: String,
actionName: String,
intent: Intent? = null,
crossinline before: (T) -> Unit
) {
launchActivity<T>(intent).use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
before(activity)
EspressoIdlingResource.decrement()
val screenshotName = createName(testClassName + "_" + actionName, "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(activity, screenshotName)
}
}
}
}

View file

@ -1,9 +1,9 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2022 Álvaro Brey Vilas
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android.files
@ -331,10 +331,7 @@ class FileMenuFilterIT : AbstractIT() {
}
}
private data class ExpectedLockVisibilities(
val lockFile: Boolean,
val unlockFile: Boolean
)
private data class ExpectedLockVisibilities(val lockFile: Boolean, val unlockFile: Boolean)
private fun configureCapability(capability: OCCapability) {
every { mockStorageManager.getCapability(any<User>()) } returns capability

View file

@ -4,7 +4,7 @@
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.files.services
@ -34,9 +34,9 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
private var uploadsStorageManager: UploadsStorageManager? = null
private val connectivityServiceMock: ConnectivityService = object : ConnectivityService {
override fun isConnected(): Boolean {
return false
}
override fun isNetworkAndServerAvailable(callback: ConnectivityService.GenericCallback<Boolean>) = Unit
override fun isConnected(): Boolean = false
override fun isInternetWalled(): Boolean = false
override fun getConnectivity(): Connectivity = Connectivity.CONNECTED_WIFI

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2021 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.operations

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.operations;

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Torsten Grote <t@grobox.de>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.providers
@ -177,31 +177,30 @@ object DocumentsProviderUtils {
*/
@Suppress("EXPERIMENTAL_API_USAGE")
@VisibleForTesting
internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) =
withTimeout(timeout) {
suspendCancellableCoroutine<Cursor> { cont ->
val cursor = query() ?: throw IOException("Initial query returned no results")
cont.invokeOnCancellation { cursor.close() }
val loading = cursor.extras.getBoolean(EXTRA_LOADING, false)
if (loading) {
Log_OC.e("TEST", "Cursor was loading, wait for update...")
cursor.registerContentObserver(
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
cursor.close()
val newCursor = query()
if (newCursor == null) {
cont.cancel(IOException("Re-query returned no results"))
} else {
cont.resume(newCursor)
}
internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) = withTimeout(timeout) {
suspendCancellableCoroutine { cont ->
val cursor = query() ?: throw IOException("Initial query returned no results")
cont.invokeOnCancellation { cursor.close() }
val loading = cursor.extras?.getBoolean(EXTRA_LOADING, false) ?: false
if (loading) {
Log_OC.e("TEST", "Cursor was loading, wait for update...")
cursor.registerContentObserver(
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
cursor.close()
val newCursor = query()
if (newCursor == null) {
cont.cancel(IOException("Re-query returned no results"))
} else {
cont.resume(newCursor)
}
}
)
} else {
// not loading, return cursor right away
cont.resume(cursor)
}
}
)
} else {
// not loading, return cursor right away
cont.resume(cursor)
}
}
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Torsten Grote <t@grobox.de>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.providers
@ -53,6 +53,14 @@ class DocumentsStorageProviderIT : AbstractOnServerIT() {
// DocumentsProvider#onCreate() is called when the application is started
// which is *after* AbstractOnServerIT adds the accounts (when the app is freshly installed).
// So we need to query our roots here to ensure that the internal storage map is initialized.
storageManager.run {
val updatedRootPath = getFileByEncryptedRemotePath(ROOT_PATH).apply {
permissions = "RSMCKGWDNV"
}
saveFile(updatedRootPath)
}
contentResolver.query(DocumentsContract.buildRootsUri(authority), null, null, null)
assertTrue("Storage root does not exist", rootDir.exists())
assertTrue(rootDir.isDirectory)

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2021 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.providers

View file

@ -1,32 +1,32 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.providers
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractOnServerIT
import org.junit.Rule
import org.junit.Test
class UsersAndGroupsSearchProviderIT : AbstractOnServerIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
@Test
@UiThread
fun searchUser() {
val activity = testActivityRule.launchActivity(null)
shortSleep()
activity.runOnUiThread {
// fragment.search("Admin")
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(isRoot()).check(matches(isDisplayed()))
}
}
}
longSleep()
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui
@ -45,14 +45,13 @@ class LoginIT : AbstractIT() {
ActivityScenario.launch(AuthenticatorActivity::class.java)
}
@Test
@Throws(InterruptedException::class)
@Suppress("MagicNumber", "SwallowedException")
/**
* The CI/CD pipeline is encountering issues related to the Android version for this functionality.
* Therefore the test will only be executed on Android versions 10 and above.
*/
@Test
@Throws(InterruptedException::class)
@Suppress("MagicNumber", "SwallowedException")
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun login() {
val arguments = InstrumentationRegistry.getArguments()
@ -71,7 +70,7 @@ class LoginIT : AbstractIT() {
Web.onWebView()
.withElement(DriverAtoms.findElement(Locator.XPATH, "//form[@id='login-form']/input[@type='submit']"))
.perform(DriverAtoms.webClick())
} catch (e: RuntimeException) {
} catch (_: RuntimeException) {
// NC < 25
Web.onWebView()
.withElement(DriverAtoms.findElement(Locator.XPATH, "//p[@id='redirect-link']/a"))
@ -94,7 +93,7 @@ class LoginIT : AbstractIT() {
Web.onWebView()
.withElement(DriverAtoms.findElement(Locator.XPATH, "//button[@type='submit']"))
.perform(DriverAtoms.webClick())
} catch (e: RuntimeException) {
} catch (_: RuntimeException) {
// NC < 25
Web.onWebView()
.withElement(DriverAtoms.findElement(Locator.XPATH, "//input[@type='submit']"))

View file

@ -0,0 +1,326 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import androidx.annotation.UiThread
import androidx.fragment.app.DialogFragment
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.client.account.UserAccountManagerImpl
import com.nextcloud.utils.extensions.getDecryptedPath
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.db.OCUpload
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Companion.newInstance
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.FileStorageUtils
import com.owncloud.android.utils.ScreenshotTest
import junit.framework.TestCase
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class ConflictsResolveActivityIT : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.activity.ConflictsResolveActivityIT"
private var returnCode = false
@Test
@UiThread
@ScreenshotTest
fun screenshotTextFiles() {
val newFile = OCFile("/newFile.txt").apply {
remoteId = "0001"
fileLength = 56000
modificationTimestamp = 1522019340
setStoragePath(FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt")
}
val existingFile = OCFile("/newFile.txt").apply {
remoteId = "0002"
fileLength = 1024000
modificationTimestamp = 1582019340
}
val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
storageManager.saveNewFile(existingFile)
val intent = Intent(targetContext, ConflictsResolveActivity::class.java).apply {
putExtra(FileActivity.EXTRA_FILE, newFile)
putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
}
launchActivity<ConflictsResolveActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val dialog = newInstance(
storageManager.getDecryptedPath(existingFile),
targetContext,
newFile,
existingFile,
UserAccountManagerImpl
.fromContext(targetContext)
.getUser()
)
dialog.showDialog(sut)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "screenshotTextFiles", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(dialog.requireDialog().window?.decorView, screenShotName)
}
}
}
}
@Test
@UiThread
fun cancel() {
val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)
val existingFile = OCFile("/newFile.txt").apply {
fileLength = 1024000
modificationTimestamp = 1582019340
}
val newFile = OCFile("/newFile.txt").apply {
fileLength = 56000
modificationTimestamp = 1522019340
setStoragePath(FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt")
}
EspressoIdlingResource.increment()
FileDataStorageManager(user, targetContext.contentResolver).run {
saveNewFile(existingFile)
}
EspressoIdlingResource.decrement()
val intent = Intent(targetContext, ConflictsResolveActivity::class.java).apply {
putExtra(FileActivity.EXTRA_FILE, newFile)
putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
}
launchActivity<ConflictsResolveActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
returnCode = false
sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
assertEquals(decision, Decision.CANCEL)
returnCode = true
}
EspressoIdlingResource.decrement()
onView(ViewMatchers.withText("Cancel")).perform(ViewActions.click())
TestCase.assertTrue(returnCode)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun keepExisting() {
returnCode = false
val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)
val existingFile = OCFile("/newFile.txt").apply {
remoteId = "0001"
fileLength = 1024000
modificationTimestamp = 1582019340
}
val newFile = OCFile("/newFile.txt").apply {
fileLength = 56000
remoteId = "0002"
modificationTimestamp = 1522019340
setStoragePath(FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt")
}
EspressoIdlingResource.increment()
FileDataStorageManager(user, targetContext.contentResolver).run {
saveNewFile(existingFile)
}
EspressoIdlingResource.decrement()
val intent = Intent(targetContext, ConflictsResolveActivity::class.java).apply {
putExtra(FileActivity.EXTRA_FILE, newFile)
putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
}
launchActivity<ConflictsResolveActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
assertEquals(decision, Decision.KEEP_SERVER)
returnCode = true
}
EspressoIdlingResource.decrement()
onView(ViewMatchers.withId(R.id.right_checkbox)).perform(ViewActions.click())
val dialog = sut.supportFragmentManager.findFragmentByTag("conflictDialog") as DialogFragment?
val screenShotName = createName(testClassName + "_" + "keepExisting", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(dialog?.requireDialog()?.window?.decorView, screenShotName)
onView(ViewMatchers.withText("OK")).perform(ViewActions.click())
assertTrue(returnCode)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun keepNew() {
returnCode = false
val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)
val existingFile = OCFile("/newFile.txt").apply {
fileLength = 1024000
modificationTimestamp = 1582019340
remoteId = "00000123abc"
}
val newFile = OCFile("/newFile.txt").apply {
fileLength = 56000
modificationTimestamp = 1522019340
setStoragePath(FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt")
}
val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
storageManager.saveNewFile(existingFile)
val intent = Intent(targetContext, ConflictsResolveActivity::class.java)
intent.putExtra(FileActivity.EXTRA_FILE, newFile)
intent.putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
launchActivity<ConflictsResolveActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
assertEquals(decision, Decision.KEEP_LOCAL)
returnCode = true
}
EspressoIdlingResource.decrement()
onView(ViewMatchers.withId(R.id.left_checkbox)).perform(ViewActions.click())
val dialog = sut.supportFragmentManager.findFragmentByTag("conflictDialog") as DialogFragment?
val screenShotName = createName(testClassName + "_" + "keepNew", "")
screenshotViaName(dialog?.requireDialog()?.window?.decorView, screenShotName)
onView(ViewMatchers.withText("OK")).perform(ViewActions.click())
assertTrue(returnCode)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun keepBoth() {
returnCode = false
val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)
val existingFile = OCFile("/newFile.txt").apply {
remoteId = "0001"
fileLength = 1024000
modificationTimestamp = 1582019340
}
val newFile = OCFile("/newFile.txt").apply {
fileLength = 56000
remoteId = "0002"
modificationTimestamp = 1522019340
setStoragePath(FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt")
}
val storageManager = FileDataStorageManager(user, targetContext.contentResolver)
storageManager.saveNewFile(existingFile)
val intent = Intent(targetContext, ConflictsResolveActivity::class.java).apply {
putExtra(FileActivity.EXTRA_FILE, newFile)
putExtra(ConflictsResolveActivity.EXTRA_EXISTING_FILE, existingFile)
putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
}
launchActivity<ConflictsResolveActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
assertEquals(decision, Decision.KEEP_BOTH)
returnCode = true
}
EspressoIdlingResource.decrement()
onView(ViewMatchers.withId(R.id.right_checkbox)).perform(ViewActions.click())
onView(ViewMatchers.withId(R.id.left_checkbox)).perform(ViewActions.click())
onView(ViewMatchers.withId(R.id.left_checkbox)).perform(ViewActions.click())
val dialog = sut.supportFragmentManager.findFragmentByTag("conflictDialog") as DialogFragment?
val screenShotName = createName(testClassName + "_" + "keepBoth", "")
screenshotViaName(dialog?.requireDialog()?.window?.decorView, screenShotName)
onView(ViewMatchers.withText("OK")).perform(ViewActions.click())
assertTrue(returnCode)
}
}
}
}
@After
override fun after() {
storageManager.deleteAllFiles()
}
}

View file

@ -3,24 +3,42 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Before
import org.junit.Test
class ContactsPreferenceActivityIT : AbstractIT() {
@get:Rule
var activityRule = IntentsTestRule(ContactsPreferenceActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.activity.ContactsPreferenceActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun openVCF() {
val file = getFile("vcard.vcf")
@ -29,23 +47,34 @@ class ContactsPreferenceActivityIT : AbstractIT() {
assertTrue(vcfFile.isDown)
val intent = Intent()
intent.putExtra(ContactsPreferenceActivity.EXTRA_FILE, vcfFile)
intent.putExtra(ContactsPreferenceActivity.EXTRA_USER, user)
val sut = activityRule.launchActivity(intent)
val intent = Intent(targetContext, ContactsPreferenceActivity::class.java).apply {
putExtra(ContactsPreferenceActivity.EXTRA_FILE, vcfFile)
putExtra(ContactsPreferenceActivity.EXTRA_USER, user)
}
shortSleep()
screenshot(sut)
launchActivity<ContactsPreferenceActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "openVCF", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun openContactsPreference() {
val sut = activityRule.launchActivity(null)
shortSleep()
screenshot(sut)
launchActivity<ContactsPreferenceActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "openContactsPreference", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -0,0 +1,128 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.accounts.Account
import android.accounts.AccountManager
import android.net.Uri
import android.view.View
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry
import com.nextcloud.client.account.User
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.account.UserAccountManagerImpl
import com.nextcloud.test.RetryTestRule
import com.owncloud.android.AbstractIT
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.lib.common.accounts.AccountUtils
import com.owncloud.android.utils.EspressoIdlingResource
import org.hamcrest.Matchers
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Rule
import org.junit.Test
import java.util.function.Supplier
class DrawerActivityIT : AbstractIT() {
@Rule
@JvmField
val retryTestRule = RetryTestRule()
@Test
@UiThread
fun switchAccountViaAccountList() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.setUser(user1)
Assert.assertEquals(account1, sut.user.get().toPlatformAccount())
onView(ViewMatchers.withId(R.id.switch_account_button)).perform(ViewActions.click())
onView(
Matchers.anyOf<View?>(
ViewMatchers.withText(account2Name),
ViewMatchers.withText(
account2DisplayName
)
)
).perform(ViewActions.click())
Assert.assertEquals(account2, sut.user.get().toPlatformAccount())
EspressoIdlingResource.decrement()
onView(ViewMatchers.withId(R.id.switch_account_button)).perform(ViewActions.click())
onView(ViewMatchers.withText(account1?.name)).perform(ViewActions.click())
}
}
}
}
companion object {
private var account1: Account? = null
private var user1: User? = null
private var account2: Account? = null
private var account2Name: String? = null
private var account2DisplayName: String? = null
@JvmStatic
@BeforeClass
fun beforeClass() {
val arguments = InstrumentationRegistry.getArguments()
val baseUrl = Uri.parse(arguments.getString("TEST_SERVER_URL"))
val platformAccountManager = AccountManager.get(targetContext)
val userAccountManager: UserAccountManager = UserAccountManagerImpl.fromContext(targetContext)
for (account in platformAccountManager.accounts) {
platformAccountManager.removeAccountExplicitly(account)
}
var loginName = "user1"
var password = "user1"
var temp = Account("$loginName@$baseUrl", MainApp.getAccountType(targetContext))
platformAccountManager.addAccountExplicitly(temp, password, null)
platformAccountManager.setUserData(
temp,
AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION,
UserAccountManager.ACCOUNT_VERSION.toString()
)
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_VERSION, "14.0.0.0")
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, baseUrl.toString())
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_USER_ID, loginName) // same as userId
account1 = userAccountManager.getAccountByName("$loginName@$baseUrl")
user1 = userAccountManager.getUser(account1!!.name)
.orElseThrow<IllegalAccessError?>(Supplier { IllegalAccessError() })
loginName = "user2"
password = "user2"
temp = Account("$loginName@$baseUrl", MainApp.getAccountType(targetContext))
platformAccountManager.addAccountExplicitly(temp, password, null)
platformAccountManager.setUserData(
temp,
AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION,
UserAccountManager.ACCOUNT_VERSION.toString()
)
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_VERSION, "14.0.0.0")
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, baseUrl.toString())
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_USER_ID, loginName) // same as userId
account2 = userAccountManager.getAccountByName("$loginName@$baseUrl")
account2Name = "$loginName@$baseUrl"
account2DisplayName = "User Two@$baseUrl"
}
}
}

View file

@ -2,7 +2,7 @@
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2019 Unpublished <unpublished@gmx.net>
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity;

View file

@ -0,0 +1,213 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2019 Kilian Périsset <kilian.perisset@infomaniak.com>
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import android.view.View
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class FolderPickerActivityIT : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.activity.FolderPickerActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
fun getActivityFile() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val origin = OCFile("/test/file.test").apply {
remotePath = "/remotePath/test"
}
// Act
sut.file = origin
val target = sut.file
// Assert
assertEquals(origin, target)
}
}
}
}
@Test
@UiThread
fun getParentFolder_isNotRootFolder() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// Arrange
val origin = OCFile("/test/").apply {
fileId = 1
remotePath = "/test/"
setStoragePath("/test/")
setFolder()
}
// Act
sut.file = origin
val target = sut.currentFolder
// Assert
assertEquals(origin, target)
}
}
}
}
@Test
@UiThread
fun getParentFolder_isRootFolder() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// Arrange
val origin = OCFile("/").apply {
fileId = 1
remotePath = "/"
setStoragePath("/")
setFolder()
}
// Act
sut.file = origin
val target = sut.currentFolder
// Assert
assertEquals(origin, target)
}
}
}
}
@Suppress("DEPRECATION")
@Test
@UiThread
fun nullFile() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// Arrange
val rootFolder = sut.storageManager.getFileByPath(OCFile.ROOT_PATH)
// Act
sut.file = null
val target = sut.currentFolder
// Assert
assertEquals(rootFolder, target)
}
}
}
}
@Test
@UiThread
fun getParentFolder() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
// Arrange
val origin = OCFile("/test/file.test").apply {
remotePath = "/test/file.test"
}
val target = OCFile("/test/")
// Act
sut.file = origin
// Assert
assertEquals(origin, target)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun open() {
launchActivity<FolderPickerActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val origin = OCFile("/test/file.txt")
sut.file = origin
sut.findViewById<View>(R.id.folder_picker_btn_copy).requestFocus()
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testMoveOrCopy() {
val intent = Intent(targetContext, FolderPickerActivity::class.java)
launchActivity<FolderPickerActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "testMoveOrCopy", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testChooseLocationAction() {
val intent = Intent(targetContext, FolderPickerActivity::class.java).apply {
putExtra(FolderPickerActivity.EXTRA_ACTION, FolderPickerActivity.CHOOSE_LOCATION)
}
launchActivity<FolderPickerActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "testChooseLocationAction", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -0,0 +1,89 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.common.Quota
import com.owncloud.android.lib.common.UserInfo
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class ManageAccountsActivityIT : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.activity.ManageAccountsActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun open() {
launchActivity<ManageAccountsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun userInfoDetail() {
launchActivity<ManageAccountsActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val user = sut.accountManager.user
val userInfo = UserInfo(
"test",
true,
"Test User",
"test@nextcloud.com",
"+49 123 456",
"Address 123, Berlin",
"https://www.nextcloud.com",
"https://twitter.com/Nextclouders",
Quota(),
ArrayList()
)
EspressoIdlingResource.decrement()
sut.showUser(user, userInfo)
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(getCurrentActivity(), screenShotName)
}
}
}
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity

View file

@ -1,66 +1,111 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class PassCodeActivityIT : AbstractIT() {
@get:Rule
var activityRule = IntentsTestRule(PassCodeActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.activity.PassCodeActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun check() {
val sut = activityRule.launchActivity(Intent(PassCodeActivity.ACTION_CHECK))
val intent = Intent(targetContext, PassCodeActivity::class.java).apply {
action = PassCodeActivity.ACTION_CHECK
}
waitForIdleSync()
launchActivity<PassCodeActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.binding.txt0.clearFocus()
Espresso.closeSoftKeyboard()
EspressoIdlingResource.decrement()
sut.runOnUiThread { sut.binding.txt0.clearFocus() }
Espresso.closeSoftKeyboard()
shortSleep()
waitForIdleSync()
screenshot(sut)
val screenShotName = createName(testClassName + "_" + "check", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun request() {
val sut = activityRule.launchActivity(Intent(PassCodeActivity.ACTION_REQUEST_WITH_RESULT))
val intent = Intent(targetContext, PassCodeActivity::class.java).apply {
action = PassCodeActivity.ACTION_REQUEST_WITH_RESULT
}
waitForIdleSync()
launchActivity<PassCodeActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.binding.txt0.clearFocus()
Espresso.closeSoftKeyboard()
EspressoIdlingResource.decrement()
sut.runOnUiThread { sut.binding.txt0.clearFocus() }
Espresso.closeSoftKeyboard()
shortSleep()
waitForIdleSync()
screenshot(sut)
val screenShotName = createName(testClassName + "_" + "request", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun delete() {
val sut = activityRule.launchActivity(Intent(PassCodeActivity.ACTION_CHECK_WITH_RESULT))
val intent = Intent(targetContext, PassCodeActivity::class.java).apply {
action = PassCodeActivity.ACTION_CHECK_WITH_RESULT
}
waitForIdleSync()
launchActivity<PassCodeActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.binding.txt0.clearFocus()
Espresso.closeSoftKeyboard()
EspressoIdlingResource.decrement()
sut.runOnUiThread { sut.binding.txt0.clearFocus() }
Espresso.closeSoftKeyboard()
shortSleep()
waitForIdleSync()
screenshot(sut)
val screenShotName = createName(testClassName + "_" + "delete", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -1,28 +1,53 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2022 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.app.Activity
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class ReceiveExternalFilesActivityIT : AbstractIT() {
@get:Rule
val activityRule = IntentsTestRule(ReceiveExternalFilesActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.activity.ReceiveExternalFilesActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun open() {
val sut: Activity = activityRule.launchActivity(null)
screenshot(sut)
launchActivity<ReceiveExternalFilesActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "open", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test

View file

@ -1,30 +1,38 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import androidx.test.espresso.intent.rule.IntentsTestRule
import com.nextcloud.test.GrantStoragePermissionRule
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.GrantStoragePermissionRule.Companion.grant
import com.owncloud.android.AbstractIT
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.FileStorageUtils
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import java.io.File
class UploadFilesActivityIT : AbstractIT() {
@get:Rule
var activityRule = IntentsTestRule(UploadFilesActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.activity.UploadFilesActivityIT"
@get:Rule
var permissionRule = GrantStoragePermissionRule.grant()
var storagePermissionRule: TestRule = grant()
private val directories = listOf("A", "B", "C", "D")
.map { File("${FileStorageUtils.getTemporalPath(account.name)}${File.separator}$it") }
@ -39,60 +47,133 @@ class UploadFilesActivityIT : AbstractIT() {
directories.forEach { it.deleteRecursively() }
}
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun noneSelected() {
val sut: UploadFilesActivity = activityRule.launchActivity(null)
launchActivity<UploadFilesActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.runOnUiThread {
sut.fileListFragment.setFiles(
directories +
listOf(
File("1.txt"),
File("2.pdf"),
File("3.mp3")
sut.fileListFragment.setFiles(
directories +
listOf(
File("1.txt"),
File("2.pdf"),
File("3.mp3")
)
)
)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "noneSelected", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.fileListFragment.binding?.listRoot, screenShotName)
}
}
}
waitForIdleSync()
longSleep()
screenshot(sut.fileListFragment.binding.listRoot)
}
@Test
@UiThread
@ScreenshotTest
fun localFolderPickerMode() {
val sut: UploadFilesActivity = activityRule.launchActivity(
Intent().apply {
putExtra(
UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE,
true
)
putExtra(
UploadFilesActivity.REQUEST_CODE_KEY,
FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM
)
}
)
sut.runOnUiThread {
sut.fileListFragment.setFiles(
directories
val intent = Intent(targetContext, UploadFilesActivity::class.java).apply {
putExtra(
UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE,
true
)
putExtra(
UploadFilesActivity.REQUEST_CODE_KEY,
FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM
)
}
waitForIdleSync()
launchActivity<UploadFilesActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
screenshot(sut)
sut.fileListFragment.setFiles(
directories
)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "localFolderPickerMode", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
fun fileSelected() {
val sut: UploadFilesActivity = activityRule.launchActivity(null)
@Test
@UiThread
@ScreenshotTest
fun search() {
launchActivity<UploadFilesActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
// TODO select one
sut.fileListFragment.performSearch("1.txt", arrayListOf(), false)
sut.fileListFragment.setFiles(
directories +
listOf(
File("1.txt"),
File("2.pdf"),
File("3.mp3")
)
)
screenshot(sut)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "search", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun selectAll() {
launchActivity<UploadFilesActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.fileListFragment.setFiles(
listOf(
File("1.txt"),
File("2.pdf"),
File("3.mp3")
)
)
sut.fileListFragment.selectAllFiles(true)
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "selectAll", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.fileListFragment.binding?.listRoot, screenShotName)
}
}
}
}
}

View file

@ -0,0 +1,71 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.activity
import android.content.Intent
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.common.UserInfo
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class UserInfoActivityIT : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.activity.UserInfoActivityIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun fullUserInfoDetail() {
val intent = Intent(targetContext, UserInfoActivity::class.java).apply {
putExtra(UserInfoActivity.KEY_ACCOUNT, user)
val userInfo = UserInfo(
"test",
true,
"Firstname Familyname",
"oss@rocks.com",
"+49 7613 672 255",
"Awesome Place Av.",
"https://www.nextcloud.com",
"nextclouders",
null,
null
)
putExtra(UserInfoActivity.KEY_USER_DATA, userInfo)
}
launchActivity<UserInfoActivity>(intent).use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
val screenShotName = createName(testClassName + "_" + "fullUserInfoDetail", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2022 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.adapter

View file

@ -0,0 +1,777 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.dialog
import android.accounts.Account
import android.accounts.AccountManager
import android.app.Dialog
import android.content.Intent
import android.net.http.SslCertificate
import android.net.http.SslError
import android.os.Looper
import android.view.ViewGroup
import android.webkit.SslErrorHandler
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.UiThread
import androidx.fragment.app.DialogFragment
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.nextcloud.android.common.ui.color.ColorUtil
import com.nextcloud.android.lib.resources.profile.Action
import com.nextcloud.android.lib.resources.profile.HoverCard
import com.nextcloud.client.account.RegisteredUser
import com.nextcloud.client.account.Server
import com.nextcloud.client.device.DeviceInfo
import com.nextcloud.client.documentscan.AppScanOptionalFeature
import com.nextcloud.ui.ChooseAccountDialogFragment.Companion.newInstance
import com.nextcloud.ui.SetOnlineStatusBottomSheet
import com.nextcloud.ui.fileactions.FileActionsBottomSheet.Companion.newInstance
import com.nextcloud.utils.EditorUtils
import com.owncloud.android.AbstractIT
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.authentication.EnforcedServer
import com.owncloud.android.datamodel.ArbitraryDataProvider
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.Creator
import com.owncloud.android.lib.common.DirectEditing
import com.owncloud.android.lib.common.Editor
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.lib.common.accounts.AccountTypeUtils
import com.owncloud.android.lib.common.accounts.AccountUtils
import com.owncloud.android.lib.resources.status.CapabilityBooleanType
import com.owncloud.android.lib.resources.status.OCCapability
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import com.owncloud.android.lib.resources.users.Status
import com.owncloud.android.lib.resources.users.StatusType
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.dialog.LoadingDialog.Companion.newInstance
import com.owncloud.android.ui.dialog.RenameFileDialogFragment.Companion.newInstance
import com.owncloud.android.ui.dialog.SharePasswordDialogFragment.Companion.newInstance
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.Companion.newInstanceForEmptySslError
import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment.Companion.newInstance
import com.owncloud.android.ui.fragment.OCFileListBottomSheetActions
import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog
import com.owncloud.android.ui.fragment.ProfileBottomSheetDialog
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.MimeTypeUtil
import com.owncloud.android.utils.ScreenshotTest
import com.owncloud.android.utils.theme.CapabilityUtils
import com.owncloud.android.utils.theme.ViewThemeUtils
import io.mockk.mockk
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.net.URI
import java.util.function.Supplier
@Suppress("TooManyFunctions")
class DialogFragmentIT : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.dialog.DialogFragmentIT"
private val serverUrl = "https://nextcloud.localhost"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@After
fun quitLooperIfNeeded() {
Looper.myLooper()?.quitSafely()
}
@Test
@UiThread
@ScreenshotTest
fun testRenameFileDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
newInstance(
OCFile("/Test/"),
OCFile("/")
).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testLoadingDialog() {
newInstance("Wait…").run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testConfirmationDialogWithOneAction() {
ConfirmationDialogFragment.newInstance(
R.string.upload_list_empty_text_auto_upload,
arrayOf(),
R.string.filedetails_sync_file,
R.string.common_ok,
-1,
-1,
-1
).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testConfirmationDialogWithTwoAction() {
ConfirmationDialogFragment.newInstance(
R.string.upload_list_empty_text_auto_upload,
arrayOf(),
R.string.filedetails_sync_file,
R.string.common_ok,
R.string.common_cancel,
-1,
-1
).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testConfirmationDialogWithThreeAction() {
ConfirmationDialogFragment.newInstance(
R.string.upload_list_empty_text_auto_upload,
arrayOf(),
R.string.filedetails_sync_file,
R.string.common_ok,
R.string.common_cancel,
R.string.common_confirm,
-1
).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testConfirmationDialogWithThreeActionRTL() {
enableRTL()
ConfirmationDialogFragment.newInstance(
R.string.upload_list_empty_text_auto_upload,
arrayOf(),
-1,
R.string.common_ok,
R.string.common_cancel,
R.string.common_confirm,
-1
).run {
showDialog(this)
resetLocale()
}
}
@Test
@UiThread
@ScreenshotTest
fun testRemoveFileDialog() {
RemoveFilesDialogFragment.newInstance(OCFile("/Test.md")).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testRemoveFilesDialog() {
val toDelete = ArrayList<OCFile>().apply {
add(OCFile("/Test.md"))
add(OCFile("/Document.odt"))
}
val dialog: RemoveFilesDialogFragment = RemoveFilesDialogFragment.newInstance(toDelete)
showDialog(dialog)
}
@Test
@UiThread
@ScreenshotTest
fun testRemoveFolderDialog() {
val dialog = RemoveFilesDialogFragment.newInstance(OCFile("/Folder/"))
showDialog(dialog)
}
@Test
@UiThread
@ScreenshotTest
fun testRemoveFoldersDialog() {
val toDelete = ArrayList<OCFile>()
toDelete.add(OCFile("/Folder/"))
toDelete.add(OCFile("/Documents/"))
val dialog: RemoveFilesDialogFragment = RemoveFilesDialogFragment.newInstance(toDelete)
showDialog(dialog)
}
@Test
@UiThread
@ScreenshotTest
fun testNewFolderDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val sut = CreateFolderDialogFragment.newInstance(OCFile("/"))
showDialog(sut)
}
@Test
@UiThread
@ScreenshotTest
fun testEnforcedPasswordDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val sut = newInstance(OCFile("/"), true, false)
showDialog(sut)
}
@Test
@UiThread
@ScreenshotTest
fun testOptionalPasswordDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val sut = newInstance(OCFile("/"), true, true)
showDialog(sut)
}
@Test
@UiThread
@ScreenshotTest
fun testAccountChooserDialog() {
val intent = Intent(targetContext, FileDisplayActivity::class.java)
ActivityScenario.launch<FileDisplayActivity>(intent).use { scenario ->
scenario.onActivity { activity: FileDisplayActivity ->
EspressoIdlingResource.increment()
val userAccountManager = activity.userAccountManager
val accountManager = AccountManager.get(targetContext)
for (account in accountManager.getAccountsByType(MainApp.getAccountType(targetContext))) {
accountManager.removeAccountExplicitly(account)
}
val newAccount = Account("test@https://nextcloud.localhost", MainApp.getAccountType(targetContext))
accountManager.addAccountExplicitly(newAccount, "password", null)
accountManager.setUserData(newAccount, AccountUtils.Constants.KEY_OC_BASE_URL, serverUrl)
accountManager.setUserData(newAccount, AccountUtils.Constants.KEY_USER_ID, "test")
accountManager.setAuthToken(
newAccount,
AccountTypeUtils.getAuthTokenTypePass(newAccount.type),
"password"
)
val newUser = userAccountManager.getUser(newAccount.name)
.orElseThrow(Supplier { RuntimeException() })
userAccountManager.setCurrentOwnCloudAccount(newAccount.name)
val newAccount2 = Account("user1@nextcloud.localhost", MainApp.getAccountType(targetContext))
accountManager.addAccountExplicitly(newAccount2, "password", null)
accountManager.setUserData(newAccount2, AccountUtils.Constants.KEY_OC_BASE_URL, serverUrl)
accountManager.setUserData(newAccount2, AccountUtils.Constants.KEY_USER_ID, "user1")
accountManager.setUserData(newAccount2, AccountUtils.Constants.KEY_OC_VERSION, "20.0.0")
accountManager.setAuthToken(
newAccount2,
AccountTypeUtils.getAuthTokenTypePass(newAccount.type),
"password"
)
val fileDataStorageManager = FileDataStorageManager(
newUser,
targetContext.contentResolver
)
val capability = OCCapability().apply {
userStatus = CapabilityBooleanType.TRUE
userStatusSupportsEmoji = CapabilityBooleanType.TRUE
}
fileDataStorageManager.saveCapabilities(capability)
EspressoIdlingResource.decrement()
try {
onIdleSync {
val sut = newInstance(
RegisteredUser(
newAccount,
OwnCloudAccount(newAccount, targetContext),
Server(URI.create(serverUrl), OwnCloudVersion.nextcloud_20)
)
)
showDialog(activity, sut)
sut.setStatus(
Status(
StatusType.DND,
"Busy fixing 🐛…",
"",
-1
),
targetContext
)
screenshot(sut, "dnd")
sut.setStatus(
Status(
StatusType.ONLINE,
"",
"",
-1
),
targetContext
)
screenshot(sut, "online")
sut.setStatus(
Status(
StatusType.ONLINE,
"Let's have some fun",
"🎉",
-1
),
targetContext
)
screenshot(sut, "fun")
sut.setStatus(
Status(StatusType.OFFLINE, "", "", -1),
targetContext
)
screenshot(sut, "offline")
sut.setStatus(
Status(StatusType.AWAY, "Vacation", "🌴", -1),
targetContext
)
screenshot(sut, "away")
}
} catch (e: AccountUtils.AccountNotFoundException) {
throw java.lang.RuntimeException(e)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
@Throws(AccountUtils.AccountNotFoundException::class)
fun testAccountChooserDialogWithStatusDisabled() {
val accountManager = AccountManager.get(targetContext)
for (account in accountManager.accounts) {
accountManager.removeAccountExplicitly(account)
}
val newAccount = Account("test@https://nextcloud.localhost", MainApp.getAccountType(targetContext))
accountManager.addAccountExplicitly(newAccount, "password", null)
accountManager.setUserData(newAccount, AccountUtils.Constants.KEY_OC_BASE_URL, serverUrl)
accountManager.setUserData(newAccount, AccountUtils.Constants.KEY_USER_ID, "test")
accountManager.setAuthToken(newAccount, AccountTypeUtils.getAuthTokenTypePass(newAccount.type), "password")
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { fda ->
onIdleSync {
EspressoIdlingResource.increment()
val userAccountManager = fda.userAccountManager
val newUser = userAccountManager.getUser(newAccount.name).get()
val fileDataStorageManager = FileDataStorageManager(
newUser,
targetContext.contentResolver
)
val capability = OCCapability().apply {
userStatus = CapabilityBooleanType.FALSE
}
fileDataStorageManager.saveCapabilities(capability)
EspressoIdlingResource.decrement()
val sut =
newInstance(
RegisteredUser(
newAccount,
OwnCloudAccount(newAccount, targetContext),
Server(
URI.create(serverUrl),
OwnCloudVersion.nextcloud_20
)
)
)
onView(isRoot()).check(matches(isDisplayed()))
showDialog(fda, sut)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testBottomSheet() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val action: OCFileListBottomSheetActions = object : OCFileListBottomSheetActions {
override fun createFolder() = Unit
override fun uploadFromApp() = Unit
override fun uploadFiles() = Unit
override fun newDocument() = Unit
override fun newSpreadsheet() = Unit
override fun newPresentation() = Unit
override fun directCameraUpload() = Unit
override fun scanDocUpload() = Unit
override fun showTemplate(creator: Creator?, headline: String?) = Unit
override fun createRichWorkspace() = Unit
}
val info = DeviceInfo()
val ocFile = OCFile("/test.md").apply {
remoteId = "00000001"
}
val intent = Intent(targetContext, FileDisplayActivity::class.java)
launchActivity<FileDisplayActivity>(intent).use { scenario ->
scenario.onActivity { fda ->
onIdleSync {
EspressoIdlingResource.increment()
// add direct editing info
var directEditing = DirectEditing()
val creators = directEditing.creators.toMutableMap()
val editors = directEditing.editors.toMutableMap()
creators.put(
"1",
Creator(
"1",
"text",
"text file",
".md",
"application/octet-stream",
false
)
)
creators.put(
"2",
Creator(
"2",
"md",
"markdown file",
".md",
"application/octet-stream",
false
)
)
editors.put(
"text",
Editor(
"1",
"Text",
ArrayList(mutableListOf(MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN)),
ArrayList(),
false
)
)
directEditing = DirectEditing(editors, creators)
val json = Gson().toJson(directEditing)
ArbitraryDataProviderImpl(targetContext).storeOrUpdateKeyValue(
user.accountName,
ArbitraryDataProvider.DIRECT_EDITING,
json
)
// activate templates
val capability = fda.capabilities.apply {
richDocuments = CapabilityBooleanType.TRUE
richDocumentsDirectEditing = CapabilityBooleanType.TRUE
richDocumentsTemplatesAvailable = CapabilityBooleanType.TRUE
accountName = user.accountName
}
CapabilityUtils.updateCapability(capability)
val appScanOptionalFeature: AppScanOptionalFeature = object : AppScanOptionalFeature() {
override fun getScanContract(): ActivityResultContract<Unit, String?> =
throw UnsupportedOperationException("Document scan is not available")
}
val materialSchemesProvider = getMaterialSchemesProvider()
val viewThemeUtils = ViewThemeUtils(
materialSchemesProvider.getMaterialSchemesForCurrentUser(),
ColorUtil(targetContext)
)
val editorUtils = EditorUtils(ArbitraryDataProviderImpl(targetContext))
val sut = OCFileListBottomSheetDialog(
fda,
action,
info,
user,
ocFile,
fda.themeUtils,
viewThemeUtils,
editorUtils,
appScanOptionalFeature
)
EspressoIdlingResource.decrement()
sut.show()
sut.behavior.setState(BottomSheetBehavior.STATE_EXPANDED)
val viewGroup = sut.window?.findViewById<ViewGroup>(android.R.id.content) ?: return@onIdleSync
hideCursors(viewGroup)
val screenShotName = createName(testClassName + "_" + "testBottomSheet", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.window?.decorView, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testOnlineStatusBottomSheet() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
// show dialog
val intent = Intent(targetContext, FileDisplayActivity::class.java)
launchActivity<FileDisplayActivity>(intent).use { scenario ->
scenario.onActivity { fda ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SetOnlineStatusBottomSheet(
Status(StatusType.DND, "Focus time", "\uD83E\uDD13", -1)
)
EspressoIdlingResource.decrement()
sut.show(fda.supportFragmentManager, "set_online_status")
val screenShotName = createName(testClassName + "_" + "testOnlineStatusBottomSheet", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.view, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testProfileBottomSheet() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
// Fixed values for HoverCard
val actions: MutableList<Action> = ArrayList()
actions.add(
Action(
"profile",
"View profile",
"https://dev.nextcloud.com/core/img/actions/profile.svg",
"https://dev.nextcloud.com/index.php/u/christine"
)
)
actions.add(
Action(
"core",
"christine.scott@nextcloud.com",
"https://dev.nextcloud.com/core/img/actions/mail.svg",
"mailto:christine.scott@nextcloud.com"
)
)
actions.add(
Action(
"spreed",
"Talk to Christine",
"https://dev.nextcloud.com/apps/spreed/img/app-dark.svg",
"https://dev.nextcloud.com/apps/spreed/?callUser=christine"
)
)
val hoverCard = HoverCard("christine", "Christine Scott", actions)
// show dialog
val intent = Intent(targetContext, FileDisplayActivity::class.java)
launchActivity<FileDisplayActivity>(intent).use { scenario ->
scenario.onActivity { fda ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = ProfileBottomSheetDialog(
fda,
user,
hoverCard,
fda.viewThemeUtils
)
EspressoIdlingResource.decrement()
sut.show()
val screenShotName = createName(testClassName + "_" + "testProfileBottomSheet", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.window?.decorView, screenShotName)
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun testSslUntrustedCertDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val certificate = SslCertificate("foo", "bar", "2022/01/10", "2022/01/30")
val sslError = SslError(SslError.SSL_UNTRUSTED, certificate)
val handler = mockk<SslErrorHandler>(relaxed = true)
newInstanceForEmptySslError(sslError, handler).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testStoragePermissionDialog() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
newInstance(false).run {
showDialog(this)
}
}
@Test
@UiThread
@ScreenshotTest
fun testFileActionsBottomSheet() {
if (Looper.myLooper() == null) {
Looper.prepare()
}
val ocFile = OCFile("/test.md").apply {
remoteId = "0001"
}
newInstance(ocFile, false).run {
showDialog(this)
}
}
private fun showDialog(dialog: DialogFragment) {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
onView(isRoot()).check(matches(isDisplayed()))
showDialog(sut, dialog)
}
}
}
}
private fun showDialog(sut: FileDisplayActivity, dialog: DialogFragment) {
dialog.show(sut.supportFragmentManager, null)
onIdleSync {
val dialogInstance = waitForDialog(dialog)
?: throw IllegalStateException("Dialog was not created")
val viewGroup = dialogInstance.window?.findViewById<ViewGroup>(android.R.id.content) ?: return@onIdleSync
hideCursors(viewGroup)
onView(isRoot()).check(matches(isDisplayed()))
screenshot(dialogInstance.window?.decorView)
}
}
private fun waitForDialog(dialogFragment: DialogFragment, timeoutMs: Long = 5000): Dialog? {
val start = System.currentTimeMillis()
while (System.currentTimeMillis() - start < timeoutMs) {
val dialog = dialogFragment.dialog
if (dialog != null) return dialog
Thread.sleep(100)
}
return null
}
private fun hideCursors(viewGroup: ViewGroup) {
for (i in 0..<viewGroup.childCount) {
val child = viewGroup.getChildAt(i)
if (child is ViewGroup) {
hideCursors(child)
}
if (child is TextView) {
child.isCursorVisible = false
}
}
}
@Test
fun testGson() {
val t = ArrayList<EnforcedServer?>().apply {
add(EnforcedServer("name", "url"))
add(EnforcedServer("name2", "url1"))
}
val s = Gson().toJson(t)
val t2 = Gson().fromJson<ArrayList<EnforcedServer>>(
s,
object : TypeToken<ArrayList<EnforcedServer?>?>() {
}.type
)
val temp = ArrayList<String?>()
for (p in t2) {
temp.add(p.name)
}
}
}

View file

@ -1,26 +1,36 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.dialog
import androidx.annotation.UiThread
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert
import org.junit.Rule
import org.junit.Before
import org.junit.Test
class SendFilesDialogTest : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.dialog.SendFilesDialogTest"
companion object {
private val FILES_SAME_TYPE = setOf(
OCFile("/1.jpg").apply {
@ -43,52 +53,77 @@ class SendFilesDialogTest : AbstractIT() {
)
}
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
private fun showDialog(files: Set<OCFile>): SendFilesDialog {
val activity = testActivityRule.launchActivity(null)
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
val fm: FragmentManager = activity.supportFragmentManager
val ft = fm.beginTransaction()
ft.addToBackStack(null)
private fun showDialog(files: Set<OCFile>, onComplete: (SendFilesDialog) -> Unit) {
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SendFilesDialog.newInstance(files)
sut.show(ft, "TAG_SEND_SHARE_DIALOG")
val fm: FragmentManager = sut.supportFragmentManager
val ft = fm.beginTransaction()
ft.addToBackStack(null)
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
shortSleep()
val dialog = SendFilesDialog.newInstance(files)
dialog.show(ft, "TAG_SEND_SHARE_DIALOG")
onComplete(dialog)
return sut
EspressoIdlingResource.decrement()
}
}
}
}
@Test
@UiThread
@ScreenshotTest
fun showDialog() {
val sut = showDialog(FILES_SAME_TYPE)
val recyclerview: RecyclerView = sut.requireDialog().findViewById(R.id.send_button_recycler_view)
Assert.assertNotNull("Adapter is null", recyclerview.adapter)
Assert.assertNotEquals("Send button list is empty", 0, recyclerview.adapter!!.itemCount)
showDialog(FILES_SAME_TYPE) { sut ->
val recyclerview: RecyclerView = sut.requireDialog().findViewById(R.id.send_button_recycler_view)
Assert.assertNotNull("Adapter is null", recyclerview.adapter)
Assert.assertNotEquals("Send button list is empty", 0, recyclerview.adapter!!.itemCount)
}
}
@Test
@UiThread
@ScreenshotTest
fun showDialog_Screenshot() {
val sut = showDialog(FILES_SAME_TYPE)
sut.requireDialog().window?.decorView.let { screenshot(it) }
showDialog(FILES_SAME_TYPE) { sut ->
val screenShotName = createName(testClassName + "_" + "showDialog_Screenshot", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.requireDialog().window?.decorView, screenShotName)
}
}
@Test
@UiThread
@ScreenshotTest
fun showDialogDifferentTypes() {
val sut = showDialog(FILES_MIXED_TYPE)
val recyclerview: RecyclerView = sut.requireDialog().findViewById(R.id.send_button_recycler_view)
Assert.assertNotNull("Adapter is null", recyclerview.adapter)
Assert.assertNotEquals("Send button list is empty", 0, recyclerview.adapter!!.itemCount)
showDialog(FILES_MIXED_TYPE) { sut ->
val recyclerview: RecyclerView = sut.requireDialog().findViewById(R.id.send_button_recycler_view)
Assert.assertNotNull("Adapter is null", recyclerview.adapter)
Assert.assertNotEquals("Send button list is empty", 0, recyclerview.adapter!!.itemCount)
}
}
@Test
@UiThread
@ScreenshotTest
fun showDialogDifferentTypes_Screenshot() {
val sut = showDialog(FILES_MIXED_TYPE)
sut.requireDialog().window?.decorView.let { screenshot(it) }
showDialog(FILES_MIXED_TYPE) { sut ->
val screenShotName = createName(testClassName + "_" + "showDialogDifferentTypes_Screenshot", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.requireDialog().window?.decorView, screenShotName)
}
}
}

View file

@ -1,46 +1,55 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.dialog
import androidx.annotation.UiThread
import androidx.fragment.app.FragmentManager
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.resources.status.OCCapability
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.Test
class SendShareDialogTest : AbstractIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.dialog.SendShareDialogTest"
@Test
@UiThread
@ScreenshotTest
fun showDialog() {
val activity = testActivityRule.launchActivity(null)
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val fm: FragmentManager = activity.supportFragmentManager
val ft = fm.beginTransaction()
ft.addToBackStack(null)
val fm: FragmentManager = activity.supportFragmentManager
val ft = fm.beginTransaction()
ft.addToBackStack(null)
val file = OCFile("/1.jpg").apply {
mimeType = "image/jpg"
}
EspressoIdlingResource.decrement()
val file = OCFile("/1.jpg").apply {
mimeType = "image/jpg"
val sut = SendShareDialog.newInstance(file, false, OCCapability())
sut.show(ft, "TAG_SEND_SHARE_DIALOG")
val screenShotName = createName(testClassName + "_" + "showDialog", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.requireDialog().window?.decorView, screenShotName)
}
}
}
val sut = SendShareDialog.newInstance(file, false, OCCapability())
sut.show(ft, "TAG_SEND_SHARE_DIALOG")
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
shortSleep()
shortSleep()
sut.requireDialog().window?.decorView.let { screenshot(it) }
}
}

View file

@ -1,79 +1,101 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.dialog
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class SetupEncryptionDialogFragmentIT : AbstractIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun showMnemonic() {
val activity = testActivityRule.launchActivity(null)
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SetupEncryptionDialogFragment.newInstance(user, 0)
val sut = SetupEncryptionDialogFragment.newInstance(user, 0)
sut.show(activity.supportFragmentManager, "1")
sut.show(activity.supportFragmentManager, "1")
val keyWords = arrayListOf(
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"absurd",
"abuse",
"access",
"accident",
"account",
"accuse"
)
sut.setMnemonic(keyWords)
sut.showMnemonicInfo()
EspressoIdlingResource.decrement()
val keyWords = arrayListOf(
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"absurd",
"abuse",
"access",
"accident",
"account",
"accuse"
)
shortSleep()
runOnUiThread {
sut.setMnemonic(keyWords)
sut.showMnemonicInfo()
val screenShotName = createName(testClassName + "_" + "showMnemonic", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.requireDialog().window?.decorView, screenShotName)
}
}
}
waitForIdleSync()
screenshot(sut.requireDialog().window!!.decorView)
}
@Test
@UiThread
@ScreenshotTest
fun error() {
val activity = testActivityRule.launchActivity(null)
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
onIdleSync {
EspressoIdlingResource.increment()
val sut = SetupEncryptionDialogFragment.newInstance(user, 0)
val sut = SetupEncryptionDialogFragment.newInstance(user, 0)
sut.show(activity.supportFragmentManager, "1")
sut.errorSavingKeys()
sut.show(activity.supportFragmentManager, "1")
EspressoIdlingResource.decrement()
shortSleep()
runOnUiThread {
sut.errorSavingKeys()
val screenShotName = createName(testClassName + "_" + "error", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut.requireDialog().window?.decorView, screenShotName)
}
}
}
shortSleep()
waitForIdleSync()
screenshot(sut.requireDialog().window!!.decorView)
}
}

View file

@ -0,0 +1,89 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android.ui.dialog
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.owncloud.android.AbstractIT
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.dialog.SyncFileNotEnoughSpaceDialogFragment.Companion.newInstance
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Before
import org.junit.Test
class SyncFileNotEnoughSpaceDialogFragmentTest : AbstractIT() {
private val testClassName = "com.owncloud.android.ui.dialog.SyncFileNotEnoughSpaceDialogFragmentTest"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@ScreenshotTest
@UiThread
fun showNotEnoughSpaceDialogForFolder() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
val ocFile = OCFile("/Document/").apply {
fileLength = 5000000
setFolder()
}
onIdleSync {
EspressoIdlingResource.increment()
newInstance(ocFile, 1000).apply {
show(sut.supportFragmentManager, "1")
}
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "showNotEnoughSpaceDialogForFolder", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
@Test
@ScreenshotTest
@UiThread
fun showNotEnoughSpaceDialogForFile() {
launchActivity<FileDisplayActivity>().use { scenario ->
scenario.onActivity { sut ->
val ocFile = OCFile("/Video.mp4").apply {
fileLength = 1000000
}
onIdleSync {
EspressoIdlingResource.increment()
newInstance(ocFile, 2000).apply {
show(sut.supportFragmentManager, "2")
}
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "showNotEnoughSpaceDialogForFile", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
}
}

View file

@ -1,15 +1,21 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.fragment
import android.graphics.BitmapFactory
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
import androidx.annotation.UiThread
import androidx.test.core.app.launchActivity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
@ -17,155 +23,171 @@ import com.owncloud.android.lib.resources.users.StatusType
import com.owncloud.android.ui.TextDrawable
import com.owncloud.android.utils.BitmapUtils
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.utils.EspressoIdlingResource
import com.owncloud.android.utils.ScreenshotTest
import org.junit.Rule
import org.junit.After
import org.junit.Before
import org.junit.Test
class AvatarIT : AbstractIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
private val testClassName = "com.owncloud.android.ui.fragment.AvatarIT"
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
}
@Test
@UiThread
@ScreenshotTest
fun showAvatars() {
val avatarRadius = targetContext.resources.getDimension(R.dimen.list_item_avatar_icon_radius)
val width = DisplayUtils.convertDpToPixel(2 * avatarRadius, targetContext)
val sut = testActivityRule.launchActivity(null)
val fragment = AvatarTestFragment()
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
sut.addFragment(fragment)
val avatarRadius = targetContext.resources.getDimension(R.dimen.list_item_avatar_icon_radius)
val width = DisplayUtils.convertDpToPixel(2 * avatarRadius, targetContext)
val fragment = AvatarTestFragment()
runOnUiThread {
fragment.addAvatar("Admin", avatarRadius, width, targetContext)
fragment.addAvatar("Test Server Admin", avatarRadius, width, targetContext)
fragment.addAvatar("Cormier Paulette", avatarRadius, width, targetContext)
fragment.addAvatar("winston brent", avatarRadius, width, targetContext)
fragment.addAvatar("Baker James Lorena", avatarRadius, width, targetContext)
fragment.addAvatar("Baker James Lorena", avatarRadius, width, targetContext)
fragment.addAvatar("email@nextcloud.localhost", avatarRadius, width, targetContext)
sut.addFragment(fragment)
fragment.run {
addAvatar("Admin", avatarRadius, width, targetContext)
addAvatar("Test Server Admin", avatarRadius, width, targetContext)
addAvatar("Cormier Paulette", avatarRadius, width, targetContext)
addAvatar("winston brent", avatarRadius, width, targetContext)
addAvatar("Baker James Lorena", avatarRadius, width, targetContext)
addAvatar("Baker James Lorena", avatarRadius, width, targetContext)
addAvatar("email@nextcloud.localhost", avatarRadius, width, targetContext)
}
EspressoIdlingResource.decrement()
val screenShotName = createName(testClassName + "_" + "showAvatars", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
shortSleep()
waitForIdleSync()
screenshot(sut)
}
@Test
@UiThread
@ScreenshotTest
fun showAvatarsWithStatus() {
val avatarRadius = targetContext.resources.getDimension(R.dimen.list_item_avatar_icon_radius)
val width = DisplayUtils.convertDpToPixel(2 * avatarRadius, targetContext)
val sut = testActivityRule.launchActivity(null)
val fragment = AvatarTestFragment()
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { sut ->
onIdleSync {
EspressoIdlingResource.increment()
val paulette = BitmapFactory.decodeFile(getFile("paulette.jpg").absolutePath)
val christine = BitmapFactory.decodeFile(getFile("christine.jpg").absolutePath)
val textBitmap = BitmapUtils.drawableToBitmap(TextDrawable.createNamedAvatar("Admin", avatarRadius))
val avatarRadius = targetContext.resources.getDimension(R.dimen.list_item_avatar_icon_radius)
val width = DisplayUtils.convertDpToPixel(2 * avatarRadius, targetContext)
val fragment = AvatarTestFragment()
sut.addFragment(fragment)
val paulette = BitmapFactory.decodeFile(getFile("paulette.jpg").absolutePath)
val christine = BitmapFactory.decodeFile(getFile("christine.jpg").absolutePath)
val textBitmap = BitmapUtils.drawableToBitmap(TextDrawable.createNamedAvatar("Admin", avatarRadius))
runOnUiThread {
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.ONLINE, "😘", targetContext),
width * 2,
1,
targetContext
)
sut.addFragment(fragment)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "☁️", targetContext),
width * 2,
1,
targetContext
)
fragment.run {
addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.ONLINE, "😘", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "☁️", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "🌴️", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.DND, "", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.AWAY, "", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.OFFLINE, "", targetContext),
width * 2,
1,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "😘", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "☁️", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "🌴️", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.DND, "", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.AWAY, "", targetContext),
width,
2,
targetContext
)
addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.OFFLINE, "", targetContext),
width,
2,
targetContext
)
}
EspressoIdlingResource.decrement()
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "🌴️", targetContext),
width * 2,
1,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.ONLINE, "", targetContext),
width * 2,
1,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.DND, "", targetContext),
width * 2,
1,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(christine, StatusType.AWAY, "", targetContext),
width * 2,
1,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(paulette, StatusType.OFFLINE, "", targetContext),
width * 2,
1,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "😘", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "☁️", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "🌴️", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.ONLINE, "", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.DND, "", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.AWAY, "", targetContext),
width,
2,
targetContext
)
fragment.addBitmap(
BitmapUtils.createAvatarWithStatus(textBitmap, StatusType.OFFLINE, "", targetContext),
width,
2,
targetContext
)
val screenShotName = createName(testClassName + "_" + "showAvatarsWithStatus", "")
onView(isRoot()).check(matches(isDisplayed()))
screenshotViaName(sut, screenShotName)
}
}
}
shortSleep()
waitForIdleSync()
screenshot(sut)
}
}

View file

@ -3,7 +3,7 @@
*
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.owncloud.android.ui.fragment
@ -21,8 +21,8 @@ import com.owncloud.android.R
import com.owncloud.android.ui.TextDrawable
internal class AvatarTestFragment : Fragment() {
lateinit var list1: LinearLayout
lateinit var list2: LinearLayout
private lateinit var list1: LinearLayout
private lateinit var list2: LinearLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.avatar_fragment, null)
@ -34,7 +34,7 @@ internal class AvatarTestFragment : Fragment() {
}
fun addAvatar(name: String, avatarRadius: Float, width: Int, targetContext: Context) {
val margin = padding
val margin = PADDING
val imageView = ImageView(targetContext)
imageView.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadius))
@ -47,7 +47,7 @@ internal class AvatarTestFragment : Fragment() {
}
fun addBitmap(bitmap: Bitmap, width: Int, list: Int, targetContext: Context) {
val margin = padding
val margin = PADDING
val imageView = ImageView(targetContext)
imageView.setImageBitmap(bitmap)
@ -64,6 +64,6 @@ internal class AvatarTestFragment : Fragment() {
}
companion object {
private const val padding = 10
private const val PADDING = 10
}
}

Some files were not shown because too many files have changed in this diff Show more