module Data.Validation.InternalSpec where ------------------------------------------------------------------------------------------------------------------------ import Test.Hspec import Data.Map (fromList) import Language.Haskell.TH ------------------------------------------------------------------------------------------------------------------------ import Data.Validation.Internal ------------------------------------------------------------------------------------------------------------------------ spec :: Spec spec = parallel $ do describe "Semigroup (VCtx f a)" $ do it "If applied to two valid contexts, it concatenate the inhabitants." $ do ValidCtx [1] <> ValidCtx [2] `shouldBe` (ValidCtx [1,2] :: VCtx String [Int]) it "If applied to an valid and disputed contexts, it results in the disputed context concatenated with the valid context." $ do let mkDis = DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) ValidCtx [1] <> (mkDis [2] :: VCtx String [Int]) `shouldBe` mkDis [1,2] it "If applied to an valid and refuted contexts, it results in the refuted context." $ do let r = RefutedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) ValidCtx [1] <> (r :: VCtx String [Int]) `shouldBe` r it "If applied to a disputed and valid context, it results in the disputed context concatenated with the valid context." $ do let mkDis = DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) mkDis [1] <> (ValidCtx [2] :: VCtx String [Int]) `shouldBe` mkDis [1,2] it "If applied to two disputed contexts, it concatenates the contexts." $ do let v1 = DisputedCtx ["Failure1"] (fromList [([mkName "Field1"], ["Field Failure 1"])]) [1] v2 = DisputedCtx ["Failure2"] (fromList [([mkName "Field2"], ["Field Failure 2"])]) [2] v3 = DisputedCtx ["Failure1", "Failure2"] (fromList [([mkName "Field1"], ["Field Failure 1"]), ([mkName "Field2"], ["Field Failure 2"])]) [1,2] (v1 :: VCtx String [Int]) <> v2 `shouldBe` v3 it "If applied to a disputed and refuted context, it results in the refuted context." $ do let v1 = DisputedCtx ["Failure1"] (fromList [([mkName "Field1"], ["Field Failure 1"])]) [1] v2 = RefutedCtx ["Failure2"] (fromList [([mkName "Field2"], ["Field Failure 2"])]) v3 = RefutedCtx ["Failure1", "Failure2"] (fromList [([mkName "Field1"], ["Field Failure 1"]), ([mkName "Field2"], ["Field Failure 2"])]) (v1 :: VCtx String [Int]) <> v2 `shouldBe` v3 it "If applied to a refuted and valid context, it results in the refuted context." $ do let r = RefutedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) r <> (ValidCtx [1] :: VCtx String [Int]) `shouldBe` r it "If applied to a refuted and disputed context, it concatenates the failures and results in a refuted context." $ do let v1 = RefutedCtx ["Failure1"] (fromList [([mkName "Field1"], ["Field Failure 1"])]) v2 = DisputedCtx ["Failure2"] (fromList [([mkName "Field2"], ["Field Failure 2"])]) [2] v3 = RefutedCtx ["Failure1", "Failure2"] (fromList [([mkName "Field1"], ["Field Failure 1"]), ([mkName "Field2"], ["Field Failure 2"])]) (v1 :: VCtx String [Int]) <> v2 `shouldBe` v3 it "If applied to two refuted contexts, it concatenates the failures." $ do let v1 = RefutedCtx ["Failure1"] (fromList [([mkName "Field1"], ["Field Failure 1"])]) v2 = RefutedCtx ["Failure2"] (fromList [([mkName "Field2"], ["Field Failure 2"])]) v3 = RefutedCtx ["Failure1", "Failure2"] (fromList [([mkName "Field1"], ["Field Failure 1"]), ([mkName "Field2"], ["Field Failure 2"])]) (v1 :: VCtx String [Int]) <> v2 `shouldBe` v3 describe "Functor (VCtx f)" $ do it "Converts a `VCtx f a` to a `VCtx f b`." $ do fmap show (ValidCtx 1 :: VCtx String Int) `shouldBe` ValidCtx "1" it "Updates the value in a disputed context while preserving failures." $ do let v1 = DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) 1 v2 = DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) "1" fmap show (v1 :: VCtx String Int) `shouldBe` (v2 :: VCtx String String) it "Does not change the contents of an refuted context." $ do let v = RefutedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) fmap show (v :: VCtx String Int) `shouldBe` (v :: VCtx String String) describe "Applicative (VCtx f)" $ do let vac = ValidCtx show :: VCtx String (Int -> String) dac = DisputedCtx ["Applicative Failure"] mempty show :: VCtx String (Int -> String) rac = RefutedCtx ["Applicative Failure"] mempty :: VCtx String (Int -> String) vc = ValidCtx 1 :: VCtx String Int dc = DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) 1 :: VCtx String Int rc = RefutedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) it "Constructs a new valid context" $ do pure 1 `shouldBe` (ValidCtx 1 :: VCtx String Int) it "If applied to two valid contexts, it maps the function of the inhabitants." $ do vac <*> vc `shouldBe` ValidCtx "1" it "If applied to an valid and disputed contexts, it maps the function over the inhabitants while preserving failures." $ do vac <*> dc `shouldBe` DisputedCtx ["Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) "1" it "If applied to an valid and refuted contexts, it results in the refuted context." $ do vac <*> rc `shouldBe` (rc :: VCtx String String) it "If applied to a disputed and valid context, it maps the function over the inhabitants while preserving failures." $ do dac <*> vc `shouldBe` DisputedCtx ["Applicative Failure"] mempty "1" it "If applied to two disputed contexts, it maps the function over the inhabitants while concatenating the failures." $ do dac <*> dc `shouldBe` DisputedCtx ["Applicative Failure", "Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) "1" it "If applied to a disputed and refuted context, it results in the refuted context." $ do dac <*> rc `shouldBe` RefutedCtx ["Applicative Failure", "Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) it "If applied to a refuted and valid context, it results in the refuted context." $ do rac <*> vc `shouldBe` RefutedCtx ["Applicative Failure"] mempty it "If applied to a refuted and disputed context, it concatenates the failures and results in a refuted context." $ do rac <*> dc `shouldBe` RefutedCtx ["Applicative Failure", "Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) it "If applied to two refuted contexts, it concatenates the failures." $ do rac <*> rc `shouldBe` RefutedCtx ["Applicative Failure", "Failure"] (fromList [([mkName "Field1"], ["Field Failure"])]) describe "Monad (VCtx f)" $ do it "Binds a valid context to a function." $ do ((ValidCtx 1 :: VCtx String Int) >>= pure . show) `shouldBe` ValidCtx "1" it "Binds a disputed context to a function while preserving failures." $ do ((DisputedCtx ["Failure"] mempty 1 :: VCtx String Int) >>= pure . show) `shouldBe` DisputedCtx ["Failure"] mempty "1" it "Does not change the contents of a refuted context." $ do ((RefutedCtx ["Failure"] mempty :: VCtx String Int) >>= pure . show) `shouldBe` RefutedCtx ["Failure"] mempty describe "(