{-# 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 n :: Int
n example :: a
example) a :: Params
a b :: ActionWith (Arg (Retry a)) -> IO ()
b c :: ProgressCallback
c
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 1 = do
        Result
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
result of
          Result _ Success{} -> Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return Result
result
          Result _ Pending{} -> Result -> IO Result
forall (m :: * -> *) a. Monad m => a -> m a
return Result
result
          Result _ 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 :: Int -> a -> Retry a
retryWith = Int -> a -> Retry a
forall a. Int -> a -> Retry a
Retry