module TimedSpecs.Core where

import TimedSpecs.Types
import qualified Test.Hspec as H
import qualified Test.Hspec.Runner as R
import Test.Hspec.Runner
import Data.Time.Clock.POSIX
import Control.Applicative ((<$>))
import Control.Monad
import System.Exit (exitFailure)

takes :: TimeInMillis -> H.Spec -> TimedSpec
takes expectedSpecRuntime spec = TimedSpec {expectedSpecRuntime = expectedSpecRuntime, spec = spec}

timedSpec :: TimedSpec -> IO()
timedSpec timedSpec = do
        timedSpecSummary <- timeAndRunSpec timedSpec
        case failureCount timedSpecSummary of
            0 -> case didRunInTime timedSpecSummary of
                    True -> putStrLn successReport
                    False -> do 
                               (putStrLn . failureReport) timedSpecSummary
                               exitFailure
            _ -> exitFailure

timeAndRunSpec :: TimedSpec -> IO TimedSpecSummary
timeAndRunSpec timedSpec = do
                    let expectedRuntime = expectedSpecRuntime timedSpec
                        specToRun = spec timedSpec
                    startTimeInMillis <- (round <$> getPOSIXTime)
                    result <- R.hspecResult specToRun
                    endTimeInMillis <- (round <$> getPOSIXTime)

                    let actualRuntime = fromIntegral (endTimeInMillis - startTimeInMillis) * 1000.0
                        didRunInTime = (round actualRuntime) <= (round expectedRuntime)

                    return TimedSpecSummary {
                               expectedRuntime = expectedRuntime,
                               actualRuntime = actualRuntime,
                               failureCount = summaryFailures result,
                               successCount = summaryExamples result - summaryFailures result,
                               didRunInTime = didRunInTime
                           }

failureReport :: TimedSpecSummary -> String
failureReport timedSpecSummary = "Expected test to run in " ++ (show . expectedRuntime) timedSpecSummary ++ " ms, but took " ++ (show . actualRuntime) timedSpecSummary ++ " ms"

successReport :: String
successReport = "Test ran in the specified amount of time"
