@@ -43,6 +43,7 @@ import Control.Monad
43
43
import Control.Monad.Reader
44
44
import Control.Monad.Writer (WriterT , runWriterT , tell )
45
45
import Data.Data
46
+ import Data.Kind
46
47
import Data.List
47
48
import Data.Monoid (Endo (.. ))
48
49
import Data.Set qualified as Set
@@ -102,13 +103,6 @@ class
102
103
-- anything.
103
104
data Action state a
104
105
105
- -- | The type of errors that actions can throw. If this is defined as anything
106
- -- other than `Void` `perform` is required to return `Either (Error state) a`
107
- -- instead of `a`.
108
- type Error state
109
-
110
- type Error state = Void
111
-
112
106
-- | Display name for `Action`.
113
107
-- This is useful to provide sensible statistics about the distribution of `Action`s run
114
108
-- when checking a property.
@@ -158,22 +152,6 @@ class
158
152
159
153
deriving instance (forall a . Show (Action state a )) => Show (Any (Action state ))
160
154
161
- -- | The result required of `perform` depending on the `Error` type
162
- -- of a state model. If there are no errors, `Error state = Void`, and
163
- -- so we don't need to specify if the action failed or not.
164
- type family PerformResult e a where
165
- PerformResult Void a = a
166
- PerformResult e a = Either e a
167
-
168
- class IsPerformResult e a where
169
- performResultToEither :: PerformResult e a -> Either e a
170
-
171
- instance {-# OVERLAPPING #-} IsPerformResult Void a where
172
- performResultToEither = Right
173
-
174
- instance {-# OVERLAPPABLE #-} (PerformResult e a ~ Either e a ) => IsPerformResult e a where
175
- performResultToEither = id
176
-
177
155
newtype PostconditionM m a = PostconditionM { runPost :: WriterT (Endo Property , Endo Property ) m a }
178
156
deriving (Functor , Applicative , Monad )
179
157
@@ -197,7 +175,33 @@ monitorPost m = PostconditionM $ tell (Endo m, mempty)
197
175
counterexamplePost :: Monad m => String -> PostconditionM m ()
198
176
counterexamplePost c = PostconditionM $ tell (mempty , Endo $ counterexample c)
199
177
178
+ -- | The result required of `perform` depending on the `Error` type.
179
+ -- If there are no errors, `Error state = Void`, and
180
+ -- so we don't need to specify if the action failed or not.
181
+ type family PerformResult state (m :: Type -> Type ) a where
182
+ PerformResult state m a = EitherIsh (Error state m ) a
183
+
184
+ type family EitherIsh e a where
185
+ EitherIsh Void a = a
186
+ EitherIsh e a = Either e a
187
+
188
+ class IsPerformResult e a where
189
+ performResultToEither :: EitherIsh e a -> Either e a
190
+
191
+ instance {-# OVERLAPPING #-} IsPerformResult Void a where
192
+ performResultToEither = Right
193
+
194
+ instance {-# OVERLAPPABLE #-} (EitherIsh e a ~ Either e a ) => IsPerformResult e a where
195
+ performResultToEither = id
196
+
200
197
class (forall a . Show (Action state a ), Monad m ) => RunModel state m where
198
+ -- | The type of errors that actions can throw. If this is defined as anything
199
+ -- other than `Void` `perform` is required to return `Either (Error state) a`
200
+ -- instead of `a`.
201
+ type Error state m
202
+
203
+ type Error state m = Void
204
+
201
205
-- | Perform an `Action` in some `state` in the `Monad` `m`. This
202
206
-- is the function that's used to exercise the actual stateful
203
207
-- implementation, usually through various side-effects as permitted
@@ -208,7 +212,7 @@ class (forall a. Show (Action state a), Monad m) => RunModel state m where
208
212
--
209
213
-- The `Lookup` parameter provides an /environment/ to lookup `Var
210
214
-- a` instances from previous steps.
211
- perform :: Typeable a => state -> Action state a -> LookUp -> m (PerformResult ( Error state ) a )
215
+ perform :: Typeable a => state -> Action state a -> LookUp -> m (PerformResult state m a )
212
216
213
217
-- | Postcondition on the `a` value produced at some step.
214
218
-- The result is `assert`ed and will make the property fail should it be `False`. This is useful
@@ -220,18 +224,18 @@ class (forall a. Show (Action state a), Monad m) => RunModel state m where
220
224
-- The result is `assert`ed and will make the property fail should it be `False`. This is useful
221
225
-- to check the implementation produces e.g. the expected errors or to check that the SUT hasn't
222
226
-- been updated during the execution of the negative action.
223
- postconditionOnFailure :: (state , state ) -> Action state a -> LookUp -> Either (Error state ) a -> PostconditionM m Bool
227
+ postconditionOnFailure :: (state , state ) -> Action state a -> LookUp -> Either (Error state m ) a -> PostconditionM m Bool
224
228
postconditionOnFailure _ _ _ _ = pure True
225
229
226
230
-- | Allows the user to attach additional information to the `Property` at each step of the process.
227
231
-- This function is given the full transition that's been executed, including the start and ending
228
232
-- `state`, the `Action`, the current environment to `Lookup` and the value produced by `perform`
229
233
-- while executing this step.
230
- monitoring :: (state , state ) -> Action state a -> LookUp -> Either (Error state ) a -> Property -> Property
234
+ monitoring :: (state , state ) -> Action state a -> LookUp -> Either (Error state m ) a -> Property -> Property
231
235
monitoring _ _ _ _ prop = prop
232
236
233
237
-- | Allows the user to attach additional information to the `Property` if a positive action fails.
234
- monitoringFailure :: state -> Action state a -> LookUp -> Error state -> Property -> Property
238
+ monitoringFailure :: state -> Action state a -> LookUp -> Error state m -> Property -> Property
235
239
monitoringFailure _ _ _ _ prop = prop
236
240
237
241
type LookUp = forall a . Typeable a = > Var a -> a
@@ -488,7 +492,7 @@ runActions
488
492
:: forall state m e
489
493
. ( StateModel state
490
494
, RunModel state m
491
- , e ~ Error state
495
+ , e ~ Error state m
492
496
, forall a . IsPerformResult e a
493
497
)
494
498
=> Actions state
@@ -506,7 +510,7 @@ runSteps
506
510
:: forall state m e
507
511
. ( StateModel state
508
512
, RunModel state m
509
- , e ~ Error state
513
+ , e ~ Error state m
510
514
, forall a . IsPerformResult e a
511
515
)
512
516
=> Annotated state
0 commit comments