10
10
{-# LANGUAGE StandaloneDeriving #-}
11
11
{-# LANGUAGE TypeFamilies #-}
12
12
{-# LANGUAGE UndecidableInstances #-}
13
+ {-# LANGUAGE TypeApplications #-}
13
14
14
15
module Spec.DynamicLogic.RegistryModel where
15
16
16
- -- import Control.Concurrent
17
+ import Control.Concurrent ( ThreadId )
17
18
import Control.Exception (SomeException (.. ))
18
- import Control.Monad.Class.MonadFork
19
+ import Control.Monad.Class.MonadFork hiding (ThreadId )
20
+ import Control.Monad.Class.MonadFork qualified as IOClass
19
21
20
22
import Control.Monad.Class.MonadThrow (try )
21
23
import Control.Monad.Class.MonadTimer (threadDelay )
@@ -33,12 +35,12 @@ import Test.Tasty.QuickCheck (testProperty)
33
35
import Spec.DynamicLogic.Registry
34
36
import Test.QuickCheck.DynamicLogic.Core
35
37
import Test.QuickCheck.StateModel
36
- import Test.QuickCheck.StateModel.IOSim
38
+ import Test.QuickCheck.StateModel.IOSim ()
37
39
38
40
data RegState = RegState
39
- { tids :: [Var ModelThreadId ]
40
- , regs :: [(String , Var ModelThreadId )]
41
- , dead :: [Var ModelThreadId ]
41
+ { tids :: [Var ThreadId ]
42
+ , regs :: [(String , Var ThreadId )]
43
+ , dead :: [Var ThreadId ]
42
44
, setup :: Bool
43
45
}
44
46
deriving (Show )
@@ -48,12 +50,12 @@ deriving instance Eq (Action RegState a)
48
50
49
51
instance StateModel RegState where
50
52
data Action RegState a where
51
- Init :: Action RegState ()
52
- Spawn :: Action RegState ModelThreadId
53
- WhereIs :: String -> Action RegState (Maybe ModelThreadId )
54
- Register :: String -> Var ModelThreadId -> Action RegState (Either SomeException () )
53
+ Init :: Action RegState ()
54
+ Spawn :: Action RegState ThreadId
55
+ WhereIs :: String -> Action RegState (Maybe ThreadId )
56
+ Register :: String -> Var ThreadId -> Action RegState (Either SomeException () )
55
57
Unregister :: String -> Action RegState (Either SomeException () )
56
- KillThread :: Var ModelThreadId -> Action RegState ()
58
+ KillThread :: Var ThreadId -> Action RegState ()
57
59
-- not generated
58
60
Successful :: Action RegState a -> Action RegState a
59
61
@@ -126,15 +128,37 @@ instance StateModel RegState where
126
128
precondition s (Successful act) = precondition s act
127
129
precondition _ _ = True
128
130
129
- postcondition _ Init _ _ = True
131
+ type RegM s = StateT (Registry (IOSim s )) (IOSim s )
132
+
133
+ instance (m ~ RegM s ) => RunModel RegState m where
134
+ perform _ Init _ = do
135
+ reg <- lift setupRegistry
136
+ put reg
137
+ perform _ Spawn _ = do
138
+ lift $ forkIO (threadDelay 10000000 )
139
+ perform _ (Register name tid) env = do
140
+ reg <- get
141
+ lift $ try $ register reg name (env tid)
142
+ perform _ (Unregister name) _ = do
143
+ reg <- get
144
+ lift $ try $ unregister reg name
145
+ perform _ (WhereIs name) _ = do
146
+ reg <- get
147
+ lift $ whereis reg name
148
+ perform _ (KillThread tid) env = do
149
+ lift $ killThread (env tid)
150
+ perform s (Successful act) env = do
151
+ perform s act env
152
+
153
+ postcondition _ Init _ _ = pure True
130
154
postcondition s (WhereIs name) env mtid =
131
- (env <$> lookup name (regs s)) == mtid
132
- postcondition _s Spawn _ _ = True
155
+ pure $ (env <$> lookup name (regs s)) == mtid
156
+ postcondition _s Spawn _ _ = pure True
133
157
postcondition s (Register name step) _ res =
134
- positive s (Register name step) == isRight res
135
- postcondition _s (Unregister _name) _ _ = True
136
- postcondition _s (KillThread _) _ _ = True
137
- postcondition _s (Successful (Register _ _)) _ res = isRight res
158
+ pure $ positive s (Register name step) == isRight res
159
+ postcondition _s (Unregister _name) _ _ = pure True
160
+ postcondition _s (KillThread _) _ _ = pure True
161
+ postcondition _s (Successful (Register _ _)) _ res = pure $ isRight res
138
162
postcondition s (Successful act) env res = postcondition s act env res
139
163
140
164
monitoring (_s, s') act _ res =
@@ -152,35 +176,6 @@ instance StateModel RegState where
152
176
WhereIs _ -> tabu " WhereIs" [case res of Nothing -> " fails" ; Just _ -> " succeeds" ]
153
177
_ -> id
154
178
155
- runModelIOSim :: forall s . RunModel RegState (IOSimModel (Registry (IOSim s )) s )
156
- runModelIOSim = RunModel performRegistry
157
- where
158
- performRegistry :: forall a . RegState -> Action RegState a -> LookUp -> IOSimModel (Registry (IOSim s )) s a
159
- performRegistry _ Init _ = do
160
- reg <- liftIOSim setupRegistry
161
- put reg
162
- performRegistry _ Spawn _ =
163
- encapsulateM $ forkIO (threadDelay 10000000 )
164
- performRegistry _ (Register name tid) env =
165
- do
166
- reg <- get
167
- tid' <- instantiateM (env tid)
168
- liftIOSim $ try $ register reg name tid'
169
- performRegistry _ (Unregister name) _ =
170
- do
171
- reg <- get
172
- liftIOSim $ try $ unregister reg name
173
- performRegistry _ (WhereIs name) _ =
174
- do
175
- reg <- get
176
- encapsulateM $ whereis reg name
177
- performRegistry _ (KillThread tid) env =
178
- do
179
- tid' <- instantiateM (env tid)
180
- liftIOSim $ killThread tid'
181
- performRegistry s (Successful act) env =
182
- performRegistry s act env
183
-
184
179
positive :: RegState -> Action RegState a -> Bool
185
180
positive s (Register name tid) =
186
181
name `notElem` map fst (regs s)
@@ -217,7 +212,7 @@ shrinkName name = [n | n <- allNames, n < name]
217
212
allNames :: [String ]
218
213
allNames = [" a" , " b" , " c" , " d" , " e" ]
219
214
220
- shrinkTid :: RegState -> Var ModelThreadId -> [Var ModelThreadId ]
215
+ shrinkTid :: RegState -> Var ThreadId -> [Var ThreadId ]
221
216
shrinkTid s tid = [tid' | tid' <- tids s, tid' < tid]
222
217
223
218
tabu :: String -> [String ] -> Property -> Property
@@ -242,15 +237,15 @@ prop_Registry :: Actions RegState -> Property
242
237
prop_Registry s =
243
238
property $
244
239
runIOSimProp $ do
245
- -- _ <- run cleanUp
246
240
monitor $ counterexample " \n Execution\n "
247
- _res <- runPropertyIOSim (runActions runModelIOSim s) (error " don't look at uninitialized state" )
241
+ _res <- runPropertyStateT (runActions s) (error " don't look at uninitialized state" )
248
242
assert True
249
243
250
- -- cleanUp :: IO [Either ErrorCall ()]
251
- -- cleanUp = sequence
252
- -- [try (unregister name) :: IO (Either ErrorCall ())
253
- -- | name <- allNames++["x"]]
244
+ -- TODO: put this in some extras module
245
+ runPropertyStateT :: Monad m => PropertyM (StateT s m ) a -> s -> PropertyM m (a , s )
246
+ runPropertyStateT p s0 = MkPropertyM $ \ k -> do
247
+ m <- unPropertyM (do a <- p; s <- run get; return (a, s)) $ fmap lift . k
248
+ return $ evalStateT m s0
254
249
255
250
propTest :: DynFormula RegState -> Property
256
251
propTest d = forAllScripts d prop_Registry
@@ -318,7 +313,7 @@ canRegisterName' name s = forAllQ (elementsQ availableTids) $ \tid ->
318
313
where
319
314
availableTids = (tids s \\ map snd (regs s)) \\ dead s
320
315
321
- canReregister' :: Show (ThreadId (IOSim s )) => RegState -> DynFormula RegState
316
+ canReregister' :: Show (IOClass. ThreadId (IOSim s )) => RegState -> DynFormula RegState
322
317
canReregister' s
323
318
| null (regs s) =
324
319
toStop $
@@ -335,4 +330,4 @@ tests =
335
330
testGroup
336
331
" registry model example"
337
332
-- TODO: fix property
338
- [testProperty " prop_Registry" (property True ) ]
333
+ [testProperty " prop_Registry" prop_Registry ]
0 commit comments