packages feed

salak-0.1.8: test/Spec.hs

{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import qualified Data.HashMap.Strict    as M
import           Data.Salak
import           Data.Salak.CommandLine
import           Data.Salak.Environment
import           Data.Salak.Operation   ()
import           Data.Text              (Text, intercalate, pack)
import           System.Environment
import           Test.Hspec
import           Test.QuickCheck

main = hspec spec

spec :: Spec
spec = do
  describe "Data.Salak.Types"   specProperty
  describe "Data.Salak"         specProperties
  describe "Data.Salak.Dynamic" specDynamic

shouldFail :: (Show a, Eq a) => a -> a -> Expectation
shouldFail f a = (f `shouldBe` a) `shouldThrow` anyErrorCall

data Config = Config
  { name :: Text
  , dir  :: Text
  , ext  :: Int
  } deriving (Eq, Show)

instance FromProperties Config where
  fromProperties v = Config
        <$> v .?> "name"
        <*> v .?> "dir"
        <*> v .?> "ext" .?= 1

specProperty = do
  context "empty" $ do
    it "normal" $ do
      let p = empty
      print p
      p `shouldBe` Properties [] []
  context "toKeys" $ do
    it "normal" $ do
      []        `shouldBe` toKeys ""
      ["a"]     `shouldBe` toKeys "a"
      ["a"]     `shouldBe` toKeys "a."
      ["a","b"] `shouldBe` toKeys "a.b"
      ["a","b"] `shouldBe` toKeys "a.....b"
    it "quickCheck" $ do
      quickCheck $ \a -> let b = toKeys $ pack a in b == toKeys (intercalate "." b)
  context "insert" $ do
    let p = PStr "Hello"
        k = toKeys "a.b"
        m = insert k p empty
    it "normal" $ do
      insert [] p empty `shouldBe` Properties [p] []
      insert k  p empty `shouldBe` Properties [] [M.insert "a" (Properties [] [M.insert "b" (Properties [p] []) M.empty]) M.empty]
    it "Reject replacement" $ do
      insert k "1" m `shouldBe` m
    it "quickCheck" $ do
      quickCheck $ \a' (b :: Int)    -> let a = pack a' in Just b == (insert (toKeys a) (PNum $ fromIntegral b) empty) .>> a
      quickCheck $ \a' (b :: Bool)   -> let a = pack a' in Just b == (insert (toKeys a) (PBool b)               empty) .>> a
      quickCheck $ \a' (b :: String) -> let a = pack a' in Just b == (insert (toKeys a) (PStr $ pack b)         empty) .>> a
  context "lookup" $ do
    it "normal" $ do
      let m = insert ["a"] (PNum 1) empty
          n = insert ["a"] (PStr "true") empty
      (empty .>> "a" :: Maybe Int)    `shouldBe`   Nothing
      (m     .>> "a" :: Maybe Int)    `shouldBe`   Just  1
      (m     .>> "a" :: Maybe Bool)   `shouldFail` Nothing
      (m     .>> "a" :: Maybe String) `shouldBe`   Just "1.0"
      (n     .>> "a" :: Maybe Int)    `shouldFail` Nothing
      (n     .>> "a" :: Maybe Bool)   `shouldBe`   Just True
      (n     .>> "a" :: Maybe Text)   `shouldBe`   Just "true"
  context "makeProperties" $ do
    it "normal" $ do
      m <- makePropertiesFromEnvironment empty
      h <- getEnv "HOME"
      (m .>> "home") `shouldBe` Just h
  context "command-line" $ do
    it "normal" $ do
      let args = ["--package.a.enabled=true","--package.b.enabled=false","package.c.enabled=false"]
      m    <- makePropertiesFromCommandLine' args defaultParseCommandLine empty
      (m .>> "package.a.enabled") `shouldBe` Just True
      (m .>> "package.b.enabled") `shouldBe` Just False
      (m .>> "package.c.enabled" :: Maybe Bool )`shouldBe` Nothing
  context "environment" $ do
    it "normal" $ do
      let args = [("PACKAGE_A_ENABLED","true"),("PACKAGE_B_ENABLED","false")]
          m    = makePropertiesFromEnvironment' args empty
      (m .>> "package.a.enabled") `shouldBe` Just True
      (m .>> "package.b.enabled") `shouldBe` Just False
      (m .>> "package.c.enabled" :: Maybe Bool )`shouldBe` Nothing

specProperties = do
  context "defaultPropertiesWithFile" $ do
    let confName = "salak.yml" :: String
        confName' = pack confName
    it "read config" $ do
      unsetEnv "SALAK_CONFIG_NAME"
      p <- defaultPropertiesWithFile confName
      p .>> "salak.config.name" `shouldBe` Just confName
    it "read config - replacement" $ do
      setEnv "SALAK_CONFIG_NAME" confName
      p <- defaultPropertiesWithFile "salak.ok"
      p .>> "salak.config.name" `shouldBe` Just confName
    it "read config - not found" $ do
      setEnv "SALAK_CONFIG_NAME" "salak.notfound"
      setEnv "SALAK_CONFIG_DIR" "test"
      defaultPropertiesWithFile confName `shouldThrow` anyException
    it "read config - read file parse Config" $ do
      setEnv "SALAK_CONFIG_NAME" confName
      setEnv "SALAK_CONFIG_DIR" "test"
      setEnv "SALAK_CONFIG" confName
      p <- defaultPropertiesWithFile confName
      (p .>> "salak.config.name")              `shouldBe`   Just confName
      (p .>> "salak.config")                   `shouldBe`   Just confName
      (p .>> "salak.config" :: Maybe Config)   `shouldBe`   Just (Config confName' "test" 1)
      (p .>> "array"        :: Maybe [String]) `shouldBe`   Just ["a","b"]
      (p .>> "array"        :: Maybe [Int])    `shouldFail` Nothing
      (p .>> "array"        :: Maybe String)   `shouldFail` Nothing

specDynamic = do
  context "Dynamic" $ do
    it "dynamic load" $ do
      p  <- defaultPropertiesWithFile "salak.yml"
      (c,s) <- runLoader p $ (,) <$> load "config" <*> askSetProperties
      c1 <- c
      s $ insert ["config","name"] "world" empty
      c2 <- c
      name c1 `shouldBe` "hello"
      name c2 `shouldBe` "world"
      dir c1  `shouldBe` dir c2
      ext c1  `shouldBe` ext c2