Skip to content

Commit a95c40c

Browse files
committed
loneElement: fix knownSize count
if the iterable can only be iterated once, the 'knownSize' will decrement on iteration, leading to errors like this: `Iterable was expected to have exactly one element, but it has 1`
1 parent 5ed575d commit a95c40c

File tree

2 files changed

+9
-2
lines changed

2 files changed

+9
-2
lines changed

core/src/main/scala/flatgraph/traversal/IterableOnceExtension.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ class IterableOnceExtension[A](val iterable: IterableOnce[A]) extends AnyVal {
1818
if (hint.isEmpty) ""
1919
else s" Hint: $hint"
2020

21+
// if the iterable can only be iterated once, the 'knownSize' will decrement on iteration, so we store the value now
22+
val knownSize = iterable.knownSize
23+
2124
val iter = iterable.iterator
2225
if (iter.isEmpty) {
2326
throw new NoSuchElementException(s"Iterable was expected to have exactly one element, but it is empty.$hintMaybe")
2427
} else {
2528
val res = iter.next()
2629
if (iter.hasNext) {
27-
val collectionSizeHint = iterable.knownSize match {
28-
case -1 => "it has more than one" // cannot be computed cheaply, i.e. without traversing the collection
30+
val collectionSizeHint = knownSize match {
31+
case -1 => "it has more than one" // cannot be computed cheaply
2932
case knownSize => s"it has $knownSize"
3033
}
3134
throw new AssertionError(s"Iterable was expected to have exactly one element, but $collectionSizeHint.$hintMaybe")

core/src/test/scala/flatgraph/traversal/IterableOnceExtensionTests.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class IterableOnceExtensionTests extends AnyWordSpec with Matchers {
2929
ArrayBuffer(1, 2).loneElement
3030
}.getMessage should include("it has 2") // ArrayBuffer can 'cheaply' compute their size, so we can have it in the exception message
3131

32+
intercept[AssertionError] {
33+
Iterator(1, 2).loneElement
34+
}.getMessage should include("it has 2") // should know that it's two elements, even if iterator consumes elements after iteration
35+
3236
intercept[AssertionError] {
3337
Seq(1, 2).loneElement("some context")
3438
}.getMessage should include("it has more than one. Hint: some context")

0 commit comments

Comments
 (0)