packages feed

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