mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-05 13:55:54 +03:00
Merge pull request #539 from eglaysher/new-stdlib
Unit Testing / Partial New Library Work
This commit is contained in:
commit
cadc61929f
71
gen/test.hoon
Normal file
71
gen/test.hoon
Normal file
@ -0,0 +1,71 @@
|
||||
/+ new-hoon, tester
|
||||
/= all-tests
|
||||
/^ (map @ta tests:tester)
|
||||
/: /===/tests
|
||||
/_ /test-tree/
|
||||
::
|
||||
=, new-hoon
|
||||
|%
|
||||
::
|
||||
++ test-runner
|
||||
:> run all tests in {a} with a filter.
|
||||
=| pax=path
|
||||
|= [filter=path eny=@uvJ a=tests:tester]
|
||||
^- tang
|
||||
%- concat:ls
|
||||
%+ turn a
|
||||
|= b=instance:tester
|
||||
^- tang
|
||||
=^ matches filter (match-filter filter p.b)
|
||||
?. matches
|
||||
~
|
||||
?- -.q.b
|
||||
%& (run-test [p.b pax] eny p.q.b)
|
||||
%| ^$(pax [p.b pax], a p.q.b)
|
||||
==
|
||||
::
|
||||
++ run-test
|
||||
:> executes an individual test.
|
||||
|= [pax=path eny=@uvJ test=$-(@uvJ (list tape))]
|
||||
^- tang
|
||||
=+ name=(spud (flop pax))
|
||||
=+ run=(mule |.((test eny)))
|
||||
?- -.run
|
||||
$| :: the stack is already flopped for output?
|
||||
;: weld
|
||||
p:run
|
||||
`tang`[[%leaf (weld name " CRASHED")] ~]
|
||||
==
|
||||
$& ?: =(~ p:run)
|
||||
[[%leaf (weld name " OK")] ~]
|
||||
:: Create a welded list of all failures indented.
|
||||
%- flop
|
||||
;: weld
|
||||
`tang`[[%leaf (weld name " FAILED")] ~]
|
||||
%+ turn p:run
|
||||
|= {i/tape}
|
||||
^- tank
|
||||
[%leaf (weld " " i)]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ match-filter
|
||||
:> checks to see if {name} matches the head of {filter}.
|
||||
|= [filter=path name=term]
|
||||
^- [? path]
|
||||
?~ filter
|
||||
:: when there's no filter, we always match.
|
||||
[%.y ~]
|
||||
[=(i.filter name) t.filter]
|
||||
--
|
||||
::
|
||||
:- %say
|
||||
|= $: [now=@da eny=@uvJ bec=beak]
|
||||
[filter=$?($~ [pax=path $~])]
|
||||
$~
|
||||
==
|
||||
:- %tang
|
||||
%^ test-runner
|
||||
?~ filter ~ pax.filter
|
||||
eny
|
||||
(test-map-to-test-list:tester all-tests)
|
1557
lib/new-hoon.hoon
Normal file
1557
lib/new-hoon.hoon
Normal file
File diff suppressed because it is too large
Load Diff
165
lib/tester.hoon
Normal file
165
lib/tester.hoon
Normal file
@ -0,0 +1,165 @@
|
||||
/+ new-hoon
|
||||
::
|
||||
:> testing utilities
|
||||
|%
|
||||
:> # %models
|
||||
+|
|
||||
+= tests
|
||||
:> a hierarchical structure of tests
|
||||
:>
|
||||
:> a recursive association list mapping a part of a path
|
||||
:> to either a test trap or a sublist of the same type.
|
||||
(list instance)
|
||||
::
|
||||
+= instance
|
||||
:> a mapping between a term and part of a test tree.
|
||||
(pair term (each $-(@uvJ (list tape)) tests))
|
||||
::
|
||||
:> # %generate
|
||||
:> utilities for generating ++tests from files and directories.
|
||||
+|
|
||||
++ merge-base-and-recur
|
||||
:> combine the current file and subdirectory.
|
||||
:>
|
||||
:> this merges the file {base} with its child files {recur}.
|
||||
|= [base=vase recur=(map @ta tests:tester)]
|
||||
^- tests
|
||||
=+ a=(gen-tests base)
|
||||
=+ b=(test-map-to-test-list recur)
|
||||
:: todo: why does ++weld not work here? {a} and {b} are cast and have the
|
||||
:: correct faces.
|
||||
(welp a b)
|
||||
::
|
||||
++ test-map-to-test-list
|
||||
:> translates ford output to something we can work with.
|
||||
:>
|
||||
:> ford gives us a `(map @ta tests:tester)`, but we actually
|
||||
:> want something like ++tests.
|
||||
|= a=(map @ta tests:tester)
|
||||
:: todo: i'd like to sort this, but ++sort has -find.a problems much like
|
||||
:: ++weld does above!?
|
||||
^- tests
|
||||
%+ turn
|
||||
(to-list:dct:new-hoon a)
|
||||
|= {key/@ta value/tests:tester}
|
||||
[key [%| value]]
|
||||
::
|
||||
++ gen-tests
|
||||
:> creates a {tests} list out of a vase of a test suite
|
||||
|= v=vase
|
||||
^- tests
|
||||
=+ arms=(sort (sloe p.v) aor)
|
||||
%+ turn arms
|
||||
|= arm/term
|
||||
:- arm
|
||||
:- %&
|
||||
|= eny=@uvJ
|
||||
=+ context=(slop !>((init-test eny)) v)
|
||||
=/ r (slap context [%cnsg [arm ~] [%$ 3] [[%$ 2] ~]])
|
||||
((hard (list tape)) q:(slap r [%limb %results]))
|
||||
::
|
||||
:> # %per-test
|
||||
:> data initialized on a per-test basis.
|
||||
::
|
||||
++ init-test
|
||||
|= {cookie/@uvJ}
|
||||
~(. tester `(list tape)`~ cookie 10 0)
|
||||
::
|
||||
++ tester-type _(init-test `@uvJ`0)
|
||||
::
|
||||
++ tester
|
||||
|_ $: error-lines=(list tape) :< output messages
|
||||
eny=@uvJ :< entropy
|
||||
check-iterations=@u :< # of check trials
|
||||
current-iteration=@u :< current iteration
|
||||
==
|
||||
:> #
|
||||
:> # %check
|
||||
:> #
|
||||
:> gates for quick check style tests.
|
||||
+|
|
||||
+- check
|
||||
|* [generator=$-(@uvJ *) test=$-(* ?)]
|
||||
|-
|
||||
^+ +>.$
|
||||
?: (gth current-iteration check-iterations)
|
||||
+>.$
|
||||
:: todo: wrap generator in mule so it can crash.
|
||||
=+ sample=(generator eny)
|
||||
:: todo: wrap test in mule so it can crash.
|
||||
=+ ret=(test sample)
|
||||
?: ret
|
||||
%= $
|
||||
eny (shaf %huh eny) :: xxx: better random?
|
||||
current-iteration (add current-iteration 1)
|
||||
==
|
||||
=+ case=(add 1 current-iteration)
|
||||
=+ case-plural=?:(=(case 1) "case" "cases")
|
||||
%= +>.$
|
||||
error-lines :*
|
||||
"falsified after {(noah !>(case))} {case-plural} by '{(noah !>(sample))}'"
|
||||
error-lines
|
||||
==
|
||||
==
|
||||
::
|
||||
:: todo: a generate function that takes an arbitrary span.
|
||||
::
|
||||
++ generate-range
|
||||
|= [min=@ max=@]
|
||||
|= c=@uvJ
|
||||
^- @
|
||||
=+ gen=(random:new-hoon c)
|
||||
=^ num gen (range:gen min max)
|
||||
num
|
||||
::
|
||||
++ generate-dict
|
||||
:> generator which will produce a dict with {count} random pairs.
|
||||
|= count=@u
|
||||
:> generate a dict with entropy {c}.
|
||||
|= c=@uvJ
|
||||
:>
|
||||
:> gen: stateful random number generator
|
||||
:> out: resulting map
|
||||
:> i: loop counter
|
||||
:>
|
||||
=/ gen (random:new-hoon c)
|
||||
=| out=(dict:new-hoon @ud @ud)
|
||||
=| i=@u
|
||||
|-
|
||||
^- (dict:new-hoon @ud @ud)
|
||||
?: =(i count)
|
||||
out
|
||||
=^ first gen (range:gen 0 100)
|
||||
=^ second gen (range:gen 0 100)
|
||||
$(out (put:dct:new-hoon out first second), i +(i))
|
||||
:> #
|
||||
:> # %test
|
||||
:> #
|
||||
:> test expectation functions
|
||||
+|
|
||||
:: todo: unit testing libraries have a lot more to them than just eq.
|
||||
++ expect-eq
|
||||
|* [a=* b=* c=tape]
|
||||
^+ +>
|
||||
?: =(a b)
|
||||
+>.$
|
||||
%= +>.$
|
||||
error-lines :*
|
||||
"failure: '{c}'"
|
||||
" actual: '{(noah !>(a))}'"
|
||||
" expected: '{(noah !>(b))}'"
|
||||
error-lines
|
||||
==
|
||||
==
|
||||
::
|
||||
:> #
|
||||
:> # %output
|
||||
:> #
|
||||
:> called by the test harness
|
||||
::
|
||||
++ results
|
||||
:> returns results.
|
||||
^- (list tape)
|
||||
error-lines
|
||||
--
|
||||
--
|
10
ren/test-tree.hoon
Normal file
10
ren/test-tree.hoon
Normal file
@ -0,0 +1,10 @@
|
||||
/+ tester
|
||||
/= base /| /!noun/
|
||||
/~ ~
|
||||
==
|
||||
/= recur /^ (map @ta tests:tester)
|
||||
/| /_ /test-tree/
|
||||
/~ ~
|
||||
==
|
||||
::
|
||||
(merge-base-and-recur:tester !>(base) recur)
|
280
tests/new-hoon/ls.hoon
Normal file
280
tests/new-hoon/ls.hoon
Normal file
@ -0,0 +1,280 @@
|
||||
/+ new-hoon, tester
|
||||
=, ls:new-hoon
|
||||
|_ tester-type:tester
|
||||
++ test-head
|
||||
(expect-eq (head [1 ~]) 1 "head")
|
||||
::
|
||||
++ test-last
|
||||
(expect-eq (last:ls [1 2 ~]) 2 "last")
|
||||
::
|
||||
++ test-tail
|
||||
(expect-eq (tail [1 2 3 ~]) [2 3 ~] "tail")
|
||||
::
|
||||
++ test-init
|
||||
(expect-eq (init [1 2 3 ~]) [1 2 ~] "init")
|
||||
::
|
||||
++ test-size
|
||||
(expect-eq (size ['a' 'b' 'c' ~]) 3 "size")
|
||||
::
|
||||
++ test-map
|
||||
(expect-eq (map:ls [1 2 ~] |=(a/@ (add 1 a))) [2 3 ~] "map")
|
||||
::
|
||||
++ test-reverse
|
||||
(expect-eq (reverse [1 2 3 ~]) [3 2 1 ~] "reverse")
|
||||
::
|
||||
++ test-intersperse
|
||||
(expect-eq (intersperse 1 [5 5 5 ~]) [5 1 5 1 5 ~] "intersperse")
|
||||
::
|
||||
++ test-intercalate
|
||||
%^ expect-eq
|
||||
(intercalate "," ["one" "two" "three" ~])
|
||||
["one,two,three"]
|
||||
"intercalate"
|
||||
::
|
||||
++ test-transpose
|
||||
%^ expect-eq
|
||||
(transpose ~[~[1 2 3] ~[4 5 6]])
|
||||
~[~[1 4] ~[2 5] ~[3 6]]
|
||||
"transpose"
|
||||
::
|
||||
++ test-foldl
|
||||
(expect-eq (foldl [1 2 3 ~] 3 |=({a/@ b/@} (add a b))) 9 "foldl")
|
||||
::
|
||||
++ test-foldr
|
||||
(expect-eq (foldr [1 2 3 ~] 1 |=({a/@ b/@} (add a b))) 7 "foldr")
|
||||
::
|
||||
++ test-concat
|
||||
(expect-eq (concat ~[~[1 2] ~[3 4]]) ~[1 2 3 4] "concat")
|
||||
::
|
||||
++ test-weld
|
||||
(expect-eq (weld:ls ~[1 2 3] ~["one" "two"]) ~[1 2 3 "one" "two"] "weld")
|
||||
::
|
||||
++ test-any-true
|
||||
(expect-eq (any [1 2 3 ~] |=(a/@ =(a 2))) %.y "any true")
|
||||
::
|
||||
++ test-any-false
|
||||
(expect-eq (any [1 2 3 ~] |=(a/@ =(a 8))) %.n "any false")
|
||||
::
|
||||
++ test-all-true
|
||||
(expect-eq (all [1 1 1 ~] |=(a/@ =(a 1))) %.y "all true")
|
||||
::
|
||||
++ test-all-false
|
||||
(expect-eq (all [1 3 1 ~] |=(a/@ =(a 1))) %.n "all false")
|
||||
::
|
||||
++ test-scanl
|
||||
%^ expect-eq
|
||||
(scanl ~[1 2 3] 0 |=({a/@ b/@} (add a b)))
|
||||
~[0 1 3 6]
|
||||
"scanl"
|
||||
::
|
||||
++ test-scanl1
|
||||
%^ expect-eq
|
||||
(scanl1 ~[1 2 3] |=({a/@ b/@} (add a b)))
|
||||
~[1 3 6]
|
||||
"scanl1"
|
||||
::
|
||||
++ test-scanr
|
||||
%^ expect-eq
|
||||
(scanr ~[1 2 3] 0 |=({a/@ b/@} (add a b)))
|
||||
~[6 5 3 0]
|
||||
"scanr"
|
||||
::
|
||||
++ test-scanr1
|
||||
%^ expect-eq
|
||||
(scanr1 ~[1 2 3] |=({a/@ b/@} (add a b)))
|
||||
~[6 5 3]
|
||||
"scanr1"
|
||||
::
|
||||
++ test-map-foldl
|
||||
%^ expect-eq
|
||||
(map-foldl ~[1 2 3] 1 |=({a/@ b/@} [(add a b) (add 1 a)]))
|
||||
[7 ~[2 3 5]]
|
||||
"map-foldl"
|
||||
::
|
||||
++ test-map-foldr
|
||||
%^ expect-eq
|
||||
(map-foldr ~[1 2 3] 1 |=({a/@ b/@} [(add a b) (add 1 a)]))
|
||||
[7 ~[7 5 2]]
|
||||
"map-foldr"
|
||||
::
|
||||
++ test-unfoldr
|
||||
%^ expect-eq
|
||||
(unfoldr 5 |=(a/@ ?:(=(a 0) ~ `[a (dec a)])))
|
||||
[5 4 3 2 1 ~]
|
||||
"unfoldr"
|
||||
::
|
||||
++ test-take
|
||||
%^ expect-eq
|
||||
(take 3 ~[1 2 3 4 5])
|
||||
[1 2 3 ~]
|
||||
"take"
|
||||
::
|
||||
++ test-drop
|
||||
%^ expect-eq
|
||||
(drop:ls 3 ~[1 2 3 4 5])
|
||||
[4 5 ~]
|
||||
"drop"
|
||||
::
|
||||
++ test-split-at
|
||||
%^ expect-eq
|
||||
(split-at 3 ~[1 2 3 4 5])
|
||||
[[1 2 3 ~] [4 5 ~]]
|
||||
"split-at"
|
||||
::
|
||||
++ test-take-while
|
||||
%^ expect-eq
|
||||
(take-while ~[1 2 3 4 5] |=(a/@ (lth a 3)))
|
||||
[1 2 ~]
|
||||
"take-while"
|
||||
::
|
||||
++ test-drop-while
|
||||
%^ expect-eq
|
||||
(drop-while ~[1 2 3 4 5] |=(a/@ (lth a 3)))
|
||||
[3 4 5 ~]
|
||||
"drop-while"
|
||||
::
|
||||
++ test-drop-while-end
|
||||
%^ expect-eq
|
||||
(drop-while-end ~[5 5 1 5 5] |=(a/@ =(a 5)))
|
||||
[5 5 1 ~]
|
||||
"drop-while-end"
|
||||
::
|
||||
++ test-split-on
|
||||
%^ expect-eq
|
||||
(split-on ~[1 2 3 4 1 2 3 4] |=(a/@ (lth a 3)))
|
||||
[[1 2 ~] [3 4 1 2 3 4 ~]]
|
||||
"split-on"
|
||||
::
|
||||
++ test-break
|
||||
%^ expect-eq
|
||||
(break ~[1 2 3 4 1 2 3 4] |=(a/@ (gth a 3)))
|
||||
[[1 2 3 ~] [4 1 2 3 4 ~]]
|
||||
"break"
|
||||
::
|
||||
++ test-strip-prefix
|
||||
%^ expect-eq
|
||||
(strip-prefix "foo" "foobar")
|
||||
[~ "bar"]
|
||||
"break"
|
||||
::
|
||||
++ test-inits
|
||||
%^ expect-eq
|
||||
(inits "abc")
|
||||
["a" "ab" "abc" ~]
|
||||
"inits"
|
||||
::
|
||||
++ test-tails
|
||||
%^ expect-eq
|
||||
(tails "abc")
|
||||
["abc" "bc" "c" ~]
|
||||
"tails"
|
||||
::
|
||||
++ test-is-prefix-of
|
||||
%^ expect-eq
|
||||
(is-prefix-of "foo" "foobar")
|
||||
%.y
|
||||
"is-prefix-of"
|
||||
::
|
||||
++ test-is-suffix-of
|
||||
%^ expect-eq
|
||||
(is-suffix-of "bar" "foobar")
|
||||
%.y
|
||||
"is-suffix-of"
|
||||
::
|
||||
++ test-is-infix-of
|
||||
%^ expect-eq
|
||||
(is-infix-of "ob" "foobar")
|
||||
%.y
|
||||
"is-infix-of"
|
||||
::
|
||||
++ test-elem
|
||||
%^ expect-eq
|
||||
(elem 5 [1 2 3 4 5 ~])
|
||||
%.y
|
||||
"elem"
|
||||
::
|
||||
++ test-lookup
|
||||
%^ expect-eq
|
||||
(lookup "two" [["one" 1] ["two" 2] ["three" 3] ~])
|
||||
[~ 2]
|
||||
"lookup"
|
||||
::
|
||||
++ test-find
|
||||
%^ expect-eq
|
||||
(find:ls [3 2 1 5 1 2 3 ~] |=(a/@ (gth a 3)))
|
||||
[~ 5]
|
||||
"find"
|
||||
::
|
||||
++ test-filter
|
||||
%^ expect-eq
|
||||
(filter [1 2 1 2 1 ~] |=(a/@ =(a 2)))
|
||||
[1 1 1 ~]
|
||||
"filter"
|
||||
::
|
||||
++ test-partition
|
||||
%^ expect-eq
|
||||
(partition [1 2 1 2 1 ~] |=(a/@ =(a 2)))
|
||||
[[2 2 ~] [1 1 1 ~]]
|
||||
"partition"
|
||||
::
|
||||
++ test-elem-index
|
||||
%^ expect-eq
|
||||
(elem-index 2 [1 2 3 4 ~])
|
||||
`1
|
||||
"elem-index"
|
||||
::
|
||||
++ test-elem-indices
|
||||
%^ expect-eq
|
||||
(elem-indices 2 [1 2 1 2 ~])
|
||||
[1 3 ~]
|
||||
"elem-indices"
|
||||
::
|
||||
++ test-find-index
|
||||
%^ expect-eq
|
||||
(find-index [1 2 3 ~] |=(a/@ =(a 2)))
|
||||
`1
|
||||
"find-index"
|
||||
::
|
||||
++ test-find-indices
|
||||
%^ expect-eq
|
||||
(find-indices [1 2 1 2 ~] |=(a/@ =(a 2)))
|
||||
[1 3 ~]
|
||||
"find-indices"
|
||||
::
|
||||
++ test-zip
|
||||
%^ expect-eq
|
||||
(zip [[1 2 3 ~] [4 5 6 ~] [7 8 9 ~] ~])
|
||||
[[1 4 7 ~] [2 5 8 ~] [3 6 9 ~] ~]
|
||||
"zip"
|
||||
::
|
||||
++ test-unique
|
||||
%^ expect-eq
|
||||
(unique [1 2 3 1 2 3 ~])
|
||||
[1 2 3 ~]
|
||||
"unique"
|
||||
::
|
||||
++ test-delete
|
||||
%^ expect-eq
|
||||
(delete 2 [1 2 3 2 ~])
|
||||
[1 3 2 ~]
|
||||
"delete"
|
||||
::
|
||||
++ test-delete-firsts
|
||||
%^ expect-eq
|
||||
(delete-firsts [1 2 2 2 3 4 5 ~] [2 2 5 ~])
|
||||
[1 2 3 4 ~]
|
||||
"delete-firsts"
|
||||
::
|
||||
++ test-union
|
||||
%^ expect-eq
|
||||
(union [1 2 3 ~] [4 2 5 ~])
|
||||
[1 2 3 4 5 ~]
|
||||
"union"
|
||||
::
|
||||
++ test-intersect
|
||||
%^ expect-eq
|
||||
(intersect [5 6 6 7 8 ~] [9 8 8 6 ~])
|
||||
[6 6 8 ~]
|
||||
"intersect"
|
||||
--
|
||||
|
360
tests/new-hoon/mp.hoon
Normal file
360
tests/new-hoon/mp.hoon
Normal file
@ -0,0 +1,360 @@
|
||||
/+ new-hoon, tester
|
||||
=, dct:new-hoon
|
||||
=+ four=(from-list [[1 "one"] [2 "two"] [3 "three"] [4 "four"] ~])
|
||||
=+ three=(from-list [[1 "one"] [2 "two"] [3 "three"] ~])
|
||||
|_ tester-type:tester
|
||||
++ test-empty
|
||||
(expect-eq (empty four) %.n "empty")
|
||||
::
|
||||
++ test-size
|
||||
(expect-eq (size four) 4 "size")
|
||||
::
|
||||
++ test-member
|
||||
(expect-eq (member four 4) %.y "member")
|
||||
::
|
||||
++ test-put-with
|
||||
=+ ints=(from-list [["one" 1] ["two" 2] ["three" 3] ["four" 4] ~])
|
||||
%^ expect-eq
|
||||
(put-with ints "three" 2 add)
|
||||
(from-list [["one" 1] ["two" 2] ["three" 5] ["four" 4] ~])
|
||||
"put-with"
|
||||
::
|
||||
++ test-put-with-key
|
||||
%^ expect-eq
|
||||
(put-with-key four 4 "four" |=({a/@ud b/tape c/tape} (weld (scow %ud a) b)))
|
||||
(from-list [[1 "one"] [2 "two"] [3 "three"] [4 "4four"] ~])
|
||||
"put-with-key"
|
||||
::
|
||||
++ test-put-lookup-with-key
|
||||
%^ expect-eq
|
||||
%- put-lookup-with-key :^
|
||||
four
|
||||
4
|
||||
"five"
|
||||
|=({key/@ud old/tape new/tape} new)
|
||||
:- `"four"
|
||||
(from-list [[1 "one"] [2 "two"] [3 "three"] [4 "five"] ~])
|
||||
"put-lookup-with-key"
|
||||
::
|
||||
++ test-delete
|
||||
%^ expect-eq
|
||||
(delete four 4)
|
||||
three
|
||||
"delete"
|
||||
::
|
||||
++ test-adjust
|
||||
%^ expect-eq
|
||||
%^ adjust
|
||||
four
|
||||
3
|
||||
|=(a/tape (weld "this" a))
|
||||
(from-list [[1 "one"] [2 "two"] [3 "thisthree"] [4 "four"] ~])
|
||||
"adjust"
|
||||
::
|
||||
++ test-adjust-with-key
|
||||
%^ expect-eq
|
||||
%^ adjust-with-key
|
||||
four
|
||||
3
|
||||
|=({a/@ud b/tape} (weld (scow %ud a) b))
|
||||
(from-list [[1 "one"] [2 "two"] [3 "3three"] [4 "four"] ~])
|
||||
"adjust-with-key"
|
||||
::
|
||||
++ test-update
|
||||
%^ expect-eq
|
||||
%^ update
|
||||
four
|
||||
3
|
||||
|=(a/tape `(maybe tape)`~)
|
||||
(from-list [[1 "one"] [2 "two"] [4 "four"] ~])
|
||||
"update"
|
||||
::
|
||||
++ test-update-with-key
|
||||
%^ expect-eq
|
||||
%^ update-with-key
|
||||
four
|
||||
3
|
||||
|=({a/@u b/tape} `(maybe tape)`[~ (weld (scow %ud a) b)])
|
||||
(from-list [[1 "one"] [2 "two"] [3 "3three"] [4 "four"] ~])
|
||||
"update-with-key"
|
||||
::
|
||||
++ test-alter-as-add
|
||||
%^ expect-eq
|
||||
%^ alter
|
||||
four
|
||||
5
|
||||
|=(a/(maybe tape) `(maybe tape)`[~ "five"])
|
||||
(from-list [[1 "one"] [2 "two"] [3 "three"] [4 "four"] [5 "five"] ~])
|
||||
"alter (as add)"
|
||||
::
|
||||
++ test-alter-as-delete
|
||||
%^ expect-eq
|
||||
%^ alter
|
||||
four
|
||||
2
|
||||
|=(a/(maybe tape) `(maybe tape)`~)
|
||||
(from-list [[1 "one"] [3 "three"] [4 "four"] ~])
|
||||
"alter (as delete)"
|
||||
::
|
||||
++ test-alter-as-change
|
||||
%^ expect-eq
|
||||
%^ alter
|
||||
four
|
||||
2
|
||||
|=(a/(maybe tape) `(maybe tape)`[~ "dos"])
|
||||
(from-list [[1 "one"] [2 "dos"] [3 "three"] [4 "four"] ~])
|
||||
"alter (as change)"
|
||||
::
|
||||
++ check-alter
|
||||
:: check random dicts of 50 items with 40 random operations done on them
|
||||
:: for validity.
|
||||
%+ check
|
||||
(generate-dict 50)
|
||||
|= a/(dict @ud @ud)
|
||||
:: this is dumb, but use {a} as entropy?
|
||||
=/ gen (random:new-hoon (jam a))
|
||||
=| i/@u
|
||||
|-
|
||||
?: =(i 40)
|
||||
%.y
|
||||
=^ key gen (range:gen 0 100)
|
||||
=^ value gen (range:gen 0 100)
|
||||
=. a %^ alter-with-key a key
|
||||
|= {key/@ud current/(maybe @ud)}
|
||||
^- (maybe @ud)
|
||||
=+ action=(mod key 2)
|
||||
?: =(action 0) :: return nothing
|
||||
~
|
||||
?: =(action 1) :: add/set value
|
||||
`value
|
||||
~ :: impossible
|
||||
?. (valid a)
|
||||
%.n
|
||||
$(i +(i))
|
||||
::
|
||||
++ test-union
|
||||
%^ expect-eq
|
||||
%+ union
|
||||
(from-list [[1 "left"] [2 "left"] ~])
|
||||
(from-list [[2 "right"] [3 "right"] ~])
|
||||
(from-list [[1 "left"] [2 "left"] [3 "right"] ~])
|
||||
"union"
|
||||
::
|
||||
++ test-union-with
|
||||
%^ expect-eq
|
||||
%^ union-with
|
||||
(from-list [[1 "left"] [2 "left"] ~])
|
||||
(from-list [[2 "right"] [3 "right"] ~])
|
||||
|=({a/tape b/tape} (weld a b))
|
||||
(from-list [[1 "left"] [2 "leftright"] [3 "right"] ~])
|
||||
"union-with"
|
||||
::
|
||||
++ test-union-with-key
|
||||
%^ expect-eq
|
||||
%^ union-with-key
|
||||
(from-list [[1 "left"] [2 "left"] ~])
|
||||
(from-list [[2 "right"] [3 "right"] ~])
|
||||
|=({a/@ud b/tape c/tape} :(weld `tape`(scow %ud a) b c))
|
||||
(from-list [[1 "left"] [2 "2leftright"] [3 "right"] ~])
|
||||
"union-with-key"
|
||||
::
|
||||
++ test-map
|
||||
%^ expect-eq
|
||||
%+ map:dct
|
||||
three
|
||||
crip
|
||||
(from-list [[1 'one'] [2 'two'] [3 'three'] ~])
|
||||
"map"
|
||||
::
|
||||
++ test-map-with-key
|
||||
%^ expect-eq
|
||||
%+ map-with-key
|
||||
three
|
||||
|=({a/@u b/tape} (weld (scow %ud a) b))
|
||||
(from-list [[1 "1one"] [2 "2two"] [3 "3three"] ~])
|
||||
"map-with-key"
|
||||
::
|
||||
++ test-map-fold
|
||||
%^ expect-eq
|
||||
%^ map-fold
|
||||
three
|
||||
"Everything: "
|
||||
|= {accumulator/tape value/tape}
|
||||
[(weld accumulator value) (weld value "X")]
|
||||
:- "Everything: twoonethree"
|
||||
(from-list [[1 "oneX"] [2 "twoX"] [3 "threeX"] ~])
|
||||
"map-fold"
|
||||
::
|
||||
++ test-map-keys
|
||||
%^ expect-eq
|
||||
%+ map-keys
|
||||
three
|
||||
|= a/@u
|
||||
(add a 10)
|
||||
(from-list [[11 "one"] [12 "two"] [13 "three"] ~])
|
||||
"map-keys"
|
||||
::
|
||||
++ test-map-keys-with
|
||||
%^ expect-eq
|
||||
%^ map-keys-with
|
||||
three
|
||||
|=(a/@u 42)
|
||||
weld
|
||||
(from-list [[42 "twothreeone"] ~])
|
||||
"map-keys-with"
|
||||
::
|
||||
++ test-fold
|
||||
%^ expect-eq
|
||||
%^ fold
|
||||
three
|
||||
"Everything: "
|
||||
:: todo: this works but replacing with just ++weld causes an out of loom.
|
||||
|= {accumulator/tape value/tape}
|
||||
^- tape
|
||||
(weld accumulator value)
|
||||
"Everything: twoonethree"
|
||||
"map-fold"
|
||||
::
|
||||
++ test-fold-with-keys
|
||||
%^ expect-eq
|
||||
%^ fold-with-keys
|
||||
three
|
||||
"Everything: "
|
||||
|= {accumulator/tape key/@u value/tape}
|
||||
^- tape
|
||||
:(weld accumulator (scow %ud key) value)
|
||||
"Everything: 2two1one3three"
|
||||
"map-fold-with-keys"
|
||||
::
|
||||
++ test-elems
|
||||
%^ expect-eq
|
||||
(elems three)
|
||||
["two" "three" "one" ~]
|
||||
"elems"
|
||||
::
|
||||
++ test-keys
|
||||
%^ expect-eq
|
||||
(keys three)
|
||||
[2 3 1 ~]
|
||||
"keys"
|
||||
::
|
||||
++ test-keys-set
|
||||
%^ expect-eq
|
||||
(keys-set three)
|
||||
(si:nl [2 3 1 ~])
|
||||
"keys-set"
|
||||
::
|
||||
++ test-from-set
|
||||
%^ expect-eq
|
||||
%+ from-set
|
||||
(si:nl [1 2 3 ~])
|
||||
|= a/@u
|
||||
(scow %ud a)
|
||||
(from-list [[1 "1"] [2 "2"] [3 "3"] ~])
|
||||
"from-set"
|
||||
::
|
||||
++ test-from-list-with
|
||||
%^ expect-eq
|
||||
%+ from-list-with
|
||||
[[1 1] [2 1] [2 1] [3 3] ~]
|
||||
add
|
||||
(from-list [[1 1] [2 2] [3 3] ~])
|
||||
"from-list-with"
|
||||
::
|
||||
++ test-filter
|
||||
%^ expect-eq
|
||||
%+ filter
|
||||
(from-list [[1 1] [2 1] [3 2] [4 1] ~])
|
||||
|=(a/@u !=(a 1))
|
||||
(from-list [[1 1] [2 1] [4 1] ~])
|
||||
"filter"
|
||||
::
|
||||
++ test-filter-with-key
|
||||
%^ expect-eq
|
||||
%+ filter-with-key
|
||||
(from-list [[1 1] [2 1] [3 2] [4 1] ~])
|
||||
|=({a/@u b/@u} =(a 2))
|
||||
(from-list [[1 1] [3 2] [4 1] ~])
|
||||
"filter-with-key"
|
||||
::
|
||||
++ test-restrict-keys
|
||||
%^ expect-eq
|
||||
%+ restrict-keys
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
(si:nl [1 3 5 ~])
|
||||
(from-list [[1 1] [3 3] [5 5] ~])
|
||||
"restrict-keys"
|
||||
::
|
||||
++ test-without-keys
|
||||
%^ expect-eq
|
||||
%+ without-keys
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
(si:nl [1 3 5 ~])
|
||||
(from-list [[2 2] [4 4] ~])
|
||||
"restrict-keys"
|
||||
::
|
||||
++ test-partition
|
||||
%^ expect-eq
|
||||
%+ partition
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
|=(a/@u |(=(a 1) =(a 3)))
|
||||
:- (from-list [[1 1] [3 3] ~])
|
||||
(from-list [[2 2] [4 4] [5 5] ~])
|
||||
"partition"
|
||||
::
|
||||
++ test-map-maybe
|
||||
%^ expect-eq
|
||||
%+ map-maybe
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
|=(a/@u ?:(=(a 3) ~ `a))
|
||||
(from-list [[1 1] [2 2] [4 4] [5 5] ~])
|
||||
"map-maybe"
|
||||
::
|
||||
++ test-map-maybe-with-key
|
||||
%^ expect-eq
|
||||
%+ map-maybe-with-key
|
||||
(from-list [[1 2] [2 3] [3 4] [4 5] [5 6] ~])
|
||||
|=({k/@u v/@u} ?:(=(k 3) ~ `v))
|
||||
(from-list [[1 2] [2 3] [4 5] [5 6] ~])
|
||||
"map-maybe-with-key"
|
||||
::
|
||||
++ test-map-either
|
||||
%^ expect-eq
|
||||
%+ map-either
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
|= value/@u
|
||||
?: =(0 (mod value 2))
|
||||
[%& "even"]
|
||||
[%| 1]
|
||||
:- (from-list [[2 "even"] [4 "even"] ~])
|
||||
(from-list [[1 1] [3 1] [5 1] ~])
|
||||
"map-either"
|
||||
::
|
||||
++ test-map-either-with-key
|
||||
%^ expect-eq
|
||||
%+ map-either-with-key
|
||||
(from-list [[1 1] [2 1] [3 1] [4 1] [5 1] ~])
|
||||
|= {key/@u value/@u}
|
||||
?: =(0 (mod key 2))
|
||||
[%& "even"]
|
||||
[%| 1]
|
||||
:- (from-list [[2 "even"] [4 "even"] ~])
|
||||
(from-list [[1 1] [3 1] [5 1] ~])
|
||||
"map-either"
|
||||
::
|
||||
++ test-is-subdict
|
||||
%^ expect-eq
|
||||
%^ is-subdict-by
|
||||
(from-list [[1 1] [4 4] ~])
|
||||
(from-list [[1 1] [2 2] [3 3] [4 4] [5 5] ~])
|
||||
|=({a/* b/*} =(a b))
|
||||
%.y
|
||||
"is-subdict"
|
||||
::
|
||||
++ test-valid
|
||||
%^ expect-eq
|
||||
(valid (from-list [[1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9] ~]))
|
||||
%.y
|
||||
"valid"
|
||||
--
|
||||
|
32
tests/new-hoon/myb.hoon
Normal file
32
tests/new-hoon/myb.hoon
Normal file
@ -0,0 +1,32 @@
|
||||
/+ new-hoon, tester
|
||||
=, myb:new-hoon
|
||||
|_ tester-type:tester
|
||||
++ test-from-list-null
|
||||
(expect-eq (from-list ~) ~ "from-list")
|
||||
::
|
||||
++ test-from-list-real
|
||||
(expect-eq (from-list [5 ~]) [~ 5] "from-list")
|
||||
::
|
||||
++ test-to-list-null
|
||||
(expect-eq (to-list ~) ~ "to-list")
|
||||
::
|
||||
++ test-to-list-real
|
||||
(expect-eq (to-list [~ 5]) [5 ~] "to-list")
|
||||
::
|
||||
++ test-concat-null
|
||||
(expect-eq (concat ~) ~ "concat")
|
||||
::
|
||||
++ test-concat-real
|
||||
:: wait, if i pull the cast out from below, the concat implementation
|
||||
:: doesn't compile anymore?
|
||||
(expect-eq (concat `(list (maybe @ud))`[~ [~ 1] ~ [~ 2] ~]) [1 2 ~] "concat")
|
||||
::
|
||||
++ test-map
|
||||
%^ expect-eq
|
||||
%+ map:myb
|
||||
[1 2 3 2 ~]
|
||||
|=(a/@u ?:(=(2 a) [~ 2] ~))
|
||||
[2 2 ~]
|
||||
"map"
|
||||
--
|
||||
|
32
tests/new-hoon/thr.hoon
Normal file
32
tests/new-hoon/thr.hoon
Normal file
@ -0,0 +1,32 @@
|
||||
:: tests for the either core.
|
||||
/+ new-hoon, tester
|
||||
=, thr:new-hoon
|
||||
=/ data/(list (either @u tape)) [[%& 1] [%| "one"] [%& 2] [%| "two"] ~]
|
||||
|_ tester-type:tester
|
||||
++ test-apply
|
||||
%^ expect-eq
|
||||
%^ apply
|
||||
`(either @u tape)`[%| "one"]
|
||||
|=(a/@u "left")
|
||||
|=(b/tape "right")
|
||||
"right"
|
||||
"apply"
|
||||
::
|
||||
++ test-firsts
|
||||
%^ expect-eq
|
||||
(firsts data)
|
||||
[1 2 ~]
|
||||
"firsts"
|
||||
::
|
||||
++ test-seconds
|
||||
%^ expect-eq
|
||||
(seconds data)
|
||||
["one" "two" ~]
|
||||
"seconds"
|
||||
::
|
||||
++ test-partition
|
||||
%^ expect-eq
|
||||
(partition data)
|
||||
[[1 2 ~] ["one" "two" ~]]
|
||||
"partition"
|
||||
--
|
52
web/testing.umd
Normal file
52
web/testing.umd
Normal file
@ -0,0 +1,52 @@
|
||||
:- ~[comments+&]
|
||||
;>
|
||||
|
||||
# Writing Unit Tests
|
||||
|
||||
Urbit comes with a built in system for writing tests. Like hoon files with a
|
||||
certain shape go in `%/app` or `%/gen` or `%/mar`, hoon files with a certain
|
||||
shape can go in `%/tests` and then are exposed to a system wide test runner.
|
||||
|
||||
Say you put a test suite in `%/tests/new-hoon/thr.hoon`:
|
||||
|
||||
> +ls %/tests
|
||||
new-hoon/
|
||||
> +ls %/tests/new-hoon
|
||||
ls/hoon mp/hoon myb/hoon thr/hoon
|
||||
|
||||
You can then just run that individual test suite (and not the ones that are beside it in the `%/tests/new-hoon` directory) with:
|
||||
|
||||
> +tests /new-hoon/thr
|
||||
/new-hoon/thr/test-seconds OK
|
||||
/new-hoon/thr/test-partition OK
|
||||
/new-hoon/thr/test-firsts OK
|
||||
/new-hoon/thr/test-apply OK
|
||||
|
||||
## The test file
|
||||
|
||||
So what is the structure of these test files? They contain a door, with arms starting with `++test-` or `++check-`. At minimum:
|
||||
|
||||
/+ tester
|
||||
|_ tester-type:tester
|
||||
++ test-some-test
|
||||
(expect-eq 4 4 "trivial")
|
||||
--
|
||||
|
||||
All of the utilities you need to write tests are in the tester library. Also, like other hoon files, you can stack cores for models and utility functions with only the final core being inspected for test arms.
|
||||
|
||||
## Some Details
|
||||
|
||||
So internally, how does this work?
|
||||
|
||||
The `+test` generator depends on each file/directory in `%/tests/` through a renderer. Each node in the filesystem tree is rendered by `%/ren/test-tree.hoon`, which calls itself recursively for subdirectories.
|
||||
|
||||
This means all compiling of test cases happens inside ford, which can cache work and not recompile tests whose dependencies haven't changed. At runtime, all the `+test` generator does is filter and execute tests from the tree.
|
||||
|
||||
I would like to get to a place where any direct scrying of the filesystem is discouraged, and almost everything flows through the functional reactive build system. This is what it is here for.
|
||||
|
||||
### Future distribution of hoon libraries
|
||||
|
||||
Implicit in having a standard way to write tests and a standard `+test` runner is the idea that all functionality on the current desk should be tested.
|
||||
|
||||
Let's say I'm shipping a program on Urbit and I use multiple third-party libraries. Each of those libraries should have their own test suites placed in `%/tests/`. When I `|merge` their desks into my application desk, having a standard test runner means that all their tests and all my application tests get run. If you're depending on a library, you want to make sure that the tests for your dependencies run when you test your application.
|
||||
|
Loading…
Reference in New Issue
Block a user