hydra-0.13.0: src/main/haskell/Hydra/Sources/Test/Lib/Maps.hs
module Hydra.Sources.Test.Lib.Maps 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
import qualified Hydra.Dsl.Meta.Lib.Maps as Maps
ns :: Namespace
ns = Namespace "hydra.test.lib.maps"
module_ :: Module
module_ = Module ns elements [] [] $
Just "Test cases for hydra.lib.maps primitives"
where
elements = [Phantoms.toBinding allTests]
emptyStringMap = intStringMap []
intStringMapOrEmpty = intStringMap
---- This is a hack for HSpec. We create a map<string, string>, because that is the map type we default to when there are no elements.
--emptyStringMap :: TTerm Term
--emptyStringMap = primitive _maps_fromList @@ (primitive _lists_drop @@ int32 1 @@ list [pair (string "") (string "")])
-- Helper to create map terms (Int -> String maps)
intStringMap :: [(Int, String)] -> TTerm Term
intStringMap pairs = Core.termMap $ Phantoms.map $ M.fromList $ fmap toPair pairs
where
toPair (k, v) = (int32 k, string v)
--intStringMapOrEmpty :: [(Int, String)] -> TTerm Term
--intStringMapOrEmpty pairs = if L.null pairs then emptyStringMap else intStringMap pairs
-- Helper for optional values
optionalString :: Maybe String -> TTerm Term
optionalString Nothing = Core.termMaybe nothing
optionalString (Just s) = Core.termMaybe $ just (Terms.string s)
-- Test groups for hydra.lib.maps primitives
mapsEmpty :: TTerm TestGroup
mapsEmpty = subgroup "empty" [
test "empty map"]
where
test name = primCase name _maps_empty [] emptyStringMap
mapsSingleton :: TTerm TestGroup
mapsSingleton = subgroup "singleton" [
test "single entry" 42 "hello" [(42, "hello")]]
where
test name k v result = primCase name _maps_singleton [int32 k, Terms.string v] (intStringMap result)
mapsFromList :: TTerm TestGroup
mapsFromList = subgroup "fromList" [
test "create from pairs" [(1, "a"), (2, "b")] [(1, "a"), (2, "b")],
test "duplicate keys" [(1, "a"), (1, "b")] [(1, "b")],
test "empty list" [] []]
where
test name input expected = primCase name _maps_fromList [
list $ Prelude.map (\(k, v) -> Core.termPair $ Phantoms.pair (int32 k) (Terms.string v)) input
] $ intStringMap expected
mapsToList :: TTerm TestGroup
mapsToList = subgroup "toList" [
test "convert to pairs" [(1, "a"), (2, "b")] [(1, "a"), (2, "b")],
test "unsorted keys" [(3, "c"), (1, "a"), (2, "b")] [(1, "a"), (2, "b"), (3, "c")],
test "empty map" [] []]
where
test name input expected = primCase name _maps_toList [intStringMap input] (
list $ Prelude.map (\(k, v) -> Core.termPair $ Phantoms.pair (int32 k) (Terms.string v)) expected)
mapsInsert :: TTerm TestGroup
mapsInsert = subgroup "insert" [
test "insert new key" 3 "c" [(1, "a"), (2, "b")] [(1, "a"), (2, "b"), (3, "c")],
test "update existing" 2 "updated" [(1, "a"), (2, "b")] [(1, "a"), (2, "updated")],
test "insert into empty" 1 "x" [] [(1, "x")]]
where
test name k v m result = primCase name _maps_insert [int32 k, Terms.string v, intStringMap m] (intStringMap result)
mapsRemove :: TTerm TestGroup
mapsRemove = subgroup "remove" [
test "remove existing" 2 [(1, "a"), (2, "b"), (3, "c")] [(1, "a"), (3, "c")],
test "remove non-existing" 4 [(1, "a"), (2, "b")] [(1, "a"), (2, "b")],
test "remove from empty" 1 [] []]
where
test name k m result = primCase name _maps_delete [int32 k, intStringMap m] (intStringMap result)
mapsLookup :: TTerm TestGroup
mapsLookup = subgroup "lookup" [
test "find existing key" 2 [(1, "a"), (2, "b")] (Just "b"),
test "key not found" 3 [(1, "a"), (2, "b")] Nothing,
test "lookup in empty" 1 [] Nothing]
where
test name k m result = primCase name _maps_lookup [int32 k, intStringMap m] (optionalString result)
mapsMember :: TTerm TestGroup
mapsMember = subgroup "member" [
test "key exists" 2 [(1, "a"), (2, "b")] true,
test "key missing" 3 [(1, "a"), (2, "b")] false,
test "empty map" 1 [] false]
where
test name k m result = primCase name _maps_member [int32 k, intStringMap m] result
mapsSize :: TTerm TestGroup
mapsSize = subgroup "size" [
test "three entries" [(1, "a"), (2, "b"), (3, "c")] 3,
test "single entry" [(42, "test")] 1,
test "empty map" [] 0]
where
test name m result = primCase name _maps_size [intStringMapOrEmpty m] (int32 result)
mapsNull :: TTerm TestGroup
mapsNull = subgroup "null" [
test "empty map" [] true,
test "non-empty map" [(1, "a")] false]
where
test name m result = primCase name _maps_null [intStringMapOrEmpty m] result
mapsKeys :: TTerm TestGroup
mapsKeys = subgroup "keys" [
test "get all keys" [(1, "a"), (2, "b"), (3, "c")] [1, 2, 3],
test "unsorted keys" [(3, "c"), (1, "a"), (2, "b")] [1, 2, 3],
test "empty map" [] []]
where
test name m result = primCase name _maps_keys [intStringMapOrEmpty m] (list $ Prelude.map int32 result)
mapsElems :: TTerm TestGroup
mapsElems = subgroup "elems" [
test "get all elements" [(1, "a"), (2, "b")] ["a", "b"],
test "unsorted keys" [(3, "c"), (1, "a"), (2, "b")] ["a", "b", "c"],
test "empty map" [] []]
where
test name m result = primCase name _maps_elems [intStringMapOrEmpty m] (list $ Prelude.map Terms.string result)
mapsMap :: TTerm TestGroup
mapsMap = subgroup "map" [
test "map over values" [(1, "a"), (2, "b")] [(1, "A"), (2, "B")],
test "map empty" [] []]
where
test name m result = primCase name _maps_map [
lambda "s" (primitive _strings_toUpper @@ var "s"),
intStringMapOrEmpty m] (intStringMapOrEmpty result)
mapsFindWithDefault :: TTerm TestGroup
mapsFindWithDefault = subgroup "findWithDefault" [
test "find existing" "default" 2 [(1, "a"), (2, "b")] "b",
test "use default" "default" 3 [(1, "a"), (2, "b")] "default"]
where
test name def k m result = primCase name _maps_findWithDefault [
Terms.string def, int32 k, intStringMap m] (Terms.string result)
mapsUnion :: TTerm TestGroup
mapsUnion = subgroup "union" [
test "union two maps" [(1, "a"), (2, "b")] [(2, "x"), (3, "c")] [(1, "a"), (2, "b"), (3, "c")],
test "union with empty" [(1, "a")] [] [(1, "a")],
test "empty with map" [] [(1, "a")] [(1, "a")]]
where
test name m1 m2 result = primCase name _maps_union [intStringMap m1, intStringMap m2] (intStringMap result)
mapsMapKeys :: TTerm TestGroup
mapsMapKeys = subgroup "mapKeys" [
test "double keys" [(1, "a"), (2, "b")] [(2, "a"), (4, "b")],
test "empty map" [] []]
where
test name m result = primCase name _maps_mapKeys [
lambda "k" (primitive _math_mul @@ var "k" @@ int32 2),
intStringMapOrEmpty m] (intStringMapOrEmpty result)
mapsFilter :: TTerm TestGroup
mapsFilter = subgroup "filter" [
test "filter values starting with a" [(1, "a"), (2, "b"), (3, "ab")] [(1, "a"), (3, "ab")],
test "filter all" [(1, "b"), (2, "c")] [],
test "empty map" [] []]
where
test name m result = primCase name _maps_filter [
lambda "v" (primitive _equality_equal @@ (primitive _strings_charAt @@ int32 0 @@ var "v") @@ int32 97), -- 'a' = 97
intStringMapOrEmpty m] (intStringMapOrEmpty result)
mapsFilterWithKey :: TTerm TestGroup
mapsFilterWithKey = subgroup "filterWithKey" [
test "filter by key > 1" [(1, "a"), (2, "b"), (3, "c")] [(2, "b"), (3, "c")],
test "filter all" [(1, "a")] [],
test "empty map" [] []]
where
test name m result = primCase name _maps_filterWithKey [
lambda "k" (lambda "v" (primitive _equality_gt @@ var "k" @@ int32 1)),
intStringMapOrEmpty m] (intStringMapOrEmpty result)
mapsBimap :: TTerm TestGroup
mapsBimap = subgroup "bimap" [
test "transform both" [(1, "a"), (2, "b")] [(2, "A"), (4, "B")],
test "empty map" [] []]
where
test name m result = primCase name _maps_bimap [
lambda "k" (primitive _math_mul @@ var "k" @@ int32 2),
lambda "v" (primitive _strings_toUpper @@ var "v"),
intStringMapOrEmpty m] (intStringMapOrEmpty result)
mapsAlter :: TTerm TestGroup
mapsAlter = subgroup "alter" [
test "insert new key" 3 [(1, "a"), (2, "b")] [(1, "a"), (2, "b"), (3, "new")],
test "update existing key" 2 [(1, "a"), (2, "b")] [(1, "a"), (2, "updated")],
test "delete key" 2 [(1, "a"), (2, "b")] [(1, "a")]]
where
-- The alter function tests use different functions:
-- insert: always return Just "new"
test "insert new key" k m result = primCase "insert new key" _maps_alter [
lambda "opt" (Core.termMaybe $ just (Terms.string "new")),
int32 k, intStringMap m] (intStringMap result)
-- update: return Just "updated" if exists
test "update existing key" k m result = primCase "update existing key" _maps_alter [
lambda "opt" (Core.termMaybe $ just (Terms.string "updated")),
int32 k, intStringMap m] (intStringMap result)
-- delete: always return Nothing
test "delete key" k m result = primCase "delete key" _maps_alter [
lambda "opt" (Core.termMaybe nothing),
int32 k, intStringMap m] (intStringMap result)
allTests :: TBinding TestGroup
allTests = definitionInModule module_ "allTests" $
Phantoms.doc "Test cases for hydra.lib.maps primitives" $
supergroup "hydra.lib.maps primitives" [
mapsAlter,
mapsBimap,
mapsElems,
mapsEmpty,
mapsFilter,
mapsFilterWithKey,
mapsFindWithDefault,
mapsFromList,
mapsInsert,
mapsKeys,
mapsLookup,
mapsMap,
mapsMapKeys,
mapsMember,
mapsNull,
mapsRemove,
mapsSingleton,
mapsSize,
mapsToList,
mapsUnion]