diff --git a/core/src/main/scala/flatgraph/traversal/IterableOnceExtension.scala b/core/src/main/scala/flatgraph/traversal/IterableOnceExtension.scala index 74fa039c..4f8b665d 100644 --- a/core/src/main/scala/flatgraph/traversal/IterableOnceExtension.scala +++ b/core/src/main/scala/flatgraph/traversal/IterableOnceExtension.scala @@ -18,14 +18,17 @@ class IterableOnceExtension[A](val iterable: IterableOnce[A]) extends AnyVal { if (hint.isEmpty) "" else s" Hint: $hint" + // if the iterable can only be iterated once, the 'knownSize' will decrement on iteration, so we store the value now + val knownSize = iterable.knownSize + val iter = iterable.iterator if (iter.isEmpty) { throw new NoSuchElementException(s"Iterable was expected to have exactly one element, but it is empty.$hintMaybe") } else { val res = iter.next() if (iter.hasNext) { - val collectionSizeHint = iterable.knownSize match { - case -1 => "it has more than one" // cannot be computed cheaply, i.e. without traversing the collection + val collectionSizeHint = knownSize match { + case -1 => "it has more than one" // cannot be computed cheaply case knownSize => s"it has $knownSize" } throw new AssertionError(s"Iterable was expected to have exactly one element, but $collectionSizeHint.$hintMaybe") diff --git a/core/src/test/scala/flatgraph/traversal/IterableOnceExtensionTests.scala b/core/src/test/scala/flatgraph/traversal/IterableOnceExtensionTests.scala index 12d66cfb..3108c581 100644 --- a/core/src/test/scala/flatgraph/traversal/IterableOnceExtensionTests.scala +++ b/core/src/test/scala/flatgraph/traversal/IterableOnceExtensionTests.scala @@ -29,6 +29,10 @@ class IterableOnceExtensionTests extends AnyWordSpec with Matchers { ArrayBuffer(1, 2).loneElement }.getMessage should include("it has 2") // ArrayBuffer can 'cheaply' compute their size, so we can have it in the exception message + intercept[AssertionError] { + Iterator(1, 2).loneElement + }.getMessage should include("it has 2") // should know that it's two elements, even if iterator consumes elements after iteration + intercept[AssertionError] { Seq(1, 2).loneElement("some context") }.getMessage should include("it has more than one. Hint: some context")