From a7b0c70b296fbb1b7e7aaf1c6708f6dcce79ca3b Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:24:19 +0700 Subject: [PATCH 1/8] Add string extension function to convert a String containing number to readable file size. --- .../android/extensions/StringExt.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt index 66d7d747612..447efd97e8a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt @@ -1,7 +1,12 @@ package com.woocommerce.android.extensions import org.apache.commons.text.StringEscapeUtils +import java.text.DecimalFormat import java.util.Locale +import kotlin.math.log10 +import kotlin.math.pow + +const val BYTES_IN_KILOBYTE = 1024.0 /** * Checks if a given string is a Float @@ -100,3 +105,28 @@ fun String.toCamelCase(delimiter: String = " "): String { fun String.capitalize(locale: Locale = Locale.getDefault()) = replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() } + +/** + * Converts a numeric string representing bytes into a human-readable file size string. + * + * Source: https://stackoverflow.com/a/5599842 + * + * Examples: + * "1024".readableFileSize() -> "1 kB" + * "1500000".readableFileSize() -> "1.4 MB" + * "0".readableFileSize() -> "0" + * Invalid input returns "0" + * + * + * @return Formatted string with size and unit (e.g., "1.5 GB") + */ +fun String.readableFileSize(): String { + val size = this.toLongOrNull() + if (size == null || size <= 0) return "0" + + val units = arrayOf("B", "kB", "MB", "GB", "TB", "PB", "EB") + val digitGroups = (log10(size.toDouble()) / log10(BYTES_IN_KILOBYTE)).toInt() + + return DecimalFormat("#,##0.#") + .format(size / BYTES_IN_KILOBYTE.pow(digitGroups.toDouble())) + " " + units[digitGroups] +} From 58c3a29c5c6aefbad83c5eafe2be53ed5ae32f59 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:26:02 +0700 Subject: [PATCH 2/8] Add unit tests --- .../android/extensions/StringExtTest.kt | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 WooCommerce/src/test/kotlin/com/woocommerce/android/extensions/StringExtTest.kt diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/extensions/StringExtTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/extensions/StringExtTest.kt new file mode 100644 index 00000000000..7b98425c5db --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/extensions/StringExtTest.kt @@ -0,0 +1,57 @@ +package com.woocommerce.android.extensions + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class StringExtTest { + @Test + fun `given string with valid size, when readableFileSize called, then returns formatted size`() { + // Given + val inputs = mapOf( + "1024" to "1 kB", + "1500000" to "1.4 MB", + "1234567" to "1.2 MB", + "1073741824" to "1 GB", + "1099511627776" to "1 TB" + ) + + // When & then + inputs.forEach { (input, expected) -> + assertThat(input.readableFileSize()).isEqualTo(expected) + } + } + + @Test + fun `given zero or negative size, when readableFileSize called, then returns zero`() { + // Given + val inputs = listOf("0", "-1024", "-1") + + // When & then + inputs.forEach { input -> + assertThat(input.readableFileSize()).isEqualTo("0") + } + } + + @Test + fun `given invalid number string, when readableFileSize called, then returns zero`() { + // Given + val inputs = listOf("", "abc", "12.34", "1,000") + + // When & then + inputs.forEach { input -> + assertThat(input.readableFileSize()).isEqualTo("0") + } + } + + @Test + fun `given very large number, when readableFileSize called, then returns correct unit`() { + // Given + val size = "1" + "0".repeat(18) // 1 quintillion bytes + + // When + val result = size.readableFileSize() + + // Then + assertThat(result).isEqualTo("888.2 PB") + } +} From 0b5a08d1ebafd85d0a36cbd1ac7825cc762c8d3a Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:26:27 +0700 Subject: [PATCH 3/8] Replace usage of commons.io function with the newly added function --- .../com/woocommerce/android/extensions/WCSSRModelExt.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt index b226692b3fe..45e47815eb4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt @@ -4,7 +4,6 @@ package com.woocommerce.android.extensions import androidx.core.text.HtmlCompat import com.woocommerce.android.util.WooLog -import org.apache.commons.io.FileUtils.byteCountToDisplaySize import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -110,7 +109,7 @@ private fun formatEnvironmentData(data: JSONObject): String { val memoryLimit = data.optString("wp_memory_limit", MISSING_VALUE) if (memoryLimit != MISSING_VALUE) { - sb.append("WP Memory Limit: ${byteCountToDisplaySize(memoryLimit.toLong())}\n") + sb.append("WP Memory Limit: ${memoryLimit.readableFileSize()}\n") } sb.append("WP Debug Mode: ${checkIfTrue(data.optBoolean("wp_debug_mode", false))}\n") @@ -123,7 +122,7 @@ private fun formatEnvironmentData(data: JSONObject): String { val postMaxSize = data.optString("php_post_max_size", MISSING_VALUE) if (postMaxSize != MISSING_VALUE) { - sb.append("PHP Post Max Size: ${byteCountToDisplaySize(postMaxSize.toLong())}\n") + sb.append("WP Memory Limit: ${postMaxSize.readableFileSize()}\n") } sb.append("PHP Time Limit: ${data.optString("php_max_execution_time", MISSING_VALUE)} s\n") @@ -134,7 +133,7 @@ private fun formatEnvironmentData(data: JSONObject): String { val maxUploadSize = data.optString("max_upload_size", MISSING_VALUE) if (maxUploadSize != MISSING_VALUE) { - sb.append("PHP Post Max Size: ${byteCountToDisplaySize(maxUploadSize.toLong())}\n") + sb.append("WP Memory Limit: ${maxUploadSize.readableFileSize()}\n") } sb.append("Default Timezone: ${data.optString("default_timezone", MISSING_VALUE)}\n") From bc230540ad4c79a0c3b2cda21e12ab008f1bc656 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:26:52 +0700 Subject: [PATCH 4/8] Remove dependency for commons-io now that it's not used anymore. --- WooCommerce/build.gradle | 1 - gradle/libs.versions.toml | 2 -- 2 files changed, 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 8959fc8e102..10af4a18dec 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -442,7 +442,6 @@ dependencies { testImplementation(libs.cashapp.turbine) implementation(libs.apache.commons.text) - implementation(libs.commons.io) implementation(libs.tinder.statemachine) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5db15828723..0725c1c9b5f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,6 @@ bumptech-glide = '4.16.0' cashapp-turbine = '1.0.0' coil = '2.1.0' commons-fileupload = '1.5' -commons-io = '2.11.0' dependency-analysis = '1.28.0' detekt = '1.23.5' facebook-flipper = '0.176.1' @@ -172,7 +171,6 @@ cashapp-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } coil-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" } commons-fileupload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commons-fileupload" } -commons-io = { group = "commons-io", name = "commons-io", version.ref = "commons-io" } detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } facebook-flipper-main = { group = "com.facebook.flipper", name = "flipper", version.ref = "facebook-flipper" } facebook-flipper-network-plugin = { group = "com.facebook.flipper", name = "flipper-network-plugin", version.ref = "facebook-flipper" } From d130bf4d1256bb0353dafb7846ce0058a54e2772 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:33:11 +0700 Subject: [PATCH 5/8] Fix labels --- .../com/woocommerce/android/extensions/WCSSRModelExt.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt index 45e47815eb4..580f24a7392 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt @@ -122,7 +122,7 @@ private fun formatEnvironmentData(data: JSONObject): String { val postMaxSize = data.optString("php_post_max_size", MISSING_VALUE) if (postMaxSize != MISSING_VALUE) { - sb.append("WP Memory Limit: ${postMaxSize.readableFileSize()}\n") + sb.append("PHP Post Max Size: ${postMaxSize.readableFileSize()}\n") } sb.append("PHP Time Limit: ${data.optString("php_max_execution_time", MISSING_VALUE)} s\n") @@ -133,7 +133,7 @@ private fun formatEnvironmentData(data: JSONObject): String { val maxUploadSize = data.optString("max_upload_size", MISSING_VALUE) if (maxUploadSize != MISSING_VALUE) { - sb.append("WP Memory Limit: ${maxUploadSize.readableFileSize()}\n") + sb.append("Max Upload Size: ${maxUploadSize.readableFileSize()}\n") } sb.append("Default Timezone: ${data.optString("default_timezone", MISSING_VALUE)}\n") From 369bcf38b81edbed1cc020ef0efe99aa5a1d65a4 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:34:38 +0700 Subject: [PATCH 6/8] Quick code cleanup --- .../kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt index 580f24a7392..29bee6443af 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt @@ -37,7 +37,7 @@ fun WCSSRModel.formatResult(): String { sb.append(HEADING_SSR) // Environment - environment?.let { it -> + environment?.let { try { sb.append(formatEnvironmentData(JSONObject(it))) } catch (e: JSONException) { From d6a4cd1fa2422928195d0d7fa79623a05cb32efc Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Thu, 5 Dec 2024 13:40:54 +0700 Subject: [PATCH 7/8] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 2343bb3ddda..bf26f1e2931 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -9,6 +9,7 @@ - [Internal] Refactored IPP Payment flow to allow customizing payment collection UI in POS [https://github.com/woocommerce/woocommerce-android/pull/13014] - [*] Blaze Campaign Intro screen now offers creating a new product if the site has no products yet [https://github.com/woocommerce/woocommerce-android/pull/13001] - [*] When entering a wrong WordPress.com account for login, retrying will bring the step back to the email input screen [https://github.com/woocommerce/woocommerce-android/pull/13024] +- [Internal] Replaces a function in WCSSRExt that then removes the need for commons-io dependency. [https://github.com/woocommerce/woocommerce-android/pull/13073] ----- From c616faf6ab1b020567aff9e77393b6e6e2f386f9 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman <hfzrhmn@gmail.com> Date: Wed, 11 Dec 2024 18:31:09 +0700 Subject: [PATCH 8/8] Remove double line break. --- .../main/kotlin/com/woocommerce/android/extensions/StringExt.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt index 447efd97e8a..ac493d8cb62 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt @@ -117,7 +117,6 @@ fun String.capitalize(locale: Locale = Locale.getDefault()) = replaceFirstChar { * "0".readableFileSize() -> "0" * Invalid input returns "0" * - * * @return Formatted string with size and unit (e.g., "1.5 GB") */ fun String.readableFileSize(): String {