From 8bbd2e609d1026e846a4bfd9a58ddf08de675a33 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 12:35:57 +0100 Subject: [PATCH 1/4] fix: eTag comparison Signed-off-by: alperozturk --- .../extensions/StringExtensionTests.kt | 48 +++++++++---------- .../utils/extensions/StringExtensions.kt | 30 +++++------- .../owncloud/android/datamodel/OCFile.java | 2 +- .../operations/RefreshFolderOperation.java | 2 +- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt b/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt index 36600e6caab6..c9985b7309fa 100644 --- a/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt +++ b/app/src/androidTest/java/com/nextcloud/extensions/StringExtensionTests.kt @@ -6,7 +6,7 @@ */ package com.nextcloud.extensions -import com.nextcloud.utils.extensions.isNotBlankAndEquals +import com.nextcloud.utils.extensions.eTagChanged import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue import org.junit.Test @@ -17,160 +17,160 @@ class StringExtensionTests { fun testIsNotBlankAndEqualsWhenGivenBothStringsAreNull() { val str1: String? = null val str2: String? = null - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsNull() { val str1: String? = null val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsNull() { val str1 = "hello" val str2: String? = null - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreEmpty() { val str1 = "" val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsEmpty() { val str1 = "" val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsEmpty() { val str1 = "hello" val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreWhitespaceOnly() { val str1 = " " val str2 = " \t " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenFirstStringIsWhitespaceOnly() { val str1 = " " val str2 = "hello" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenSecondStringIsWhitespaceOnly() { val str1 = "hello" val str2 = " " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenStringsAreDifferentButBothValid() { val str1 = "hello" val str2 = "world" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenStringsHaveDifferentCase() { val str1 = "Hello" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenMixedCaseStrings() { val str1 = "HeLLo WoRLd" val str2 = "hello world" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenUppercaseStrings() { val str1 = "HELLO" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalAndValid() { val str1 = "hello" val str2 = "hello" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpaces() { val str1 = "hello world" val str2 = "hello world" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalSingleCharacter() { val str1 = "a" val str2 = "A" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothStringsAreIdenticalWithSpecialCharacters() { val str1 = "hello@world!123" val str2 = "HELLO@WORLD!123" - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneHasLeadingWhitespaceAndOtherDoesNot() { val str1 = " hello" val str2 = "HELLO" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneHasTrailingWhitespaceAndOtherDoesNot() { val str1 = "hello" val str2 = "HELLO " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenBothHaveIdenticalWhitespacePaddingDifferentCase() { val str1 = " hello " val str2 = " HELLO " - assertTrue(str1.isNotBlankAndEquals(str2)) + assertFalse(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenMixedWhitespaceCharacters() { val str1 = "\t" val str2 = "\n" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsEmpty() { val str1: String? = null val str2 = "" - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } @Test fun testIsNotBlankAndEqualsWhenGivenOneIsNullAndOtherIsWhitespace() { val str1: String? = null val str2 = " " - assertFalse(str1.isNotBlankAndEquals(str2)) + assertTrue(str1.eTagChanged(str2)) } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index b802bac34a55..bd552e5eb76a 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -25,23 +25,19 @@ fun String.removeFileExtension(): String { } } -/** - * Checks if two nullable strings are both valid (non-null, non-empty, non-blank) and equal. - * - * It returns `true` only when both strings meet all the following criteria: - * - Neither string is null - * - Neither string is empty ("") - * - Neither string contains only whitespace characters (spaces, tabs, newlines, etc.) - * - Both strings are equal ignoring case differences - * - * @param other The other nullable string to compare with this string - * @return `true` if both strings are valid and equal ignoring case differences, `false` otherwise - */ -fun String?.isNotBlankAndEquals(other: String?): Boolean = this != null && - other != null && - this.isNotBlank() && - other.isNotBlank() && - this.equals(other, ignoreCase = true) +fun String?.eTagChanged(eTagOnServer: String?): Boolean { + if (eTagOnServer?.isEmpty() == true) { + // provided eTag is empty can't compare treat as eTag changed + return true + } + + return if (this != null) { + !this.equals(eTagOnServer, ignoreCase = true) + } else { + // provided eTag is null can't compare treat as eTag changed + true + } +} fun String.truncateWithEllipsis(limit: Int) = take(limit) + if (length > limit) StringConstants.THREE_DOT else "" diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 11455a2707d2..d9db1173002f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -796,7 +796,7 @@ public String getEtagOnServer() { } public boolean isEtagChanged() { - return !StringExtensionsKt.isNotBlankAndEquals(getEtag(), getEtagOnServer()); + return StringExtensionsKt.eTagChanged(getEtag(), getEtagOnServer()); } public boolean isSharedViaLink() { diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 66bd13aff1a7..43885e40ab89 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -419,7 +419,7 @@ private RemoteOperationResult checkForChanges(OwnCloudClient client) { String remoteFolderETag = remoteFile.getEtag(); if (remoteFolderETag != null) { String localFolderEtag = mLocalFolder.getEtag(); - mRemoteFolderChanged = !StringExtensionsKt.isNotBlankAndEquals(remoteFolderETag, localFolderEtag); + mRemoteFolderChanged = StringExtensionsKt.eTagChanged(remoteFolderETag, localFolderEtag); Log_OC.d( TAG, "📂 eTag check\n" + From d1b6705dc05324800a871b4bb0b24ba820e0049c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 14:48:42 +0100 Subject: [PATCH 2/4] better condition Signed-off-by: alperozturk --- .../nextcloud/utils/extensions/StringExtensions.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index bd552e5eb76a..afab68450edb 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -26,17 +26,12 @@ fun String.removeFileExtension(): String { } fun String?.eTagChanged(eTagOnServer: String?): Boolean { - if (eTagOnServer?.isEmpty() == true) { - // provided eTag is empty can't compare treat as eTag changed + if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { + // provided eTag are empty or null can't compare treat as eTag changed return true } - return if (this != null) { - !this.equals(eTagOnServer, ignoreCase = true) - } else { - // provided eTag is null can't compare treat as eTag changed - true - } + return !this.equals(eTagOnServer, ignoreCase = true) } fun String.truncateWithEllipsis(limit: Int) = take(limit) + if (length > limit) StringConstants.THREE_DOT else "" From a826bdccb9baed8fc4b91e516ea3eb9b66944d46 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 14:49:49 +0100 Subject: [PATCH 3/4] better condition Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/extensions/StringExtensions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index afab68450edb..f79e2ecda00b 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -27,7 +27,7 @@ fun String.removeFileExtension(): String { fun String?.eTagChanged(eTagOnServer: String?): Boolean { if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { - // provided eTag are empty or null can't compare treat as eTag changed + // provided eTags are empty or null can't compare treat as eTag changed return true } From abc8e9956ba9d56b8e01d725952526c39ce08b63 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 18 Dec 2025 16:02:36 +0100 Subject: [PATCH 4/4] fix codacy Signed-off-by: alperozturk --- .../main/java/com/nextcloud/utils/extensions/StringExtensions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index f79e2ecda00b..0f6a4b304f20 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -25,6 +25,7 @@ fun String.removeFileExtension(): String { } } +@Suppress("ComplexCondition") fun String?.eTagChanged(eTagOnServer: String?): Boolean { if (this == null || this.isEmpty() || eTagOnServer == null || eTagOnServer.isEmpty()) { // provided eTags are empty or null can't compare treat as eTag changed