packages feed

himari-1.1.1.0: test/HlintBaseSpec.hs

module HlintBaseSpec (spec) where

import Data.Text qualified as T
import Himari
import Test.Syd

spec :: Spec
spec = do
  describe "hlint base library rules" . beforeAll runHlintOnSample $ do
    describe "Data.List partial functions" $ do
      itWithOuter "Data.List.head should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarning "headMay"

    describe "NonEmpty.head should be safe" $ do
      itWithOuter "Data.List.NonEmpty.head should NOT warn (it's safe)" $ \output -> do
        output `shouldSatisfy` notContainsWarningAt "useNonEmptyHead"

    describe "Debug.Trace functions suggest pTrace*" $ do
      itWithOuter "Debug.Trace.trace should suggest pTrace" $ \output -> do
        output `shouldSatisfy` containsWarningAt "trace" "pTrace"

      itWithOuter "Debug.Trace.traceShow should suggest pTraceShow" $ \output -> do
        output `shouldSatisfy` containsWarningAt "traceShow" "pTraceShow"

      itWithOuter "Debug.Trace.traceM should suggest pTraceM" $ \output -> do
        output `shouldSatisfy` containsWarningAt "traceM" "pTraceM"

    describe "Numeric integer-showing functions are partial" $ do
      itWithOuter "showHex should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarningAt "showHex" "non-negative"

      itWithOuter "showInt should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarningAt "showInt" "non-negative"

      itWithOuter "showOct should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarningAt "showOct" "non-negative"

      itWithOuter "showBin should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarningAt "showBin" "non-negative"

      itWithOuter "showIntAtBase should warn (partial function)" $ \output -> do
        output `shouldSatisfy` containsWarningAt "showIntAtBase" "base > 1"

runHlintOnSample :: IO Text
runHlintOnSample = do
  (exitCode, stdoutOutput, stderrOutput) <-
    readProcess $
      proc "hlint" ["test/HlintSamples/BasePartial.hs"]
  pure $ case exitCode of
    ExitSuccess -> convert stdoutOutput
    ExitFailure _ -> convert stdoutOutput <> convert stderrOutput

containsWarning :: Text -> Text -> Bool
containsWarning expectedMsg output = expectedMsg `T.isInfixOf` output

containsWarningAt :: Text -> Text -> Text -> Bool
containsWarningAt funcName expectedMsg output =
  let msgAndFunc = funcName `T.isInfixOf` output && expectedMsg `T.isInfixOf` output
   in msgAndFunc

notContainsWarningAt :: Text -> Text -> Bool
notContainsWarningAt funcName output =
  let linesWithFunc =
        filter (T.isInfixOf funcName) (T.lines output)
   in null linesWithFunc