registry-0.4.0.0: test/Test/Data/Registry/Make/SpecializationFunctionsSpec.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}
module Test.Data.Registry.Make.SpecializationFunctionsSpec where
import Data.Registry
import Protolude hiding (C1)
import Test.Tasty.Extensions
-- | Case 1: contextual setting of different values for a given type
test_specialization_1 = test "values can be built from specialized functions depending on some context" $ do
-- this function uses the default Int (and has unused parameters)
let useDefaultInt (_t :: Text) = Config
-- this function doubles the default Int (and has unused parameters)
let useTwiceDefaultInt i (_t :: Text) (_b :: Bool) = Config $ i * 2
(c1, c2) <- liftIO $ do
let r =
specialize @UseConfig1 (fun useDefaultInt)
. specialize @UseConfig2 (fun useTwiceDefaultInt)
$ fun newUseConfig2
<: fun newUseConfig1
<: val (Config 3)
<: val (1 :: Int)
<: val True
<: val ("text" :: Text)
pure (printConfig1 (make @UseConfig1 r), printConfig2 (make @UseConfig2 r))
c1 === Config 1
c2 === Config 2
test_missing_inputs = test "values can be built from specialized functions depending on some context" $ do
-- this function uses the default Int (and has unused parameters)
let useDefaultInt (_t :: Text) = Config
-- this function doubles the default Int (it has unused parameters, but will be missing the Bool parameter which is not in the registry)
let useTwiceDefaultInt i (_t :: Text) (_b :: Bool) = Config $ i * 2
(c1, c2) <- liftIO $ do
let r =
specialize @UseConfig1 (fun useDefaultInt)
. specialize @UseConfig2 (fun useTwiceDefaultInt)
$ fun newUseConfig2
<: fun newUseConfig1
<: val (Config 3)
<: val (1 :: Int)
<: val ("text" :: Text)
pure (printConfig1 (make @UseConfig1 r), printConfig2 (make @UseConfig2 r))
c1 === Config 1
annotate "if inputs are missing for a specialization, we use the default value"
c2 === Config 3
-- we want the following graph
{-
+---------- Base ------------+
| |
v v
(client1 :: Client1) (client2 :: Client2)
| |
v v
(useConfig1 :: UseConfig) (useConfig2 :: UseConfig)
| |
v v
(config1 :: Config) (config2 :: Config)
-}
newtype Config = Config {configInt :: Int} deriving (Eq, Show)
newtype UseConfig1 = UseConfig1 {printConfig1 :: Config}
newUseConfig1 config = UseConfig1 {printConfig1 = config}
newtype UseConfig2 = UseConfig2 {printConfig2 :: Config}
newUseConfig2 config = UseConfig2 {printConfig2 = config}
newtype UseConfig = UseConfig {printConfig :: Config}
newUseConfig config = UseConfig {printConfig = config}
newtype Client1 = Client1 {printClientConfig1 :: Config}
newClient1 useConfig = Client1 {printClientConfig1 = printConfig useConfig}
newtype Client2 = Client2 {printClientConfig2 :: Config}
newClient2 useConfig = Client2 {printClientConfig2 = printConfig useConfig}
newtype Base = Base {printBase :: (Config, Config)}
newBase client1 client2 = Base {printBase = (printClientConfig1 client1, printClientConfig2 client2)}