Skip to content

Commit

Permalink
feat(#12): add element's positional insertion in NotEmptyMutableList
Browse files Browse the repository at this point in the history
  • Loading branch information
LVMVRQUXL committed Aug 11, 2022
1 parent 5475fb1 commit 3abc6f9
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 12 deletions.
9 changes: 9 additions & 0 deletions src/main/kotlin/kotools/types/Errors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kotools.types

internal fun indexOutOfBounds(index: Int, size: Int): Nothing {
val message: String = indexOutOfBoundsMessage(index, size)
throw IndexOutOfBoundsException(message)
}

internal fun indexOutOfBoundsMessage(index: Int, size: Int): String =
"Index: $index, Size: $size"
23 changes: 19 additions & 4 deletions src/main/kotlin/kotools/types/collections/NotEmptyMutableList.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kotools.types.collections

import kotools.types.annotations.SinceKotoolsTypes
import kotools.types.indexOutOfBounds

// ---------- Conversions ----------

Expand Down Expand Up @@ -78,13 +79,13 @@ public inline infix fun <reified E> Collection<E>.toNotEmptyMutableListOrElse(
* containing all the elements of the optional [tail].
*/
@SinceKotoolsTypes("1.3")
public class NotEmptyMutableList<E>(override val head: E, vararg tail: E) :
public class NotEmptyMutableList<E>(override var head: E, vararg tail: E) :
AbstractMutableList<E>(),
NotEmptyMutableCollection<E> {
private val tail: List<E>
private val tail: MutableList<E>

init {
this.tail = tail.toList()
this.tail = tail.toMutableList()
}

// ---------- Query operations ----------
Expand All @@ -95,7 +96,21 @@ public class NotEmptyMutableList<E>(override val head: E, vararg tail: E) :

// ---------- Positional Access Operations ----------

override fun add(index: Int, element: E): Unit = TODO("Not implemented yet")
/**
* Inserts the [element] into this list at the specified [index], or throws
* an [IndexOutOfBoundsException] if the [index] is out of bounds.
*/
@Throws(IndexOutOfBoundsException::class)
override fun add(index: Int, element: E): Unit = when (index) {
in 1 until size -> tail.add(index - 1, element)
0 -> {
tail.add(0, head)
head = element
}
size -> tail += element
else -> indexOutOfBounds(index, size)
}

override fun get(index: Int): E = if (index == 0) head else tail[index - 1]
override fun removeAt(index: Int): E = TODO("Not implemented yet")
override fun set(index: Int, element: E): E = TODO("Not implemented yet")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import io.github.kotools.assert.assertEquals
import io.github.kotools.assert.assertNotEquals
import io.github.kotools.assert.assertNotNull
import io.github.kotools.assert.assertNull
import kotools.types.indexOutOfBoundsMessage
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.assertDoesNotThrow
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse

class NotEmptyMutableListTest {
@Nested
Expand Down Expand Up @@ -47,7 +48,6 @@ class NotEmptyMutableListTest {

@Nested
inner class Add {
@Ignore
@Test
fun `should insert the element to the beginning of the list with an index that equals 0`() {
// GIVEN
Expand All @@ -61,14 +61,79 @@ class NotEmptyMutableListTest {
// WHEN
assertDoesNotThrow { list.add(index, element) }
// THEN
list.forEachIndexed { index2: Int, element2: String ->
element2 assertEquals expectedList[index2]
list.run {
size assertEquals expectedList.size
forEachIndexed { index2: Int, element2: String ->
element2 assertEquals expectedList[index2]
}
}
}

@Test
fun `should insert the element to the end of the list with an index that equals the list's size`() {
// GIVEN
val expectedList: NotEmptyList<String> =
NotEmptyList("one", "two", "three")
val list: NotEmptyMutableList<String> = expectedList
.subList(0, expectedList.size - 1)
.toNotEmptyMutableList()
val index = list.size
val element: String = expectedList.last()
// WHEN
assertDoesNotThrow { list.add(index, element) }
// THEN
list.run {
size assertEquals expectedList.size
forEachIndexed { index2: Int, element2: String ->
element2 assertEquals expectedList[index2]
}
}
}

@Test
fun `should insert the element in the middle of the list with an index between 1 until the list's size`() {
// GIVEN
val expectedList: NotEmptyList<String> =
NotEmptyList("one", "two", "three")
val list: NotEmptyMutableList<String> = expectedList
.subList(1, expectedList.size)
.toNotEmptyMutableList()
val index = 0
val element: String = expectedList.head
// WHEN
assertDoesNotThrow { list.add(index, element) }
// THEN
list.run {
size assertEquals expectedList.size
forEachIndexed { index2: Int, element2: String ->
element2 assertEquals expectedList[index2]
}
}
}

@Test
fun `should throw an error with an index that is out of bounds`() {
// GIVEN
val expectedList: NotEmptyList<String> = NotEmptyList("one", "two")
val list: NotEmptyMutableList<String> =
expectedList.toNotEmptyMutableList()
val index = expectedList.size + 1
val element = "three"
val expectedMessage: String =
indexOutOfBoundsMessage(index, list.size)
// WHEN
val error: IndexOutOfBoundsException =
assertFailsWith { list.add(index, element) }
// THEN
error.message.assertNotNull() assertEquals expectedMessage
list.run {
size assertEquals expectedList.size
assertFalse { contains(element) }
forEachIndexed { index2: Int, element2: String ->
element2 assertEquals expectedList[index2]
}
}
TODO()
}
// TODO: 21/07/2022 Should insert the element to the end of the list with an index that equals the list's size
// TODO: 21/07/2022 Should insert the element in the middle of the list with an index between 0 and the list's size excluded
// TODO: 21/07/2022 Should throw an error with an index that is out of bounds
}

@Nested
Expand Down

0 comments on commit 3abc6f9

Please sign in to comment.