Skip to content

Commit

Permalink
refactor(#9)!: replace asNotEmptySet property by toNotEmptySet function
Browse files Browse the repository at this point in the history
  • Loading branch information
LVMVRQUXL committed Jan 3, 2023
1 parent 05547d8 commit 23be758
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 47 deletions.
2 changes: 1 addition & 1 deletion changelog.md
Expand Up @@ -63,7 +63,7 @@ notEmptyListOf(1, 2, 3).toList() // after

```kotlin
notEmptySetOf(1, 2, 3) as Set<Int> // before
notEmptySetOf(1, 2, 3).asSet // after
notEmptySetOf(1, 2, 3).toSet() // after
```

- Remove inheritance between the `NotEmptyMap` and the `Map` types (issue
Expand Down
4 changes: 2 additions & 2 deletions src/commonMain/kotlin/kotools/types/collection/NotEmptyMap.kt
Expand Up @@ -44,12 +44,12 @@ public data class NotEmptyMap<K, out V> internal constructor(

/** All entries of this map. */
public val entries: NotEmptySet<Map.Entry<K, V>> by lazy(
asMap.entries.asNotEmptySet::getOrThrow
asMap.entries.toNotEmptySet()::getOrThrow
)

/** All keys of this map. */
public val keys: NotEmptySet<K> by lazy(
asMap.keys.asNotEmptySet::getOrThrow
asMap.keys.toNotEmptySet()::getOrThrow
)

/** All values of this map. */
Expand Down
38 changes: 20 additions & 18 deletions src/commonMain/kotlin/kotools/types/collection/NotEmptySet.kt
Expand Up @@ -14,12 +14,7 @@ import kotools.types.number.StrictlyPositiveInt
import kotools.types.number.toStrictlyPositiveInt
import kotools.types.toSuccessfulResult

/**
* Representation of sets that contain at least one element of type [E].
*
* See the [notEmptySetOf] function or the [asNotEmptySet] property for building
* a [NotEmptySet].
*/
/** Representation of sets that contain at least one element of type [E]. */
@Serializable(NotEmptySetSerializer::class)
@SinceKotoolsTypes("4.0")
public data class NotEmptySet<out E> internal constructor(
Expand All @@ -44,23 +39,30 @@ public data class NotEmptySet<out E> internal constructor(
}

/**
* Returns a [NotEmptySet] containing all the elements of this collection, or
* returns an [IllegalArgumentException] if this collection is empty.
* Creates a [NotEmptySet] starting with a [head] and containing all the
* elements of the optional [tail].
*/
@SinceKotoolsTypes("4.0")
public val <E> Collection<E>.asNotEmptySet: Result<NotEmptySet<E>>
get() = if (isEmpty()) Result.failure(EmptyCollectionException)
else toSuccessfulResult {
NotEmptySet(head = first(), tail = drop(1).asNotEmptySet.getOrNull())
}
public fun <E> notEmptySetOf(head: E, vararg tail: E): NotEmptySet<E> =
setOf(head, *tail)
.toNotEmptySet()
.getOrThrow()

/**
* Creates a [NotEmptySet] starting with a [head] and containing all the
* elements of the optional [tail].
* Returns a [NotEmptySet] containing all the elements of this collection, or
* returns an [IllegalArgumentException] if this collection is empty.
*/
@SinceKotoolsTypes("4.0")
public fun <E> notEmptySetOf(head: E, vararg tail: E): NotEmptySet<E> =
setOf(head, *tail).asNotEmptySet.getOrThrow()
public fun <E> Collection<E>.toNotEmptySet(): Result<NotEmptySet<E>> =
takeIf(Collection<E>::isNotEmpty)
?.toSuccessfulResult {
val head: E = it.first()
val tail: NotEmptySet<E>? = it.drop(1)
.toNotEmptySet()
.getOrNull()
NotEmptySet(head, tail)
}
?: Result.failure(EmptyCollectionException)

internal class NotEmptySetSerializer<E>(elementSerializer: KSerializer<E>) :
KSerializer<NotEmptySet<E>> {
Expand All @@ -81,7 +83,7 @@ internal class NotEmptySetSerializer<E>(elementSerializer: KSerializer<E>) :

override fun deserialize(decoder: Decoder): NotEmptySet<E> = decoder
.decodeSerializableValue(delegate)
.asNotEmptySet
.toNotEmptySet()
.getOrNull()
?: throw SerializationException(EmptyCollectionException)
}
53 changes: 27 additions & 26 deletions src/commonTest/kotlin/kotools/types/collection/NotEmptySetTest.kt
Expand Up @@ -17,7 +17,7 @@ class NotEmptySetTest {
@Test
fun head_should_return_the_first_element_of_this_set() {
val elements: NotEmptySet<Int> = List(3) { Random.nextInt() }
.asNotEmptySet
.toNotEmptySet()
.getOrThrow()
val result: Int = elements.head
result shouldEqual elements.toSet().first()
Expand All @@ -26,7 +26,7 @@ class NotEmptySetTest {
@Test
fun tail_should_return_all_elements_of_this_set_except_the_first_one() {
val elements: NotEmptySet<Int> = List(3) { Random.nextInt() }
.asNotEmptySet
.toNotEmptySet()
.getOrThrow()
val result: NotEmptySet<Int>? = elements.tail
val expected: List<Int> = elements.toSet().drop(1)
Expand All @@ -39,54 +39,55 @@ class NotEmptySetTest {
assertNull(result)
}

@Test
fun asSet_should_return_all_elements_as_a_Set() {
val elements: Set<Int> = List(3) { Random.nextInt() }
.toSet()
val result: Set<Int> = elements.asNotEmptySet.getOrThrow().toSet()
result contentShouldEqual elements
}

@Test
fun size_should_return_the_size_of_this_set_as_a_StrictlyPositiveInt() {
val elements: NotEmptySet<Int> = List(3) { Random.nextInt() }
.asNotEmptySet
.toNotEmptySet()
.getOrThrow()
val result: StrictlyPositiveInt = elements.size
result.toInt() shouldEqual elements.toSet().size
}

@Test
fun toSet_should_return_all_elements_as_a_Set() {
val elements: Set<Int> = List(3) { Random.nextInt() }
.toSet()
val result: Set<Int> = elements.toNotEmptySet().getOrThrow().toSet()
result contentShouldEqual elements
}

@Test
fun toString_should_behave_like_a_Set() {
val elements: NotEmptySet<Int> = List(3) { Random.nextInt() }
.asNotEmptySet
.toNotEmptySet()
.getOrThrow()
"$elements" shouldEqual "${elements.toSet()}"
}

@Test
fun collection_asNotEmptySet_should_pass_with_a_not_empty_Collection() {
fun notEmptySetOf_should_pass() {
val head: Int = Random.nextInt()
val tail: Array<Int> = List(2) { Random.nextInt() }
.toTypedArray()
val result: NotEmptySet<Int> = notEmptySetOf(head, *tail)
result.toSet() contentShouldEqual listOf(head) + tail
}

@Test
fun collection_toNotEmptySet_should_pass_with_a_not_empty_Collection() {
val elements: List<Int> = List(3) { Random.nextInt() }
val result: Result<NotEmptySet<Int>> = elements.asNotEmptySet
val result: Result<NotEmptySet<Int>> = elements.toNotEmptySet()
result.getOrThrow().toSet() contentShouldEqual elements
}

@Test
fun collection_asNotEmptySet_should_fail_with_an_empty_Collection() {
val result: Result<NotEmptySet<Int>> = emptySet<Int>().asNotEmptySet
fun collection_toNotEmptySet_should_fail_with_an_empty_Collection() {
val result: Result<NotEmptySet<Int>> = emptySet<Int>()
.toNotEmptySet()
val exception: IllegalArgumentException =
assertFailsWith(block = result::getOrThrow)
exception.shouldHaveAMessage()
}

@Test
fun notEmptySetOf_should_pass() {
val head: Int = Random.nextInt()
val tail: Array<Int> = List(2) { Random.nextInt() }
.toTypedArray()
val result: NotEmptySet<Int> = notEmptySetOf(head, *tail)
result.toSet() contentShouldEqual listOf(head) + tail
}
}

class NotEmptySetSerializerTest {
Expand All @@ -102,7 +103,7 @@ class NotEmptySetSerializerTest {
@Test
fun serialization_should_behave_like_a_Set() {
val elements: NotEmptySet<Int> = List(3) { Random.nextInt() }
.asNotEmptySet
.toNotEmptySet()
.getOrThrow()
val result: String = Json.encodeToString(elements)
result shouldEqual Json.encodeToString(elements.toSet())
Expand Down

0 comments on commit 23be758

Please sign in to comment.