content: {-# LANGUAGE NoMonomorphismRestriction #-}
  {-# LANGUAGE StandaloneDeriving #-}
  {-# LANGUAGE CPP #-}
  {-# OPTIONS_GHC -fno-warn-orphans #-}
  {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
  {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
  module Test.Hspec.Core.QuickCheck.UtilSpec (spec) where
  
  import           Prelude ()
  import           Helper
  
  import qualified Test.QuickCheck.Property as QCP
  
  import           Test.Hspec.Core.QuickCheck.Util
  
  deriving instance Eq QuickCheckResult
  deriving instance Eq Status
  deriving instance Eq QuickCheckFailure
  
  spec :: Spec
  spec = do
    describe "formatNumbers" $ do
      it "includes number of tests" $ do
        formatNumbers 1 0 `shouldBe` "(after 1 test)"
  
      it "pluralizes number of tests" $ do
        formatNumbers 3 0 `shouldBe` "(after 3 tests)"
  
      it "includes number of shrinks" $ do
        formatNumbers 3 1 `shouldBe` "(after 3 tests and 1 shrink)"
  
      it "pluralizes number of shrinks" $ do
        formatNumbers 3 3 `shouldBe` "(after 3 tests and 3 shrinks)"
  
    describe "stripSuffix" $ do
      it "drops the given suffix from a list" $ do
        stripSuffix "bar" "foobar" `shouldBe` Just "foo"
  
    describe "splitBy" $ do
      it "splits a string by a given infix" $ do
        splitBy "bar" "foo bar baz" `shouldBe` Just ("foo ", " baz")
  
    describe "parseQuickCheckResult" $ do
      let
        args = stdArgs {chatty = False, replay = Just (mkGen 0, 0)}
        qc = quickCheckWithResult args
  
      context "with Success" $ do
        let p :: Int -> Bool
            p n = n == n
  
        it "parses result" $ do
          parseQuickCheckResult <$> qc p `shouldReturn`
            QuickCheckResult 100 "+++ OK, passed 100 tests." QuickCheckSuccess
  
        it "includes labels" $ do
          parseQuickCheckResult <$> qc (label "unit" p) `shouldReturn`
            QuickCheckResult 100 "+++ OK, passed 100 tests (100% unit)." QuickCheckSuccess
  
      context "with GaveUp" $ do
        let p :: Int -> Property
            p n = (n == 1234) ==> True
  
            qc = quickCheckWithResult args {maxSuccess = 2, maxDiscardRatio = 1}
            result = QuickCheckResult 0 "" (QuickCheckOtherFailure "Gave up after 0 tests; 2 discarded!")
  
        it "parses result" $ do
          parseQuickCheckResult <$> qc p `shouldReturn` result
  
        it "includes verbose output" $ do
          let
            info = intercalate "\n" [
                "Skipped (precondition false):"
              , "0"
              , ""
              , "Skipped (precondition false):"
              , "0"
              ]
          parseQuickCheckResult <$> qc (verbose p) `shouldReturn` result {quickCheckResultInfo = info}
  
      context "with NoExpectedFailure" $ do
        let
          p :: Int -> Property
          p _ = expectFailure True
  
        it "parses result" $ do
          parseQuickCheckResult <$> qc p `shouldReturn`
            QuickCheckResult 100 "" (QuickCheckOtherFailure "Passed 100 tests (expected failure).")
  
        it "includes verbose output" $ do
          let
            info = intercalate "\n" [
                "Passed:"
              , "0"
              , ""
              , "Passed:"
              , "23"
              ]
          parseQuickCheckResult <$> quickCheckWithResult args {maxSuccess = 2} (verbose p) `shouldReturn`
            QuickCheckResult 2 info (QuickCheckOtherFailure "Passed 2 tests (expected failure).")
  
      context "with cover" $ do
        context "without checkCoverage" $ do
          let
            p :: Int -> Property
            p n = cover 10 (n == 5) "is 5" True
  
          it "parses result" $ do
            parseQuickCheckResult <$> qc p `shouldReturn`
              QuickCheckResult 100 "+++ OK, passed 100 tests (1% is 5).\n\nOnly 1% is 5, but expected 10%" QuickCheckSuccess
  
          it "includes verbose output" $ do
            let
              info = intercalate "\n" [
                  "Passed:"
                , "0"
                , ""
                , "Passed:"
                , "23"
                , ""
  #if MIN_VERSION_QuickCheck(2,15,0)
                , "+++ OK, passed 2 tests (0% is 5)."
  #else
                , "+++ OK, passed 2 tests."
  #endif
                , ""
                , "Only 0% is 5, but expected 10%"
                ]
            parseQuickCheckResult <$> quickCheckWithResult args {maxSuccess = 2} (verbose p) `shouldReturn`
              QuickCheckResult 2 info QuickCheckSuccess
  
        context "with checkCoverage" $ do
          let
            p :: Int -> Property
            p n = checkCoverage $ cover 10 (n == 23) "is 23" True
  
            failure :: QuickCheckFailure
            failure = QCFailure {
                quickCheckFailureNumShrinks = 0
              , quickCheckFailureException = Nothing
              , quickCheckFailureReason = "Insufficient coverage"
              , quickCheckFailureCounterexample = [
                  " 0.9% is 23"
                , ""
                , "Only 0.9% is 23, but expected 10.0%"
                ]
              }
  
          it "parses result" $ do
            parseQuickCheckResult <$> qc p `shouldReturn`
              QuickCheckResult 800 "" (QuickCheckFailure failure)
  
          it "includes verbose output" $ do
  -- This off-by-one error was fixed in QuickCheck 2.15
  #if MIN_VERSION_QuickCheck(2,15,0)
            let info = intercalate "\n\n" (replicate 800 "Passed:")
  #else
            let info = intercalate "\n\n" (replicate 799 "Passed:")
  #endif
            parseQuickCheckResult <$> qc (verbose . p) `shouldReturn`
              QuickCheckResult 800 info (QuickCheckFailure failure)
  
      context "with Failure" $ do
        context "with single-line failure reason" $ do
          let
            p :: Int -> Bool
            p = (< 1)
  
            err = "Falsified"
            result = QuickCheckResult 4 "" (QuickCheckFailure $ QCFailure 2 Nothing err ["1"])
  
          it "parses result" $ do
            parseQuickCheckResult <$> qc p `shouldReturn` result
  
          it "includes verbose output" $ do
            let info = intercalate "\n" [
                    "Passed:"
                  , "0"
                  , ""
                  , "Passed:"
                  , "0"
                  , ""
                  , "Passed:"
                  , "-2"
                  , ""
                  , "Failed:"
                  , "3"
                  , ""
                  , "Passed:"
                  , "0"
                  , ""
                  , "Failed:"
                  , "2"
                  , ""
                  , "Passed:"
                  , "0"
                  , ""
                  , "Failed:"
                  , "1"
                  , ""
                  , "Passed:"
                  , "0"
                  ]
  
            parseQuickCheckResult <$> qc (verbose p) `shouldReturn` result {quickCheckResultInfo = info}
  
        context "with multi-line failure reason" $ do
          let
            p :: Int -> QCP.Result
            p n = if n /= 2 then QCP.succeeded else QCP.failed {QCP.reason = err}
  
            err = "foo\nbar"
            result = QuickCheckResult 5 "" (QuickCheckFailure $ QCFailure 0 Nothing err ["2"])
  
          it "parses result" $ do
            parseQuickCheckResult <$> qc p `shouldReturn` result
  
          it "includes verbose output" $ do
            let info = intercalate "\n" [
                    "Passed:"
                  , "0"
                  , ""
                  , "Passed:"
                  , "0"
                  , ""
                  , "Passed:"
                  , "-2"
                  , ""
                  , "Passed:"
                  , "3"
                  , ""
                  , "Failed:"
                  , "2"
                  , ""
                  , "Passed:"
                  , "0"
                  , ""
                  , "Passed:"
                  , "1"
                  ]
            parseQuickCheckResult <$> qc (verbose p) `shouldReturn` result {quickCheckResultInfo = info}
  
        context "with HUnit assertion" $ do
          let p :: Int -> Int -> Expectation
              p m n = do
                m `shouldBe` n
  
          it "includes counterexample" $ do
            result <- qc p
            let QuickCheckResult _ _ (QuickCheckFailure r) = parseQuickCheckResult result
            quickCheckFailureCounterexample r `shouldBe` ["0", "1"]
  