schema-0.0.2: test/Data/SchemaSpec.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.SchemaSpec (spec) where
import Control.Applicative ((<$>), (<*>))
import Control.Monad (when)
import Data.Proxy (Proxy (..))
import Debug.Trace (trace)
import GHC.Generics (Generic)
import Test.Hspec
import Test.QuickCheck
import Text.Groom (groom)
import Data.MessagePack (MessagePack (..), Object (..))
import Data.Schema
--------------------------------------------------------------------------------
-- Version 1 of the protocol.
--
data MyRecordV1 = MyRecordV1
{ recordField1V1 :: Int
, recordField2V1 :: Double
, recordField3V1 :: String
}
deriving (Eq, Show, Read, Generic)
instance MessagePack MyRecordV1
instance Arbitrary MyRecordV1 where
arbitrary = MyRecordV1
<$> arbitrary
<*> arbitrary
<*> arbitrary
instance HasSchema MyRecordV1 where
schema p = Type
{ typeName = "MyRecord"
, typeSchema = SchemaRecord
[ Field "recordField1" $ schema $ recordField1V1 <$> p
, Field "recordField2" $ schema $ recordField2V1 <$> p
, Field "recordField3" $ schema $ recordField3V1 <$> p
]
}
--------------------------------------------------------------------------------
-- Version 2 of the protocol.
--
-- This version has reordered the second and third field.
--
data MyRecordV2 = MyRecordV2
{ recordField1V2 :: Int
, recordField3V2 :: String
, recordField2V2 :: Double
}
deriving (Eq, Show, Read, Generic)
instance MessagePack MyRecordV2
instance Arbitrary MyRecordV2 where
arbitrary = MyRecordV2
<$> arbitrary
<*> arbitrary
<*> arbitrary
instance HasSchema MyRecordV2 where
schema p = Type
{ typeName = "MyRecord"
, typeSchema = SchemaRecord
[ Field "recordField1" $ schema $ recordField1V2 <$> p
-- Also reordered here so we know the order in the schema.
, Field "recordField3" $ schema $ recordField3V2 <$> p
, Field "recordField2" $ schema $ recordField2V2 <$> p
]
}
--------------------------------------------------------------------------------
-- Implementation of schema loading goes here:
--
fromObjectWithSchema :: (MessagePack a, HasSchema a) => Type -> Type -> Object -> a
fromObjectWithSchema srcType tgtType obj =
trace ("Loading object: " ++ groom obj) $
trace ("Source schema: " ++ groom srcType) $
trace ("Target schema: " ++ groom tgtType) $
error "unimplemented: fromObjectWithSchema"
spec :: Spec
spec =
describe "msgpack formats" $
it "can be translated from v1 to v2 and back" $
property $ \(v1 :: MyRecordV1) ->
let
-- Forward:
obj1 = toObject v1
scm1 = schema (Proxy :: Proxy MyRecordV1)
v2 :: MyRecordV2
v2 = fromObjectWithSchema scm1 scm2 obj1
-- And back:
obj2 = toObject v2
scm2 = schema (Proxy :: Proxy MyRecordV2)
v1' :: MyRecordV1
v1' = fromObjectWithSchema scm2 scm1 obj2
in
when False $
v1' `shouldBe` v1