{-# LANGUAGE RecursiveDo #-} module Reflex.Data.StackSpec ( spec ) where import Relude import Test.Hspec import Test.Hspec.Contrib.HUnit ( fromHUnitTest ) import Test.HUnit import qualified Data.List as L ( last ) import Reflex import Reflex.Data.Stack import Reflex.Potato.Helpers import Reflex.Test.Host data TestCmd a = TCPush a | TCPop | TCClear deriving (Eq, Show) simple_state_network :: forall t a s m . (t ~ SpiderTimeline Global, m ~ SpiderHost Global) => (a -> s -> s) -- ^ do/redo method to transform state -> (a -> s -> s) -- ^ undo method to transform state -> s -- ^ initial state -> (Event t (TestCmd a) -> PerformEventT t m (Event t s)) -- ^ test app producing final state simple_state_network fdo fundo initial ev = do let pushEv = flip fmapMaybe ev $ \case TCPush n -> Just n _ -> Nothing popEv = flip fmapMaybe ev $ \case TCPop -> Just () _ -> Nothing clearEv = flip fmapMaybe ev $ \case TCClear -> Just () _ -> Nothing mds = DynamicStackConfig { _dynamicStackConfig_push = pushEv , _dynamicStackConfig_pop = popEv , _dynamicStackConfig_clear = clearEv } ds :: DynamicStack t a <- holdDynamicStack [] mds adder :: Dynamic t s <- foldDynMergeWith initial [fmap fdo (_dynamicStack_pushed ds), fmap fundo (_dynamicStack_popped ds)] return $ updated adder adder_test :: Test adder_test = TestLabel "adder app" $ TestCase $ do let bs = fmap TCPush [1 .. 4] <> fmap (const TCPop) [(), (), (), (), (), (), ()] <> fmap TCPush [100] run = runAppSimple (simple_state_network (+) (flip (-)) (0 :: Int)) bs v <- liftIO run L.last v @?= [Just 100] clear_test_network :: forall t m . (t ~ SpiderTimeline Global, m ~ SpiderHost Global) => (Event t (TestCmd Int) -> PerformEventT t m (Event t [Int])) clear_test_network ev = do let pushEv = flip fmapMaybe ev $ \case TCPush n -> Just n _ -> Nothing popEv = fmapMaybe (\x -> if x == TCPop then Just () else Nothing) ev clearEv = fmapMaybe (\x -> if x == TCClear then Just () else Nothing) ev mds = DynamicStackConfig { _dynamicStackConfig_push = pushEv , _dynamicStackConfig_pop = popEv , _dynamicStackConfig_clear = clearEv } ds :: DynamicStack t Int <- holdDynamicStack [] (mds :: DynamicStackConfig t Int) return $ updated (_dynamicStack_contents ds) clear_test :: Test clear_test = TestLabel "clear" $ TestCase $ do let bs = fmap TCPush [1 .. 13] <> fmap (const TCPop) [(), (), ()] <> [TCClear] <> fmap TCPush [100] run = runAppSimple clear_test_network bs v <- liftIO run L.last v @?= [Just [100]] basic_test_network :: forall t m . (t ~ SpiderTimeline Global, m ~ SpiderHost Global) => (Event t (Either Int ()) -> PerformEventT t m (Event t [Int])) basic_test_network ev = do let pushEv = fmapMaybe getLeft ev popEv = fmapMaybe getRight ev mds = DynamicStackConfig { _dynamicStackConfig_push = pushEv , _dynamicStackConfig_pop = popEv , _dynamicStackConfig_clear = never } ds :: DynamicStack t Int <- holdDynamicStack [] (mds :: DynamicStackConfig t Int) return $ updated (_dynamicStack_contents ds) basic_test :: Test basic_test = TestLabel "basic" $ TestCase $ do let bs = fmap Left [1 .. 13] <> fmap Right [(), (), ()] :: [Either Int ()] run = runAppSimple basic_test_network bs v <- liftIO run L.last v @?= [Just (drop (length (rights bs)) . reverse $ lefts bs)] spec :: Spec spec = do describe "Stack" $ do fromHUnitTest basic_test fromHUnitTest clear_test fromHUnitTest adder_test