-- | Tests a property with a custom generated commands.
-- The property takes the issued commands, the responses that each process provided
-- and must answer if they are correct.
--
-- Several command sequences are generated. Sequences that make the property fail are
-- yielded as part of the result.
--
-- @testProp@ takes the configuration parameters and a callback which is
-- evaluated for every error. The callback takes the error and an error-indentifying
-- index.
--
testProp :: TestConfig -> (TestError -> Int -> IO ()) -> ([ProcCommand] -> [[Response]] -> [(String,Bool)]) -> IO [TestError]
testProp c onError f = go (mkStdGen 0) [] (nErrors c) (nTries c)
  where
    go _g errors _ 0 = return errors
    go _g errors 0 _ = return errors
    go g errors errCount tryCount = do
      (tr,g') <- genCommands c g
      let tr' = map snd tr
      me <- testCommands c tr' f
      case me of
        Just err -> do err' <- shrink c [SrkRemoveInteraction] tr err f
                       onError err' (length errors)
                       go g' (err':errors) (errCount-1) (tryCount-1)
        Nothing  -> go g' errors errCount (tryCount-1)

-- | Runs a sequence of commands and verifies that the given predicate holds on the results.
testProp :: TestConfig -> (TestError -> Int -> IO ()) -> ([ProcCommand] -> [[Response]] -> [(String,Bool)]) -> IO [TestError]
testProp c onError f = go (mkStdGen 0) [] (nErrors c) (nTries c)
  where
    go _g errors _ 0 = return errors
    go _g errors 0 _ = return errors
    go g errors errCount tryCount = do
      (tr,g') <- genCommands c g
      let tr' = map snd tr
      me <- testCommands c tr' f
      case me of
        Just err -> do err' <- shrink c [SrkRemoveInteraction] tr err f
                       onError err' (length errors)
                       go g' (err':errors) (errCount-1) (tryCount-1)
        Nothing  -> go g' errors errCount (tryCount-1)

-- | Runs a sequence of commands and verifies that the given predicate holds on the results.
testProp c onError f = go (mkStdGen 0) [] (nErrors c) (nTries c)
  where
    go _g errors _ 0 = return errors
    go _g errors 0 _ = return errors
    go g errors errCount tryCount = do
      (tr,g') <- genCommands c g
      let tr' = map snd tr
      me <- testCommands c tr' f
      case me of
        Just err -> do err' <- shrink c [SrkRemoveInteraction] tr err f
                       onError err' (length errors)
                       go g' (err':errors) (errCount-1) (tryCount-1)
        Nothing  -> go g' errors errCount (tryCount-1)

-- | Runs a sequence of commands and verifies that the given predicate holds on the results.