packages feed

list-t-1.0.5.2: tests/Main.hs

{-# OPTIONS_GHC -F -pgmF htfpp #-}

import BasePrelude hiding (toList)
import Control.Monad.Morph
import qualified ListT as L
import MTLPrelude
import Test.Framework

main = htfMain $ htf_thisModulesTests

-- * MMonad

-- embed lift = id
prop_mmonadLaw1 (l :: [Int]) =
  let s = L.fromFoldable l
   in runIdentity $ streamsEqual s (embed lift s)

-- embed f (lift m) = f m
prop_mmonadLaw2 l =
  let s = (L.fromFoldable :: [Int] -> L.ListT Identity Int) l
      f = MaybeT . fmap Just
      run = runIdentity . L.toList . runMaybeT
   in run (f s)
        == run (embed f (lift s))

-- * Applicative

prop_applicativeIdentityLaw (l :: [Int]) =
  runIdentity $ streamsEqual (pure id <*> s) s
  where
    s = L.fromFoldable l

prop_applicativeBehavesLikeList =
  \(ns :: [Int]) ->
    let a = fs <*> ns
        b = runIdentity (toList $ L.fromFoldable fs <*> L.fromFoldable ns)
     in a == b
  where
    fs = [(+ 1), (+ 3), (+ 5)]

-- * Monad

test_monadLaw1 =
  assertBool =<< streamsEqual (return a >>= k) (k a)
  where
    a = 2
    k a = return $ chr a

test_monadLaw2 =
  assertBool =<< streamsEqual (m >>= return) m
  where
    m = L.fromFoldable ['a' .. 'z']

test_monadLaw3 =
  assertBool =<< streamsEqual (m >>= (\x -> k x >>= h)) ((m >>= k) >>= h)
  where
    m = L.fromFoldable ['a' .. 'z']
    k a = return $ ord a
    h a = return $ a + 1

test_monadLaw4 =
  assertBool =<< streamsEqual (fmap f xs) (xs >>= return . f)
  where
    f = ord
    xs = L.fromFoldable ['a' .. 'z']

-- * Monoid

test_mappend =
  assertBool
    =<< streamsEqual
      (L.fromFoldable [0 .. 7])
      (L.fromFoldable [0 .. 3] <> L.fromFoldable [4 .. 7])

test_mappendAndTake =
  assertBool
    =<< streamsEqual
      (L.fromFoldable [0 .. 5])
      (L.take 6 $ L.fromFoldable [0 .. 3] <> L.fromFoldable [4 .. 7])

test_mappendDoesntCauseTraversal =
  do
    ref <- newIORef 0
    (flip runReaderT) ref (toList $ L.take 5 $ stream <> stream)
    assertEqual 5 =<< readIORef ref
  where
    stream =
      do
        ref <- lift $ ask
        x <- L.fromFoldable [0 .. 4]
        liftIO $ modifyIORef ref (+ 1)
        return x

-- * Other

test_repeat =
  assertEqual [2, 2, 2] =<< do
    toList $ L.take 3 $ L.repeat (2 :: Int)

test_traverseDoesntCauseTraversal =
  do
    ref <- newIORef 0
    (flip runReaderT) ref (toList stream3)
    assertEqual 3 =<< readIORef ref
  where
    stream1 =
      do
        ref <- lift $ ask
        x <- L.fromFoldable ['a' .. 'z']
        liftIO $ modifyIORef ref (+ 1)
        return x
    stream2 =
      L.traverse (return . toUpper) stream1
    stream3 =
      L.take 3 stream2

test_takeDoesntCauseTraversal =
  do
    ref <- newIORef 0
    (flip runReaderT) ref (toList $ L.take 3 $ L.take 7 $ stream)
    assertEqual 3 =<< readIORef ref
  where
    stream =
      do
        ref <- lift $ ask
        x <- L.fromFoldable [0 .. 10]
        liftIO $ modifyIORef ref (+ 1)
        return x

test_drop =
  assertEqual [3, 4] =<< do
    toList $ L.drop 2 $ L.fromFoldable [1 .. 4]

test_slice =
  assertEqual ["abc", "def", "gh"] =<< do
    toList $ L.slice 3 $ L.fromFoldable ("abcdefgh" :: [Char])

toList :: Monad m => L.ListT m a -> m [a]
toList = L.toList

streamsEqual :: (Applicative m, Monad m, Eq a) => L.ListT m a -> L.ListT m a -> m Bool
streamsEqual a b =
  (==) <$> L.toList a <*> L.toList b