@@ -27,6 +27,7 @@ import Data.Align
27import Reflex
27import Reflex
28import Reflex.EventWriter.Base
28import Reflex.EventWriter.Base
29import Test.Run
29import Test.Run
30import Reflex.Spider.Internal (EventLoopException)
31import Reflex.Spider.Internal (EventLoopException)
31import Data.Witherable (Filterable)
32import Data.Witherable (Filterable)
@@ -36,7 +37,7 @@ import Data.These.Lens
37type Widget t m = (MonadHold t m, Reflex t, MonadFix m)
38type Widget t m = (MonadHold t m, Reflex t, MonadFix m)
39−connectDyn ::Widget t m => Event t () -> (Dynamic t a, Dynamic t a) -> m (Dynamic t a)
40+connectDyn :: Widget t m => Event t () -> (Dynamic t a, Dynamic t a) -> m (Dynamic t a)
40connectDyn e (d, d') = do
41connectDyn e (d, d') = do
41 dd <- holdDyn d (d' <$ e)
42 dd <- holdDyn d (d' <$ e)
42 return $ join dd
43 return $ join dd
@@ -85,8 +86,8 @@ connectButton click e = do
85 d <- hold never (e <$ click)
86 d <- hold never (e <$ click)
86 return (switch d)
87 return (switch d)
88−switchLoop :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
89+switchLoop01 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
89−switchLoop (e1, e2) = do
90+switchLoop01 (e1, e2) = do
91 e' <- connectButton e2 (updated d)
92 e' <- connectButton e2 (updated d)
92 d <- count (align e' e1)
93 d <- count (align e' e1)
@@ -103,76 +104,68 @@ mergeLoop (e1, e2) = do
103 c <- count e1
104 c <- count e1
104 tellEvent (updated ((pure <$> c) :: Dynamic t [Int]))
105 tellEvent (updated ((pure <$> c) :: Dynamic t [Int]))
106−switchLoop' :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
107+switchLoop02 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
107−switchLoop' (e1, e2) = do
108+switchLoop02 (e1, e2) = do
109 e' <- connectButton e2 (updated d)
110 e' <- connectButton e2 (updated d)
110 d <- count (leftmost [e', e1])
111 d <- count (leftmost [e', e1])
111 return $ updated d
112 return $ updated d
113−switchLoop2 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
114+switchLoop03 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
114−switchLoop2 (e1, e2) = do
115+switchLoop03 (e1, e2) = do
116 e' <- connectButton e2 (addHeight $ updated d)
117 e' <- connectButton e2 (addHeight $ updated d)
117 d <- count (align e' e1)
118 d <- count (align e' e1)
118 return $ updated d
119 return $ updated d
120−staticLoop :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
121+staticLoop01 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
121−staticLoop (e1, e2) = do
122+staticLoop01 (e1, e2) = do
123 d <- foldDyn (+) (0 :: Int) (1 <$ align e1 (updated d))
124 d <- foldDyn (+) (0 :: Int) (1 <$ align e1 (updated d))
124 return $ updated d
125 return $ updated d
126−staticLoop' :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
127+staticLoop02 :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
127−staticLoop' (e1, e2) = do
128+staticLoop02 (e1, e2) = do
129 d <- foldDyn (+) (0 :: Int) (leftmost [e1, updated d])
130 d <- foldDyn (+) (0 :: Int) (leftmost [e1, updated d])
130 return $ updated d
131 return $ updated d
132buildStaticLoop :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
133buildStaticLoop :: Widget t m => (Event t Int, Event t ()) -> m (Event t Int)
133buildStaticLoop (e1, e2) = switchHold never buildLoop
134buildStaticLoop (e1, e2) = switchHold never buildLoop
134− where buildLoop = pushAlways (const $ staticLoop (e1, e2)) e2
135+ where buildLoop = pushAlways (const $ staticLoop01 (e1, e2)) e2
136splitThese :: Filterable f => f (These a b) -> (f a, f b)
137splitThese :: Filterable f => f (These a b) -> (f a, f b)
137splitThese f = (mapMaybe (preview here) f, mapMaybe (preview there) f)
138splitThese f = (mapMaybe (preview here) f, mapMaybe (preview there) f)
139−pattern RunTestCaseFlag = "--run-test"
141−runTest :: (String, TestCase) -> IO ()
142−runTest (name, TestCase test) = do
143− putStrLn ("Test: " <> name)
144− mError <- timeout (milliseconds 5) $
145− run `catch` \(e :: EventLoopException) -> pure (show e)
147− Just err -> putStrLn err
148− Nothing -> error "timed out (loop not detected)"
151− r <- runApp' (test . splitThese) (Just <$> occs)
152− error (name <> ": unexpected success " <> show r)
153− occs = [ This 1, This 2, That (), This 3, That (), This 1 ]
154− milliseconds = (*1000)
156−newtype TestCase = TestCase { unTest :: forall t m. (Widget t m, Adjustable t m) => (Event t Int, Event t ()) -> m (Event t Int) }
158−tests :: [(String, TestCase)]
160− [ ("switchLoop'", TestCase switchLoop')
161− , ("switchLoop", TestCase switchLoop)
162− , ("mergeLoop", TestCase mergeLoop)
165− -- , ("switchLoop2", TestCase switchLoop2)
167− -- , ("staticLoop'", TestCase staticLoop')
168− -- , ("staticLoop", TestCase staticLoop)
169− -- ("buildStaticLoop", TestCase buildStaticLoop)
170− -- , ("buildSwitchLoop", TestCase $ buildLoop switchLoop)
172− -- ("coincidenceLoop", TestCase coincidenceLoop)
173− -- , ("dynLoop", TestCase dynLoop)
174− -- , ("buildCoincidenceLoop", TestCase $ buildLoop coincidenceLoop)
177main :: IO ()
140main :: IO ()
178−main = traverse_ runTest tests
141+main = hspec $ do
142+ describe "DebugCycles" $ do
143+ it "throws EventLoopException on switchLoop01" $ do
145+ it "throws EventLoopException on switchLoop02" $ do
147+ it "throws EventLoopException on switchLoop03" $ do
149+ it "throws EventLoopException on buildSwitchLoop" $ do
150+ check $ buildLoop switchLoop01
151+ xit "throws EventLoopException on mergeLoop" $ do
153+ xit "throws EventLoopException on staticLoop01" $ do
155+ xit "throws EventLoopException on staticLoop02" $ do
157+ xit "throws EventLoopException on buildStaticLoop" $ do
158+ check buildStaticLoop
159+ xit "throws EventLoopException on coincidenceLoop" $ do
160+ check coincidenceLoop
161+ xit "throws EventLoopException on dynLoop" $ do
163+ xit "throws EventLoopException on buildCoincidenceLoop" $ do
164+ check $ buildLoop coincidenceLoop
166+ milliseconds = (*1000)
167+ occs = [ This 1, This 2, That (), This 3, That (), This 1 ]
169+ let action = timeout (milliseconds 50) $ do
170+ runApp' (test . splitThese) (Just <$> occs)
171+ action `shouldThrow` (const True :: Selector EventLoopException)