Skip to content

Commit 7011d5e

Browse files
authored
[skip circleci] Rename hlint test data files and add regression tests (#2321)
* Rename test data files * Add regression tests * Add regression test for #1279 * Use timeout * Correct waitForProgressDone in ghcide * Remove unnecessary waitForDiagnostics * Mark test broken for hlint on ghclib * Add test over unused extensions * Add test for #2042 * Add data for #2280 * Use waitForAllProgressDone * Add test for #2280 * correct module name * Add reproduction for #2290 * Correct test case * Comment about knownBrokenForHlint* * Correction
1 parent 44fa1d7 commit 7011d5e

28 files changed

+132
-72
lines changed

ghcide/test/exe/Main.hs

+5
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,22 @@ import Test.Tasty.QuickCheck
115115
import Text.Printf (printf)
116116
import Text.Regex.TDFA ((=~))
117117

118+
-- | Wait for the next progress begin step
118119
waitForProgressBegin :: Session ()
119120
waitForProgressBegin = skipManyTill anyMessage $ satisfyMaybe $ \case
120121
FromServerMess SProgress (NotificationMessage _ _ (ProgressParams _ (Begin _))) -> Just ()
121122
_ -> Nothing
122123

124+
-- | Wait for the first progress end step
125+
-- Also implemented in hls-test-utils Test.Hls
123126
waitForProgressDone :: Session ()
124127
waitForProgressDone = skipManyTill anyMessage $ satisfyMaybe $ \case
125128
FromServerMess SProgress (NotificationMessage _ _ (ProgressParams _ (End _))) -> Just ()
126129
_ -> Nothing
127130

128131
-- | Wait for all progress to be done
129132
-- Needs at least one progress done notification to return
133+
-- Also implemented in hls-test-utils Test.Hls
130134
waitForAllProgressDone :: Session ()
131135
waitForAllProgressDone = loop
132136
where
@@ -136,6 +140,7 @@ waitForAllProgressDone = loop
136140
_ -> Nothing
137141
done <- null <$> getIncompleteProgressSessions
138142
unless done loop
143+
139144
main :: IO ()
140145
main = do
141146
-- We mess with env vars so run single-threaded.

hls-test-utils/src/Test/Hls.hs

+7-12
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ import Development.IDE.Plugin.Test (TestRequest (GetLastBuildKeys,
5454
import Development.IDE.Types.Options
5555
import GHC.IO.Handle
5656
import Ide.Plugin.Config (Config, formattingProvider)
57-
import Ide.PluginUtils (idePluginsToPluginDesc, pluginDescToIdePlugins)
57+
import Ide.PluginUtils (idePluginsToPluginDesc,
58+
pluginDescToIdePlugins)
5859
import Ide.Types
5960
import Language.LSP.Test
6061
import Language.LSP.Types hiding
@@ -190,17 +191,11 @@ runSessionWithServer' plugin conf sconf caps root s = withLock lock $ keepCurren
190191
putStrLn $ "Finishing canceling (took " <> showDuration t <> "s)"
191192
pure x
192193

193-
-- | Wait for all progress to be done
194-
-- Needs at least one progress done notification to return
194+
-- | Wait for the next progress end step
195195
waitForProgressDone :: Session ()
196-
waitForProgressDone = loop
197-
where
198-
loop = do
199-
() <- skipManyTill anyMessage $ satisfyMaybe $ \case
200-
FromServerMess SProgress (NotificationMessage _ _ (ProgressParams _ (End _))) -> Just ()
201-
_ -> Nothing
202-
done <- null <$> getIncompleteProgressSessions
203-
unless done loop
196+
waitForProgressDone = skipManyTill anyMessage $ satisfyMaybe $ \case
197+
FromServerMess SProgress (NotificationMessage _ _ (ProgressParams _ (End _))) -> Just ()
198+
_ -> Nothing
204199

205200
-- | Wait for all progress to be done
206201
-- Needs at least one progress done notification to return
@@ -233,7 +228,7 @@ callTestPlugin cmd = do
233228
return $ do
234229
e <- _result
235230
case A.fromJSON e of
236-
A.Error err -> Left $ ResponseError InternalError (T.pack err) Nothing
231+
A.Error err -> Left $ ResponseError InternalError (T.pack err) Nothing
237232
A.Success a -> pure a
238233

239234
waitForAction :: String -> TextDocumentIdentifier -> Session (Either ResponseError WaitForIdeRuleResult)

plugins/hls-hlint-plugin/test/Main.hs

+79-35
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ module Main
44
) where
55

66
import Control.Lens ((^.))
7-
import Data.Aeson (toJSON, Value (..), object, (.=))
7+
import Data.Aeson (Value (..), object, toJSON, (.=))
88
import Data.List (find)
99
import qualified Data.Map as Map
1010
import Data.Maybe (fromJust, isJust)
1111
import qualified Data.Text as T
12+
import Ide.Plugin.Config (Config (..), PluginConfig (..),
13+
hlintOn)
14+
import qualified Ide.Plugin.Config as Plugin
1215
import qualified Ide.Plugin.Hlint as HLint
13-
import Ide.Plugin.Config (hlintOn, Config (..), PluginConfig (..))
1416
import qualified Language.LSP.Types.Lens as L
1517
import System.FilePath ((</>))
1618
import Test.Hls
17-
import qualified Ide.Plugin.Config as Plugin
1819

1920
main :: IO ()
2021
main = defaultTestRunner tests
@@ -32,7 +33,7 @@ suggestionsTests :: TestTree
3233
suggestionsTests =
3334
testGroup "hlint suggestions" [
3435
testCase "provides 3.8 code actions including apply all" $ runHlintSession "" $ do
35-
doc <- openDoc "ApplyRefact2.hs" "haskell"
36+
doc <- openDoc "Base.hs" "haskell"
3637
diags@(reduceDiag:_) <- waitForDiagnosticsFromSource doc "hlint"
3738

3839
liftIO $ do
@@ -58,7 +59,7 @@ suggestionsTests =
5859
liftIO $ contents @?= "main = undefined\nfoo x = x\n"
5960

6061
, testCase "falls back to pre 3.8 code actions" $ runSessionWithServer' [hlintPlugin] def def noLiteralCaps "test/testdata" $ do
61-
doc <- openDoc "ApplyRefact2.hs" "haskell"
62+
doc <- openDoc "Base.hs" "haskell"
6263

6364
_ <- waitForDiagnosticsFromSource doc "hlint"
6465

@@ -71,7 +72,7 @@ suggestionsTests =
7172
liftIO $ contents @?= "main = undefined\nfoo = id\n"
7273

7374
, testCase "changing document contents updates hlint diagnostics" $ runHlintSession "" $ do
74-
doc <- openDoc "ApplyRefact2.hs" "haskell"
75+
doc <- openDoc "Base.hs" "haskell"
7576
testHlintDiagnostics doc
7677

7778
let change = TextDocumentContentChangeEvent
@@ -86,60 +87,63 @@ suggestionsTests =
8687
changeDoc doc [change']
8788
testHlintDiagnostics doc
8889

89-
, knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $
90-
testCase "hlint diagnostics works with CPP via ghc -XCPP argument (#554)" $ runHlintSession "cpp" $ do
91-
doc <- openDoc "ApplyRefact3.hs" "haskell"
90+
, knownBrokenForHlintOnGhcLib "hlint doesn't take in account cpp flag as ghc -D argument" $
91+
testCase "[#554] hlint diagnostics works with CPP via ghc -XCPP argument" $ runHlintSession "cpp" $ do
92+
doc <- openDoc "CppCond.hs" "haskell"
9293
testHlintDiagnostics doc
9394

94-
, knownBrokenForGhcVersions [GHC88, GHC86] "hlint doesn't take in account cpp flag as ghc -D argument" $
95-
testCase "hlint diagnostics works with CPP via language pragma (#554)" $ runHlintSession "" $ do
96-
doc <- openDoc "ApplyRefact3.hs" "haskell"
95+
, knownBrokenForHlintOnGhcLib "hlint doesn't take in account cpp flag as ghc -D argument" $
96+
testCase "[#554] hlint diagnostics works with CPP via language pragma" $ runHlintSession "" $ do
97+
doc <- openDoc "CppCond.hs" "haskell"
9798
testHlintDiagnostics doc
9899

99-
, testCase "hlint diagnostics works with CPP via -XCPP argument and flag via #include header (#554)" $ runHlintSession "cpp" $ do
100-
doc <- openDoc "ApplyRefact2.hs" "haskell"
100+
, testCase "[#554] hlint diagnostics works with CPP via -XCPP argument and flag via #include header" $ runHlintSession "cpp" $ do
101+
doc <- openDoc "CppHeader.hs" "haskell"
101102
testHlintDiagnostics doc
102103

103-
, testCase "apply-refact works with -XLambdaCase argument (#590)" $ runHlintSession "lambdacase" $ do
104-
testRefactor "ApplyRefact1.hs" "Redundant bracket"
104+
, testCase "[#590] apply-refact works with -XLambdaCase argument" $ runHlintSession "lambdacase" $ do
105+
testRefactor "LambdaCase.hs" "Redundant bracket"
105106
expectedLambdaCase
106107

107-
, testCase "apply-refact works with -XTypeApplications argument (#1242)" $ runHlintSession "typeapps" $ do
108-
testRefactor "ApplyRefact1.hs" "Redundant bracket"
108+
, testCase "[#1242] apply-refact works with -XTypeApplications argument" $ runHlintSession "typeapps" $ do
109+
testRefactor "TypeApplication.hs" "Redundant bracket"
109110
expectedTypeApp
110111

111112
, testCase "apply hints works with LambdaCase via language pragma" $ runHlintSession "" $ do
112-
testRefactor "ApplyRefact1.hs" "Redundant bracket"
113+
testRefactor "LambdaCase.hs" "Redundant bracket"
113114
("{-# LANGUAGE LambdaCase #-}" : expectedLambdaCase)
114115

115116
, expectFailBecause "apply-refact doesn't work with cpp" $
116117
testCase "apply hints works with CPP via -XCPP argument" $ runHlintSession "cpp" $ do
117-
testRefactor "ApplyRefact3.hs" "Redundant bracket"
118+
testRefactor "CppCond.hs" "Redundant bracket"
118119
expectedCPP
119120

120121
, expectFailBecause "apply-refact doesn't work with cpp" $
121122
testCase "apply hints works with CPP via language pragma" $ runHlintSession "" $ do
122-
testRefactor "ApplyRefact3.hs" "Redundant bracket"
123+
testRefactor "CppCond.hs" "Redundant bracket"
123124
("{-# LANGUAGE CPP #-}" : expectedCPP)
124125

125126
, testCase "hlint diagnostics ignore hints honouring .hlint.yaml" $ runHlintSession "ignore" $ do
126-
doc <- openDoc "ApplyRefact.hs" "haskell"
127+
doc <- openDoc "CamelCase.hs" "haskell"
127128
expectNoMoreDiagnostics 3 doc "hlint"
128129

129130
, testCase "hlint diagnostics ignore hints honouring ANN annotations" $ runHlintSession "" $ do
130-
doc <- openDoc "ApplyRefact4.hs" "haskell"
131+
doc <- openDoc "IgnoreAnn.hs" "haskell"
131132
expectNoMoreDiagnostics 3 doc "hlint"
132133

133-
, knownBrokenForGhcVersions [GHC810, GHC90] "hlint plugin doesn't honour HLINT annotations (#838)" $
134+
, knownBrokenForHlintOnRawGhc "[#838] hlint plugin doesn't honour HLINT annotations" $
134135
testCase "hlint diagnostics ignore hints honouring HLINT annotations" $ runHlintSession "" $ do
135-
doc <- openDoc "ApplyRefact5.hs" "haskell"
136+
doc <- openDoc "IgnoreAnnHlint.hs" "haskell"
136137
expectNoMoreDiagnostics 3 doc "hlint"
137138

138139
, testCase "apply-refact preserve regular comments" $ runHlintSession "" $ do
139-
testRefactor "ApplyRefact6.hs" "Redundant bracket" expectedComments
140+
testRefactor "Comments.hs" "Redundant bracket" expectedComments
141+
142+
, testCase "[#2290] apply all hints works with a trailing comment" $ runHlintSession "" $ do
143+
testRefactor "TwoHintsAndComment.hs" "Apply all hints" expectedComments2
140144

141145
, testCase "applyAll is shown only when there is at least one diagnostic in range" $ runHlintSession "" $ do
142-
doc <- openDoc "ApplyRefact8.hs" "haskell"
146+
doc <- openDoc "TwoHints.hs" "haskell"
143147
_ <- waitForDiagnosticsFromSource doc "hlint"
144148

145149
firstLine <- map fromAction <$> getCodeActions doc (mkRange 0 0 0 0)
@@ -153,6 +157,30 @@ suggestionsTests =
153157
liftIO $ hasApplyAll secondLine @? "Missing apply all code action"
154158
liftIO $ not (hasApplyAll thirdLine) @? "Unexpected apply all code action"
155159
liftIO $ hasApplyAll multiLine @? "Missing apply all code action"
160+
161+
, knownBrokenForHlintOnRawGhc "[#2042] maybe hlint is ignoring pragmas" $
162+
testCase "hlint should warn about unused extensions" $ runHlintSession "unusedext" $ do
163+
doc <- openDoc "UnusedExtension.hs" "haskell"
164+
diags@(unusedExt:_) <- waitForDiagnosticsFromSource doc "hlint"
165+
166+
liftIO $ do
167+
length diags @?= 1
168+
unusedExt ^. L.code @?= Just (InR "refact:Unused LANGUAGE pragma")
169+
170+
, knownBrokenForHlintOnGhcLib "[#1279] hlint uses a fixed set of extensions" $
171+
testCase "hlint should not activate extensions like PatternSynonyms" $ runHlintSession "" $ do
172+
doc <- openDoc "PatternKeyword.hs" "haskell"
173+
174+
waitForAllProgressDone
175+
-- hlint will report a parse error if PatternSynonyms is enabled
176+
expectNoMoreDiagnostics 3 doc "hlint"
177+
, knownBrokenForHlintOnRawGhc "[#2280] maybe hlint is ignoring pragmas" $
178+
testCase "hlint should not warn about redundant irrefutable pattern with LANGUAGE Strict" $ runHlintSession "" $ do
179+
doc <- openDoc "StrictData.hs" "haskell"
180+
181+
waitForAllProgressDone
182+
183+
expectNoMoreDiagnostics 3 doc "hlint"
156184
]
157185
where
158186
testRefactor file caTitle expected = do
@@ -168,26 +196,29 @@ suggestionsTests =
168196
contents <- skipManyTill anyMessage $ getDocumentEdit doc
169197
liftIO $ contents @?= T.unlines expected
170198

171-
expectedLambdaCase = [ "module ApplyRefact1 where", ""
199+
expectedLambdaCase = [ "module LambdaCase where", ""
172200
, "f = \\case \"true\" -> True"
173201
, " _ -> False"
174202
]
175-
expectedCPP = [ "module ApplyRefact3 where", ""
203+
expectedCPP = [ "module CppCond where", ""
176204
, "#ifdef FLAG"
177205
, "f = 1"
178206
, "#else"
179207
, "g = 2"
180208
, "#endif", ""
181209
]
182210
expectedComments = [ "-- comment before header"
183-
, "module ApplyRefact6 where", ""
211+
, "module Comments where", ""
184212
, "{-# standalone annotation #-}", ""
185213
, "-- standalone comment", ""
186214
, "-- | haddock comment"
187215
, "f = {- inline comment -}{- inline comment inside refactored code -} 1 -- ending comment", ""
188216
, "-- final comment"
189217
]
190-
expectedTypeApp = [ "module ApplyRefact1 where", ""
218+
expectedComments2 = [ "module TwoHintsAndComment where"
219+
, "biggest = foldr1 max -- the line above will show two hlint hints, \"eta reduce\" and \"use maximum\""
220+
]
221+
expectedTypeApp = [ "module TypeApplication where", ""
191222
, "a = id @Int 1"
192223
]
193224

@@ -198,7 +229,7 @@ configTests = testGroup "hlint plugin config" [
198229
let config = def { hlintOn = True }
199230
sendConfigurationChanged (toJSON config)
200231

201-
doc <- openDoc "ApplyRefact2.hs" "haskell"
232+
doc <- openDoc "Base.hs" "haskell"
202233
testHlintDiagnostics doc
203234

204235
let config' = def { hlintOn = False }
@@ -212,7 +243,7 @@ configTests = testGroup "hlint plugin config" [
212243
let config = def { hlintOn = True }
213244
sendConfigurationChanged (toJSON config)
214245

215-
doc <- openDoc "ApplyRefact2.hs" "haskell"
246+
doc <- openDoc "Base.hs" "haskell"
216247
testHlintDiagnostics doc
217248

218249
let config' = pluginGlobalOn config "hlint" False
@@ -226,7 +257,7 @@ configTests = testGroup "hlint plugin config" [
226257
let config = def { hlintOn = True }
227258
sendConfigurationChanged (toJSON config)
228259

229-
doc <- openDoc "ApplyRefact2.hs" "haskell"
260+
doc <- openDoc "Base.hs" "haskell"
230261
testHlintDiagnostics doc
231262

232263
let config' = hlintConfigWithFlags ["--ignore=Redundant id", "--hint=test-hlint-config.yaml"]
@@ -240,7 +271,7 @@ configTests = testGroup "hlint plugin config" [
240271
let config = def { hlintOn = True }
241272
sendConfigurationChanged (toJSON config)
242273

243-
doc <- openDoc "ApplyRefact7.hs" "haskell"
274+
doc <- openDoc "Generalise.hs" "haskell"
244275

245276
expectNoMoreDiagnostics 3 doc "hlint"
246277

@@ -285,3 +316,16 @@ hlintConfigWithFlags flags =
285316
where
286317
unObject (Object obj) = obj
287318
unObject _ = undefined
319+
320+
-- We have two main code paths in the plugin depending on how hlint interacts with ghc:
321+
-- * One when hlint uses ghc-lib (all ghc versions but the last version supported by hlint)
322+
-- * Another one when hlint uses directly ghc (only one version, which not have to be the last version supported by ghcide)
323+
-- As we always are using ghc through ghcide the code to get the ghc parsed AST differs
324+
-- So the issues and bugs usually only affects to one code path or the other.
325+
-- Although a given hlint version supports one direct ghc, we could use several versions of hlint
326+
-- each one supporting a different ghc version. It should be a temporary situation though.
327+
knownBrokenForHlintOnGhcLib :: String -> TestTree -> TestTree
328+
knownBrokenForHlintOnGhcLib = knownBrokenForGhcVersions [GHC88, GHC86]
329+
330+
knownBrokenForHlintOnRawGhc :: String -> TestTree -> TestTree
331+
knownBrokenForHlintOnRawGhc = knownBrokenForGhcVersions [GHC810, GHC90]

plugins/hls-hlint-plugin/test/testdata/ApplyRefact6.hs renamed to plugins/hls-hlint-plugin/test/testdata/Comments.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-- comment before header
2-
module ApplyRefact6 where
2+
module Comments where
33

44
{-# standalone annotation #-}
55

plugins/hls-hlint-plugin/test/testdata/ApplyRefact3.hs renamed to plugins/hls-hlint-plugin/test/testdata/CppCond.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{-# LANGUAGE CPP #-}
2-
module ApplyRefact3 where
2+
module CppCond where
33

44
#ifdef FLAG
55
f = (1)

plugins/hls-hlint-plugin/test/testdata/ApplyRefact4.hs renamed to plugins/hls-hlint-plugin/test/testdata/IgnoreAnn.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module ApplyRefact4 where
1+
module IgnoreAnn where
22

33
{-# ANN module "HLint: ignore Redundant bracket" #-}
44
f = (1)

plugins/hls-hlint-plugin/test/testdata/ApplyRefact5.hs renamed to plugins/hls-hlint-plugin/test/testdata/IgnoreAnnHlint.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module ApplyRefact5 where
1+
module IgnoreHlintAnn where
22

33
{- HLINT ignore "Redundant bracket" -}
44
f = (1)
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{-# LANGUAGE LambdaCase #-}
2-
module ApplyRefact1 where
2+
module LambdaCase where
33

44
f = \case "true" -> (True)
55
_ -> False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Foo (pattern) where
2+
3+
pattern = 42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{-# LANGUAGE Strict #-}
2+
f ~x = x
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
f = (1)
22
g = (1)
3-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module TwoHintsAndComment where
2+
biggest items = foldr1 max items -- the line above will show two hlint hints, "eta reduce" and "use maximum"

plugins/hls-hlint-plugin/test/testdata/cpp/ApplyRefact2.hs renamed to plugins/hls-hlint-plugin/test/testdata/cpp/CppHeader.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module ApplyRefact2 where
1+
module CppHeader where
22

33
#include "test.h"
44

plugins/hls-hlint-plugin/test/testdata/cpp/hie.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ cradle:
33
arguments:
44
- "-XCPP"
55
- "-DFLAG"
6-
- "ApplyRefact3"
7-
- "ApplyRefact2"
6+
- "CppCond"
7+
- "CppHeader"

0 commit comments

Comments
 (0)