packages feed

effectful-2.7.1.0: tests/OutputTests.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
module OutputTests (outputTests) where

import Data.Foldable qualified as F
import Test.Tasty
import Test.Tasty.HUnit

import Effectful
import Effectful.State.Static.Local
import Effectful.Output.Dynamic qualified as OD
import Effectful.Output.Static.Action qualified as OA
import Effectful.Output.Static.Local.Array qualified as OLA
import Effectful.Output.Static.Local.List qualified as OLL
import Effectful.Output.Static.Shared.Array qualified as OSA
import Effectful.Output.Static.Shared.List qualified as OSL
import Effectful.Labeled.Output qualified as LO
import Utils qualified as U

outputTests :: TestTree
outputTests = testGroup "Output"
  [ testCase "static local list" test_localList
  , testCase "static local array" test_localArray
  , testCase "static shared list" test_sharedList
  , testCase "static shared array" test_sharedArray
  , testCase "static action" test_action
  , testCase "dynamic dispatches to all backends" test_dynamic
  , testCase "labeled outputs are independent" test_labeled
  ]

test_localList :: Assertion
test_localList = runEff $ do
  (r, xs) <- OLL.runOutput $ do
    mapM_ OLL.output values
    pure "done"
  U.assertEqual "value" "done" r
  U.assertEqual "list" values xs

test_localArray :: Assertion
test_localArray = runEff $ do
  (r, arr) <- OLA.runOutput $ do
    mapM_ OLA.output values
    pure "done"
  U.assertEqual "value" "done" r
  U.assertEqual "array" values (F.toList arr)

test_sharedList :: Assertion
test_sharedList = runEff $ do
  (r, xs) <- OSL.runOutput $ do
    mapM_ OSL.output values
    pure "done"
  U.assertEqual "value" "done" r
  U.assertEqual "list" values xs

test_sharedArray :: Assertion
test_sharedArray = runEff $ do
  (r, arr) <- OSA.runOutput $ do
    mapM_ OSA.output values
    pure "done"
  U.assertEqual "value" "done" r
  U.assertEqual "array" values (F.toList arr)

test_action :: Assertion
test_action = runEff $ do
  (_, acc) <- runState @[Int] [] . OA.runOutput @Int (\o -> modify (o :)) $ do
    mapM_ OA.output values
  U.assertEqual "values fed in order" (reverse values) acc

test_dynamic :: Assertion
test_dynamic = runEff $ do
  (_, la) <- OD.runOutputLocalArray prog
  U.assertEqual "local array" values (F.toList la)
  (_, ll) <- OD.runOutputLocalList prog
  U.assertEqual "local list" values ll
  (_, sa) <- OD.runOutputSharedArray prog
  U.assertEqual "shared array" values (F.toList sa)
  (_, sl) <- OD.runOutputSharedList prog
  U.assertEqual "shared list" values sl
  (_, acc) <- runState @[Int] [] . OD.runOutputAction @Int (\o -> modify (o :)) $ prog
  U.assertEqual "action" (reverse values) acc
  where
    prog :: (HasCallStack, OD.Output Int :> es) => Eff es ()
    prog = mapM_ OD.output values

test_labeled :: Assertion
test_labeled = runEff $ do
  ((_, bs), as) <- LO.runOutputLocalList @"a" @Int . LO.runOutputLocalList @"b" @Int $ do
    LO.output @"a" @Int 1
    LO.output @"b" @Int 10
    LO.output @"a" @Int 2
    LO.output @"b" @Int 20
  U.assertEqual "label a" [1, 2] as
  U.assertEqual "label b" [10, 20] bs

-- | Emitting more values than the initial (zero) capacity exercises the array
-- growth path in the array backends.
values :: [Int]
values = [1 .. 10]