aboutsummaryrefslogtreecommitdiff
path: root/core/src/test/scala
diff options
context:
space:
mode:
authorAmir Saeid <amir@glgdgt.com>2026-02-14 12:53:37 +0000
committerAmir Saeid <amir@glgdgt.com>2026-02-14 12:53:37 +0000
commit33c328fe9e08e642b28b310f9ab7f2fa704a3a2f (patch)
tree9e69e52e31dd592ef5b5cd3050329dc0d9f67dc7 /core/src/test/scala
parent21cd15d7a259e3ada2401e2585455587a56bdfbd (diff)
Add tests
Diffstat (limited to 'core/src/test/scala')
-rw-r--r--core/src/test/scala/com/codiff/fairstream/PythagoreanSuite.scala99
1 files changed, 99 insertions, 0 deletions
diff --git a/core/src/test/scala/com/codiff/fairstream/PythagoreanSuite.scala b/core/src/test/scala/com/codiff/fairstream/PythagoreanSuite.scala
new file mode 100644
index 0000000..8ab73ba
--- /dev/null
+++ b/core/src/test/scala/com/codiff/fairstream/PythagoreanSuite.scala
@@ -0,0 +1,99 @@
+package com.codiff.fairstream
+
+import cats.Eval
+import cats.syntax.all._
+import munit.FunSuite
+
+class PythagoreanSuite extends FunSuite {
+
+ def isPythagorean(t: (Int, Int, Int)): Boolean = {
+ val (i, j, k) = t
+ i * i + j * j == k * k
+ }
+
+ // -- Fair tests (FBackTrack.hs) --
+
+ test("Fair: pythagorean triples (generic MonadPlus style)") {
+ import Fair._
+
+ lazy val number: Fair[Int] = mplus(unit(0), number.map(_ + 1))
+
+ val triples = for {
+ i <- number
+ _ <- guard(i > 0)
+ j <- number
+ _ <- guard(j > 0)
+ k <- number
+ _ <- guard(k > 0)
+ _ <- guard(i * i + j * j == k * k)
+ } yield (i, j, k)
+
+ val results = Fair.runM(None, Some(7), triples)
+ assertEquals(results.length, 7)
+ assert(results.forall(isPythagorean))
+ }
+
+ test("Fair: pythagorean triples with left recursion") {
+ import Fair._
+
+ lazy val number: Fair[Int] = mplus((Incomplete(number): Fair[Int]).map(_ + 1), unit(0))
+
+ val triples = for {
+ i <- number
+ j <- number
+ k <- number
+ _ <- guard(i * i + j * j == k * k)
+ } yield (i, j, k)
+
+ val results = Fair.runM(None, Some(27), triples)
+ assertEquals(results.length, 27)
+ assert(results.forall(isPythagorean))
+ }
+
+ // -- FairT tests (FBackTrackT.hs) --
+ // Using Eval as M because:
+ // - Id is strict with no trampolining → stack overflow on deep Incomplete chains
+ // - Eval provides stack-safe trampolined flatMap with minimal overhead
+ // - IO works but has too much per-step overhead for large searches
+
+ def guardF(cond: Boolean): FairT[Eval, Unit] =
+ if (cond) FairT.unit[Eval, Unit](()) else FairT.empty[Eval, Unit]
+
+ test("FairT[Eval]: pythagorean triples (generic MonadPlus style)") {
+ lazy val number: FairT[Eval, Int] =
+ FairT.mplus[Eval, Int](FairT.unit[Eval, Int](0), number.map(_ + 1))
+
+ val triples: FairT[Eval, (Int, Int, Int)] = for {
+ i <- number
+ _ <- guardF(i > 0)
+ j <- number
+ _ <- guardF(j > 0)
+ k <- number
+ _ <- guardF(k > 0)
+ _ <- guardF(i * i + j * j == k * k)
+ } yield (i, j, k)
+
+ val results = FairT.runM[Eval, (Int, Int, Int)](None, Some(7), triples).value
+ assertEquals(results.length, 7)
+ assert(results.forall(isPythagorean))
+ }
+
+ test("FairT[Eval]: pythagorean triples with left recursion") {
+ lazy val number: FairT[Eval, Int] =
+ FairT.mplus[Eval, Int](
+ FairT.suspend[Eval, Int](number).map(_ + 1),
+ FairT.unit[Eval, Int](0)
+ )
+
+ val triples: FairT[Eval, (Int, Int, Int)] = for {
+ i <- number
+ j <- number
+ k <- number
+ _ <- guardF(i * i + j * j == k * k)
+ } yield (i, j, k)
+
+ val results = FairT.runM[Eval, (Int, Int, Int)](None, Some(27), triples).value
+ assertEquals(results.length, 27)
+ assert(results.forall(isPythagorean))
+ }
+}