packages feed

freckle-app-1.0.0.1: tests/Freckle/App/Env/InternalSpec.hs

module Freckle.App.Env.InternalSpec
  ( spec
  )
where

import Prelude

import Control.Applicative
import Freckle.App.Env
import Freckle.App.Env.Internal
import Numeric.Natural
import Test.Hspec

spec :: Spec
spec = do
  describe "Parser" $ do
    context "Alternative" $ do
      let
        run :: Parser a -> Either [(String, Error)] a
        run p = unParser p [("PRESENT", "present"), ("INVALID_NAT", "-1")]

      -- Left identity: 'empty <|> x == x'
      it "satisfies left identity" $ do
        run @String (empty <|> var str "PRESENT" mempty)
          `shouldBe` Right "present"

        run @Natural (empty <|> var auto "INVALID_NAT" mempty) `shouldBe` Left
          [("INVALID_NAT", InvalidError "Prelude.read: no parse: \"-1\"")]

        run @String (empty <|> var str "MISSING" mempty)
          `shouldBe` Left [("MISSING", UnsetError)]

      -- Right identity: 'x <|> empty == x'
      it "satisfies right identity" $ do
        run @String (var str "PRESENT" mempty <|> empty)
          `shouldBe` Right "present"

        run @Natural (var auto "INVALID_NAT" mempty <|> empty) `shouldBe` Left
          [("INVALID_NAT", InvalidError "Prelude.read: no parse: \"-1\"")]

        run @String (var str "MISSING" mempty <|> empty)
          `shouldBe` Left [("MISSING", UnsetError)]

      -- Annihilation: 'f <$> empty == empty'
      it "satisfies annihilation" $ do
        run @Natural ((+ 1) <$> empty) `shouldBe` Left []
        run @String ((++ "!") <$> empty) `shouldBe` Left []

      -- Associativity: 'x <|> (y <|> z) == (x <|> y) <|> z'
      it "satisfies associativity" $ do
        run @String (empty <|> (empty <|> empty)) `shouldBe` Left []
        run @String ((empty <|> empty) <|> empty) `shouldBe` Left []

        run @Natural
            (empty
            <|> (var auto "INVALID_NAT" mempty <|> var auto "MISSING" mempty)
            )
          `shouldBe` Left
                       [ ( "INVALID_NAT"
                         , InvalidError "Prelude.read: no parse: \"-1\""
                         )
                       ]
        run @Natural
            ((empty <|> var auto "INVALID_NAT" mempty)
            <|> var auto "MISSING" mempty
            )
          `shouldBe` Left
                       [ ( "INVALID_NAT"
                         , InvalidError "Prelude.read: no parse: \"-1\""
                         )
                       ]

        run @String
            (empty <|> (var str "MISSING" mempty <|> var str "PRESENT" mempty))
          `shouldBe` Right "present"
        run @String
            ((empty <|> var str "MISSING" mempty) <|> var str "PRESENT" mempty)
          `shouldBe` Right "present"

      -- Distributivity: 'f <$> (x <|> y) == (f <$> x) <|> (f <$> y)'
      it "satisfies distributivity" $ do
        run @Natural
            ((+ 1)
            <$> (var auto "NOT_PRESENT" mempty
                <|> var auto "INVALID_NAT" mempty
                )
            )
          `shouldBe` Left
                       [ ("NOT_PRESENT", UnsetError)
                       , ( "INVALID_NAT"
                         , InvalidError "Prelude.read: no parse: \"-1\""
                         )
                       ]

        run @Natural
            ((+ 1)
            <$> var auto "NOT_PRESENT" mempty
            <|> (+ 1)
            <$> var auto "INVALID_NAT" mempty
            )
          `shouldBe` Left
                       [ ("NOT_PRESENT", UnsetError)
                       , ( "INVALID_NAT"
                         , InvalidError "Prelude.read: no parse: \"-1\""
                         )
                       ]

        run @String
            ((++ "!")
            <$> (var str "NOT_PRESENT" mempty <|> var str "PRESENT" mempty)
            )
          `shouldBe` Right "present!"

        run @String
            ((++ "!")
            <$> var str "NOT_PRESENT" mempty
            <|> (++ "!")
            <$> var str "PRESENT" mempty
            )
          `shouldBe` Right "present!"

      -- Left catch: 'pure x <|> empty = pure x'
      it "satisfies left catch"
        $ run (pure True <|> empty)
        `shouldBe` Right True