hydra-0.15.0: src/main/haskell/Hydra/Sources/Test/Lib/Lists.hs
module Hydra.Sources.Test.Lib.Lists where
-- Standard imports for shallow DSL tests
import Hydra.Kernel
import Hydra.Dsl.Meta.Testing as Testing
import Hydra.Dsl.Meta.Terms as Terms
import Hydra.Sources.Kernel.Types.All
import qualified Hydra.Dsl.Meta.Core as Core
import qualified Hydra.Dsl.Meta.Phantoms as Phantoms
import qualified Hydra.Dsl.Meta.Types as T
import qualified Hydra.Sources.Test.TestGraph as TestGraph
import qualified Hydra.Sources.Test.TestTerms as TestTerms
import qualified Hydra.Sources.Test.TestTypes as TestTypes
import qualified Data.List as L
import qualified Data.Map as M
-- Additional imports specific to this file
import Hydra.Testing
import Hydra.Sources.Libraries
ns :: Namespace
ns = Namespace "hydra.test.lib.lists"
module_ :: Module
module_ = Module {
moduleNamespace = ns,
moduleDefinitions = definitions,
moduleTermDependencies = [TestGraph.ns, Namespace "hydra.reduction", Namespace "hydra.show.core"],
moduleTypeDependencies = kernelTypesNamespaces,
moduleDescription = (Just "Test cases for hydra.lib.lists primitives")}
where
definitions = [
Phantoms.toDefinition allTests]
define :: String -> TTerm a -> TTermDefinition a
define = definitionInModule module_
-- Helper functions for building test terms
intList :: [Int] -> TTerm Term
intList els = list (int32 <$> els)
intListList :: [[Int]] -> TTerm Term
intListList lists = list (intList <$> lists)
optionalInt32 :: Maybe Int -> TTerm Term
optionalInt32 Nothing = Core.termMaybe nothing
optionalInt32 (Just x) = Core.termMaybe $ just (int32 x)
optionalIntList :: Maybe [Int] -> TTerm Term
optionalIntList Nothing = Core.termMaybe nothing
optionalIntList (Just xs) = Core.termMaybe $ just (intList xs)
optionalIntAndIntList :: Maybe (Int, [Int]) -> TTerm Term
optionalIntAndIntList Nothing = Core.termMaybe nothing
optionalIntAndIntList (Just (x, xs)) = Core.termMaybe $ just (pair (int32 x) (intList xs))
optionalString :: Maybe String -> TTerm Term
optionalString Nothing = Core.termMaybe nothing
optionalString (Just x) = Core.termMaybe $ just (string x)
optionalStringList :: Maybe [String] -> TTerm Term
optionalStringList Nothing = Core.termMaybe nothing
optionalStringList (Just xs) = Core.termMaybe $ just (stringList xs)
stringList :: [String] -> TTerm Term
stringList els = list (string <$> els)
allTests :: TTermDefinition TestGroup
allTests = define "allTests" $
Phantoms.doc "Test cases for hydra.lib.lists primitives" $
supergroup "hydra.lib.lists primitives" [
listsApply,
listsBind,
listsConcat,
listsConcat2,
listsCons,
listsDrop,
listsDropWhile,
listsElem,
listsFilter,
listsFind,
listsFoldl,
listsFoldr,
listsGroup,
listsIntercalate,
listsIntersperse,
listsLength,
listsMap,
listsMaybeAt,
listsMaybeHead,
listsMaybeInit,
listsMaybeLast,
listsMaybeTail,
listsNub,
listsNull,
listsPartition,
listsPure,
listsReplicate,
listsReverse,
listsSingleton,
listsSort,
listsSortOn,
listsSpan,
listsTake,
listsTranspose,
listsUncons,
listsZip,
listsZipWith]
where
listsApply = supergroup "apply" [
subgroup "string transformations" [
testStr "string transformations" [primitive _strings_toUpper, primitive _strings_toLower] ["One", "Two", "Three"] ["ONE", "TWO", "THREE", "one", "two", "three"]],
subgroup "edge cases" [
testStr "empty function list" [] ["a", "b"] [],
testStr "empty input list" [primitive _strings_toUpper] [] [],
testStr "single function" [primitive _strings_toUpper] ["hello"] ["HELLO"],
testStr "single input" [primitive _strings_toUpper, primitive _strings_toLower] ["Test"] ["TEST", "test"]]]
where
testStr name funs lst result = primCase name _lists_apply [list funs, stringList lst] (stringList result)
listsBind = subgroup "bind" [
test "negation function" [1, 2, 3, 4] (lambda "x" (primitive _lists_pure @@ (primitive _math_negate @@ var "x"))) (negate <$> [1, 2, 3, 4]),
test "empty list" [] (lambda "x" (primitive _lists_pure @@ (primitive _math_negate @@ var "x"))) [],
test "single element" [5] (lambda "x" (primitive _lists_pure @@ (primitive _math_negate @@ var "x"))) [-5],
test "duplicate elements" [1, 1, 2] (lambda "x" (primitive _lists_pure @@ (primitive _math_negate @@ var "x"))) [-1, -1, -2]]
where
test name lst fun result = primCase name _lists_bind [intList lst, fun] (intList result)
listsConcat = subgroup "concat" [
test "multiple non-empty lists" [[1, 2, 3], [4, 5], [6, 7, 8]] [1, 2, 3, 4, 5, 6, 7, 8],
test "empty lists included" [[], [1, 2], [], [3]] [1, 2, 3],
test "single list" [[1, 2, 3]] [1, 2, 3],
test "all empty lists" [[], [], []] [],
test "empty list of lists" [] []]
where
test name lists result = primCase name _lists_concat [intListList lists] (intList result)
listsConcat2 = subgroup "concat2" [
testInt "two non-empty lists" [1, 2] [3, 4] [1, 2, 3, 4],
testInt "first list empty" [] [1, 2] [1, 2],
testInt "second list empty" [1, 2] [] [1, 2],
testInt "both lists empty" [] [] [],
testInt "single elements" [1] [2] [1, 2],
testStr "string lists" ["a", "b"] ["c", "d"] ["a", "b", "c", "d"]]
where
testInt name lst1 lst2 result = primCase name _lists_concat2 [intList lst1, intList lst2] (intList result)
testStr name lst1 lst2 result = primCase name _lists_concat2 [stringList lst1, stringList lst2] (stringList result)
listsCons = subgroup "cons" [
testInt "cons to non-empty list" 1 [2, 3] [1, 2, 3],
testInt "cons to empty list" 1 [] [1],
testInt "cons negative number" (-1) [2, 3] [-1, 2, 3],
testStr "cons string" "hello" ["world"] ["hello", "world"]]
where
testInt name x lst result = primCase name _lists_cons [int32 x, intList lst] (intList result)
testStr name x lst result = primCase name _lists_cons [string x, stringList lst] (stringList result)
listsDrop = subgroup "drop" [
test "drop from beginning" 2 [1, 2, 3, 4, 5] [3, 4, 5],
test "drop zero elements" 0 [1, 2, 3] [1, 2, 3],
test "drop all elements" 3 [1, 2, 3] [],
test "drop more than length" 5 [1, 2] [],
test "drop from empty list" 3 [] [],
test "drop negative amount" (-1) [1, 2, 3] [1, 2, 3]]
where
test name n lst result = primCase name _lists_drop [int32 n, intList lst] (intList result)
listsDropWhile = subgroup "dropWhile" [
test "drop while less than 3" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 3)) [1, 2, 3, 2, 1] [3, 2, 1],
test "drop all elements" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 10)) [1, 2, 3] [],
test "drop no elements" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 0)) [1, 2, 3] [1, 2, 3],
test "empty list" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 5)) [] []]
where
test name pred lst result = primCase name _lists_dropWhile [pred, intList lst] (intList result)
listsElem = subgroup "elem" [
testInt "element present" 2 [1, 2, 3] True,
testInt "element not present" 4 [1, 2, 3] False,
testInt "empty list" 1 [] False,
testInt "single element present" 1 [1] True,
testInt "single element not present" 2 [1] False,
testInt "duplicate elements" 2 [1, 2, 2, 3] True,
testStr "string element present" "hello" ["world", "hello", "test"] True,
testStr "string element not present" "missing" ["world", "hello"] False]
where
testInt name x lst result = primCase name _lists_elem [int32 x, intList lst] (boolean result)
testStr name x lst result = primCase name _lists_elem [string x, stringList lst] (boolean result)
listsFilter = subgroup "filter" [
test "filter positive numbers" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 0)) [-1, 2, -3, 4, 5] [2, 4, 5],
test "filter all elements" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 10)) [1, 2, 3] [1, 2, 3],
test "filter no elements" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 10)) [1, 2, 3] [],
test "empty list" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 0)) [] []]
where
test name pred lst result = primCase name _lists_filter [pred, intList lst] (intList result)
listsFind = subgroup "find" [
test "find existing element" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 3)) [1, 2, 4, 5] (Just 4),
test "find first matching" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 0)) [1, 2, 3] (Just 1),
test "find no match" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 10)) [1, 2, 3] Nothing,
test "find in empty list" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 0)) [] Nothing,
test "find single element" (lambda "x" (primitive _equality_equal @@ var "x" @@ int32 42)) [42] (Just 42)]
where
test name pred lst result = primCase name _lists_find [pred, intList lst] (optionalInt32 result)
listsFoldl = subgroup "foldl" [
test "sum with addition" (primitive _math_add) 0 [1, 2, 3, 4] 10,
test "product with multiplication" (primitive _math_mul) 1 [2, 3, 4] 24,
test "empty list" (primitive _math_add) 5 [] 5,
test "single element" (primitive _math_add) 10 [5] 15,
test "subtraction fold" (primitive _math_sub) 10 [1, 2, 3] 4]
where
test name op acc lst result = primCase name _lists_foldl [op, int32 acc, intList lst] (int32 result)
listsFoldr = subgroup "foldr" [
test "subtraction fold right" (primitive _math_sub) 0 [1, 2, 3] 2,
test "empty list" (primitive _math_add) 5 [] 5,
test "single element" (primitive _math_add) 10 [5] 15,
test "sum with addition" (primitive _math_add) 0 [1, 2, 3, 4] 10,
test "subtraction vs foldl" (primitive _math_sub) 10 [1, 2, 3] (-8)]
where
test name op acc lst result = primCase name _lists_foldr [op, int32 acc, intList lst] (int32 result)
listsGroup = subgroup "group" [
test "consecutive duplicates" [1, 1, 2, 2, 2, 3, 1] [[1, 1], [2, 2, 2], [3], [1]],
test "no duplicates" [1, 2, 3] [[1], [2], [3]],
test "all same" [1, 1, 1] [[1, 1, 1]],
test "empty list" [] [],
test "single element" [1] [[1]]]
where
test name lst result = primCase name _lists_group [intList lst] (intListList result)
listsIntercalate = subgroup "intercalate" [
test "double zero separator" [0, 0] [[1, 2, 3], [4, 5], [6, 7, 8]] [1, 2, 3, 0, 0, 4, 5, 0, 0, 6, 7, 8],
test "empty separator" [] [[1, 2], [3, 4]] [1, 2, 3, 4],
test "single element separator" [99] [[1], [2], [3]] [1, 99, 2, 99, 3],
test "empty list of lists" [0] [] [],
test "single list" [0] [[1, 2, 3]] [1, 2, 3],
test "lists with empty lists" [0] [[], [1], []] [0, 1, 0]]
where
test name ifx lists result = primCase name _lists_intercalate [intList ifx, intListList lists] (intList result)
listsIntersperse = subgroup "intersperse" [
testStr "string interspersion" "and" ["one", "two", "three"] ["one", "and", "two", "and", "three"],
testStr "single element" "x" ["only"] ["only"],
testStr "empty list" "x" [] [],
testStr "two elements" "+" ["a", "b"] ["a", "+", "b"],
testInt "number interspersion" 0 [1, 2, 3] [1, 0, 2, 0, 3]]
where
testStr name ifx lst result = primCase name _lists_intersperse [string ifx, stringList lst] (stringList result)
testInt name ifx lst result = primCase name _lists_intersperse [int32 ifx, intList lst] (intList result)
listsLength = subgroup "length" [
testInt "three elements" [1, 2, 3] 3,
testInt "empty list" [] 0,
testInt "single element" [42] 1,
testInt "many elements" [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 10,
testStr "string list" ["a", "b", "c"] 3]
where
testInt name lst result = primCase name _lists_length [intList lst] (int32 result)
testStr name lst result = primCase name _lists_length [stringList lst] (int32 result)
listsMap = subgroup "map" [
testStr "string to uppercase" (primitive _strings_toUpper) ["one", "two"] ["ONE", "TWO"],
testStr "empty list" (primitive _strings_toUpper) [] [],
testStr "single element" (primitive _strings_toUpper) ["hello"] ["HELLO"],
testInt "number negation" (primitive _math_negate) [1, 2, 3] [-1, -2, -3],
testInt "identity function" (primitive _equality_identity) [1, 2, 3] [1, 2, 3]]
where
testStr name fun lst result = primCase name _lists_map [fun, stringList lst] (stringList result)
testInt name fun lst result = primCase name _lists_map [fun, intList lst] (intList result)
listsMaybeAt = subgroup "maybeAt" [
test "valid index" 1 [10, 20, 30] (Just 20),
test "first element" 0 [10, 20, 30] (Just 10),
test "last element" 2 [10, 20, 30] (Just 30),
test "out of bounds" 5 [10, 20, 30] Nothing,
test "negative index" (-1) [10, 20, 30] Nothing,
test "empty list" 0 [] Nothing]
where
test name i lst result = primCase name _lists_maybeAt [int32 i, intList lst] (optionalInt32 result)
listsMaybeHead = subgroup "maybeHead" [
testInt "non-empty int list" [1, 2, 3] (Just 1),
testInt "empty int list" [] Nothing,
testInt "single element" [42] (Just 42),
testStr "non-empty string list" ["hello", "world"] (Just "hello"),
testStr "empty string list" [] Nothing]
where
testInt name lst result = primCase name _lists_maybeHead [intList lst] (optionalInt32 result)
testStr name lst result = primCase name _lists_maybeHead [stringList lst] (optionalString result)
listsMaybeInit = subgroup "maybeInit" [
testInt "three elements" [1, 2, 3] (Just [1, 2]),
testInt "single element" [42] (Just []),
testInt "empty list" [] Nothing,
testStr "string list" ["a", "b", "c"] (Just ["a", "b"])]
where
testInt name lst result = primCase name _lists_maybeInit [intList lst] (optionalIntList result)
testStr name lst result = primCase name _lists_maybeInit [stringList lst] (optionalStringList result)
listsMaybeLast = subgroup "maybeLast" [
testInt "three elements" [1, 2, 3] (Just 3),
testInt "single element" [42] (Just 42),
testInt "empty list" [] Nothing,
testStr "string list" ["hello", "world"] (Just "world")]
where
testInt name lst result = primCase name _lists_maybeLast [intList lst] (optionalInt32 result)
testStr name lst result = primCase name _lists_maybeLast [stringList lst] (optionalString result)
listsMaybeTail = subgroup "maybeTail" [
testInt "three elements" [1, 2, 3] (Just [2, 3]),
testInt "single element" [42] (Just []),
testInt "empty list" [] Nothing,
testStr "string list" ["a", "b", "c"] (Just ["b", "c"])]
where
testInt name lst result = primCase name _lists_maybeTail [intList lst] (optionalIntList result)
testStr name lst result = primCase name _lists_maybeTail [stringList lst] (optionalStringList result)
listsNub = subgroup "nub" [
testInt "remove duplicates" [1, 2, 1, 3, 2, 4] [1, 2, 3, 4],
testInt "no duplicates" [1, 2, 3] [1, 2, 3],
testInt "all duplicates" [1, 1, 1] [1],
testInt "empty list" [] [],
testInt "single element" [1] [1],
testStr "string duplicates" ["a", "b", "a", "c"] ["a", "b", "c"]]
where
testInt name lst result = primCase name _lists_nub [intList lst] (intList result)
testStr name lst result = primCase name _lists_nub [stringList lst] (stringList result)
listsNull = subgroup "null" [
testInt "empty int list" [] True,
testInt "single element" [1] False,
testInt "multiple elements" [1, 2, 3] False,
testStr "empty string list" [] True,
testStr "non-empty string list" ["a"] False]
where
testInt name lst result = primCase name _lists_null [intList lst] (boolean result)
testStr name lst result = primCase name _lists_null [stringList lst] (boolean result)
listsPartition = subgroup "partition" [
test "partition greater than 3" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 3)) [1, 2, 3, 4, 5, 6] ([4, 5, 6], [1, 2, 3]),
test "partition all elements" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 10)) [1, 2, 3] ([1, 2, 3], []),
test "partition no elements" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 10)) [1, 2, 3] ([], [1, 2, 3]),
test "partition even numbers" (lambda "x" (primitive _math_even @@ var "x")) [1, 2, 3, 4, 5, 6] ([2, 4, 6], [1, 3, 5]),
test "empty list" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 5)) [] ([], [])]
where
test name pred lst (yes, no) = primCase name _lists_partition [pred, intList lst] (pair (intList yes) (intList no))
listsPure = subgroup "pure" [
testStr "string element" "one" ["one"],
testStr "empty string" "" [""],
testInt "number element" 42 [42],
testInt "negative number" (-5) [-5]]
where
testStr name arg result = primCase name _lists_pure [string arg] (stringList result)
testInt name arg result = primCase name _lists_pure [int32 arg] (intList result)
listsReplicate = subgroup "replicate" [
testInt "replicate three times" 3 42 [42, 42, 42],
testInt "replicate zero times" 0 1 [],
testInt "replicate once" 1 99 [99],
testStr "replicate string" 2 "hello" ["hello", "hello"]]
where
testInt name n x result = primCase name _lists_replicate [int32 n, int32 x] (intList result)
testStr name n x result = primCase name _lists_replicate [int32 n, string x] (stringList result)
listsReverse = subgroup "reverse" [
testInt "multiple elements" [1, 2, 3, 4] [4, 3, 2, 1],
testInt "single element" [1] [1],
testInt "empty list" [] [],
testInt "two elements" [1, 2] [2, 1],
testStr "string list" ["a", "b", "c"] ["c", "b", "a"]]
where
testInt name lst result = primCase name _lists_reverse [intList lst] (intList result)
testStr name lst result = primCase name _lists_reverse [stringList lst] (stringList result)
listsSingleton = subgroup "singleton" [
testInt "number element" 42 [42],
testInt "negative number" (-1) [-1],
testInt "zero" 0 [0],
testStr "string element" "hello" ["hello"]]
where
testInt name x result = primCase name _lists_singleton [int32 x] (intList result)
testStr name x result = primCase name _lists_singleton [string x] (stringList result)
listsSort = subgroup "sort" [
testInt "unsorted numbers" [3, 1, 4, 1, 5] [1, 1, 3, 4, 5],
testInt "already sorted" [1, 2, 3] [1, 2, 3],
testInt "reverse sorted" [3, 2, 1] [1, 2, 3],
testInt "single element" [1] [1],
testInt "empty list" [] [],
testInt "duplicates" [2, 1, 2, 3, 1] [1, 1, 2, 2, 3],
testStr "string sort" ["zebra", "apple", "banana"] ["apple", "banana", "zebra"]]
where
testInt name lst result = primCase name _lists_sort [intList lst] (intList result)
testStr name lst result = primCase name _lists_sort [stringList lst] (stringList result)
listsSortOn = subgroup "sortOn" [
testStr "sort by string length" (primitive _strings_length) ["hello", "hi", "world"] ["hi", "hello", "world"],
testStr "empty string list" (primitive _strings_length) [] [],
testStr "single string element" (primitive _strings_length) ["test"] ["test"],
testInt "sort by negation" (primitive _math_negate) [1, 3, 2] [3, 2, 1],
testInt "sort by absolute value" (primitive _math_abs) [-1, -3, 2] [-1, 2, -3]]
where
testStr name keyFn lst result = primCase name _lists_sortOn [keyFn, stringList lst] (stringList result)
testInt name keyFn lst result = primCase name _lists_sortOn [keyFn, intList lst] (intList result)
listsSpan = subgroup "span" [
test "span less than 3" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 3)) [1, 2, 3, 1, 2] ([1, 2], [3, 1, 2]),
test "span all elements" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 10)) [1, 2, 3] ([1, 2, 3], []),
test "span no elements" (lambda "x" (primitive _equality_gt @@ var "x" @@ int32 10)) [1, 2, 3] ([], [1, 2, 3]),
test "empty list" (lambda "x" (primitive _equality_lt @@ var "x" @@ int32 5)) [] ([], [])]
where
test name pred lst (prefix, suffix) = primCase name _lists_span [pred, intList lst] (pair (intList prefix) (intList suffix))
listsTake = subgroup "take" [
test "take from beginning" 2 [1, 2, 3, 4, 5] [1, 2],
test "take zero elements" 0 [1, 2, 3] [],
test "take all elements" 3 [1, 2, 3] [1, 2, 3],
test "take more than length" 5 [1, 2] [1, 2],
test "take from empty list" 3 [] [],
test "take negative amount" (-1) [1, 2, 3] []]
where
test name n lst result = primCase name _lists_take [int32 n, intList lst] (intList result)
listsTranspose = subgroup "transpose" [
test "square matrix" [[1, 2, 3], [4, 5, 6]] [[1, 4], [2, 5], [3, 6]],
test "empty lists" [] [],
test "single row" [[1, 2, 3]] [[1], [2], [3]],
test "single column" [[1], [2], [3]] [[1, 2, 3]],
test "ragged matrix" [[1, 2], [3], [4, 5, 6]] [[1, 3, 4], [2, 5], [6]]]
where
test name matrix result = primCase name _lists_transpose [intListList matrix] (intListList result)
listsUncons = subgroup "uncons" [
test "three elements" [1, 2, 3] (Just (1, [2, 3])),
test "single element" [42] (Just (42, [])),
test "empty list" [] Nothing]
where
test name lst result = primCase name _lists_uncons [intList lst] (optionalIntAndIntList result)
listsZip = subgroup "zip" [
test "equal length lists" [1, 2, 3] ["a", "b", "c"] [(1, "a"), (2, "b"), (3, "c")],
test "first list shorter" [1, 2] ["a", "b", "c"] [(1, "a"), (2, "b")],
test "second list shorter" [1, 2, 3] ["a", "b"] [(1, "a"), (2, "b")],
test "empty first list" [] ["a", "b"] [],
test "empty second list" [1, 2] [] [],
test "both empty lists" [] [] []]
where
test name lst1 lst2 result = primCase name _lists_zip [intList lst1, stringList lst2] (list ((\(x, y) -> pair (int32 x) (string y)) <$> result))
listsZipWith = subgroup "zipWith" [
testInt "addition" (primitive _math_add) [1, 2, 3] [4, 5, 6] [5, 7, 9],
testInt "first list shorter" (primitive _math_add) [1, 2] [4, 5, 6] [5, 7],
testInt "second list shorter" (primitive _math_add) [1, 2, 3] [4, 5] [5, 7],
testInt "empty first list" (primitive _math_add) [] [1, 2, 3] [],
testInt "empty second list" (primitive _math_add) [1, 2, 3] [] [],
testStr "string concatenation" (primitive _strings_cat2) ["a", "b"] ["1", "2"] ["a1", "b2"]]
where
testInt name op lst1 lst2 result = primCase name _lists_zipWith [op, intList lst1, intList lst2] (intList result)
testStr name op lst1 lst2 result = primCase name _lists_zipWith [op, stringList lst1, stringList lst2] (stringList result)