Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions app/src/androidTest/java/com/nmc/android/ConflictDialogResourceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nmc.android

import android.content.Context
import android.content.res.Configuration
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.owncloud.android.R
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Locale

/**
* Test class to verify the strings customized in this branch PR for NMC
*/
@RunWith(AndroidJUnit4::class)
class ConflictDialogResourceTest {

private val baseContext = ApplicationProvider.getApplicationContext<Context>()

private val localizedStringMap = mapOf(
R.string.conflict_replace to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Replace",
Locale.GERMAN to "Ersetzen"
)
),
R.string.conflict_replace_all to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Replace all",
Locale.GERMAN to "Alle ersetzen"
)
),
R.string.conflict_keep_both to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Keep both",
Locale.GERMAN to "Beide behalten"
)
),
R.string.conflict_keep_both_all to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Keep both for all",
Locale.GERMAN to "Beide Versionen für alle behalten"
)
),
R.string.conflict_more_details to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "More details",
Locale.GERMAN to "Mehr Details"
)
),
R.string.conflict_cancel_keep_existing to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Cancel and keep existing",
Locale.GERMAN to "Abbrechen und bestehende Datei behalten"
)
),
R.string.conflict_dialog_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "File conflict",
Locale.GERMAN to "Dateikonflikt"
)
),
R.string.conflict_dialog_title_multiple to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "%d File conflicts",
Locale.GERMAN to "%d Dateikonflikte"
)
),
R.string.conflict_dialog_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "%1\$s already exists in this location. Do you want to replace it with the file you are moving?",
Locale.GERMAN to "%1\$s ist im Zielordner bereits vorhanden. Möchten Sie die bestehende Datei behalten oder überschreiben?"
)
),
R.string.conflict_dialog_message_multiple to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "The files already exist in this location. Do you want to replace them with the files you are moving?",
Locale.GERMAN to "Die Dateien sind im Zielordner bereits vorhanden. Möchten Sie die bestehenden Dateien behalten oder überschreiben?"
)
),
)

@Test
fun verifyLocalizedStrings() {
localizedStringMap.forEach { (stringRes, expected) ->
expected.translations.forEach { (locale, expectedText) ->

val config = Configuration(baseContext.resources.configuration)
config.setLocale(locale)

val localizedContext = baseContext.createConfigurationContext(config)
val actualText = localizedContext.getString(stringRes)

assertEquals(
"Mismatch for ${baseContext.resources.getResourceEntryName(stringRes)} in $locale",
expectedText,
actualText
)
}
}
}

data class ExpectedLocalizedString(val translations: Map<Locale, String>)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nmc.android.ui.conflict

import android.content.Intent
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry
import com.nextcloud.client.account.UserAccountManagerImpl
import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog.Companion.newInstance
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.activity.ConflictsResolveActivity
import com.owncloud.android.ui.activity.FileActivity
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
import com.owncloud.android.utils.FileStorageUtils
import junit.framework.TestCase
import org.junit.After
import org.junit.Assert
import org.junit.Rule
import org.junit.Test

class ConflictsResolveConsentDialogIT : AbstractIT() {
@get:Rule
val activityRule = IntentsTestRule(ConflictsResolveActivity::class.java, true, false)

private var returnCode = false

@Test
fun replaceWithNewFile() {
returnCode = false

val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)

val existingFile = OCFile("/newFile.txt")
existingFile.fileLength = 1024000
existingFile.modificationTimestamp = 1582019340
existingFile.remoteId = "00000123abc"

val newFile = OCFile("/newFile.txt")
newFile.fileLength = 56000
newFile.modificationTimestamp = 1522019340
newFile.storagePath = 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)
intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)

val sut = activityRule.launchActivity(intent)

val dialog = newInstance(
targetContext,
existingFile,
newFile,
UserAccountManagerImpl
.fromContext(targetContext)
.user
)
dialog.showDialog(sut)

sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
Assert.assertEquals(decision, Decision.KEEP_LOCAL)
returnCode = true
}

InstrumentationRegistry.getInstrumentation().waitForIdleSync()

Espresso.onView(ViewMatchers.withId(R.id.replace_btn)).perform(ViewActions.click())

TestCase.assertTrue(returnCode)
}

@Test
fun keepBothFiles() {
returnCode = false

val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)

val existingFile = OCFile("/newFile.txt")
existingFile.fileLength = 1024000
existingFile.modificationTimestamp = 1582019340

val newFile = OCFile("/newFile.txt")
newFile.fileLength = 56000
newFile.modificationTimestamp = 1522019340
newFile.storagePath = 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(FileActivity.EXTRA_USER, user)
intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)

val sut = activityRule.launchActivity(intent)

val dialog = newInstance(
targetContext,
existingFile,
newFile,
UserAccountManagerImpl
.fromContext(targetContext)
.user
)
dialog.showDialog(sut)

sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
Assert.assertEquals(decision, Decision.KEEP_BOTH)
returnCode = true
}

InstrumentationRegistry.getInstrumentation().waitForIdleSync()

Espresso.onView(ViewMatchers.withId(R.id.keep_both_btn)).perform(ViewActions.click())

TestCase.assertTrue(returnCode)
}

@Test
fun keepExistingFile() {
returnCode = false

val newUpload = OCUpload(
FileStorageUtils.getSavePath(user.accountName) + "/nonEmpty.txt",
"/newFile.txt",
user.accountName
)

val existingFile = OCFile("/newFile.txt")
existingFile.fileLength = 1024000
existingFile.modificationTimestamp = 1582019340

val newFile = OCFile("/newFile.txt")
newFile.fileLength = 56000
newFile.modificationTimestamp = 1522019340
newFile.storagePath = 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(FileActivity.EXTRA_USER, user)
intent.putExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, newUpload.uploadId)
intent.putExtra(ConflictsResolveActivity.EXTRA_LAUNCHED_FROM_TEST, true)

val sut = activityRule.launchActivity(intent)

val dialog = newInstance(
targetContext,
existingFile,
newFile,
UserAccountManagerImpl
.fromContext(targetContext)
.user
)
dialog.showDialog(sut)

sut.listener = OnConflictDecisionMadeListener { decision: Decision? ->
Assert.assertEquals(decision, Decision.KEEP_SERVER)
returnCode = true
}

InstrumentationRegistry.getInstrumentation().waitForIdleSync()

Espresso.onView(ViewMatchers.withId(R.id.cancel_keep_existing_btn)).perform(ViewActions.click())

TestCase.assertTrue(returnCode)
}

@After
override fun after() {
storageManager.deleteAllFiles()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.nextcloud.ui.composeActivity.ComposeActivity;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
import com.nextcloud.ui.trashbinFileActions.TrashbinFileActionsBottomSheet;
import com.nmc.android.ui.conflict.ConflictsResolveConsentDialog;
import com.nmc.android.ui.LauncherActivity;
import com.owncloud.android.MainApp;
import com.owncloud.android.authentication.AuthenticatorActivity;
Expand Down Expand Up @@ -381,6 +382,9 @@ abstract class ComponentsModule {
@ContributesAndroidInjector
abstract ConflictsResolveDialog conflictsResolveDialog();

@ContributesAndroidInjector
abstract ConflictsResolveConsentDialog conflictsResolveConsentDialog();

@ContributesAndroidInjector
abstract CreateFolderDialogFragment createFolderDialogFragment();

Expand Down
Loading