Add a TestConsole
Implements suggestion in #4393
Would it make sense to shape a test console around an ADT? We have this implementation in otel4s: https://github.com/typelevel/otel4s/blob/4b5f51093e3bb2fbb20914f901a5752a88d8e26c/sdk/common/shared/src/test/scala/org/typelevel/otel4s/sdk/test/InMemoryConsole.scala#L28
The ADT offers enough flexibility to test operations.
P. S. To be fair, it doesn't support read operations, but it can be implemented with a separate read queue.
On the other hand, since TestConsole covers different scenarios, it might be worth exploring two different implementations.
Is there a reason to have a separate
logsRef? It seems redundant given that we havestderr/stdout
Those are for capturing meta information that's useful when tests fail, like that there was X amount left in the buffer at close, the exact sequence of reads and writes, etc.
For context: I initially wrote this as a local helper when writing tests for typelevel/log4cats#912, and the additional context was really helpful for debugging those tests.
Would it make sense to shape a test console around an ADT?
I think the main reason I went with a design that provided the full output of each stream, rather than an ADT tracking each operation, is that it would encourage writing tests using it which would be less sensitive to internal implementation changes.
It feels like a smell if we encourage users to write tests that care if there's a switch under the hood from console.println(fooNel.mkString_("\n")) to fooNel.traverse_(console.println(_)), since the observable behavior is the same.