content: {-# LANGUAGE RecordWildCards #-}
  {-# OPTIONS_GHC -Wno-incomplete-patterns #-}
  
  module Test.All(test) where
  
  import Control.Exception
  import Control.Monad
  import Control.Monad.IO.Class
  import Data.Char
  import Data.Either.Extra
  import Data.Foldable
  import Data.List
  import Data.Maybe
  import System.Directory
  import System.FilePath
  import Data.Functor
  import Prelude
  
  import Config.Type
  import Config.Read
  import CmdLine
  import Refact
  import Hint.All
  import Test.Annotations
  import Test.InputOutput
  import Test.Util
  import System.IO.Extra
  import Language.Haskell.GhclibParserEx.GHC.Utils.Outputable
  
  
  test :: Cmd -> ([String] -> IO ()) -> FilePath -> [FilePath] -> IO Int
  test CmdMain{..} main dataDir files = do
      rpath <- refactorPath (if cmdWithRefactor == "" then Nothing else Just cmdWithRefactor)
  
      (failures, ideas) <- withBuffering stdout NoBuffering $ withTests $ do
          hasSrc <- liftIO $ doesFileExist "hlint.cabal"
          let useSrc = hasSrc && null files
          testFiles <- if files /= [] then pure files else do
              xs <- liftIO $ getDirectoryContents dataDir
              pure [dataDir </> x | x <- xs, takeExtension x `elem` [".yml",".yaml"]]
          testFiles <- liftIO $ forM testFiles $ \file -> do
              hints <- readFilesConfig [(file, Nothing),("CommandLine.yaml", Just "- group: {name: testing, enabled: true}")]
              pure (file, hints ++ (if takeBaseName file /= "Test" then [] else map (Builtin . fst) builtinHints))
          let wrap msg act = do liftIO $ putStr (msg ++ " "); act; liftIO $ putStrLn ""
  
          liftIO $ putStrLn $ "Testing (" ++ (if isRight rpath then "with" else "WITHOUT") ++ " refactoring)"
          liftIO $ checkCommentedYaml $ dataDir </> "default.yaml"
          when useSrc $ wrap "Source annotations" $ do
              config <- liftIO $ readFilesConfig [(".hlint.yaml",Nothing)]
              forM_ builtinHints $ \(name,_) -> do
                  progress
                  testAnnotations (Builtin name : if name == "Restrict" then config else [])
                                  ("src/Hint" </> name <.> "hs")
                                  (eitherToMaybe rpath)
          when useSrc $ wrap "Input/outputs" $ testInputOutput main
  
          wrap "Hint names" $ mapM_ (\x -> do progress; testNames $ snd x) testFiles
          wrap "Hint annotations" $ forM_ testFiles $ \(file,h) -> do progress; testAnnotations h file (eitherToMaybe rpath)
  
          when (null files && not hasSrc) $ liftIO $ putStrLn "Warning, couldn't find source code, so non-hint tests skipped"
  
      case rpath of
          Left refactorNotFound -> putStrLn $ unlines [refactorNotFound, "Refactoring tests skipped"]
          _ -> pure ()
      pure failures
  
  
  ---------------------------------------------------------------------
  -- VARIOUS SMALL TESTS
  
  -- Check all hints in the standard config files get sensible names
  testNames :: [Setting] -> Test ()
  testNames hints = sequence_
      [ failed ["No name for the hint " ++ unsafePrettyPrint hintRuleLHS ++ " ==> " ++ unsafePrettyPrint hintRuleRHS]
      | SettingMatchExp x@HintRule{..} <- hints, hintRuleName == defaultHintName]
  
  
  -- Check that the default.yaml template I supply is valid when I strip off all the comments, since that's
  -- what a user gets with --default
  checkCommentedYaml :: FilePath -> IO ()
  checkCommentedYaml file = do
      src <- lines <$> readFile' file
      let src2 = [x | x <- src, Just x <- [stripPrefix "# " x], not $ all (\x -> isAlpha x || x == '$') $ take 1 x]
      e <- readFilesConfig [(file, Just $ unlines src2)]
      void $ evaluate $ length e
  