packages feed

penny-0.24.0.0: tests/Copper/Render.hs

{-# OPTIONS_GHC -fno-warn-missing-signatures
                -fno-warn-orphans #-}
{-# LANGUAGE TemplateHaskell #-}
module Copper.Render where

import Control.Applicative ((<*))
import qualified Copper.Gen.Parsers as G
import qualified Penny.Copper.Interface as I
import qualified Penny.Copper.Render as R
import qualified Penny.Copper.Parsec as P
import qualified Penny.Lincoln as L
import Penny.Lincoln ((==~))
import qualified Text.Parsec as Ps
import qualified Text.Parsec.Text as Ps
import qualified Test.QuickCheck as Q
import qualified Test.QuickCheck.All as A
import qualified Test.QuickCheck.Property as QCP
import Test.QuickCheck (Gen, arbitrary, Arbitrary)
import Data.Text (Text)

renParse
  :: (Eq a, Show a)
  => (a -> Maybe Text)
  -> Ps.Parser a
  -> Gen (a, b)
  -> Q.Property
renParse r p g = Q.forAll (fmap fst g) $ \ a ->
  doParse r p a

doParseWithPdct
  :: Show a
  => (a -> a -> Bool)
  -> (a -> Maybe Text)
  -> Ps.Parser a
  -> a
  -> QCP.Result
doParseWithPdct pdct r p a =
  case r a of
    Nothing -> QCP.failed { QCP.reason = "render failed: "
                            ++ show a }
    Just rend -> case Ps.parse (p <* Ps.eof) "" rend of
      Left e -> QCP.failed { QCP.reason = "parse failed: "
                             ++ show e }
      Right g ->
        if pdct g a
        then QCP.succeeded
        else QCP.failed
             { QCP.reason = "parsed not equal to original. "
               ++ "Original: " ++ show a ++ " parsed: "
               ++ show g }

doParse
  :: (Eq a, Show a)
  => (a -> Maybe Text)
  -> Ps.Parser a
  -> a
  -> QCP.Result
doParse = doParseWithPdct (==)

doParseEv
  :: (L.Equivalent a, Show a)
  => (a -> Maybe Text)
  -> Ps.Parser a
  -> a
  -> QCP.Result
doParseEv = doParseWithPdct (==~)

prop_quotedLvl1Acct =
  renParse R.quotedLvl1Acct P.quotedLvl1Acct G.quotedLvl1Acct

prop_lvl2Acct =
  renParse R.lvl2Acct P.lvl2Acct G.lvl2Acct

prop_ledgerAcct =
  renParse R.ledgerAcct P.ledgerAcct G.ledgerAcct

prop_quotedLvl1Cmdty =
  renParse R.quotedLvl1Cmdty P.quotedLvl1Cmdty
  (fmap (\ (G.QuotedLvl1Cmdty c _) -> (c, ())) G.quotedLvl1Cmdty)

prop_lvl2Cmdty =
  renParse R.lvl2Cmdty P.lvl2Cmdty
  (fmap (\(G.Lvl2Cmdty c _) -> (c, ())) G.lvl2Cmdty)

prop_lvl3Cmdty =
  renParse R.lvl3Cmdty P.lvl3Cmdty
  (fmap (\(G.Lvl3Cmdty c _) -> (c, ())) G.lvl3Cmdty)


prop_qtyRep = do
  qr <- arbitrary
  return $ doParseEv (fmap Just R.qtyRep) P.qtyRep qr

prop_amount = do
  cy <- G.genCmdty
  qr <- G.ast
  let rend (am, sd, sb) = R.amount Nothing (Just sd) (Just sb) (Left am)
  r <- fmap (\ ((am, _), sb, sd) -> (am, sd, sb)) (G.amount cy qr)
  return $ doParseEv rend P.amount r

prop_comment =
  renParse R.comment P.comment G.comment

prop_dateTime =
  renParse (fmap Just R.dateTime) P.dateTime G.dateTime

prop_entry = do
  cy <- G.genCmdty
  dc <- G.drCr
  qr <- G.ast
  let rend (iEn, iSd, iSb) = R.entry Nothing (Just iSd) (Just iSb)
                                     (Left iEn)
  ((en, _), sb, sd) <- G.entry cy dc qr
  return $ doParseEv rend P.entry (en, sd, sb)

prop_flag =
  renParse R.flag P.flag G.flag

prop_postingMemoLine = do
  i <- Q.choose (0,4)
  (t, _) <- G.postingMemoLine
  let rend = R.postingMemoLine i
  return $ doParse rend P.postingMemoLine t

prop_postingMemo = do
  b <- arbitrary
  (m, _) <- G.postingMemo
  let rend = R.postingMemo b
  return $ doParse rend P.postingMemo m

prop_transactionMemoLine =
  renParse R.transactionMemoLine P.transactionMemoLine G.transactionMemoLine

prop_transactionMemo =
  renParse R.transactionMemo (fmap snd P.transactionMemo)
           G.transactionMemo

prop_number =
  renParse R.number P.number G.number

prop_quotedLvl1Payee =
  renParse R.quotedLvl1Payee P.quotedLvl1Payee G.quotedLvl1Payee

prop_lvl2Payee =
  renParse R.lvl2Payee P.lvl2Payee G.lvl2Payee

prop_price = do
  (pr, _) <- G.price
  return $ doParseWithPdct priceEq R.price P.price pr

prop_tag =
  renParse R.tag P.tag G.tag

prop_tags =
  renParse R.tags P.tags G.tags

prop_topLineCore =
  renParse R.topLine (fmap toTopLine P.topLine) G.topLineCore

toTopLine :: I.ParsedTopLine -> L.TopLineCore
toTopLine (I.ParsedTopLine dt nu fl pa me _) =
  L.TopLineCore dt nu fl pa (fmap fst me)


prop_transaction = do
  let rend = R.transaction Nothing
      toPair (tl, es) = (toTopLine tl, fmap fst es)
  (genTx, _) <- G.transaction
  return $ doParseEv rend (fmap toPair P.transaction) genTx

priceEq :: L.PricePoint -> L.PricePoint -> Bool
priceEq (L.PricePoint xdt xpr xsd xsb _)
        (L.PricePoint ydt ypr ysd ysb _)
  = xdt == ydt && xpr ==~ ypr && xsd == ysd && xsb == ysb

runTests :: (Q.Property -> IO Q.Result) -> IO Bool
runTests = $(A.forAllProperties)