From 300eb6fd4cd94f6adeb04a81cfcf6fc996798f2a Mon Sep 17 00:00:00 2001 From: daniele-verducci Date: Thu, 15 Oct 2026 10:27:06 +0200 Subject: [PATCH 1/4] Fix: areImageDimensionsSame remote file check is now symmetric to local one (it doesn't fail when dimensions are unknown) Signed-off-by: daniele-verducci --- .../utils/extensions/RemoteFileExtensions.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt index ed7590991eb1..3cfb152dadeb 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt @@ -9,6 +9,7 @@ package com.nextcloud.utils.extensions import com.nextcloud.utils.AppConstants import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.shares.ShareeUser import com.owncloud.android.lib.resources.tags.Tag @@ -51,17 +52,24 @@ fun RemoteFile.toAlbumItem(): OCFile = FileStorageUtils.fillOCFile(this).apply { @Suppress("ReturnCount") private fun RemoteFile.areImageDimensionsSame(path: String): Boolean { + val TAG = "areImageDimensionsSame" if (!MimeTypeUtil.isImage(mimeType)) { - // can't compare it's not image + Log_OC.i(TAG, "Can't compare: it's not an image") return true } val localFileImageDimension = path.getExifSize() ?: path.getBitmapSize() if (localFileImageDimension == null) { - // can't compare local file image dimension is not determined + Log_OC.w(TAG, "Can't compare: local file image dimension is not determined") return true } - return localFileImageDimension.first.toFloat() == imageDimension?.width && - localFileImageDimension.second.toFloat() == imageDimension?.height + val remoteFileImageDimension = imageDimension + if (remoteFileImageDimension == null) { + Log_OC.w(TAG, "Can't compare: remote file image dimension is not determined") + return true + } + + return localFileImageDimension.first.toFloat() == remoteFileImageDimension.width && + localFileImageDimension.second.toFloat() == remoteFileImageDimension.height } From 5d8435163904c3e8284819d81d8a639ddaed886e Mon Sep 17 00:00:00 2001 From: daniele-verducci Date: Thu, 15 Oct 2026 14:11:50 +0200 Subject: [PATCH 2/4] Implemented tests Signed-off-by: daniele-verducci # Conflicts: # app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt --- .../RemoteFileExtensionsImageTest.kt | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt diff --git a/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt b/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt new file mode 100644 index 000000000000..48e2b4fa73b3 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt @@ -0,0 +1,131 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.extensions + +import android.graphics.Bitmap +import com.nextcloud.utils.extensions.areImageDimensionsSame +import com.owncloud.android.lib.resources.files.model.ImageDimension +import com.owncloud.android.lib.resources.files.model.RemoteFile +import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import java.io.File +import java.io.OutputStream +import java.nio.file.Files +import java.nio.file.Path +import kotlin.io.path.exists + +class RemoteFileExtensionsImageTest { + + private lateinit var tempDir: Path + + @Test + fun remoteFileAreImageDimensionsSame_checkForAllConditions() { + val remoteFile = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = ImageDimension(IMAGE_WIDTH.toFloat(), IMAGE_HEIGHT.toFloat()) + } + + // local not an image + assertTrue( + "comparing with non-image", + remoteFile.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) + ) + + // same dimensions + assertTrue( + "comparing with same-size image", + remoteFile.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) + ) + + // different dimensions + val biggerRemoteImage = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = ImageDimension((IMAGE_WIDTH * 2).toFloat(), IMAGE_HEIGHT.toFloat()) + } + assertFalse( + "comparing with different-size image", + biggerRemoteImage.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) + ) + } + + @Test + fun remoteFileAreImageDimensionsSame_checkForEdgeCases() { + val remoteFileWithDimensions = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = ImageDimension(IMAGE_WIDTH.toFloat(), IMAGE_HEIGHT.toFloat()) + } + val remoteFileWithoutDimensions = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = null + } + + // local file with null dimensions + assertTrue( + "comparing null-dimensions local file with valid remote file", + remoteFileWithoutDimensions.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) + ) + + // remote file with null dimensions + assertTrue( + "comparing with null-dimensions remote file", + remoteFileWithoutDimensions.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) + ) + + // both files with null dimensions + assertTrue( + "comparing null-dimensions local file with null-dimensions remote file", + remoteFileWithoutDimensions.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) + ) + } + + @After + fun cleanup() { + val tf = File(getPath(TEXT_FILENAME).toUri()) + val imgf = File(getPath(IMAGE_FILENAME).toUri()) + tf.delete() + imgf.delete() + } + + @Before + fun setup() { + tempDir = Files.createTempDirectory(TMP_DIR) + assertTrue("Temp directory should exist", tempDir.exists()) + + createImageFile() + createTextFile() + } + + private fun getPath(filename: String): Path = tempDir.resolve("test_$filename") + + private fun createImageFile() { + val bitmap = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888) + val imagePath = getPath(IMAGE_FILENAME) + + Files.newOutputStream(imagePath).use { out: OutputStream -> + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out) + } + + assertTrue(imagePath.exists()) + } + + private fun createTextFile() { + val f = File(getPath(TEXT_FILENAME).toUri()) + f.writeText("Lorem ipsum") + } + + companion object { + val TMP_DIR = "remoteFileExtensionsTest" + val TEXT_FILENAME = "text.txt" + val IMAGE_FILENAME = "image.jpg" + + val IMAGE_WIDTH = 123 + val IMAGE_HEIGHT = 45 + } +} From 62e06864a1ff593ef1bc0a40ed4d7f82ee3387bd Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 20 Oct 2026 07:29:27 +0200 Subject: [PATCH 3/4] rebase Signed-off-by: alperozturk96 --- .../utils/extensions/RemoteFileExtensions.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt index 3cfb152dadeb..108840b5138e 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/RemoteFileExtensions.kt @@ -7,6 +7,7 @@ package com.nextcloud.utils.extensions +import androidx.annotation.VisibleForTesting import com.nextcloud.utils.AppConstants import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.utils.Log_OC @@ -17,6 +18,8 @@ import com.owncloud.android.utils.FileStorageUtils import com.owncloud.android.utils.FileUtil import com.owncloud.android.utils.MimeTypeUtil +private const val TAG = "RemoteFileExtensions" + fun RemoteFile.isSame(path: String?): Boolean { val localFile = path?.toFile() ?: return false @@ -51,22 +54,22 @@ fun RemoteFile.toAlbumItem(): OCFile = FileStorageUtils.fillOCFile(this).apply { } @Suppress("ReturnCount") -private fun RemoteFile.areImageDimensionsSame(path: String): Boolean { - val TAG = "areImageDimensionsSame" +@VisibleForTesting +fun RemoteFile.areImageDimensionsSame(path: String): Boolean { if (!MimeTypeUtil.isImage(mimeType)) { - Log_OC.i(TAG, "Can't compare: it's not an image") + Log_OC.i(TAG, "areImageDimensionsSame: Can't compare: it's not an image") return true } val localFileImageDimension = path.getExifSize() ?: path.getBitmapSize() if (localFileImageDimension == null) { - Log_OC.w(TAG, "Can't compare: local file image dimension is not determined") + Log_OC.w(TAG, "areImageDimensionsSame: Can't compare: local file image dimension is not determined") return true } val remoteFileImageDimension = imageDimension if (remoteFileImageDimension == null) { - Log_OC.w(TAG, "Can't compare: remote file image dimension is not determined") + Log_OC.w(TAG, "areImageDimensionsSame: Can't compare: remote file image dimension is not determined") return true } From 332f6f58ce0eec53155cc120f591102e10fe3795 Mon Sep 17 00:00:00 2001 From: daniele-verducci Date: Wed, 21 Oct 2026 12:03:36 +0200 Subject: [PATCH 4/4] Refactored tests Signed-off-by: daniele-verducci --- .../RemoteFileExtensionsImageTest.kt | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt b/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt index 48e2b4fa73b3..12a1b93915eb 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/RemoteFileExtensionsImageTest.kt @@ -1,7 +1,8 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2026 Your Name + * SPDX-FileCopyrightText: 2026 Daniele Verducci + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ package com.nextcloud.extensions @@ -24,26 +25,35 @@ import kotlin.io.path.exists class RemoteFileExtensionsImageTest { private lateinit var tempDir: Path + private val remoteFileWithDimensions = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = ImageDimension(IMAGE_WIDTH.toFloat(), IMAGE_HEIGHT.toFloat()) + } + private val remoteFileWithoutDimensions = RemoteFile().apply { + mimeType = "image/jpeg" + imageDimension = null + } @Test - fun remoteFileAreImageDimensionsSame_checkForAllConditions() { - val remoteFile = RemoteFile().apply { - mimeType = "image/jpeg" - imageDimension = ImageDimension(IMAGE_WIDTH.toFloat(), IMAGE_HEIGHT.toFloat()) - } - + fun testAreImageDimensionsSameWhenLocalFileIsNotImage_ShouldReturnTrue() { // local not an image assertTrue( "comparing with non-image", - remoteFile.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) + remoteFileWithDimensions.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) ) + } + @Test + fun testAreImageDimensionsSame_ShouldReturnTrue() { // same dimensions assertTrue( "comparing with same-size image", - remoteFile.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) + remoteFileWithDimensions.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) ) + } + @Test + fun testAreImageDimensionsSame_ShouldReturnFalse() { // different dimensions val biggerRemoteImage = RemoteFile().apply { mimeType = "image/jpeg" @@ -56,28 +66,25 @@ class RemoteFileExtensionsImageTest { } @Test - fun remoteFileAreImageDimensionsSame_checkForEdgeCases() { - val remoteFileWithDimensions = RemoteFile().apply { - mimeType = "image/jpeg" - imageDimension = ImageDimension(IMAGE_WIDTH.toFloat(), IMAGE_HEIGHT.toFloat()) - } - val remoteFileWithoutDimensions = RemoteFile().apply { - mimeType = "image/jpeg" - imageDimension = null - } - + fun testAreImageDimensionsSameWhenLocalFileHasNoDimensions_ShouldReturnTrue() { // local file with null dimensions assertTrue( "comparing null-dimensions local file with valid remote file", remoteFileWithoutDimensions.areImageDimensionsSame(getPath(TEXT_FILENAME).toString()) ) + } + @Test + fun testAreImageDimensionsSameWhenRemoteFileHasNoDimensions_ShouldReturnTrue() { // remote file with null dimensions assertTrue( "comparing with null-dimensions remote file", remoteFileWithoutDimensions.areImageDimensionsSame(getPath(IMAGE_FILENAME).toString()) ) + } + @Test + fun testAreImageDimensionsSameWhenBothFilesHaveNoDimensions_ShouldReturnTrue() { // both files with null dimensions assertTrue( "comparing null-dimensions local file with null-dimensions remote file",