packages feed

tasty-auto (empty) → 0.0.0.0

raw patch · 13 files changed

+446/−0 lines, 13 filesdep +basedep +directorydep +filepathsetup-changed

Dependencies added: base, directory, filepath, tasty, tasty-auto, tasty-hspec, tasty-hunit, tasty-quickcheck, tasty-smallcheck

Files

+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2017 Daniel Mendler++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,86 @@+# tasty-auto: Simple auto discovery for Tasty++[![Hackage](https://img.shields.io/hackage/v/tasty-auto.svg)](https://hackage.haskell.org/package/tasty-auto)+[![Build Status](https://secure.travis-ci.org/minad/tasty-auto.png?branch=master)](http://travis-ci.org/minad/tasty-auto)++This package provides auto discovery for the tasty test framework.++* Install tasty-auto (using cabal or stack)++* Create a file test/test.hs++``` haskell+-- test/test.hs+{-# OPTIONS_GHC -F -pgmF tasty-auto #-}+```++* Put your tests in files with the suffix `*Test.hs` or `*Spec.hs`. Functions+with the following prefixes are automatically discovered:++* `prop_` for QuickCheck properties+* `scprop_` for SmallCheck properties+* `case_` for HUnit test cases (overloaded for `IO ()`, `IO String` and `(String -> IO ()) -> IO`)+* `spec_` for Hspec specifications+* `test_` for Tasty TestTrees (overloaded for `TestTree`, `[TestTree]`, `IO TestTree` and `IO [TestTree]`)++## Examples++``` haskell+-- test/PropTest.hs+module PropTest where++prop_Addition_is_commutative :: Int -> Int -> Bool+prop_Addition_is_commutative a b = a + b == b + a+```++``` haskell+-- test/CaseTest.hs+module CaseTest where++import Test.Tasty.HUnit++case_List_comparison_with_different_length :: IO ()+case_List_comparison_with_different_length = [1, 2, 3] `compare` [1,2] @?= GT+```++``` haskell+-- test/TestSpec.hs+module TestSpec where++import Test.Tasty.Hspec++spec_Prelude :: Spec+spec_Prelude = do+  describe "Prelude.head" $ do+    it "returns the first element of a list" $ do+      head [23 ..] `shouldBe` (23 :: Int)+```++``` haskell+-- test/TreeTest.hs+{-# LANGUAGE ScopedTypeVariables #-}+module TreeTest where++import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.HUnit++test_Addition :: TestTree+test_Addition = testProperty "Addition commutes" $ \(a :: Int) (b :: Int) -> a + b == b + a++test_Multiplication :: [TestTree]+test_Multiplication =+  [ testProperty "Multiplication commutes" $ \(a :: Int) (b :: Int) -> a * b == b * a+  , testProperty "One is identity" $ \(a :: Int) -> a * 1 == a+  ]++test_Generate_Tree :: IO TestTree+test_Generate_Tree = do+  input <- pure "Some input"+  pure $ testCase input $ pure ()++test_Generate_Trees :: IO [TestTree]+test_Generate_Trees = do+  inputs <- pure ["First input", "Second input"]+  pure $ map (\s -> testCase s $ pure ()) inputs+```
+ Setup.hs view
@@ -0,0 +1,69 @@+{-# OPTIONS_GHC -Wall #-}+module Main where++import Data.Char (isSpace)+import Data.List (dropWhileEnd)+import Data.Version (showVersion)+import Distribution.PackageDescription (PackageDescription(..), defaultExtensions, libBuildInfo)+import Distribution.Simple (defaultMainWithHooks, UserHooks(..), simpleUserHooks)+import Distribution.Simple (packageVersion)+import Distribution.Simple.BuildPaths (autogenModulesDir)+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo())+import Distribution.Simple.Setup (BuildFlags(buildVerbosity), fromFlag)+import Distribution.Simple.Utils (createDirectoryIfMissingVerbose)+import Distribution.Text (display)+import Distribution.Verbosity (Verbosity)+import System.Exit (ExitCode(..))+import System.FilePath ((</>))+import System.Process (readProcessWithExitCode)++main :: IO ()+main = defaultMainWithHooks simpleUserHooks+  { buildHook = \pkg lbi hooks flags -> do+      generateBuildModule (fromFlag (buildVerbosity flags)) pkg lbi+      buildHook simpleUserHooks pkg lbi hooks flags+  }++git :: [String] -> IO String+git args = do+  (code, out, _) <- readProcessWithExitCode "git" args ""+  pure $ case code of+    ExitSuccess -> dropWhileEnd isSpace out+    ExitFailure{} -> "Unknown"++generateBuildModule :: Verbosity -> PackageDescription -> LocalBuildInfo -> IO ()+generateBuildModule verbosity pkg lbi = do+  let dir = autogenModulesDir lbi+  createDirectoryIfMissingVerbose verbosity True dir++  gitTag <- git ["describe", "--dirty", "--tags", "--all"]+  gitCommit <- git ["rev-parse", "HEAD"]+  gitDate <- git ["log", "HEAD", "-1", "--format=%cd"]+  --buildTime <- readProcess "date" ["-R"] ""++  let exts = maybe [] (map display . defaultExtensions . libBuildInfo) (library pkg)++  writeFile (dir </> "Build_chili.hs") $ unlines $+    [ "module Build_chili where"+    , ""+    , "import Chili.Intro"+    , ""+    , "gitCommit :: String"+    , "gitCommit = " ++ show gitCommit+    , ""+    , "gitTag :: String"+    , "gitTag = " ++ show gitTag+    , ""+    , "gitDate :: String"+    , "gitDate = " ++ show gitDate+    , ""+    -- Think about this because of reproducible builds+--    , "buildTime :: String"+--    , "buildTime = " ++ show buildTime+--    , ""+    , "chiliVersion :: String"+    , "chiliVersion = " ++ show (showVersion $ packageVersion pkg)+    , ""+    , "languageExtensions :: [String]"+    , "languageExtensions = " ++ show exts+    ]
+ src/Test/Tasty/Auto.hs view
@@ -0,0 +1,125 @@+module Test.Tasty.Auto (findTests, showTestDriver) where++import Data.Function (on)+import Data.List (find, isPrefixOf, isSuffixOf, nub, intersperse, groupBy, sortOn)+import Data.Maybe (fromJust)+import System.Directory (getDirectoryContents, doesDirectoryExist)+import Data.Traversable (for)+import System.FilePath ((</>), takeDirectory, pathSeparator, dropExtension)+import Data.Monoid (Endo(..))+import Data.Foldable (fold)++data Generator = Generator+  { genPrefix :: String+  , genImport :: ShowS+  , genInstance :: ShowS+  , genSetup :: Test -> ShowS }++data Test = Test { testModule, testFunction :: String }++str :: String -> ShowS+str = (++)++sp, nl :: ShowS+sp = (' ':)+nl = ('\n':)++tr :: Char -> Char -> String -> String+tr a b = map $ \c -> if c == a then b else c++name, fn, var :: Test -> ShowS+name = shows . tr '_' ' ' . tail . dropWhile (/= '_') . testFunction+fn t = str (testModule t) . ('.':) . str (testFunction t)+var t = str "setup_" . str (tr '.' '_' $ testModule t) . ('_':) . str (testFunction t)++generators :: [Generator]+generators =+  [ Generator { genPrefix = "prop_"+              , genImport = str "import qualified Test.Tasty.QuickCheck\n"+              , genInstance = id+              , genSetup = \t -> str "pure $ Test.Tasty.QuickCheck.testProperty " . name t . sp . fn t }+  , Generator { genPrefix = "scprop_"+              , genImport = str "import qualified Test.Tasty.SmallCheck\n"+              , genInstance = id+              , genSetup = \t -> str "pure $ Test.Tasty.SmallCheck.testProperty " . name t . sp . fn t }+  , Generator { genPrefix = "case_"+              , genImport = str "import qualified Test.Tasty.HUnit\n"+              , genInstance =+                  str "class TestCase a where testCase :: String -> a -> IO Test.Tasty.TestTree\n"+                . str "instance TestCase (IO ())                      where testCase n = pure . Test.Tasty.HUnit.testCase      n\n"+                . str "instance TestCase (IO String)                  where testCase n = pure . Test.Tasty.HUnit.testCaseInfo  n\n"+                . str "instance TestCase ((String -> IO ()) -> IO ()) where testCase n = pure . Test.Tasty.HUnit.testCaseSteps n\n"+              , genSetup = \t -> str "testCase " . name t . sp . fn t }+  , Generator { genPrefix = "spec_"+              , genImport = str "import qualified Test.Tasty.Hspec\n"+              , genInstance = id+              , genSetup = \t -> str "Test.Tasty.Hspec.testSpec " . name t . sp . fn t }+  , Generator { genPrefix = "test_"+              , genImport = id+              , genInstance =+                  str "class TestGroup a where testGroup :: String -> a -> IO Test.Tasty.TestTree\n"+                . str "instance TestGroup Test.Tasty.TestTree          where testGroup _ a = pure a\n"+                . str "instance TestGroup [Test.Tasty.TestTree]        where testGroup n a = pure $ Test.Tasty.testGroup n a\n"+                . str "instance TestGroup (IO Test.Tasty.TestTree)     where testGroup _ a = a\n"+                . str "instance TestGroup (IO [Test.Tasty.TestTree])   where testGroup n a = Test.Tasty.testGroup n <$> a\n"+              , genSetup = \t -> str "testGroup " . name t . sp . fn t } ]++testFileSuffixes :: [String]+testFileSuffixes = (++) <$> ["Spec", "Test"] <*> [".lhs", ".hs"]++getGenerator :: Test -> Generator+getGenerator t = fromJust $ find ((`isPrefixOf` testFunction t) . genPrefix) generators++getGenerators :: [Test] -> [Generator]+getGenerators = map head . groupBy  ((==) `on` genPrefix) . sortOn genPrefix . map getGenerator++showImports :: [Test] -> ShowS+showImports = foldEndo . map (\m -> str "import qualified " . str m . nl) . nub . map testModule++showSetup :: Test -> ShowS+showSetup t = str "  " . var t . str " <- " . genSetup (getGenerator t) t . nl++foldEndo :: (Functor f, Foldable f) => f (a -> a) -> (a -> a)+foldEndo = appEndo . fold . fmap Endo++showTestDriver :: FilePath -> [Test] -> ShowS+showTestDriver src ts = let gs = getGenerators ts in+    str "{-# LINE 1 " . shows src . str " #-}\n"+  . str "{-# LANGUAGE FlexibleInstances #-}\n"+  . str "module Main where\n"+  . str "import Prelude\n"+  . str "import qualified Test.Tasty\n"+  . foldEndo (map genImport gs)+  . showImports ts+  . foldEndo (map genInstance gs)+  . str "main :: IO ()\n"+  . str "main = do\n"+  . foldEndo (map showSetup ts)+  . str "  Test.Tasty.defaultMain $ Test.Tasty.testGroup " . shows src+  . str "\n    [ "+  . foldEndo (intersperse (str "\n    , ") $ map var ts)+  . str " ]\n"++filesBySuffix :: FilePath -> [String] -> IO [FilePath]+filesBySuffix dir suffixes = do+  entries <- filter (\s -> head s /= '.') <$> getDirectoryContents dir+  found <- for entries $ \entry -> do+    let dir' = dir </> entry+    exists <- doesDirectoryExist dir'+    if exists then map (entry </>) <$> filesBySuffix dir' suffixes else pure []+  pure $ filter (\x -> any (`isSuffixOf` x) suffixes) entries ++ concat found++findTests :: FilePath -> IO [Test]+findTests src = do+  let dir = takeDirectory src+  files <- filesBySuffix dir testFileSuffixes+  concat <$> traverse (\f -> extractTests f <$> readFile (dir </> f)) files++mkTest :: FilePath -> String -> Test+mkTest = Test . tr pathSeparator '.' . dropExtension++extractTests :: FilePath -> String -> [Test]+extractTests file =+    map (mkTest file) . nub+  . filter (\n -> any ((`isPrefixOf` n) . genPrefix) generators)+  . map fst . concatMap lex . lines
+ tasty-auto.cabal view
@@ -0,0 +1,75 @@+-- This file has been generated from package.yaml by hpack version 0.15.0.+--+-- see: https://github.com/sol/hpack++name:           tasty-auto+version:        0.0.0.0+synopsis:       Simple auto discovery for Tasty+description:    Simple auto discovery for Tasty+category:       Testing+stability:      experimental+homepage:       https://github.com/minad/tasty-auto#readme+bug-reports:    https://github.com/minad/tasty-auto/issues+author:         Daniel Mendler <mail@daniel-mendler.de>+maintainer:     Daniel Mendler <mail@daniel-mendler.de>+copyright:      2017 Daniel Mendler+license:        MIT+license-file:   LICENSE+tested-with:    GHC == 7.10.3, GHC == 8.0.1+build-type:     Simple+cabal-version:  >= 1.10++extra-source-files:+    README.md++source-repository head+  type: git+  location: https://github.com/minad/tasty-auto++library+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      base       >= 4.8 && < 5+    , directory  >= 1.1 && < 1.3+    , filepath   >= 1.3 && < 1.5+  exposed-modules:+      Test.Tasty.Auto+  default-language: Haskell2010++executable tasty-auto+  main-is: tasty-auto.hs+  ghc-options: -Wall+  build-depends:+      base       >= 4.8 && < 5+    , directory  >= 1.1 && < 1.3+    , filepath   >= 1.3 && < 1.5+    , tasty-auto+  default-language: Haskell2010++test-suite test+  type: exitcode-stdio-1.0+  main-is: test.hs+  hs-source-dirs:+      test+  ghc-options: -Wall+  build-depends:+      base       >= 4.8 && < 5+    , directory  >= 1.1 && < 1.3+    , filepath   >= 1.3 && < 1.5+    , base+    , tasty+    , tasty-auto+    , tasty-hspec+    , tasty-hunit+    , tasty-quickcheck+    , tasty-smallcheck+  other-modules:+      CaseTest+      PropTest+      SCPropTest+      SubMod.PropTest+      TestSpec+      TreeTest+  default-language: Haskell2010
+ tasty-auto.hs view
@@ -0,0 +1,15 @@+import System.Exit (exitFailure)+import System.Environment (getArgs)+import System.IO (hPutStrLn, stderr)+import Test.Tasty.Auto++main :: IO ()+main = do+  args <- getArgs+  case args of+    src : _ : dst : _ -> do+      tests <- findTests src+      writeFile dst $ showTestDriver src tests ""+    _ -> do+      hPutStrLn stderr "tasty-auto: Expected source and destination arguments"+      exitFailure
+ test/CaseTest.hs view
@@ -0,0 +1,6 @@+module CaseTest where++import Test.Tasty.HUnit++case_List_comparison_with_different_length :: IO ()+case_List_comparison_with_different_length = [(1 :: Int), 2, 3] `compare` [1,2] @?= GT
+ test/PropTest.hs view
@@ -0,0 +1,4 @@+module PropTest where++prop_Addition_is_commutative :: Int -> Int -> Bool+prop_Addition_is_commutative a b = a + b == b + a
+ test/SCPropTest.hs view
@@ -0,0 +1,6 @@+module SCPropTest where++import Data.List (sort)++scprop_sort_reverse :: [Int] -> Bool+scprop_sort_reverse list = sort list == sort (reverse list)
+ test/SubMod/PropTest.hs view
@@ -0,0 +1,4 @@+module SubMod.PropTest where++prop_Addition_is_associative :: Int -> Int -> Int -> Bool+prop_Addition_is_associative a b c = (a + b) + c == a + (b + c)
+ test/TestSpec.hs view
@@ -0,0 +1,9 @@+module TestSpec where++import Test.Tasty.Hspec++spec_Prelude :: Spec+spec_Prelude = do+  describe "Prelude.head" $ do+    it "returns the first element of a list" $ do+      head [23 ..] `shouldBe` (23 :: Int)
+ test/TreeTest.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE ScopedTypeVariables #-}+module TreeTest where++import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.HUnit++test_Addition :: TestTree+test_Addition = testProperty "Addition commutes" $ \(a :: Int) (b :: Int) -> a + b == b + a++test_Multiplication :: [TestTree]+test_Multiplication =+  [ testProperty "Multiplication commutes" $ \(a :: Int) (b :: Int) -> a * b == b * a+  , testProperty "One is identity" $ \(a :: Int) -> a * 1 == a+  ]++test_Generate_Tree :: IO TestTree+test_Generate_Tree = do+  input <- pure "Some input"+  pure $ testCase input $ pure ()++test_Generate_Trees :: IO [TestTree]+test_Generate_Trees = do+  inputs <- pure ["First input", "Second input"]+  pure $ map (\s -> testCase s $ pure ()) inputs
+ test/test.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF tasty-auto #-}