Skip to content

Commit

Permalink
add single and singleOrNull to EntityBag
Browse files Browse the repository at this point in the history
  • Loading branch information
Quillraven committed Oct 1, 2024
1 parent 596bf8e commit 300b37d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,30 @@ interface EntityBag {
*/
fun randomOrNull(): Entity?

/**
* Returns the single [entity][Entity] of the bag, or throws an exception
* if the bag is empty or has more than one [entity][Entity].
*/
fun single(): Entity

/**
* Returns the single [entity][Entity] of the bag matching the given [predicate],
* or throws an exception if the bag is empty or has more than one [entity][Entity].
*/
fun single(predicate: (Entity) -> Boolean): Entity

/**
* Returns single [entity][Entity] of the bag, or null
* if the bag is empty or has more than one [entity][Entity].
*/
fun singleOrNull(): Entity?

/**
* Returns the single [entity][Entity] of the bag matching the given [predicate],
* or null if the bag is empty or has more than one [entity][Entity].
*/
fun singleOrNull(predicate: (Entity) -> Boolean): Entity?

/**
* Returns a [List] containing the first [n] [entities][Entity].
*/
Expand Down Expand Up @@ -1122,6 +1146,68 @@ class MutableEntityBag(
return values[Random.Default.nextInt(size)]
}

/**
* Returns the single [entity][Entity] of the bag, or throws an exception
* if the bag is empty or has more than one [entity][Entity].
*/
override fun single(): Entity {
return when (size) {
0 -> throw NoSuchElementException("Bag is empty.")
1 -> values[0]
else -> throw IllegalArgumentException("Bag has more than one element.")
}
}

/**
* Returns the single [entity][Entity] of the bag matching the given [predicate],
* or throws an exception if the bag is empty or has more than one [entity][Entity].
*/
override fun single(predicate: (Entity) -> Boolean): Entity {
var single: Entity? = null
for (i in 0 until size) {
val entity = values[i]
if (predicate(entity)) {
if (single != null) {
throw IllegalArgumentException("Bag contains more than one matching element.")
}
single = entity
}
}
if (single == null) {
throw NoSuchElementException("Bag contains no element matching the predicate.")
}
return single
}

/**
* Returns single [entity][Entity] of the bag, or null
* if the bag is empty or has more than one [entity][Entity].
*/
override fun singleOrNull(): Entity? {
return when (size) {
1 -> values[0]
else -> null
}
}

/**
* Returns the single [entity][Entity] of the bag matching the given [predicate],
* or null if the bag is empty or has more than one [entity][Entity].
*/
override fun singleOrNull(predicate: (Entity) -> Boolean): Entity? {
var single: Entity? = null
for (i in 0 until size) {
val entity = values[i]
if (predicate(entity)) {
if (single != null) {
return null
}
single = entity
}
}
return single
}

/**
* Returns a [List] containing the first [n] [entities][Entity].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class EntityBagTest {
this += testEntity1
this += testEntity2
}
private val testBagSingle = MutableEntityBag(2).apply {
this += testEntity1
}

private fun bagOf(entity: Entity) = MutableEntityBag(1).apply {
this += entity
Expand Down Expand Up @@ -595,6 +598,26 @@ class EntityBagTest {
assertTrue(actual == testEntity1 || actual == testEntity2)
}

@Test
fun testSingle() {
assertEquals(testEntity1, testBagSingle.single())
assertEquals(testEntity1, testBagSingle.single { it == testEntity1 })
assertFailsWith<IllegalArgumentException> { testBag.single() }
assertFailsWith<IllegalArgumentException> { bagOf(testEntity1, testEntity1).single { it == testEntity1 } }
assertFailsWith<NoSuchElementException> { MutableEntityBag().single() }
assertFailsWith<NoSuchElementException> { testBag.single { it.id == 3 } }
}

@Test
fun testSingleOrNull() {
assertEquals(testEntity1, testBagSingle.singleOrNull())
assertEquals(testEntity1, testBagSingle.singleOrNull { it == testEntity1 })
assertNull(testBag.singleOrNull())
assertNull(bagOf(testEntity1, testEntity1).singleOrNull { it == testEntity1 })
assertNull(MutableEntityBag().singleOrNull())
assertNull(testBag.singleOrNull { it.id == 3 })
}

@Test
fun testTake() {
assertTrue(testBag.take(-1).isEmpty())
Expand Down

0 comments on commit 300b37d

Please sign in to comment.