sv-core-0.2: test/Data/Sv/Core/Laws.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module Data.Sv.Core.Laws (test_Laws) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Monoid (Last)
import Data.Profunctor (Profunctor (dimap))
import Data.Semigroupoid (Semigroupoid (o))
import qualified Data.Validation as V
import Data.Vector (Vector, fromList, toList)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (Arbitrary (arbitrary), CoArbitrary (coarbitrary), Gen, testProperty, oneof, listOf)
import Data.Sv.Decode.Type
import qualified Data.Sv.Decode.Core as D
test_Laws :: TestTree
test_Laws =
testGroup "Laws"
[ testGroup "Decode Semigroupoid" $ fmap (uncurry testProperty)
[ ("Decode Semigroupoid associativity", decodeAssoc)
]
]
decodeAssoc :: Gen Bool
decodeAssoc = do
dec1 <- decodeGen :: Gen (Decode ByteString ByteString ByteString)
dec2 <- decodeGen :: Gen (Decode ByteString ByteString ByteString)
dec3 <- decodeGen :: Gen (Decode ByteString ByteString ByteString)
v <- arbOut
i <- arbOut
let comp1 = (dec1 `o` dec2) `o` dec3
let comp2 = dec1 `o` (dec2 `o` dec3)
pure (eqDecode v i comp1 comp2)
eqDecode :: (Eq e, Eq a) => Vector s -> Ind -> Decode e s a -> Decode e s a -> Bool
eqDecode v i d e =
D.runDecode d v i == D.runDecode e v i
decodeGen :: (CoArbitrary (In s), Arbitrary (Out a), Arbitrary (Out e)) => Gen (Decode e s a)
decodeGen =
buildDecode <$> (unwrap <$> arbitrary)
unwrap :: (Input s -> Output e a) -> Vector s -> Ind -> (Validation e a, Last Bool, Ind)
unwrap = curry . dimap Input unwrapO
newtype Output e a =
Output { unwrapO :: (Validation e a, Last Bool, Ind) }
newtype Input s = Input (Vector s, Ind)
newtype In a = In a
newtype Out a = Out { unout :: a }
coarbIn :: CoArbitrary (In a) => a -> Gen b -> Gen b
coarbIn = coarbitrary . In
arbOut :: Arbitrary (Out a) => Gen a
arbOut = unout <$> arbitrary
instance (Arbitrary (Out e), Arbitrary (Out a)) => Arbitrary (Output e a) where
arbitrary =
Output <$>
((,,) <$> oneof [V.Failure <$> arbOut, V.Success <$> arbOut]
<*> arbitrary
<*> (Ind <$> arbOut))
instance (CoArbitrary (In (Vector s)), CoArbitrary (In Ind)) => CoArbitrary (Input s) where
coarbitrary (Input (v,i)) = coarbIn v . coarbIn i
instance Arbitrary (Out ByteString) where
arbitrary = Out <$> (BS.pack <$> arbitrary)
instance CoArbitrary (In ByteString) where
coarbitrary (In bs) = coarbitrary (BS.unpack bs)
instance Arbitrary (Out Ind) where
arbitrary = Out . Ind <$> arbitrary
instance Arbitrary (Out Int) where
arbitrary = Out <$> arbitrary
instance CoArbitrary (In s) => CoArbitrary (In (Vector s)) where
coarbitrary (In v) = coarbitrary (In <$> toList v)
instance CoArbitrary (In Ind) where
coarbitrary (In (Ind i)) = coarbitrary i
instance Arbitrary (Out e) => Arbitrary (Out (DecodeErrors e)) where
arbitrary = Out . DecodeErrors <$> arbOut
instance Arbitrary (Out e) => Arbitrary (Out (NonEmpty e)) where
arbitrary = Out <$> ((:|) <$> arbOut <*> arbOut)
instance Arbitrary (Out e) => Arbitrary (Out [e]) where
arbitrary = Out <$> listOf arbOut
instance Arbitrary (Out e) => Arbitrary (Out (Vector e)) where
arbitrary = Out . fromList <$> arbOut
instance Arbitrary (Out e) => Arbitrary (Out (DecodeError e)) where
arbitrary = Out <$> oneof
[ pure UnexpectedEndOfRow
, ExpectedEndOfRow <$> arbOut
, UnknownCategoricalValue <$> arbOut <*> arbOut
, BadParse <$> arbOut
, BadDecode <$> arbOut
]