tasty-autocollect-0.1.0.0: test/Test/Tasty/AutoCollect/ConvertTestTest.hs
{- AUTOCOLLECT.TEST -}
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
#if __GLASGOW_HASKELL__ >= 902
#define __TEST_CONSTRUCTOR_WITH_TYPE_ARGS__ True
#else
#define __TEST_CONSTRUCTOR_WITH_TYPE_ARGS__ False
#endif
module Test.Tasty.AutoCollect.ConvertTestTest (
-- $AUTOCOLLECT.TEST.export$
) where
import Control.Monad (forM_)
import Data.Maybe (catMaybes, maybeToList)
import Data.Text (Text)
import qualified Data.Text as Text
import Test.Predicates
import Test.Predicates.HUnit
import Test.Tasty
import Test.Tasty.HUnit
import Text.Printf (printf)
import TestUtils.Golden
import TestUtils.Integration
import TestUtils.Predicates
test_testCase :: Assertion
test_testCase "plugin works without tasty installed" =
assertSuccess_ $
runTestWith
( \proj ->
modifyFile "Test.hs" (filter (not . isTastyImport)) $
proj{dependencies = filter (/= "tasty") (dependencies proj)}
)
[ "test_testCase :: Assertion"
, "test_testCase \"test\" = 1 @?= 1"
]
where
isTastyImport line =
case Text.unpack <$> Text.stripPrefix "import Test.Tasty" line of
-- not an import / import from non-tasty library
Nothing -> False
-- import from `Test.Tasty`
Just "" -> True
-- import from `Test.Tasty (...)` or `Test.Tasty hiding (...)`
Just " " -> True
-- import from `Test.Tasty.Foo` or `Test.TastyFoo`, which is ok
_ -> False
test_batch :: [TestTree]
test_batch =
[ testCase ("plugin works when " ++ mkLabel ext) $
assertSuccess_ $
runTestWith
(\proj -> proj{extraGhcArgs = maybeToList ext <> extraGhcArgs proj})
[ "test_testCase :: Assertion"
, "test_testCase \"1 = 1\" = 1 @?= 1"
]
| ext <-
[ Just "-XOverloadedStrings"
, Just "-XOverloadedLists"
, Nothing
]
]
where
mkLabel = \case
Nothing -> "no extensions are enabled"
Just ext -> "enabling " <> Text.unpack ext
test_batch :: [TestTree]
test_batch =
[ testCase ("test runs with " <> label <> " as an argument") $
assertSuccess_ . runTest $
[ "test_foo :: Assertion"
, "test_foo " <> arg <> " = return ()"
, ""
, "foo :: a -> Assertion -> TestTree"
, "foo _ = testCase \"test helper\""
, extraCode
]
| (label, arg, extraCode) <-
catMaybes
[ test "literal int" "1" simple
, test "literal float" "1.5" simple
, test "literal empty list" "[]" simple
, test "literal list" "[1,2,3]" simple
, test "literal tuple" "(1, True)" simple
, test "constructor" "(Just True)" simple
, test "infix constructor" "(1 :+ 2)" (withExtra "data Foo = (:+) Int Int")
, test "record constructor" "Foo{a = 1}" (withExtra "data Foo = Foo{a :: Int}")
, test "constructor with type args" "(Just @Int 1)" (onlyWhen __TEST_CONSTRUCTOR_WITH_TYPE_ARGS__)
, test "type signature" "(1 :: Int)" simple
]
]
where
test label arg f = f $ Just (label, arg, "" :: Text)
simple = id
withExtra extraCode = fmap (\(label, arg, _) -> (label, arg, extraCode))
onlyWhen b = if b then id else const Nothing
test_batch :: [TestTree]
test_batch =
[ testCase "plugin propagates constructor type args correctly" $ do
(_, stderr) <-
assertAnyFailure . runTest $
[ "test_foo :: Assertion"
, "test_foo (Just @Int True) \"a test\" = return ()"
, " where foo = const testCase"
]
stderr @?~ hasSubstr "Couldn't match expected type ‘Int’ with actual type ‘Bool’"
| __TEST_CONSTRUCTOR_WITH_TYPE_ARGS__
]
test_testCase :: Assertion
test_testCase "test body can use definitions in where clause" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_testCase :: Assertion"
, "test_testCase \"a test\" = constant @?= 42"
, " where"
, " constant = 42"
]
getTestLines stdout @?~ containsStripped (eq "a test: OK")
test_testCase :: Assertion
test_testCase "test arguments can be defined in where clause" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_testCase :: Assertion"
, "test_testCase label = constant @?= 42"
, " where"
, " label = \"constant is \" ++ show constant"
, ""
, "constant :: Int"
, "constant = 42"
]
getTestLines stdout @?~ containsStripped (eq "constant is 42: OK")
test_testCase :: Assertion
test_testCase "test can be defined with arbitrary testers" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_boolTestCase :: Bool"
, "test_boolTestCase \"this is a successful test\" = 10 > 2"
, ""
, "boolTestCase :: TestName -> Bool -> TestTree"
, "boolTestCase name x = testCase name $ assertBool \"assertion failed\" x"
]
getTestLines stdout @?~ containsStripped (eq "this is a successful test: OK")
test_testCase :: Assertion
test_testCase "test can be defined with arbitrary testers in where clause" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_boolTestCase :: Bool"
, "test_boolTestCase \"this is a successful test\" = 10 > 2"
, " where"
, " boolTestCase :: TestName -> Bool -> TestTree"
, " boolTestCase name x = testCase name $ assertBool \"assertion failed\" x"
]
getTestLines stdout @?~ containsStripped (eq "this is a successful test: OK")
test_testCase :: Assertion
test_testCase "testers can have any number of arguments" =
assertSuccess_ $ runTest $ map Text.pack $ concatMap mkTest [1 .. 10]
where
-- test_fooX :: Assertion
-- test_fooX "X args" 1 2 3 ... = return ()
-- where
-- fooX name _ _ _ ... = testCase name
mkTest arity =
[ printf "test_foo%d :: Assertion" arity
, printf "test_foo%d \"%d args\" %s = return ()" arity arity (mkArgs arity)
, printf " where"
, printf " foo%d name %s = testCase name" arity (mkPatterns arity)
]
mkArgs arity = concatMap (\x -> show x <> " ") [1 .. arity]
mkPatterns arity = concat $ replicate arity "_ "
test_testCase :: Assertion
test_testCase "tests fail when omitting export comment" = do
(_, stderr) <-
assertAnyFailure . runTestWith (modifyFile "Test.hs" (map removeExports)) $
[ "test_testCase :: Assertion"
, "test_testCase \"a test\" = return ()"
]
getTestLines stderr @?~ containsStripped (startsWith "Module ‘Test’ does not export")
where
removeExports s
| "module " `Text.isPrefixOf` s = "module Test () where"
| otherwise = s
test_testCase :: Assertion
test_testCase "test file can omit an explicit export list" = do
(stdout, _) <-
assertSuccess . runTestWith (modifyFile "Test.hs" (map removeExports)) $
[ "test_testCase :: Assertion"
, "test_testCase \"a test\" = return ()"
]
getTestLines stdout @?~ containsStripped (eq "a test: OK")
where
removeExports s
| "module " `Text.isPrefixOf` s = "module Test where"
| otherwise = s
test_testCase :: Assertion
test_testCase "test file can contain multi-function signature" =
assertSuccess_ . runTest $
[ "test_testCase :: Assertion"
, "test_testCase \"test\" = timesTen 1 @?= timesFive 2"
, ""
, "timesTen, timesFive :: Int -> Int"
, "timesTen = (* 10)"
, "timesFive = (* 5)"
]
test_testCase :: Assertion
test_testCase "test_batch generates multiple tests" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_batch :: [TestTree]"
, "test_batch ="
, " [ testCase (\"test #\" ++ show x) $ return ()"
, " | x <- [1 .. 5]"
, " ]"
]
forM_ [1 .. 5 :: Int] $ \x ->
getTestLines stdout @?~ containsStripped (eq . Text.pack $ printf "test #%d: OK" x)
test_testCase :: Assertion
test_testCase "test_batch includes where clause" = do
(stdout, _) <-
assertSuccess . runTest $
[ "test_batch :: [TestTree]"
, "test_batch ="
, " [ testCase (label x) $ return ()"
, " | x <- [1 .. 5]"
, " ]"
, " where"
, " label x = \"test #\" ++ show x"
]
forM_ [1 .. 5 :: Int] $ \x ->
getTestLines stdout @?~ containsStripped (eq . Text.pack $ printf "test #%d: OK" x)
test_testGolden :: IO Text
test_testGolden "test_batch fails when given arguments" "test_batch_args.golden" = do
(_, stderr) <-
assertAnyFailure . runTest $
[ "test_batch :: [TestTree]"
, "test_batch \"some name\" = []"
]
return stderr
test_testGolden :: IO Text
test_testGolden "test_batch fails when specifying wrong type" "test_batch_type.golden" = do
(_, stderr) <-
assertAnyFailure . runTest $
[ "test_batch :: Int"
, "test_batch = []"
]
return stderr