hydra-0.15.0: src/main/haskell/Hydra/Sources/Test/Lib/Maybes.hs
{-# LANGUAGE FlexibleContexts #-}
module Hydra.Sources.Test.Lib.Maybes 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.Equality as Equality
import qualified Hydra.Dsl.Meta.Lib.Literals as Literals
import qualified Hydra.Dsl.Meta.Lib.Logic as Logic
import qualified Hydra.Dsl.Meta.Lib.Math as Math
import qualified Hydra.Dsl.Meta.Lib.Maybes as Maybes
import qualified Hydra.Sources.Kernel.Terms.Show.Core as ShowCore
ns :: Namespace
ns = Namespace "hydra.test.lib.maybes"
module_ :: Module
module_ = Module {
moduleNamespace = ns,
moduleDefinitions = definitions,
moduleTermDependencies = [Namespace "hydra.reduction", ShowCore.ns],
moduleTypeDependencies = kernelTypesNamespaces,
moduleDescription = Just "Test cases for hydra.lib.maybes primitives"}
where
definitions = [Phantoms.toDefinition allTests]
(#) :: (AsTerm f (a -> b), AsTerm g a) => f -> g -> TTerm b
(#) = (Phantoms.@@)
infixl 1 #
showInt32 :: TTerm (Int -> String)
showInt32 = Phantoms.lambda "n" $ Literals.showInt32 (Phantoms.var "n")
showBool :: TTerm (Bool -> String)
showBool = Phantoms.lambda "b" $ Literals.showBoolean (Phantoms.var "b")
showMaybeInt :: TTerm (Maybe Int -> String)
showMaybeInt = Phantoms.lambda "mx" $ ShowCore.maybe_ # showInt32 # Phantoms.var "mx"
showIntList :: TTerm ([Int] -> String)
showIntList = Phantoms.lambda "xs" $ ShowCore.list_ # showInt32 # Phantoms.var "xs"
showMaybeString :: TTerm (Maybe String -> String)
showMaybeString = Phantoms.lambda "mx" $ ShowCore.maybe_ # (Phantoms.lambda "s" $ Literals.showString (Phantoms.var "s")) # Phantoms.var "mx"
-- Phantom-typed helpers
justInt :: Int -> TTerm (Maybe Int)
justInt x = Phantoms.just (Phantoms.int32 x)
nothingInt :: TTerm (Maybe Int)
nothingInt = Phantoms.nothing
-- Test groups
maybesIsJust :: TTerm TestGroup
maybesIsJust = subgroup "isJust" [
test "just value" (justInt 42) True,
test "nothing" nothingInt False]
where
test name x result = evalPair name showBool
(Maybes.isJust x)
(Phantoms.boolean result)
maybesIsNothing :: TTerm TestGroup
maybesIsNothing = subgroup "isNothing" [
test "just value" (justInt 42) False,
test "nothing" nothingInt True]
where
test name x result = evalPair name showBool
(Maybes.isNothing x)
(Phantoms.boolean result)
maybesFromMaybe :: TTerm TestGroup
maybesFromMaybe = subgroup "fromMaybe" [
test "just value" 0 (justInt 42) 42,
test "nothing with default" 99 nothingInt 99]
where
test name def x result = evalPair name showInt32
(Maybes.fromMaybe (Phantoms.int32 def) x)
(Phantoms.int32 result)
maybesMaybe :: TTerm TestGroup
maybesMaybe = subgroup "maybe" [
test "just value applies function" 0 (justInt 5) 10,
test "nothing returns default" 99 nothingInt 99]
where
test name def x result = evalPair name showInt32
(Maybes.maybe (Phantoms.int32 def) (Phantoms.lambda "x" $ Math.mul (Phantoms.var "x") (Phantoms.int32 2)) x)
(Phantoms.int32 result)
maybesPure :: TTerm TestGroup
maybesPure = subgroup "pure" [
testInt "wraps integer" 42 42,
testStr "wraps string" "hello" "hello"]
where
testInt name x expected = evalPair name showMaybeInt
(Maybes.pure (Phantoms.int32 x))
(justInt expected)
testStr name x expected = evalPair name showMaybeString
(Maybes.pure (Phantoms.string x))
(Phantoms.just (Phantoms.string expected))
maybesCat :: TTerm TestGroup
maybesCat = subgroup "cat" [
test "filters nothings" [justInt 1, nothingInt, justInt 2] [1, 2],
test "all justs" [justInt 1, justInt 2] [1, 2],
test "all nothings" [nothingInt, nothingInt] [],
test "empty list" ([] :: [TTerm (Maybe Int)]) []]
where
test name input expected = evalPair name showIntList
(Maybes.cat (Phantoms.list input))
(Phantoms.list (Phantoms.int32 <$> expected))
maybesMap :: TTerm TestGroup
maybesMap = subgroup "map" [
test "maps just value" (justInt 5) (justInt 10),
test "nothing unchanged" nothingInt nothingInt]
where
test name x expected = evalPair name showMaybeInt
(Maybes.map (Phantoms.lambda "x" $ Math.mul (Phantoms.var "x") (Phantoms.int32 2)) x)
expected
maybesApply :: TTerm TestGroup
maybesApply = subgroup "apply" [
test "both just" (Phantoms.just (Phantoms.lambda "x" $ Math.add (Phantoms.int32 3) (Phantoms.var "x"))) (justInt 5) (justInt 8),
test "nothing function" (Phantoms.nothing :: TTerm (Maybe (Int -> Int))) (justInt 5) nothingInt,
test "nothing value" (Phantoms.just (Phantoms.lambda "x" $ Math.add (Phantoms.int32 3) (Phantoms.var "x"))) nothingInt nothingInt]
where
test name f x expected = evalPair name showMaybeInt
(Maybes.apply f x)
expected
maybesBind :: TTerm TestGroup
maybesBind = subgroup "bind" [
test "just to just" (justInt 5) (justInt 10),
test "nothing to nothing" nothingInt nothingInt]
where
test name x expected = evalPair name showMaybeInt
(Maybes.bind x (Phantoms.lambda "x" $ Phantoms.just (Math.mul (Phantoms.var "x") (Phantoms.int32 2))))
expected
maybesCases :: TTerm TestGroup
maybesCases = subgroup "cases" [
test "just applies function" (justInt 5) 0 10,
test "nothing returns default" nothingInt 99 99]
where
test name opt def expected = evalPair name showInt32
(Maybes.cases opt (Phantoms.int32 def) (Phantoms.lambda "x" $ Math.mul (Phantoms.var "x") (Phantoms.int32 2)))
(Phantoms.int32 expected)
maybesMapMaybe :: TTerm TestGroup
maybesMapMaybe = subgroup "mapMaybe" [
test "filter and transform" [1, 2, 3, 4, 5] [6, 8, 10],
test "empty result" [1, 2] [],
test "empty input" [] []]
where
filterFn = Phantoms.lambda "x" $
Logic.ifElse (Equality.gt (Phantoms.var "x") (Phantoms.int32 2))
(Phantoms.just (Math.mul (Phantoms.var "x") (Phantoms.int32 2)))
(Phantoms.nothing :: TTerm (Maybe Int))
test name xs expected = evalPair name showIntList
(Maybes.mapMaybe filterFn (Phantoms.list $ Phantoms.int32 <$> xs))
(Phantoms.list $ Phantoms.int32 <$> expected)
maybesCompose :: TTerm TestGroup
maybesCompose = subgroup "compose" [
test "both succeed" 5 (justInt 12),
testFails "first fails" 10,
testFails "second fails" 3]
where
-- f: x -> if x <= 5 then Just (x + 1) else Nothing
funF = Phantoms.lambda "x" $
Logic.ifElse (Equality.lte (Phantoms.var "x") (Phantoms.int32 5))
(Phantoms.just (Math.add (Phantoms.var "x") (Phantoms.int32 1)))
(Phantoms.nothing :: TTerm (Maybe Int))
-- g: y -> if y >= 5 then Just (y * 2) else Nothing
funG = Phantoms.lambda "y" $
Logic.ifElse (Equality.gte (Phantoms.var "y") (Phantoms.int32 5))
(Phantoms.just (Math.mul (Phantoms.var "y") (Phantoms.int32 2)))
(Phantoms.nothing :: TTerm (Maybe Int))
test name input expected = evalPair name showMaybeInt
(Maybes.compose funF funG # Phantoms.int32 input)
expected
testFails name input = evalPair name showMaybeInt
(Maybes.compose funF funG # Phantoms.int32 input)
nothingInt
maybesToList :: TTerm TestGroup
maybesToList = subgroup "toList" [
test "just value" (justInt 42) [42],
test "nothing" nothingInt []]
where
test name x expected = evalPair name showIntList
(Maybes.toList x)
(Phantoms.list $ Phantoms.int32 <$> expected)
allTests :: TTermDefinition TestGroup
allTests = definitionInModule module_ "allTests" $
Phantoms.doc "Test cases for hydra.lib.maybes primitives" $
supergroup "hydra.lib.maybes primitives" [
maybesApply,
maybesBind,
maybesCases,
maybesCat,
maybesCompose,
maybesFromMaybe,
maybesIsJust,
maybesIsNothing,
maybesMap,
maybesMapMaybe,
maybesMaybe,
maybesPure,
maybesToList]