aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/control/interval.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/test/lux/control/interval.lux')
-rw-r--r--stdlib/source/test/lux/control/interval.lux235
1 files changed, 235 insertions, 0 deletions
diff --git a/stdlib/source/test/lux/control/interval.lux b/stdlib/source/test/lux/control/interval.lux
new file mode 100644
index 000000000..6d00a36e9
--- /dev/null
+++ b/stdlib/source/test/lux/control/interval.lux
@@ -0,0 +1,235 @@
+(.module:
+ lux/test
+ [lux #*
+ [control
+ ["M" monad (#+ do Monad)]
+ pipe
+ ["&" interval]]
+ [math
+ ["r" random]]
+ [data
+ ["." number]
+ [collection
+ ["S" set]
+ ["L" list]]]])
+
+(context: "Equivalence."
+ (<| (times 100)
+ (do @
+ [bottom r.int
+ top r.int
+ #let [(^open "&/.") &.equivalence]]
+ ($_ seq
+ (test "Every interval is equal to itself."
+ (and (let [self (&.between number.enum bottom top)]
+ (&/= self self))
+ (let [self (&.between number.enum top bottom)]
+ (&/= self self))
+ (let [self (&.singleton number.enum bottom)]
+ (&/= self self))))))))
+
+(context: "Boundaries"
+ (<| (times 100)
+ (do @
+ [bottom r.int
+ top r.int
+ #let [interval (&.between number.enum bottom top)]]
+ ($_ seq
+ (test "Every boundary value belongs to it's interval."
+ (and (&.within? interval bottom)
+ (&.within? interval top)))
+ (test "Every interval starts with its bottom."
+ (&.starts-with? bottom interval))
+ (test "Every interval ends with its top."
+ (&.ends-with? top interval))
+ (test "The boundary values border the interval."
+ (and (&.borders? interval bottom)
+ (&.borders? interval top)))
+ ))))
+
+(def: (list-to-4tuple list)
+ (-> (List Int) [Int Int Int Int])
+ (case list
+ (^ (list x0 x1 x2 x3))
+ [x0 x1 x2 x3]
+
+ _
+ (undefined)))
+
+
+(do-template [<name> <cmp>]
+ [(def: <name>
+ (r.Random (&.Interval Int))
+ (do r.monad
+ [bottom r.int
+ top (|> r.int (r.filter (|>> (i/= bottom) not)))]
+ (if (<cmp> top bottom)
+ (wrap (&.between number.enum bottom top))
+ (wrap (&.between number.enum top bottom)))))]
+
+ [gen-inner i/<]
+ [gen-outer i/>]
+ )
+
+(def: gen-singleton
+ (r.Random (&.Interval Int))
+ (do r.monad
+ [point r.int]
+ (wrap (&.singleton number.enum point))))
+
+(def: gen-interval
+ (r.Random (&.Interval Int))
+ ($_ r.either
+ gen-inner
+ gen-outer
+ gen-singleton))
+
+(context: "Unions"
+ (<| (times 100)
+ (do @
+ [some-interval gen-interval
+ left-inner gen-inner
+ right-inner gen-inner
+ left-singleton gen-singleton
+ right-singleton gen-singleton
+ left-outer gen-outer
+ right-outer gen-outer
+ #let [(^open "&/.") &.equivalence]]
+ ($_ seq
+ (test "The union of an interval to itself yields the same interval."
+ (&/= some-interval (&.union some-interval some-interval)))
+ (test "The union of 2 inner intervals is another inner interval."
+ (&.inner? (&.union left-inner right-inner)))
+ (test "The union of 2 outer intervals yields an inner interval when their complements don't overlap, and an outer when they do."
+ (if (&.overlaps? (&.complement left-outer) (&.complement right-outer))
+ (&.outer? (&.union left-outer right-outer))
+ (&.inner? (&.union left-outer right-outer))))
+ ))))
+
+(context: "Intersections"
+ (<| (times 100)
+ (do @
+ [some-interval gen-interval
+ left-inner gen-inner
+ right-inner gen-inner
+ left-singleton gen-singleton
+ right-singleton gen-singleton
+ left-outer gen-outer
+ right-outer gen-outer
+ #let [(^open "&/.") &.equivalence]]
+ ($_ seq
+ (test "The intersection of an interval to itself yields the same interval."
+ (&/= some-interval (&.intersection some-interval some-interval)))
+ (test "The intersection of 2 inner intervals yields an inner interval when they overlap, and an outer when they don't."
+ (if (&.overlaps? left-inner right-inner)
+ (&.inner? (&.intersection left-inner right-inner))
+ (&.outer? (&.intersection left-inner right-inner))))
+ (test "The intersection of 2 outer intervals is another outer interval."
+ (&.outer? (&.intersection left-outer right-outer)))
+ ))))
+
+(context: "Complement"
+ (<| (times 100)
+ (do @
+ [some-interval gen-interval
+ #let [(^open "&/.") &.equivalence]]
+ ($_ seq
+ (test "The complement of a complement is the same as the original."
+ (&/= some-interval (|> some-interval &.complement &.complement)))
+ (test "The complement of an interval does not overlap it."
+ (not (&.overlaps? some-interval (&.complement some-interval))))
+ ))))
+
+(context: "Positioning/location"
+ (<| (times 100)
+ (do @
+ [[l m r] (|> (r.set number.hash 3 r.int)
+ (:: @ map (|>> S.to-list
+ (L.sort i/<)
+ (case> (^ (list b t1 t2))
+ [b t1 t2]
+
+ _
+ (undefined)))))
+ #let [left (&.singleton number.enum l)
+ right (&.singleton number.enum r)]]
+ ($_ seq
+ (test "'precedes?' and 'succeeds?' are symetric."
+ (and (&.precedes? right left)
+ (&.succeeds? left right)))
+ (test "Can check if an interval is before or after some element."
+ (and (&.before? m left)
+ (&.after? m right)))
+ ))))
+
+(context: "Touching intervals"
+ (<| (times 100)
+ (do @
+ [[b t1 t2] (|> (r.set number.hash 3 r.int)
+ (:: @ map (|>> S.to-list
+ (L.sort i/<)
+ (case> (^ (list b t1 t2))
+ [b t1 t2]
+
+ _
+ (undefined)))))
+ #let [int-left (&.between number.enum t1 t2)
+ int-right (&.between number.enum b t1)]]
+ ($_ seq
+ (test "An interval meets another if it's top is the other's bottom."
+ (&.meets? int-left int-right))
+ (test "Two intervals touch one another if any one meets the other."
+ (&.touches? int-left int-right))
+ (test "Can check if 2 intervals start together."
+ (&.starts? (&.between number.enum b t2)
+ (&.between number.enum b t1)))
+ (test "Can check if 2 intervals finish together."
+ (&.finishes? (&.between number.enum b t2)
+ (&.between number.enum t1 t2)))
+ ))))
+
+(context: "Nesting & overlap"
+ (<| (times 100)
+ (do @
+ [some-interval gen-interval
+ [x0 x1 x2 x3] (|> (r.set number.hash 4 r.int)
+ (:: @ map (|>> S.to-list
+ (L.sort i/<)
+ (case> (^ (list x0 x1 x2 x3))
+ [x0 x1 x2 x3]
+
+ _
+ (undefined)))))]
+ ($_ seq
+ (test "Every interval is nested into itself."
+ (&.nested? some-interval some-interval))
+ (test "No interval overlaps with itself."
+ (not (&.overlaps? some-interval some-interval)))
+ (let [small-inner (&.between number.enum x1 x2)
+ large-inner (&.between number.enum x0 x3)]
+ (test "Inner intervals can be nested inside one another."
+ (and (&.nested? large-inner small-inner)
+ (not (&.nested? small-inner large-inner)))))
+ (let [left-inner (&.between number.enum x0 x2)
+ right-inner (&.between number.enum x1 x3)]
+ (test "Inner intervals can overlap one another."
+ (and (&.overlaps? left-inner right-inner)
+ (&.overlaps? right-inner left-inner))))
+ (let [small-outer (&.between number.enum x2 x1)
+ large-outer (&.between number.enum x3 x0)]
+ (test "Outer intervals can be nested inside one another."
+ (and (&.nested? small-outer large-outer)
+ (not (&.nested? large-outer small-outer)))))
+ (let [left-inner (&.between number.enum x0 x1)
+ right-inner (&.between number.enum x2 x3)
+ outer (&.between number.enum x0 x3)]
+ (test "Inners can be nested inside outers."
+ (and (&.nested? outer left-inner)
+ (&.nested? outer right-inner))))
+ (let [left-inner (&.between number.enum x0 x2)
+ right-inner (&.between number.enum x1 x3)
+ outer (&.between number.enum x1 x2)]
+ (test "Inners can overlap outers."
+ (and (&.overlaps? outer left-inner)
+ (&.overlaps? outer right-inner))))
+ ))))