Skip to content

Commit

Permalink
feat: allow null AString values as KTX arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
tynn committed Mar 15, 2023
1 parent eaf07af commit 8bf7d28
Show file tree
Hide file tree
Showing 60 changed files with 1,306 additions and 629 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Components provided by the _Material_ components by _Google_:

## License

Copyright (C) 2020-2022 Christian Schmitz
Copyright (C) 2020-2023 Christian Schmitz

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
91 changes: 51 additions & 40 deletions astring/src/main/kotlin/xyz/tynn/astring/AString.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,85 +6,96 @@ package xyz.tynn.astring
import android.content.Context
import android.view.View
import androidx.fragment.app.Fragment
import java.util.Objects.requireNonNull
import kotlin.reflect.KProperty

/**
* Invokes the `AString` with [Fragment.requireContext]
* Invokes the [aString] with [Context]
*/
public operator fun AString.invoke(
fragment: Fragment,
): CharSequence? = invoke(
fragment.requireContext(),
@JvmName("invoke")
public fun Context.aString(
aString: AString?,
): CharSequence? = aString?.invoke(
requireNonNull(this, "context"),
)

/**
* Invokes the `AString` with [View.getContext]
* Invokes the [aString] with [Fragment.requireContext]
*/
public operator fun AString.invoke(
view: View,
): CharSequence? = invoke(
view.context,
@JvmName("invoke")
public fun Fragment.aString(
aString: AString?,
): CharSequence? = aString?.invoke(
requireContext(),
)

/**
* Invokes the [aString] with [View.getContext]
*/
@JvmName("invoke")
public fun View.aString(
aString: AString?,
): CharSequence? = aString?.invoke(
context,
)

/**
* Delegates a `CharSequence?` property within a [Context] to the `AString`
*/
@JvmSynthetic
public operator fun AString.getValue(
public operator fun AString?.getValue(
thisRef: Context,
property: KProperty<*>,
): CharSequence? = invoke(
thisRef,
): CharSequence? = thisRef.aString(
this,
)

/**
* Delegates a `CharSequence?` property within a [Fragment] to the `AString`
*/
@JvmSynthetic
public operator fun AString.getValue(
public operator fun AString?.getValue(
thisRef: Fragment,
property: KProperty<*>,
): CharSequence? = invoke(
thisRef.requireContext(),
): CharSequence? = thisRef.aString(
this,
)

/**
* Delegates a `CharSequence?` property within a [View] to the `AString`
*/
@JvmSynthetic
public operator fun AString.getValue(
public operator fun AString?.getValue(
thisRef: View,
property: KProperty<*>,
): CharSequence? = invoke(
thisRef.context,
)

/**
* Invokes the [aString] with [Context]
*/
@[JvmSynthetic Suppress("NOTHING_TO_INLINE")]
public inline fun Context.aString(
aString: AString,
): CharSequence? = aString(
): CharSequence? = thisRef.aString(
this,
)

/**
* Invokes the [aString] with [Fragment.requireContext]
* Invokes the `AString` with [Fragment.requireContext]
*/
@[JvmSynthetic Suppress("NOTHING_TO_INLINE")]
public inline fun Fragment.aString(
aString: AString,
): CharSequence? = aString(
requireContext(),
@Deprecated(
"Replace with null-safe variant",
ReplaceWith("fragment.aString(this)"),
DeprecationLevel.ERROR,
)
public operator fun AString.invoke(
fragment: Fragment,
): CharSequence? = invoke(
fragment.requireContext(),
)

/**
* Invokes the [aString] with [View.getContext]
* Invokes the `AString` with [View.getContext]
*/
@[JvmSynthetic Suppress("NOTHING_TO_INLINE")]
public inline fun View.aString(
aString: AString,
): CharSequence? = aString(
context,
@Deprecated(
"Replace with null-safe variant",
ReplaceWith("view.aString(this)"),
DeprecationLevel.ERROR,
)
public operator fun AString.invoke(
view: View,
): CharSequence? = invoke(
view.context,
)
32 changes: 16 additions & 16 deletions astring/src/main/kotlin/xyz/tynn/astring/AStringFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,6 @@ import androidx.annotation.StringRes
import xyz.tynn.astring.ContextValueProvider.AppIdProvider
import xyz.tynn.astring.ContextValueProvider.AppVersionProvider

/**
* An `AString` always providing the application id
*
* @see Context.getPackageName
*/
@JvmField
public val appIdAString: AString = AppIdProvider

/**
* An `AString` always providing the application version
*
* @see PackageInfo.versionName
*/
@JvmField
public val appVersionAString: AString = AppVersionProvider

/**
* An `AString` always providing `null`
*/
Expand Down Expand Up @@ -165,3 +149,19 @@ public fun TextResource(
else ResourceDelegate.text(
resId,
)

/**
* An `AString` always providing the application id
*
* @see Context.getPackageName
*/
@JvmField
public val appIdAString: AString = AppIdProvider

/**
* An `AString` always providing the application version
*
* @see PackageInfo.versionName
*/
@JvmField
public val appVersionAString: AString = AppVersionProvider
79 changes: 70 additions & 9 deletions astring/src/test/java/xyz/tynn/astring/AStringKtTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
package xyz.tynn.astring;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static io.mockk.MockKKt.every;

import android.content.Context;
import android.view.View;

import androidx.fragment.app.Fragment;

import org.junit.Rule;
import org.junit.Test;

import io.mockk.impl.annotations.MockK;
import io.mockk.impl.annotations.RelaxedMockK;
import io.mockk.junit4.MockKRule;

Expand All @@ -24,46 +27,104 @@ public class AStringKtTest {
@RelaxedMockK
AString aString;

@MockK
Context context;
@RelaxedMockK
Fragment fragment;
@RelaxedMockK
View view;

@Test
public void invoke_should_delegate_to_context() {
every(scope -> aString.invoke(context)).returns("context");

assertEquals("context", AStringKt.invoke(context, aString));
}

@Test
public void invoke_should_delegate_null_to_context() {
assertNull(AStringKt.invoke(context, null));
}

@SuppressWarnings("ConstantConditions")
@Test(expected = NullPointerException.class)
public void invoke_should_throw_on_null_context() {
AStringKt.invoke((Context) null, aString);
}

@Test
public void invoke_should_delegate_to_fragment() {
every(scope -> aString.invoke(fragment.requireContext())).returns("fragment");

assertEquals("fragment", AStringKt.invoke(aString, fragment));
assertEquals("fragment", AStringKt.invoke(fragment, aString));
}

@Test
public void invoke_should_delegate_null_to_fragment() {
assertNull(AStringKt.invoke(fragment, null));
}

@SuppressWarnings("ConstantConditions")
@Test(expected = NullPointerException.class)
public void invoke_fragment_should_throw_on_null_string_with() {
AStringKt.invoke(null, fragment);
public void invoke_should_throw_on_null_fragment() {
AStringKt.invoke((Fragment) null, aString);
}

@Test
public void invoke_should_delegate_to_view() {
every(scope -> aString.invoke(view.getContext())).returns("view");

assertEquals("view", AStringKt.invoke(view, aString));
}

@Test
public void invoke_should_delegate_null_to_view() {
assertNull(AStringKt.invoke(view, null));
}

@SuppressWarnings("ConstantConditions")
@Test(expected = NullPointerException.class)
public void invoke_should_throw_on_null_fragment() {
public void invoke_should_throw_on_null_view() {
AStringKt.invoke((View) null, aString);
}

@SuppressWarnings("deprecation")
@Test
public void deprecated_invoke_should_delegate_to_fragment() {
every(scope -> aString.invoke(fragment.requireContext())).returns("fragment");

assertEquals("fragment", AStringKt.invoke(aString, fragment));
}

@SuppressWarnings({"ConstantConditions", "deprecation"})
@Test(expected = NullPointerException.class)
public void deprecated_invoke_fragment_should_throw_on_null_string_with() {
AStringKt.invoke(null, fragment);
}

@SuppressWarnings({"ConstantConditions", "deprecation"})
@Test(expected = NullPointerException.class)
public void deprecated_invoke_should_throw_on_null_fragment() {
AStringKt.invoke(aString, (Fragment) null);
}

@SuppressWarnings("deprecation")
@Test
public void invoke_should_delegate_to_view() {
public void deprecated_invoke_should_delegate_to_view() {
every(scope -> aString.invoke(view.getContext())).returns("view");

assertEquals("view", AStringKt.invoke(aString, view));
}

@SuppressWarnings("ConstantConditions")
@SuppressWarnings({"ConstantConditions", "deprecation"})
@Test(expected = NullPointerException.class)
public void invoke_with_view_should_throw_on_null_string() {
public void deprecated_invoke_with_view_should_throw_on_null_string() {
AStringKt.invoke(null, view);
}

@SuppressWarnings("ConstantConditions")
@SuppressWarnings({"ConstantConditions", "deprecation"})
@Test(expected = NullPointerException.class)
public void invoke_should_throw_on_null_view() {
public void deprecated_invoke_should_throw_on_null_view() {
AStringKt.invoke(aString, (View) null);
}
}
23 changes: 15 additions & 8 deletions astring/src/test/kotlin/xyz/tynn/astring/AStringKtKtTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,30 @@ import kotlin.test.Test

internal class AStringKtKtTest {

val aString = mockk<AString>(relaxed = true)
val aContext = mockk<Context>()
private val aString = mockk<AString>(relaxed = true)
private val aContext = mockk<Context>()

@Test
fun `invoke with fragment delegates to context`() {
aString(mockk<Fragment> {
fun `aString with context delegates to this`() {
aContext.aString(aString)

verify { aString(aContext) }
}

@Test
fun `aString with fragment delegates to context`() {
mockk<Fragment> {
every { requireContext() } returns aContext
})
}.aString(aString)

verify { aString(aContext) }
}

@Test
fun `invoke with view delegates to context`() {
aString(mockk<View> {
fun `aString with view delegates to context`() {
mockk<View> {
every { context } returns aContext
})
}.aString(aString)

verify { aString(aContext) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ internal class AppIdProviderTest {
}

@Test
@Suppress("KotlinConstantConditions")
fun `equals should be true for same type`() {
assertTrue {
ContextValueProvider.AppIdProvider == ContextValueProvider.AppIdProvider
}
}

@Test
@Suppress("EqualsBetweenInconvertibleTypes")
@Suppress("EqualsBetweenInconvertibleTypes", "KotlinConstantConditions")
fun `equals should be false for non AppIdProvider`() {
assertFalse {
ContextValueProvider.AppIdProvider.equals("foo")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ internal class AppVersionProviderTest {
}

@Test
@Suppress("KotlinConstantConditions")
fun `equals should be true for same type`() {
assertTrue {
ContextValueProvider.AppVersionProvider == ContextValueProvider.AppVersionProvider
}
}

@Test
@Suppress("EqualsBetweenInconvertibleTypes")
@Suppress("EqualsBetweenInconvertibleTypes", "KotlinConstantConditions")
fun `equals should be false for non AppVersionProvider`() {
assertFalse {
ContextValueProvider.AppVersionProvider.equals("foo")
Expand Down
Loading

0 comments on commit 8bf7d28

Please sign in to comment.