aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/data/collection/tree/zipper.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/test/lux/data/collection/tree/zipper.lux')
-rw-r--r--stdlib/source/test/lux/data/collection/tree/zipper.lux115
1 files changed, 115 insertions, 0 deletions
diff --git a/stdlib/source/test/lux/data/collection/tree/zipper.lux b/stdlib/source/test/lux/data/collection/tree/zipper.lux
new file mode 100644
index 000000000..f4b812420
--- /dev/null
+++ b/stdlib/source/test/lux/data/collection/tree/zipper.lux
@@ -0,0 +1,115 @@
+(.module:
+ [lux #*
+ data/text/format
+ ["_" test (#+ Test)]
+ [abstract/monad (#+ do Monad)]
+ [control
+ pipe]
+ [data
+ ["." maybe]
+ ["." text]
+ [number
+ ["." nat]]
+ [collection
+ ["." list]]]
+ [math
+ ["r" random]]]
+ ["." //]
+ {1
+ ["." / (#+ Zipper)
+ ["tree" //]]}
+ )
+
+(def: #export test
+ Test
+ (<| (_.context (%name (name-of /.Zipper)))
+ (do r.monad
+ [size (:: @ map (|>> (n/% 90) (n/+ 10)) r.nat)
+ sample (//.tree size r.nat)
+ mid-val r.nat
+ new-val r.nat
+ pre-val r.nat
+ post-val r.nat
+ #let [(^open "tree@.") (tree.equivalence nat.equivalence)
+ (^open "list@.") (list.equivalence nat.equivalence)]]
+ ($_ _.and
+ (_.test "Trees can be converted to/from zippers."
+ (|> sample
+ /.zip /.unzip
+ (tree@= sample)))
+ (_.test "Creating a zipper gives you a start node."
+ (|> sample /.zip /.start?))
+ (_.test "Can move down inside branches. Can move up from lower nodes."
+ (let [zipper (/.zip sample)]
+ (if (/.branch? zipper)
+ (let [child (|> zipper /.down)]
+ (and (not (tree@= sample (/.unzip child)))
+ (|> child /.up (is? zipper) not)
+ (|> child /.start (is? zipper) not)))
+ (and (/.leaf? zipper)
+ (|> zipper (/.prepend-child new-val) /.branch?)))))
+ (do @
+ [branch-value r.nat
+ #let [zipper (|> (/.zip (tree.branch branch-value (list (tree.leaf mid-val))))
+ (/.prepend-child pre-val)
+ (/.append-child post-val))]]
+ (_.test "Can prepend and append children."
+ (and (and (|> zipper /.down /.value (is? pre-val))
+ (|> zipper /.down /.right /.left /.value (is? pre-val))
+ (|> zipper /.down /.rightmost /.leftmost /.value (is? pre-val)))
+ (|> zipper /.down /.right /.value (is? mid-val))
+ (and (|> zipper /.down /.right /.right /.value (is? post-val))
+ (|> zipper /.down /.rightmost /.value (is? post-val))))))
+ (do @
+ [branch-value r.nat
+ #let [zipper (/.zip (tree.branch branch-value (list (tree.leaf mid-val))))]]
+ (_.test "Can insert children around a node (unless it's start)."
+ (and (let [zipper (|> zipper
+ /.down
+ (/.insert-left pre-val)
+ maybe.assume
+ (/.insert-right post-val)
+ maybe.assume
+ /.up)]
+ (and (|> zipper /.down /.value (is? pre-val))
+ (|> zipper /.down /.right /.value (is? mid-val))
+ (|> zipper /.down /.right /.right /.value (is? post-val))
+ (|> zipper /.down /.rightmost /.leftmost /.value (is? pre-val))
+ (|> zipper /.down /.right /.left /.value (is? pre-val))
+ (|> zipper /.down /.rightmost /.value (is? post-val))))
+ (and (|> zipper
+ (/.insert-left pre-val)
+ (case> (#.Some _) false
+ #.None true))
+ (|> zipper
+ (/.insert-right post-val)
+ (case> (#.Some _) false
+ #.None true))))))
+ (_.test "Can set and update the value of a node."
+ (|> sample /.zip (/.set new-val) /.value (n/= new-val)))
+ (_.test "Zipper traversal follows the outline of the tree depth-first."
+ (let [root (/.zip sample)]
+ (list@= (tree.flatten sample)
+ (loop [zipper (/.start root)]
+ (let [zipper' (/.next zipper)]
+ (#.Cons (/.value zipper)
+ (if (:: (/.equivalence nat.equivalence) = root zipper')
+ (list)
+ (recur zipper'))))))))
+ (_.test "Backwards zipper traversal yield reverse tree flatten."
+ (let [root (/.zip sample)]
+ (list@= (list.reverse (tree.flatten sample))
+ (loop [zipper (/.end root)]
+ (#.Cons (/.value zipper)
+ (if (:: (/.equivalence nat.equivalence) = root zipper)
+ (list)
+ (recur (/.prev zipper))))))))
+ (_.test "Can remove nodes (except start nodes)."
+ (let [zipper (/.zip sample)]
+ (if (/.branch? zipper)
+ (and (|> zipper /.down /.start? not)
+ (|> zipper /.down /.remove (case> #.None false
+ (#.Some node) (/.start? node))))
+ (|> zipper /.remove (case> #.None true
+ (#.Some _) false)))))
+ ))))