weeder-2.7.0: test/Spec.hs
import qualified Weeder.Main
import qualified Weeder.Run
import qualified Weeder
import qualified TOML
import qualified UnitTests
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.Hspec
import Control.Monad (zipWithM_, when)
import Control.Exception ( throwIO, IOException, handle )
import Data.Maybe (isJust)
import Data.List (find, sortOn)
main :: IO ()
main = do
args <- getArgs
testOutputFiles <- fmap sortTests discoverIntegrationTests
let hieDirectories = map (dropExtension . snd) testOutputFiles
drawDots = mapM_ (drawDot . (<.> ".dot")) hieDirectories
graphviz = "--graphviz" `elem` args
withArgs (filter (/="--graphviz") args) $
hspec $ afterAll_ (when graphviz drawDots) $ do
describe "Weeder.Run" $
describe "runWeeder" $
zipWithM_ (uncurry integrationTestSpec) testOutputFiles hieDirectories
UnitTests.spec
where
-- Draw a dotfile via graphviz
drawDot f = callCommand $ "dot -Tpng " ++ f ++ " -o " ++ (f -<.> ".png")
-- Sort the output files such that the failing ones go last
sortTests = sortOn (isJust . fst)
-- | 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@.
integrationTestSpec :: Maybe FilePath -> FilePath -> FilePath -> Spec
integrationTestSpec failingFile stdoutFile hieDirectory = do
it (integrationTestText ++ hieDirectory) $ do
expectedOutput <- readFile stdoutFile
actualOutput <- integrationTestOutput hieDirectory
case failingFile of
Just f -> do
failingOutput <- readFile f
actualOutput `shouldNotBe` expectedOutput
actualOutput `shouldBe` failingOutput
Nothing ->
actualOutput `shouldBe` expectedOutput
where
integrationTestText = case failingFile of
Nothing -> "produces the expected output for "
Just _ -> "produces the expected (wrong) output for "
-- | Returns detected .failing and .stdout files in ./test/Spec
discoverIntegrationTests :: IO [(Maybe FilePath, FilePath)]
discoverIntegrationTests = do
contents <- listDirectory testPath
let stdoutFiles = map (testPath </>) $
filter (".stdout" `isExtensionOf`) contents
pure . map (\s -> (findFailing s contents, s)) $ stdoutFiles
where
findFailing s = fmap (testPath </>) . find (takeBaseName s <.> ".failing" ==)
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 String
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 (unlines $ map Weeder.Run.formatWeed weeds)
where
configExpr = hieDirectory <.> ".toml"