packages feed

fourmolu-0.7.0.0: fixity-tests/Main.hs

{-# LANGUAGE RecordWildCards #-}

import Control.Monad (forM_, when)
import System.Directory (copyFile, findExecutable)
import System.Exit (ExitCode (..))
import System.IO.Temp (withSystemTempDirectory)
import System.Process (readProcessWithExitCode)
import Test.Hspec

main :: IO ()
main = hspec $
  describe "fixity-tests" . beforeAll getExe $
    forM_ tests $ \Test {..} ->
      specify testLabel $ \fourmoluExe ->
        withSystemTempDirectory "fixity-test-dir" $ \tmpdir -> do
          let configFile = tmpdir ++ "/fourmolu.yaml"
              srcFile = tmpdir ++ "/input.hs"

          copyFile ("fixity-tests/" ++ testInputFileName) srcFile

          -- extend fourmolu.yaml to keep same formatting as Ormolu
          rootConfig <- readFile "fourmolu.yaml"
          writeFile configFile $
            if testUseConfig
              then
                unlines
                  [ rootConfig,
                    "fixities:",
                    "- 'infixr 8 .='",
                    "- 'infixr 5 #'"
                  ]
              else rootConfig

          actual <-
            readProcess fourmoluExe . concat $
              [ [srcFile, "--check-idempotence"],
                testArgs,
                if testUseConfig then [] else ["--no-cabal"]
              ]
          expected <- readFile $ "fixity-tests/" ++ testExpectedFileName
          actual `shouldBe` expected

data Test = Test
  { testLabel :: String,
    testInputFileName :: FilePath,
    testArgs :: [String],
    testUseConfig :: Bool,
    testExpectedFileName :: FilePath
  }

tests :: [Test]
tests =
  [ Test
      { testLabel = "File #0 works with no extra info",
        testInputFileName = "test-0-input.hs",
        testArgs = [],
        testUseConfig = False,
        testExpectedFileName = "test-0-no-extra-info-expected.hs"
      },
    Test
      { testLabel = "File #0 works with manual fixity info",
        testInputFileName = "test-0-input.hs",
        testArgs = ["--fixity", "infixr 8 .="],
        testUseConfig = False,
        testExpectedFileName = "test-0-with-fixity-info-expected.hs"
      },
    Test
      { testLabel = "File #0 works with fixity info from config",
        testInputFileName = "test-0-input.hs",
        testArgs = [],
        testUseConfig = True,
        testExpectedFileName = "test-0-with-fixity-info-expected.hs"
      },
    Test
      { testLabel = "File #1 works with no extra info",
        testInputFileName = "test-1-input.hs",
        testArgs = [],
        testUseConfig = False,
        testExpectedFileName = "test-1-no-extra-info-expected.hs"
      },
    Test
      { testLabel = "File #1 works with manual fixity info",
        testInputFileName = "test-1-input.hs",
        testArgs = ["--fixity", "infixr 8 .=", "--fixity", "infixr 5 #"],
        testUseConfig = False,
        testExpectedFileName = "test-1-with-fixity-info-expected.hs"
      },
    Test
      { testLabel = "File #1 works with fixity info from config",
        testInputFileName = "test-1-input.hs",
        testArgs = [],
        testUseConfig = True,
        testExpectedFileName = "test-1-with-fixity-info-expected.hs"
      }
  ]

-- | Find a `fourmolu` executable on PATH.
getExe :: IO FilePath
getExe = findExecutable "fourmolu" >>= maybe (fail "Could not find fourmolu executable") return

readProcess :: FilePath -> [String] -> IO String
readProcess cmd args = do
  (code, stdout, stderr) <- readProcessWithExitCode cmd args ""
  when (code /= ExitSuccess) $ do
    putStrLn $ "Command failed: " ++ (unwords . map (\s -> "\"" ++ s ++ "\"")) (cmd : args)
    putStrLn "========== stdout =========="
    putStrLn stdout
    putStrLn "========== stderr =========="
    putStrLn stderr
    fail "Command failed. See output for more details."
  return stdout