From 1e093eea3b064be51742cd9e88005790b393f797 Mon Sep 17 00:00:00 2001 From: Sascha Bieberstein Date: Mon, 4 Mar 2024 15:16:32 +0100 Subject: [PATCH 01/10] Adds an GH action which controls the PR labels before merging --- .github/workflows/enforce-pr-label.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/enforce-pr-label.yml diff --git a/.github/workflows/enforce-pr-label.yml b/.github/workflows/enforce-pr-label.yml new file mode 100644 index 00000000..ee1e10e2 --- /dev/null +++ b/.github/workflows/enforce-pr-label.yml @@ -0,0 +1,25 @@ +name: Enforce PR Labels +on: + pull_request: + types: [opened, labeled, unlabeled, synchronize] +jobs: + label: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: mheap/github-action-required-labels@v5 + with: + mode: minimum + count: 1 + labels: "💣 BREAKING CHANGE, 🧬 Enhancement, 🐛 Bugfix, 🛠️ Maintenance, ⬆️ Dependencies" + add_comment: true + message: "This PR can only be merged after at least one of our categorizing labels has been added: {{ provided }}" + - uses: mheap/github-action-required-labels@v5 + with: + mode: exactly + count: 0 + labels: "🎁 Next version, 🖐 Keep open, 🕔 Wait for sirius" + add_comment: true + message: "This PR can only be merged after all blocking labels have been removed: {{ provided }}" From f77b85237a85a5e5676e76eac99eb59297455e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Mo=CC=88ller?= Date: Thu, 21 Mar 2024 13:18:30 +0100 Subject: [PATCH 02/10] Allow 1 and 0 for boolean values in Value#asBoolean in https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#boolean 1 and 0 are also allowed as valid boolean values. In Some places we read from XML and have StructuredNode.queryValue("VALUE_WITH_0_OR_1").asBoolean(false) which should also return true if the value is 1 - fixes: SE-13483 --- .../java/sirius/kernel/commons/Value.java | 23 +++++++++++-------- .../kotlin/sirius/kernel/commons/ValueTest.kt | 10 +++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/sirius/kernel/commons/Value.java b/src/main/java/sirius/kernel/commons/Value.java index 15bbaed0..349fcd4e 100644 --- a/src/main/java/sirius/kernel/commons/Value.java +++ b/src/main/java/sirius/kernel/commons/Value.java @@ -802,7 +802,7 @@ public String asSmartRoundedString() { * * @param defaultValue the value to be used if the wrapped value cannot be converted to a boolean. * @return true if the wrapped value is true - * or if the string representation of it is {@code "true"}. Returns false otherwise, + * or if the string representation of it is {@code "true"} or {@code "1!"}. Returns false otherwise, * especially if the wrapped value is null */ public boolean asBoolean(boolean defaultValue) { @@ -813,16 +813,21 @@ public boolean asBoolean(boolean defaultValue) { return booleanValue; } - // fast-track for common cases without the need to involve NLS framework - if ("true".equalsIgnoreCase(String.valueOf(data))) { - return true; + String stringValue = String.valueOf(data); + return fastPathBoolean(stringValue).orElseGet(() -> { + return Objects.requireNonNullElse(NLS.parseUserString(Boolean.class, stringValue.trim()), defaultValue); + }); + } + + // fast-track for common boolean cases without the need to involve NLS framework + private Optional fastPathBoolean(String value) { + if ("true".equalsIgnoreCase(value) || "1".equals(value)) { + return Optional.of(true); } - if ("false".equalsIgnoreCase(String.valueOf(data))) { - return false; + if ("false".equalsIgnoreCase(value) || "0".equals(value)) { + return Optional.of(false); } - - return Objects.requireNonNullElse(NLS.parseUserString(Boolean.class, String.valueOf(data).trim()), - defaultValue); + return Optional.empty(); } /** diff --git a/src/test/kotlin/sirius/kernel/commons/ValueTest.kt b/src/test/kotlin/sirius/kernel/commons/ValueTest.kt index b7d2731f..9313c3cf 100644 --- a/src/test/kotlin/sirius/kernel/commons/ValueTest.kt +++ b/src/test/kotlin/sirius/kernel/commons/ValueTest.kt @@ -114,12 +114,16 @@ class ValueTest { @Test fun `Test asBoolean with default`() { assertEquals(false, Value.of("").asBoolean(false)) - assertEquals(false, Value.of("false").asBoolean(false)) - assertEquals(true, Value.of("true").asBoolean(false)) assertEquals(false, Value.of(false).asBoolean(false)) + assertEquals(false, Value.of("false").asBoolean(false)) + assertEquals(false, Value.of(0).asBoolean(false)) + assertEquals(false, Value.of("0").asBoolean(false)) + assertEquals(false, Value.of(NLS.get("NLS.no")).asBoolean(false)) assertEquals(true, Value.of(true).asBoolean(false)) + assertEquals(true, Value.of("true").asBoolean(false)) + assertEquals(true, Value.of(1).asBoolean(false)) + assertEquals(true, Value.of("1").asBoolean(false)) assertEquals(true, Value.of(NLS.get("NLS.yes")).asBoolean(false)) - assertEquals(false, Value.of(NLS.get("NLS.no")).asBoolean(false)) } @Test From 3aee7a51bcda7a92d8f453143d401c4ceb1f86b1 Mon Sep 17 00:00:00 2001 From: Jakob Vogel Date: Thu, 21 Mar 2024 13:23:46 +0100 Subject: [PATCH 03/10] =?UTF-8?q?Fixes=20typos=20=F0=9F=A7=91=E2=80=8D?= =?UTF-8?q?=F0=9F=8F=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/sirius/kernel/commons/Amount.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/sirius/kernel/commons/Amount.java b/src/main/java/sirius/kernel/commons/Amount.java index 0f43aa2b..9c3e8b13 100644 --- a/src/main/java/sirius/kernel/commons/Amount.java +++ b/src/main/java/sirius/kernel/commons/Amount.java @@ -30,7 +30,7 @@ *

* Adds some extended computations as well as locale aware formatting options to perform "exact" computations on * numeric value. The internal representation is BigDecimal and uses MathContext.DECIMAL128 for - * numerical operations. Also the scale of each value is fixed to 5 decimal places after the comma, since this is + * numerical operations. Also, the scale of each value is fixed to 5 decimal places after the comma, since this is * enough for most business applications and rounds away any rounding errors introduced by doubles. *

* A textual representation can be created by calling one of the toString methods or by supplying @@ -39,7 +39,7 @@ * Note that {@link #toMachineString()} to be used to obtain a technical representation suitable for file formats * like XML etc. This is also used by {@link NLS#toMachineString(Object)}. The default representation uses two * decimal digits. However, if the amount has bed {@link #round(int, RoundingMode) rounded}, the given amount - * of decimals will be used in all subesquent call to {@link #toMachineString()}. Therefore, this can be used to + * of decimals will be used in all subsequent call to {@link #toMachineString()}. Therefore, this can be used to * control the exact formatting (e.g. when writing XML or JSON). *

* Being able to be empty, this class handles null values gracefully, which simplifies many operations. From ebaf1864f7864e95bb9bb9ad504d4e801980e832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Mo=CC=88ller?= Date: Thu, 21 Mar 2024 13:24:05 +0100 Subject: [PATCH 04/10] also use the fast path in coerce and fix default-value behaviour. Therefore add missing tests for coerce with default values and always trim to be less strict BREAKING: Value#coerce(Boolean.class, true) now return true as expected and no longer false if the value is empty - fixes: SE-13483 --- .../java/sirius/kernel/commons/Value.java | 9 ++++--- .../kotlin/sirius/kernel/commons/ValueTest.kt | 26 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/sirius/kernel/commons/Value.java b/src/main/java/sirius/kernel/commons/Value.java index 349fcd4e..cf8bbb7d 100644 --- a/src/main/java/sirius/kernel/commons/Value.java +++ b/src/main/java/sirius/kernel/commons/Value.java @@ -528,12 +528,13 @@ public Value first() { public T coerce(Class targetClazz, T defaultValue) { if (Boolean.class.equals(targetClazz) || boolean.class.equals(targetClazz)) { if (isEmptyString()) { - return (T) Boolean.FALSE; + return defaultValue != null ? defaultValue : (T) Boolean.FALSE; } if (data instanceof Boolean) { return (T) data; } - return (T) NLS.parseMachineString(Boolean.class, String.valueOf(data)); + String stringValue = String.valueOf(data).trim(); + return (T) fastPathBoolean(stringValue).orElseGet(() -> NLS.parseMachineString(Boolean.class, stringValue)); } if (data == null) { return defaultValue; @@ -813,9 +814,9 @@ public boolean asBoolean(boolean defaultValue) { return booleanValue; } - String stringValue = String.valueOf(data); + String stringValue = String.valueOf(data).trim(); return fastPathBoolean(stringValue).orElseGet(() -> { - return Objects.requireNonNullElse(NLS.parseUserString(Boolean.class, stringValue.trim()), defaultValue); + return Objects.requireNonNullElse(NLS.parseUserString(Boolean.class, stringValue), defaultValue); }); } diff --git a/src/test/kotlin/sirius/kernel/commons/ValueTest.kt b/src/test/kotlin/sirius/kernel/commons/ValueTest.kt index 9313c3cf..448b6085 100644 --- a/src/test/kotlin/sirius/kernel/commons/ValueTest.kt +++ b/src/test/kotlin/sirius/kernel/commons/ValueTest.kt @@ -135,14 +135,38 @@ class ValueTest { } @Test - fun `Test coerce boolean and without default`() { + fun `Test coerce boolean without default`() { assertEquals(false, Value.of("").coerce(Boolean::class.java, null)) assertEquals(false, Value.of("false").coerce(Boolean::class.java, null)) assertEquals(true, Value.of("true").coerce(Boolean::class.java, null)) + assertEquals(false, Value.of("0").coerce(Boolean::class.java, null)) + assertEquals(true, Value.of("1").coerce(Boolean::class.java, null)) assertEquals(false, Value.of(false).coerce(Boolean::class.java, null)) assertEquals(true, Value.of(true).coerce(Boolean::class.java, null)) } + @Test + fun `Test coerce boolean with default true`() { + assertEquals(true, Value.of("").coerce(Boolean::class.java, true)) + assertEquals(false, Value.of("false").coerce(Boolean::class.java, true)) + assertEquals(true, Value.of("true").coerce(Boolean::class.java, true)) + assertEquals(false, Value.of("0").coerce(Boolean::class.java, true)) + assertEquals(true, Value.of("1").coerce(Boolean::class.java, true)) + assertEquals(false, Value.of(false).coerce(Boolean::class.java, true)) + assertEquals(true, Value.of(true).coerce(Boolean::class.java, true)) + } + + @Test + fun `Test coerce boolean with default false`() { + assertEquals(false, Value.of("").coerce(Boolean::class.java, false)) + assertEquals(false, Value.of("false").coerce(Boolean::class.java, false)) + assertEquals(true, Value.of("true").coerce(Boolean::class.java, false)) + assertEquals(false, Value.of("0").coerce(Boolean::class.java, false)) + assertEquals(true, Value.of("1").coerce(Boolean::class.java, false)) + assertEquals(false, Value.of(false).coerce(Boolean::class.java, false)) + assertEquals(true, Value.of(true).coerce(Boolean::class.java, false)) + } + @Test fun `Boxing and retrieving an amount works`() { assertEquals(Amount.of(0.00001), Value.of(Amount.of(0.00001)).getAmount()) From c13aa232c00b538fbece58da91ec1c25de17bdac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Mo=CC=88ller?= Date: Thu, 21 Mar 2024 13:24:21 +0100 Subject: [PATCH 05/10] drive-by: typo --- src/main/java/sirius/kernel/commons/AdvancedDateParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/sirius/kernel/commons/AdvancedDateParser.java b/src/main/java/sirius/kernel/commons/AdvancedDateParser.java index da2b76d7..9cb9ddab 100644 --- a/src/main/java/sirius/kernel/commons/AdvancedDateParser.java +++ b/src/main/java/sirius/kernel/commons/AdvancedDateParser.java @@ -27,7 +27,7 @@ * A flexible parser for dates in various formats. *

* It can parse formats like DD.MM.YYYY, DD-MM-YYYY, MM/DD/YYYY or ISO dates like YYYY-MM-DDTHH:MM:SS along with some - * modifiers as decribed below. + * modifiers as described below. *

* A valid expression is defined by the following grammar: *

    From 2d1a2d16decc83c73f4013175a94eff7246e68e0 Mon Sep 17 00:00:00 2001 From: Jakob Vogel Date: Thu, 21 Mar 2024 13:27:17 +0100 Subject: [PATCH 06/10] =?UTF-8?q?Allows=20fetching=20the=20value=20without?= =?UTF-8?q?=20trailing=20zeros=20in=20the=20decimal=20part=20=E2=9C=82?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was originally developed by @idlira in OX's `ItemMasterdataService`. Co-authored-by: Idevaldo de Lira --- src/main/java/sirius/kernel/commons/Amount.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/sirius/kernel/commons/Amount.java b/src/main/java/sirius/kernel/commons/Amount.java index 9c3e8b13..d3a2d871 100644 --- a/src/main/java/sirius/kernel/commons/Amount.java +++ b/src/main/java/sirius/kernel/commons/Amount.java @@ -22,6 +22,7 @@ import java.math.MathContext; import java.math.RoundingMode; import java.text.DecimalFormat; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; @@ -247,6 +248,22 @@ public BigDecimal getAmount() { return value; } + /** + * Unwraps the internally used BigDecimal like {@link #getAmount()}, but also strips trailing zeros from + * the decimal part. + * + * @return the amount with trailing zeros stripped of the decimal part + */ + @Nullable + public BigDecimal fetchAmountWithoutTrailingZeros() { + return Optional.ofNullable(value) + .map(BigDecimal::stripTrailingZeros) + .map(bigDecimal -> bigDecimal.scale() < 0 ? + bigDecimal.setScale(0, RoundingMode.UNNECESSARY) : + bigDecimal) + .orElse(null); + } + /** * Unwraps the internally used BigDecimal with rounding like in {@link #toMachineString()} applied. * This is used for Jackson Object Mapping. From 532dec2e3494dea542c608ceb5f74555b50a3bc9 Mon Sep 17 00:00:00 2001 From: Jakob Vogel Date: Thu, 21 Mar 2024 13:28:00 +0100 Subject: [PATCH 07/10] =?UTF-8?q?Reformats=20code=20=F0=9F=93=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sirius/kernel/commons/AmountTest.kt | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/test/kotlin/sirius/kernel/commons/AmountTest.kt b/src/test/kotlin/sirius/kernel/commons/AmountTest.kt index 9d9b9a0a..3c95d98f 100644 --- a/src/test/kotlin/sirius/kernel/commons/AmountTest.kt +++ b/src/test/kotlin/sirius/kernel/commons/AmountTest.kt @@ -160,7 +160,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 42 | 46.2 42 | 4.2 | 46.2 0 | 42 | 42 @@ -169,9 +169,9 @@ class AmountTest { 42 | | 42 """ ) fun `add() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.add(b)) @@ -179,7 +179,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 42 | -37.8 42 | 4.2 | 37.8 0 | 42 | -42 @@ -188,9 +188,9 @@ class AmountTest { 42 | | 42 """ ) fun `subtract() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.subtract(b)) @@ -198,7 +198,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 42 | 176.4 42 | 4.2 | 176.4 0 | 42 | 0 @@ -207,16 +207,16 @@ class AmountTest { 42 | | """ ) fun `times() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.times(b)) } @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 42 | 0.1 42 | 4.2 | 10 0 | 42 | 0 @@ -225,16 +225,16 @@ class AmountTest { 42 | | """ ) fun `divideBy() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.divideBy(b)) } @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | -4.2 -4.2 | 4.2 42 | -42 @@ -243,15 +243,15 @@ class AmountTest { | """ ) fun `negate() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.negate()) } @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 10 | 4.62 0 | 42 | 0 42 | 0 | 42 @@ -259,9 +259,9 @@ class AmountTest { 42 | | 42 """ ) fun `increasePercent() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.increasePercent(b)) @@ -269,7 +269,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 10 | 3.78 0 | 42 | 0 42 | 0 | 42 @@ -277,9 +277,9 @@ class AmountTest { 42 | | 42""" ) fun `decreasePercent() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.decreasePercent(b)) @@ -287,7 +287,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.2 | 42 | 10 0 | 42 | 0 42 | 0 | @@ -295,9 +295,9 @@ class AmountTest { 42 | | """ ) fun `percentageOf() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.percentageOf(b)) @@ -305,7 +305,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 4.62 | 4.2 | 10 0 | 42 | -100 42 | 0 | @@ -313,9 +313,9 @@ class AmountTest { 42 | | """ ) fun `percentageDifferenceOf() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.percentageDifferenceOf(b)) @@ -323,7 +323,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 0.42 | 42 1 | 100 2 | 200 @@ -331,8 +331,8 @@ class AmountTest { | """ ) fun `toPercent() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.toPercent()) @@ -341,7 +341,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 42 | 0.42 100 | 1 200 | 2 @@ -349,8 +349,8 @@ class AmountTest { | """ ) fun `asDecimal() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.asDecimal()) @@ -358,7 +358,7 @@ class AmountTest { @ParameterizedTest @CsvSource( - delimiter = '|', textBlock = """ + delimiter = '|', textBlock = """ 10 | 2 | 0 10 | 3 | 1 10 | 0 | @@ -367,9 +367,9 @@ class AmountTest { 10 | | """ ) fun `remainder() works as expected`( - @ConvertWith(AmountConverter::class) a: Amount, - @ConvertWith(AmountConverter::class) b: Amount, - @ConvertWith(AmountConverter::class) result: Amount, + @ConvertWith(AmountConverter::class) a: Amount, + @ConvertWith(AmountConverter::class) b: Amount, + @ConvertWith(AmountConverter::class) result: Amount, ) { assertEquals(result, a.remainder(b)) From 8ca81ebd8fb11620993450ccf1942061fd139cd8 Mon Sep 17 00:00:00 2001 From: Jakob Vogel Date: Thu, 21 Mar 2024 13:28:36 +0100 Subject: [PATCH 08/10] =?UTF-8?q?Adds=20test=20for=20method=20stripping=20?= =?UTF-8?q?trailing=20zeros=20=F0=9F=A7=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/sirius/kernel/commons/AmountTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/kotlin/sirius/kernel/commons/AmountTest.kt b/src/test/kotlin/sirius/kernel/commons/AmountTest.kt index 3c95d98f..c28d368c 100644 --- a/src/test/kotlin/sirius/kernel/commons/AmountTest.kt +++ b/src/test/kotlin/sirius/kernel/commons/AmountTest.kt @@ -374,4 +374,20 @@ class AmountTest { assertEquals(result, a.remainder(b)) } + + @ParameterizedTest + @CsvSource( + delimiter = '|', textBlock = """ + 0.420 | 0.42 + 1.0 | 1 + 200 | 200 + 200.0000 | 200 + 600.010 | 600.01""" + ) + fun `getAmountWithoutTrailingZeros() works as expected`( + @ConvertWith(AmountConverter::class) a: Amount, + result: String, + ) { + assertEquals(result, a.fetchAmountWithoutTrailingZeros()?.toPlainString()) + } } From 9503ff583ce11bcd5ca476f84f0372260cdcd9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Mo=CC=88ller?= Date: Thu, 21 Mar 2024 13:43:35 +0100 Subject: [PATCH 09/10] rename method and add javadoc for clarity - fixes: SE-13483 --- src/main/java/sirius/kernel/commons/Value.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/sirius/kernel/commons/Value.java b/src/main/java/sirius/kernel/commons/Value.java index cf8bbb7d..3249d638 100644 --- a/src/main/java/sirius/kernel/commons/Value.java +++ b/src/main/java/sirius/kernel/commons/Value.java @@ -534,7 +534,7 @@ public T coerce(Class targetClazz, T defaultValue) { return (T) data; } String stringValue = String.valueOf(data).trim(); - return (T) fastPathBoolean(stringValue).orElseGet(() -> NLS.parseMachineString(Boolean.class, stringValue)); + return (T) parseWithoutNLS(stringValue).orElseGet(() -> NLS.parseMachineString(Boolean.class, stringValue)); } if (data == null) { return defaultValue; @@ -815,13 +815,18 @@ public boolean asBoolean(boolean defaultValue) { } String stringValue = String.valueOf(data).trim(); - return fastPathBoolean(stringValue).orElseGet(() -> { + return parseWithoutNLS(stringValue).orElseGet(() -> { return Objects.requireNonNullElse(NLS.parseUserString(Boolean.class, stringValue), defaultValue); }); } - // fast-track for common boolean cases without the need to involve NLS framework - private Optional fastPathBoolean(String value) { + /** + * Fast-track for common boolean cases without the need to involve NLS framework + * + * @param value the value to parse + * @return an optional boolean value + */ + private Optional parseWithoutNLS(String value) { if ("true".equalsIgnoreCase(value) || "1".equals(value)) { return Optional.of(true); } From cbb8ee5d6353ba25f1cee9c78833844594946096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20M=C3=B6ller?= Date: Thu, 21 Mar 2024 13:50:48 +0100 Subject: [PATCH 10/10] Update src/main/java/sirius/kernel/commons/Value.java fix typo Co-authored-by: Sascha Bieberstein --- src/main/java/sirius/kernel/commons/Value.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/sirius/kernel/commons/Value.java b/src/main/java/sirius/kernel/commons/Value.java index 3249d638..6b0f0c65 100644 --- a/src/main/java/sirius/kernel/commons/Value.java +++ b/src/main/java/sirius/kernel/commons/Value.java @@ -803,7 +803,7 @@ public String asSmartRoundedString() { * * @param defaultValue the value to be used if the wrapped value cannot be converted to a boolean. * @return true if the wrapped value is true - * or if the string representation of it is {@code "true"} or {@code "1!"}. Returns false otherwise, + * or if the string representation of it is {@code "true"} or {@code "1"}. Returns false otherwise, * especially if the wrapped value is null */ public boolean asBoolean(boolean defaultValue) {