{- |
Module      :  Test.Serial
Description :  Test.Serial run serialization tests against static files
Copyright   :  (c) Plow Technologies
License     :  MIT License
Maintainer  :  Scott Murphy
Stability   :  unstable 
Portability :   non-portable (System.Posix)


-}


{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

module Test.Serial (runAesonSerializationTest, TestError (..) ) where

import           Data.Aeson (ToJSON
                           , FromJSON
                           , toJSON
                           , encode
                           , eitherDecode)


import qualified Data.ByteString.Lazy as BLazy
import           GHC.Generics
import           System.IO (withFile, IOMode(..),openFile,hIsEOF)
--------------------------------------------------

data TestError = NoFileFound |  -- NoFileFound could simply mean it is the first time the test was ran
                 AesonError String
      deriving (Generic,Read,Show,Eq,Ord)

instance ToJSON TestError where

newtype MockInference a = MockInference a
   deriving (Generic)

instance ToJSON a => ToJSON (MockInference a) where             


makeMockInference :: (ToJSON a, FromJSON a) => a -> MockInference a
makeMockInference testVal = MockInference testVal

runAesonSerializationTest :: (ToJSON a, FromJSON a) => a -> FilePath -> IO (Either TestError a)
runAesonSerializationTest dataUnderTest file = withFile file ReadWriteMode createAesonSerializeTest
 where
    createAesonSerializeTest h = do
      aNewFile <- hIsEOF h
      if aNewFile
        then writeOutputAndExit h
        else createAesonSerializeTest' h
             
    createAesonSerializeTest' h = do
      aesonByteString <- BLazy.hGetContents h
      case eitherDecode aesonByteString of
        (Left s) -> return . Left .  AesonError $ s
        (Right a) 
          |(toJSON . makeMockInference $ a) == (toJSON.makeMockInference $ dataUnderTest)
           -> return . Right $ a
          |otherwise -> return . Left . AesonError $ "Serializations do not match"
  
    writeOutputAndExit h = do
      putStrLn "file not found, writing given serialization to disk, rerun tests"
      BLazy.hPut h $ encode dataUnderTest
      return . Left $ NoFileFound