packages feed

di-0.2: test/Main.hs

{-# LANGUAGE CPP #-}
module Main where

import Control.Applicative (liftA2)
import qualified Control.Exception as Ex
import Control.Concurrent.STM
  (STM, atomically, TQueue, newTQueue, writeTQueue, tryReadTQueue)
import Data.Foldable (for_)
import Data.Function (fix)
import Data.Monoid (Sum(Sum, getSum))
import qualified Test.Tasty as Tasty
import qualified Test.Tasty.HUnit as HU
import Test.Tasty.HUnit ((@?=))
import qualified Test.Tasty.QuickCheck as QC
import qualified Test.Tasty.Runners as Tasty

import Di (Di)
import qualified Di

--------------------------------------------------------------------------------

main :: IO ()
main = Tasty.defaultMainWithIngredients
  [ Tasty.consoleTestReporter
  , Tasty.listingTests
  ] tt

tt :: Tasty.TestTree
tt = Tasty.testGroup "di"
  [ QC.testProperty "log" $ do
      QC.forAll QC.arbitrary $ \lpms ->
        QC.ioProperty $ do
          expect lpms $ \di0 -> do
            for_ lpms $ \(l, p, m) -> do
              Di.log (Di.push p di0) l m

  , HU.testCase "push" $ do
       let x = [("","",""), ("","",""), ("","1",""), ("","12",""), ("","12",""), ("","","")]
       expect x $ \di0 -> do
          Di.log di0 "" ""
          -- Identity
          Di.log (Di.push "" di0) "" ""
          -- Composition
          Di.log (Di.push "1" di0) "" ""
          Di.log ((Di.push "2" . Di.push "1") di0) "" ""
          Di.log (Di.push "12" di0) "" ""
          -- Checking that di0 still works
          Di.log di0 "" ""

  , HU.testCase "contralevel" $ do
       let x = [("1","",""), ("1","",""), ("1","",""), ("2","",""), ("2","",""), ("1","","")]
           n = 1 :: Int
       expect x $ \di0 -> do
          Di.log di0 "1" ""
          -- Identity
          Di.log (Di.contralevel id di0) "1" ""
          -- Composition
          Di.log (Di.contralevel show di0) n ""
          Di.log ((Di.contralevel succ . Di.contralevel show) di0) n ""
          Di.log (Di.contralevel (show . succ) di0) n ""
          -- Checking that di0 still works
          Di.log di0 "1" ""

  , HU.testCase "contrapath" $ do
       let x = [("","",""), ("","1",""), ("","1",""), ("","1",""), ("","2",""), ("","2",""), ("","","")]
           n = Sum (1 :: Int)
       expect x $ \di0 -> do
          Di.log di0 "" ""
          Di.log (Di.push "1" di0) "" ""
          -- Identity
          Di.log (Di.push "1" (Di.contrapath id di0)) "" ""
          -- Composition
          Di.log (Di.push n (Di.contrapath (show . getSum) di0)) "" ""
          Di.log (Di.push n ((Di.contrapath (mappend n) . Di.contrapath (show . getSum)) di0)) "" ""
          Di.log (Di.push n (Di.contrapath (show . getSum . mappend n) di0)) "" ""
          -- Checking that di0 still works
          Di.log di0 "" ""

  , HU.testCase "contramsg" $ do
       let x = [("","","1"), ("","","1"), ("","","1"), ("","","2"), ("","","2"),  ("","","1")]
           n = 1 :: Int
       expect x $ \di0 -> do
          Di.log di0 "" "1"
          -- Identity
          Di.log (Di.contramsg id di0) "" "1"
          -- Composition
          Di.log (Di.contramsg show di0) "" n
          Di.log ((Di.contramsg succ . Di.contramsg show) di0) "" n
          Di.log (Di.contramsg (show . succ) di0) "" n
          -- Checking that di0 still works
          Di.log di0 "" "1"

  , HU.testCase "filter" $ do
       let x = [("1","","a"), ("2","","c"), ("1","","d"), ("3","","g"), ("3","","j"), ("3","","m"), ("1","","n")]
       expect x $ \di0 -> do
          Di.log di0 "1" "a"
          -- Predicates
          Di.log (Di.filter (/= "1") di0) "1" "b"
          Di.log (Di.filter (/= "1") di0) "2" "c"
          -- Identity
          Di.log (Di.filter (const True) di0) "1" "d"
          -- Composition
          Di.log ((Di.filter (/= "1") . Di.filter (/= "2")) di0) "1" "e"
          Di.log ((Di.filter (/= "1") . Di.filter (/= "2")) di0) "2" "f"
          Di.log ((Di.filter (/= "1") . Di.filter (/= "2")) di0) "3" "g"
          Di.log (Di.filter (liftA2 (&&) (/= "1") (/= "2")) di0) "1" "h"
          Di.log (Di.filter (liftA2 (&&) (/= "1") (/= "2")) di0) "2" "i"
          Di.log (Di.filter (liftA2 (&&) (/= "1") (/= "2")) di0) "3" "j"
          -- Conmutativity (c.f., "e" "f" "g")
          Di.log ((Di.filter (/= "2") . Di.filter (/= "1")) di0) "1" "k"
          Di.log ((Di.filter (/= "2") . Di.filter (/= "1")) di0) "2" "l"
          Di.log ((Di.filter (/= "2") . Di.filter (/= "1")) di0) "3" "m"
          -- Checking that di0 still works
          Di.log di0 "1" "n"
  ]

expect :: [(String, String, String)] -> (Di String String String -> IO a) -> IO a
expect as0 k = Ex.bracket
  (do tq <- atomically newTQueue
      di <- Di.mkDi (\_ l p m -> atomically (writeTQueue tq (l, p, m)))
      pure (tq, di))
  (\(tq, di) -> do
      Di.flush di
      as1 <- atomically (drainTQueue tq)
      as1 @?= as0)
  (\(_, di) -> k di)

drainTQueue :: TQueue a -> STM [a]
drainTQueue tq = do
  let go as = maybe (pure as) (\a -> go (a:as)) =<< tryReadTQueue tq
  fmap reverse (go [])

#if !MIN_VERSION_QuickCheck(2,10,0)
instance QC.Testable () where
  property () = QC.property True
#endif