Skip to content

Commit

Permalink
✨ Add EmailAddress.Companion.fromString(Any, Any) (#635)
Browse files Browse the repository at this point in the history
  • Loading branch information
LVMVRQUXL committed Apr 1, 2024
1 parent c5d3cf4 commit ef79030
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/api/types.api
Original file line number Diff line number Diff line change
Expand Up @@ -444,12 +444,14 @@ public final class org/kotools/types/EmailAddress {
public static final field Companion Lorg/kotools/types/EmailAddress$Companion;
public static final field PATTERN Ljava/lang/String;
public static final fun fromString (Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public static final fun fromString (Ljava/lang/Object;Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public static final fun fromStringOrNull (Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public static final fun fromStringOrNull (Ljava/lang/Object;Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
}

public final class org/kotools/types/EmailAddress$Companion {
public final fun fromString (Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public final fun fromString (Ljava/lang/Object;Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public final fun fromStringOrNull (Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
public final fun fromStringOrNull (Ljava/lang/Object;Ljava/lang/Object;)Lorg/kotools/types/EmailAddress;
}
Expand Down
78 changes: 74 additions & 4 deletions src/commonMain/kotlin/org/kotools/types/EmailAddress.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,57 @@ public class EmailAddress private constructor() {
@JvmStatic
public fun fromString(value: Any): EmailAddress {
val address: EmailAddress? = fromStringOrNull(value)
return requireNotNull(address) {
InvalidEmailAddress(value).message
return requireNotNull(address) { InvalidEmailAddress(value) }
}

/**
* Creates an instance of [EmailAddress] from the string representation
* of the specified [value].
* Throws an [IllegalArgumentException] if the string representation of
* [value] doesn't match the string representation of the specified
* [pattern], or if the string representation of [pattern] doesn't match
* the [default pattern][PATTERN].
*
* <br>
* <details open>
* <summary>
* <b>Calling from Kotlin</b>
* </summary>
*
* Here's an example of calling this function from Kotlin code:
*
* SAMPLE: EmailAddressCompanionKotlinSample.fromString_Any_Any.md
* </details>
*
* <br>
* <details>
* <summary>
* <b>Calling from Java</b>
* </summary>
*
* Here's an example of calling this function from Java code:
*
* SAMPLE: EmailAddressCompanionJavaSample.fromString_Any_Any.md
* </details>
* <br>
*
* You can use the [fromStringOrNull] function for returning `null`
* instead of throwing an exception in case of invalid [value] or
* [pattern].
*/
@JvmStatic
public fun fromString(value: Any, pattern: Any): EmailAddress {
val patternAsString: String = pattern.toString()
val defaultRegex = Regex(PATTERN)
require(patternAsString matches defaultRegex) {
InvalidEmailAddressPattern(pattern)
}
val valueAsString: String = value.toString()
val customRegex = Regex(patternAsString)
require(valueAsString matches customRegex) {
InvalidEmailAddress(value, pattern)
}
return EmailAddress()
}

/**
Expand Down Expand Up @@ -164,6 +212,10 @@ public class EmailAddress private constructor() {
*
* SAMPLE: EmailAddressCompanionJavaSample.fromStringOrNull_Any_Any.md
* </details>
* <br>
*
* You can use the [fromString] function for throwing an exception
* instead of returning `null` in case of invalid [value] or [pattern].
*/
@JvmStatic
public fun fromStringOrNull(value: Any, pattern: Any): EmailAddress? {
Expand All @@ -178,6 +230,24 @@ public class EmailAddress private constructor() {
}
}

internal class InvalidEmailAddress(value: Any) : IllegalArgumentException() {
override val message: String = "\"$value\" is an invalid email address."
@OptIn(ExperimentalKotoolsTypesApi::class)
internal class InvalidEmailAddress(
value: Any,
pattern: Any = EmailAddress.PATTERN
) : IllegalArgumentException() {
override val message: String = "\"$value\" is an invalid email address." +
" It should match the following pattern: $pattern"

override fun toString(): String = message
}

internal class InvalidEmailAddressPattern(
pattern: Any
) : IllegalArgumentException() {
@OptIn(ExperimentalKotoolsTypesApi::class)
override val message: String =
"$pattern is an invalid email address pattern." +
" It should match the following one: ${EmailAddress.PATTERN}"

override fun toString(): String = message
}
34 changes: 34 additions & 0 deletions src/commonTest/kotlin/org/kotools/types/EmailAddressTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,40 @@ class EmailAddressCompanionTest {
assertEquals(expected, actual)
}

@Test
fun fromString_Any_Any_should_pass_with_valid_value_and_pattern() {
val value: Any = "[email protected]"
val pattern: Any = "^[a-z]+@[a-z]+\\.[a-z]+\$"
val result: Result<EmailAddress> = kotlin.runCatching {
EmailAddress.fromString(value, pattern)
}
assertTrue(result.isSuccess)
}

@Test
fun fromString_Any_Any_should_fail_with_invalid_value() {
val value: Any = "[email protected]"
val pattern: Any = "^[a-z]+@[a-z]+\\.[a-z]+\$"
val exception: IllegalArgumentException = assertFailsWith {
EmailAddress.fromString(value, pattern)
}
val actual: String? = exception.message
val expected: String = InvalidEmailAddress(value, pattern).message
assertEquals(expected, actual)
}

@Test
fun fromString_Any_Any_should_fail_with_invalid_pattern() {
val value: Any = "[email protected]"
val pattern: Any = "^[a-z]+\\.[a-z]+\$"
val exception: IllegalArgumentException = assertFailsWith {
EmailAddress.fromString(value, pattern)
}
val actual: String? = exception.message
val expected: String = InvalidEmailAddressPattern(pattern).message
assertEquals(expected, actual)
}

@Test
fun fromStringOrNull_Any_should_pass_with_a_valid_value() {
val value: Any = "[email protected]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ void fromString_Any() {
// Output: success
} // END

void fromString_Any_Any() {
final Object value = "[email protected]";
final Object pattern = "^[a-z]+@[a-z]+\\.[a-z]+$";
try {
EmailAddress.fromString(value, pattern); // TABS: 1
System.out.println("success"); // TABS: 1
} catch (final IllegalArgumentException exception) {
System.out.println("failure"); // TABS: 1
}
// Output: success
} // END

void fromStringOrNull_Any() {
final Object value = "[email protected]";
final EmailAddress address = EmailAddress.fromStringOrNull(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ internal object EmailAddressCompanionKotlinSample {
println(result.isSuccess) // true
} // END

@Suppress("FunctionName")
fun fromString_Any_Any() {
val value: Any = "[email protected]"
val pattern: Any = "^[a-z]+@[a-z]+\\.[a-z]+\$"
val result: Result<EmailAddress> = kotlin.runCatching {
EmailAddress.fromString(value, pattern) // TABS: 1
}
println(result.isSuccess) // true
} // END

@Suppress("FunctionName")
fun fromStringOrNull_Any() {
val value: Any = "[email protected]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ void fromString_Any_should_pass() {
Assertions.assertEquals(expected, actual);
}

@Test
void fromString_Any_Any_should_pass() {
final EmailAddressCompanionJavaSample sample =
new EmailAddressCompanionJavaSample();
final String actual = Assertions.assertDoesNotThrow(
() -> SystemLambda.tapSystemOut(sample::fromString_Any_Any)
).trim();
final String expected = "success";
Assertions.assertEquals(expected, actual);
}

@Test
void fromStringOrNull_Any_should_pass() {
final EmailAddressCompanionJavaSample sample =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class EmailAddressCompanionKotlinSampleTest {
assertTrue(actual)
}

@Test
fun `fromString(Any, Any) should pass`() {
val actual: Boolean = SystemLambda
.tapSystemOut(Sample::fromString_Any_Any)
.trim()
.toBooleanStrict()
assertTrue(actual)
}

@Test
fun `fromStringOrNull(Any) should pass`() {
val actual: Boolean = SystemLambda
Expand Down

0 comments on commit ef79030

Please sign in to comment.