    {-# LANGUAGE TypeFamilies #-}
    -- |
    -- maintainer: Junji Hashimoto <junji.hashimoto@gree.net>
    module Test.Hspec.Contrib.Retry (retryWith) where

    import           Test.Hspec.Core.Spec

    data Retry a = Retry Int a

    instance Example a => Example (Retry a) where
      type Arg (Retry a) = Arg a
      evaluateExample :: Retry a
    -> Params
    -> (ActionWith (Arg (Retry a)) -> IO ())
    -> ProgressCallback
    -> IO Result
    evaluateExample (Retry Int
    n a
    example) Params
    a ActionWith (Arg (Retry a)) -> IO ()
    b ProgressCallback
    c
        | Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    1 = do
            result <- a
    -> Params
    -> (ActionWith (Arg a) -> IO ())
    -> ProgressCallback
    -> IO Result
    forall e.
    Example e =>
    e
    -> Params
    -> (ActionWith (Arg e) -> IO ())
    -> ProgressCallback
    -> IO Result
    safeEvaluateExample a
    example Params
    a ActionWith (Arg a) -> IO ()
    ActionWith (Arg (Retry a)) -> IO ()
    b ProgressCallback
    c
            case result of
              Result String
    _ Success{} -> Result -> IO Result
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    result
              Result String
    _ Pending{} -> Result -> IO Result
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    result
              Result String
    _ Failure{} -> IO Result
    retry
        | Bool
    otherwise = a
    -> Params
    -> (ActionWith (Arg a) -> IO ())
    -> ProgressCallback
    -> IO Result
    forall e.
    Example e =>
    e
    -> Params
    -> (ActionWith (Arg e) -> IO ())
    -> ProgressCallback
    -> IO Result
    evaluateExample a
    example Params
    a ActionWith (Arg a) -> IO ()
    ActionWith (Arg (Retry a)) -> IO ()
    b ProgressCallback
    c
        where
          retry :: IO Result
    retry = Retry a
    -> Params
    -> (ActionWith (Arg (Retry a)) -> IO ())
    -> ProgressCallback
    -> IO Result
    forall e.
    Example e =>
    e
    -> Params
    -> (ActionWith (Arg e) -> IO ())
    -> ProgressCallback
    -> IO Result
    evaluateExample (Int -> a -> Retry a
    forall a. Int -> a -> Retry a
    Retry (Int -> Int
    forall a. Enum a => a -> a
    pred Int
    n) a
    example) Params
    a ActionWith (Arg (Retry a)) -> IO ()
    b ProgressCallback
    c

    -- | Retry evaluating example that may be failed until success.
    retryWith :: Int
              -- ^ number of retries, when this number is 1, just evaluate example and finish.
              -> a
              -- ^ retried example
              -> Retry a
              -- ^ Retry is instance of Example.
    retryWith :: forall a. Int -> a -> Retry a
    retryWith = Int -> a -> Retry a
    forall a. Int -> a -> Retry a
    Retry