{-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Main (main) where import Data.Bifunctor import Data.Binary import Data.Binary.Tagged import Data.Either import Data.Monoid import Data.Proxy import Test.Tasty import Test.Tasty.QuickCheck import qualified Rec1 import qualified Rec2 main :: IO () main = defaultMain $ testGroup "Tests" [ roundtrips , wrongRoundtrips , failedRoundtrips , testProperty "Interleave" interleaveProp ] -- | We actually check that this compiles. interleaveProp :: Property interleaveProp = property $ once $ lhs === rhs where lhs :: Proxy 7 lhs = Proxy rhs :: Proxy (Interleave 2 1) rhs = Proxy instance Arbitrary a => Arbitrary (BinaryTagged v a) where arbitrary = fmap BinaryTagged arbitrary proxyRec1 :: Proxy Rec1.Rec proxyRec1 = Proxy proxyRec1Ver0 :: Proxy (BinaryTagged 0 Rec1.Rec) proxyRec1Ver0 = Proxy proxyRec1Ver1 :: Proxy (BinaryTagged 1 Rec1.Rec) proxyRec1Ver1 = Proxy proxyRec2 :: Proxy Rec2.Rec proxyRec2 = Proxy proxyRec2Ver0 :: Proxy (BinaryTagged 0 Rec2.Rec) proxyRec2Ver0 = Proxy proxyRec2Ver1 :: Proxy (BinaryTagged 1 Rec2.Rec) proxyRec2Ver1 = Proxy eqRec1Rec2 :: Rec1.Rec -> Rec2.Rec -> Bool eqRec1Rec2 (Rec1.Rec (Sum a) (Product b)) (Rec2.Rec (Product a') (Sum b')) = a == a' && b == b' roundtrips :: TestTree roundtrips = testGroup "Roundtrip" [ testProperty "Rec1" $ roundtrip proxyRec1 , testProperty "BinaryTagged 0 Rec1" $ roundtrip proxyRec1Ver0 , testProperty "BinaryTagged 1 Rec1" $ roundtrip proxyRec1Ver1 , testProperty "Rec2" $ roundtrip proxyRec2 , testProperty "BinaryTagged 0 Rec2" $ roundtrip proxyRec2Ver0 , testProperty "BinaryTagged 1 Rec2" $ roundtrip proxyRec2Ver1 ] wrongRoundtrips :: TestTree wrongRoundtrips = testGroup "Decode successful, data invalid" [ testProperty "Rec1 -> Rec2" $ wrongRoundtrip eqRec1Rec2 , testProperty "Rec2 -> Rec1" $ wrongRoundtrip eqRec1Rec2 ] failedRoundtrips :: TestTree failedRoundtrips = testGroup "Failed roundtrips" [ testProperty "Different version" $ failedRoundtrip proxyRec1Ver0 proxyRec1Ver1 , testProperty "Different structure" $ failedRoundtrip proxyRec1Ver0 proxyRec2Ver0 ] roundtrip :: (Eq a, Show a, Arbitrary a, Binary a) => Proxy a -> a -> Property roundtrip _ x = x === decode (encode x) wrongRoundtrip :: (Arbitrary a, Binary a, Binary b) => (a -> b -> Bool) -> a -> Property wrongRoundtrip eq x = property $ eq x $ decode (encode x) trdOf3 :: (a, b, c) -> c trdOf3 (_, _, c) = c isLeftProperty :: (Show a, Show b) => Either a b -> Property isLeftProperty x = counterexample ("not isLeft: " <> show x) (isLeft x) failedRoundtrip :: forall a b. (Arbitrary a, Binary a, Binary b, Show b) => Proxy a -> Proxy b -> a -> Property failedRoundtrip _ _ x = let x' = bimap trdOf3 trdOf3 $ decodeOrFail (encode x) :: Either String b in isLeftProperty x'