diff --git a/test/Main.hs b/test/Main.hs new file mode 100644 index 0000000..0b6ef21 --- /dev/null +++ b/test/Main.hs @@ -0,0 +1,80 @@ +module Main (main) where + +import qualified Weeder.Main +import qualified Weeder.Run +import qualified Weeder +import qualified TOML +import qualified UnitTests.Weeder.ConfigSpec + +import Algebra.Graph.Export.Dot +import GHC.Types.Name.Occurrence (occNameString) +import System.Directory +import System.Environment (getArgs, withArgs) +import System.FilePath +import System.Process +import System.IO (stderr, hPrint) +import Test.Tasty (TestTree, defaultMain, testGroup) +import Control.Monad (zipWithM_, when) +import Control.Exception ( throwIO, IOException, handle ) +import Data.Maybe (isJust) +import Data.List (find, sortOn) +import Data.ByteString (ByteString) +import qualified Data.ByteString.Lazy as LBS +import Data.Text (Text, pack) +import Data.Text.Encoding (encodeUtf8) +import Test.Tasty.Golden + +main :: IO () +main = do + testOutputFiles <- discoverIntegrationTests + let hieDirectories = map dropExtension testOutputFiles + defaultMain $ + testGroup "Weeder" + [ testGroup "Weeder.Run" $ + [ testGroup "runWeeder" $ + zipWith integrationTest + testOutputFiles + hieDirectories + ] + , UnitTests.Weeder.ConfigSpec.tests + ] + +-- | Run weeder on @hieDirectory@, comparing the output to @stdoutFile@. +-- +-- The directory containing @hieDirectory@ must also have a @.toml@ file +-- with the same name as @hieDirectory@. +-- +-- If @failingFile@ is @Just@, it is used as the expected output instead of +-- @stdoutFile@, and a different failure message is printed if the output +-- matches @stdoutFile@. +integrationTest :: FilePath -> FilePath -> TestTree +integrationTest stdoutFile hieDirectory = do + goldenVsString (integrationTestText ++ hieDirectory) stdoutFile $ + integrationTestOutput hieDirectory + where + integrationTestText = "produces the expected output for " + +-- | Returns detected .failing and .stdout files in ./test/Spec +discoverIntegrationTests :: IO [FilePath] +discoverIntegrationTests = do + contents <- listDirectory testPath + let stdoutFiles = map (testPath ) $ + filter (".stdout" `isExtensionOf`) contents + pure stdoutFiles + where + testPath = "./test/Spec" + +-- | Run weeder on the given directory for .hie files, returning stdout +-- Also creates a dotfile containing the dependency graph as seen by Weeder +integrationTestOutput :: FilePath -> IO LBS.ByteString +integrationTestOutput hieDirectory = do + hieFiles <- Weeder.Main.getHieFiles ".hie" [hieDirectory] True + weederConfig <- TOML.decodeFile configExpr >>= either throwIO pure + let (weeds, analysis) = Weeder.Run.runWeeder weederConfig hieFiles + graph = Weeder.dependencyGraph analysis + graph' = export (defaultStyle (occNameString . Weeder.declOccName)) graph + handle (\e -> hPrint stderr (e :: IOException)) $ + writeFile (hieDirectory <.> ".dot") graph' + pure (LBS.fromStrict $ encodeUtf8 $ pack $ unlines $ map Weeder.Run.formatWeed weeds) + where + configExpr = hieDirectory <.> ".toml" diff --git a/test/Spec/ApplicativeDo.stdout b/test/Spec/ApplicativeDo.stdout deleted file mode 100644 index e69de29..0000000 diff --git a/test/Spec/Monads.stdout b/test/Spec/Monads.stdout deleted file mode 100644 index e69de29..0000000 diff --git a/test/Spec/NumInstanceLiteral.failing b/test/Spec/NumInstanceLiteral.failing deleted file mode 100644 index 0d42ea6..0000000 --- a/test/Spec/NumInstanceLiteral.failing +++ /dev/null @@ -1 +0,0 @@ -test/Spec/NumInstanceLiteral/NumInstanceLiteral.hs:7: (Instance) :: Num Modulo1 diff --git a/test/Spec/NumInstanceLiteral.stdout b/test/Spec/NumInstanceLiteral.stdout index e69de29..0d42ea6 100644 --- a/test/Spec/NumInstanceLiteral.stdout +++ b/test/Spec/NumInstanceLiteral.stdout @@ -0,0 +1 @@ +test/Spec/NumInstanceLiteral/NumInstanceLiteral.hs:7: (Instance) :: Num Modulo1 diff --git a/test/Spec/OverloadedLists.failing b/test/Spec/OverloadedLists.failing deleted file mode 100644 index a1c1f30..0000000 --- a/test/Spec/OverloadedLists.failing +++ /dev/null @@ -1 +0,0 @@ -test/Spec/OverloadedLists/OverloadedLists.hs:9: (Instance) :: IsList (BetterList x) diff --git a/test/Spec/OverloadedLists.stdout b/test/Spec/OverloadedLists.stdout index e69de29..a1c1f30 100644 --- a/test/Spec/OverloadedLists.stdout +++ b/test/Spec/OverloadedLists.stdout @@ -0,0 +1 @@ +test/Spec/OverloadedLists/OverloadedLists.hs:9: (Instance) :: IsList (BetterList x) diff --git a/test/Spec/OverloadedStrings.stdout b/test/Spec/OverloadedStrings.stdout index e69de29..5f77a90 100644 --- a/test/Spec/OverloadedStrings.stdout +++ b/test/Spec/OverloadedStrings.stdout @@ -0,0 +1 @@ +test/Spec/OverloadedStrings/OverloadedStrings.hs:10: (Instance) :: IsString BetterString diff --git a/test/Spec/RangeEnum.stdout b/test/Spec/RangeEnum.stdout deleted file mode 100644 index e69de29..0000000 diff --git a/test/Spec/TypeFamilies.stdout b/test/Spec/TypeFamilies.stdout deleted file mode 100644 index a7d9a6b..0000000 --- a/test/Spec/TypeFamilies.stdout +++ /dev/null @@ -1 +0,0 @@ -test/Spec/TypeFamilies/TypeFamilies.hs:9: (Type Family Instance) :: Family Bool diff --git a/test/UnitTests.hs b/test/UnitTests.hs deleted file mode 100644 index 359d26c..0000000 --- a/test/UnitTests.hs +++ /dev/null @@ -1 +0,0 @@ -{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=UnitTests #-} diff --git a/test/UnitTests/Weeder/ConfigSpec.hs b/test/UnitTests/Weeder/ConfigSpec.hs index f0c0004..adfdb43 100644 --- a/test/UnitTests/Weeder/ConfigSpec.hs +++ b/test/UnitTests/Weeder/ConfigSpec.hs @@ -1,20 +1,19 @@ -module UnitTests.Weeder.ConfigSpec (spec) where +module UnitTests.Weeder.ConfigSpec (tests) where import Weeder.Config import qualified TOML import qualified Data.Text as T -import Test.Hspec (Spec, describe, it) +import Test.Tasty.HUnit +import Test.Hspec.Expectations (shouldBe) +import Test.Tasty (TestTree, testGroup) -spec :: Spec -spec = - describe "Weeder.Config" $ - describe "configToToml" $ - it "passes prop_configToToml" prop_configToToml +tests :: TestTree +tests = + testGroup "Weeder.Config" + [ testCase "configToToml" configToTomlTests ] --- >>> prop_configToToml --- True -prop_configToToml :: Bool -prop_configToToml = +configToTomlTests :: Assertion +configToTomlTests = let cf = Config { rootPatterns = mempty , typeClassRoots = True @@ -22,4 +21,4 @@ prop_configToToml = , unusedTypes = True } cf' = T.pack $ configToToml cf - in TOML.decode cf' == Right cf + in TOML.decode cf' `shouldBe` Right cf diff --git a/weeder.cabal b/weeder.cabal index 35a6547..9ceb056 100644 --- a/weeder.cabal +++ b/weeder.cabal @@ -70,19 +70,21 @@ test-suite weeder-test , directory , filepath , ghc - , hspec , process + , tasty + , tasty-hunit-compat + , tasty-golden , text , toml-reader , weeder + , hspec-expectations + , text + , bytestring type: exitcode-stdio-1.0 - main-is: Spec.hs + main-is: Main.hs hs-source-dirs: test - autogen-modules: - Paths_weeder other-modules: Paths_weeder - UnitTests -- Tests Spec.ApplicativeDo.ApplicativeDo Spec.BasicExample.BasicExample