From aa328d3b4586354ce22efe669f81b9ad5aedff30 Mon Sep 17 00:00:00 2001 From: Christian Schmitz Date: Sun, 3 Dec 2023 14:02:34 +0100 Subject: [PATCH] feat: invoke AString format args --- .github/workflows/build.yml | 4 +- .github/workflows/publish.yml | 2 +- .../tynn/astring/ParcelableAStringTest.java | 4 +- .../main/java/xyz/tynn/astring/ToString.java | 28 +++++++- .../kotlin/xyz/tynn/astring/ToStringTest.kt | 70 +++++++++++-------- gradle/libs.versions.toml | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 7 files changed, 73 insertions(+), 41 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 906b926..9d6a4c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: adopt java-version: 17 @@ -29,7 +29,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: adopt java-version: 17 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dfb045a..bcfacfb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: adopt java-version: 17 diff --git a/astring/src/androidTest/java/xyz/tynn/astring/ParcelableAStringTest.java b/astring/src/androidTest/java/xyz/tynn/astring/ParcelableAStringTest.java index e6ed6ea..61941c7 100644 --- a/astring/src/androidTest/java/xyz/tynn/astring/ParcelableAStringTest.java +++ b/astring/src/androidTest/java/xyz/tynn/astring/ParcelableAStringTest.java @@ -24,7 +24,7 @@ public class ParcelableAStringTest { private static final int RES_ID = 123; private static final int QUANTITY = 456; private static final AString FORMAT = new Format(); - private static final Object[] FORMAT_ARGS = {"arg1", 2, 3L, 4.5, 6F, new Date()}; + private static final Object[] FORMAT_ARGS = {"arg1", 2, 3L, 4.5, 6F, new Date(), Wrapper.wrap("test-string")}; @Test public void Wrapper_should_implement_parcelable() { @@ -115,7 +115,7 @@ private static class Format implements AString { @Nullable @Override public String invoke(@NonNull Context context) { - return "%s%d%d%f%f%s"; + return "%s%d%d%f%f%s%s"; } @Override diff --git a/astring/src/main/java/xyz/tynn/astring/ToString.java b/astring/src/main/java/xyz/tynn/astring/ToString.java index 5acd157..dfc8a66 100644 --- a/astring/src/main/java/xyz/tynn/astring/ToString.java +++ b/astring/src/main/java/xyz/tynn/astring/ToString.java @@ -8,6 +8,7 @@ import static androidx.core.os.ParcelCompat.readParcelable; import static androidx.core.os.ParcelCompat.readSerializable; import static java.lang.String.format; +import static java.util.Arrays.copyOf; import static xyz.tynn.astring.Wrapper.NULL; import android.content.Context; @@ -28,12 +29,20 @@ final class ToString implements AString { private final AString delegate; private final Locale locale; - private final Object[] formatArgs; + private final Object[] formatArgs, aStringArgs; private ToString(AString delegate, Locale locale, Object[] formatArgs) { this.delegate = delegate; this.locale = locale; this.formatArgs = formatArgs; + this.aStringArgs = maybeCopyFormatArgs(formatArgs); + } + + private static Object[] maybeCopyFormatArgs(Object[] formatArgs) { + if (formatArgs != null) for (Object arg : formatArgs) + if (arg instanceof AString) + return copyOf(formatArgs, formatArgs.length, Object[].class); + return null; } static AString wrap(AString delegate, Locale locale, Object[] formatArgs) { @@ -53,8 +62,21 @@ static AString wrap(AString delegate, Locale locale, Object[] formatArgs) { @Override public String invoke(@NonNull Context context) { CharSequence formatString = delegate.invoke(context); - return formatString == null ? null : formatArgs == null ? formatString.toString() - : format(getLocale(context), formatString.toString(), formatArgs); + if (formatString == null) return null; + Object[] formatArgs = getFormatArgs(context); + if (formatArgs == null) return formatString.toString(); + return format(getLocale(context), formatString.toString(), formatArgs); + } + + private Object[] getFormatArgs(Context context) { + Object[] formatArgs = this.formatArgs; + if (formatArgs == null) return null; + Object[] aStringArgs = this.aStringArgs; + if (aStringArgs == null) return formatArgs; + for (int i = 0; i < formatArgs.length; i++) + if (formatArgs[i] instanceof AString) + aStringArgs[i] = ((AString) formatArgs[i]).invoke(context); + return aStringArgs; } @SuppressWarnings("deprecation") diff --git a/astring/src/test/kotlin/xyz/tynn/astring/ToStringTest.kt b/astring/src/test/kotlin/xyz/tynn/astring/ToStringTest.kt index acdada2..62f76c8 100644 --- a/astring/src/test/kotlin/xyz/tynn/astring/ToStringTest.kt +++ b/astring/src/test/kotlin/xyz/tynn/astring/ToStringTest.kt @@ -17,6 +17,7 @@ internal class ToStringTest { private val locale = Locale.CANADA private val format = Format() + private val formatArgs = arrayOf('1', 2, "3") @Test fun `invoke should return string without locale`() { @@ -28,17 +29,24 @@ internal class ToStringTest { } assertEquals( - "23", - ToString.wrap(format, null, arrayOf(2, "3")).invoke(context), + "123", + ToString.wrap(format, null, formatArgs).invoke(context), ) } @Test fun `invoke should return string with locale`() { assertEquals( - "23", - ToString.wrap(format, locale, arrayOf(2, "3")) - .invoke(mockk()), + "123", + ToString.wrap(format, locale, formatArgs).invoke(mockk()), + ) + } + + @Test + fun `invoke should invoke AString args`() { + assertEquals( + "123", + ToString.wrap(format, locale, arrayOf("1".asAString(), 2, "3")).invoke(mockk()), ) } @@ -65,20 +73,20 @@ internal class ToStringTest { ToString.wrap(format, locale, arrayOf()) } assertTrue { - ToString.wrap(format, null, arrayOf(2, "3")) == - ToString.wrap(format, null, arrayOf(2, "3")) + ToString.wrap(format, null, formatArgs) == + ToString.wrap(format, null, formatArgs) } assertTrue { - ToString.wrap(format, locale, arrayOf(2, "3")) == - ToString.wrap(format, locale, arrayOf(2, "3")) + ToString.wrap(format, locale, formatArgs) == + ToString.wrap(format, locale, formatArgs) } } @Test fun `equals should be false for non matching locales`() { assertFalse { - ToString.wrap(format, Locale.GERMAN, arrayOf(2, "3")) == - ToString.wrap(format, locale, arrayOf(2, "3")) + ToString.wrap(format, Locale.GERMAN, formatArgs) == + ToString.wrap(format, locale, formatArgs) } } @@ -89,28 +97,28 @@ internal class ToStringTest { ToString.wrap(TextResource(1), null, arrayOf()) } assertFalse { - ToString.wrap(format, null, arrayOf(2, "3")) == - ToString.wrap(TextResource(1), null, arrayOf(2, "3")) + ToString.wrap(format, null, formatArgs) == + ToString.wrap(TextResource(1), null, formatArgs) } } @Test fun `equals should be false for non matching format args`() { assertFalse { - ToString.wrap(format, null, arrayOf(2, 3)) == - ToString.wrap(format, null, arrayOf("2", "3")) + ToString.wrap(format, null, arrayOf(1, 2, 3)) == + ToString.wrap(format, null, formatArgs) } assertFalse { - ToString.wrap(format, locale, arrayOf(2, 3)) == - ToString.wrap(format, locale, arrayOf("2", "3")) + ToString.wrap(format, locale, arrayOf(1, 2, 3)) == + ToString.wrap(format, locale, formatArgs) } assertFalse { ToString.wrap(format, null, arrayOf()) == - ToString.wrap(format, null, arrayOf(2, "3")) + ToString.wrap(format, null, formatArgs) } assertFalse { ToString.wrap(format, locale, arrayOf()) == - ToString.wrap(format, locale, arrayOf(2, "3")) + ToString.wrap(format, locale, formatArgs) } } @@ -152,13 +160,12 @@ internal class ToStringTest { ToString.wrap(format, locale, arrayOf()).hashCode(), ) assertEquals( - 41436, - ToString.wrap(format, null, arrayOf(2, "3")).hashCode(), + 117355, + ToString.wrap(format, null, formatArgs).hashCode(), ) assertEquals( - -1299735837, - ToString.wrap(format, locale, arrayOf(2, "3")) - .hashCode(), + -1299659918, + ToString.wrap(format, locale, formatArgs).hashCode(), ) } @@ -169,18 +176,21 @@ internal class ToStringTest { ToString.wrap(format, null, arrayOf()).toString(), ) assertEquals( - "AString(Format($format,2,3))", - ToString.wrap(format, null, arrayOf(2, "3")).toString(), + "AString(Format($format,AString(CharSequence(1))))", + ToString.wrap(format, null, arrayOf("1".asAString())).toString(), + ) + assertEquals( + "AString(Format($format,1,2,3))", + ToString.wrap(format, null, formatArgs).toString(), ) assertEquals( - "AString(Format($locale,$format,2,3))", - ToString.wrap(format, locale, arrayOf(2, "3")) - .toString(), + "AString(Format($locale,$format,1,2,3))", + ToString.wrap(format, locale, formatArgs).toString(), ) } private class Format : AString { - override fun invoke(context: Context) = "%d%s" + override fun invoke(context: Context) = "%s%d%s" override fun writeToParcel(dest: Parcel, flags: Int) = Unit override fun equals(other: Any?) = other is Format override fun hashCode() = 11 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fd2f304..1781157 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -android = "8.1.4" -compose-compiler = "1.5.4" +android = "8.2.0" +compose-compiler = "1.5.5" kotlin = "1.9.21" [plugins] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8838ba9..e6aba25 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME