@@ -1,7 +1,6 @@
11-- Copyright (c) 2019 The DAML Authors. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
4−{-# LANGUAGE AllowAmbiguousTypes #-}
54{-# LANGUAGE DuplicateRecordFields #-}
65{-# LANGUAGE PatternSynonyms #-}
76{-# LANGUAGE CPP #-}
@@ -10,32 +9,31 @@
109module Main (main) where
1110
1211import Control.Applicative.Combinators
13−import Control.Exception (bracket, catch)
14−import qualified Control.Lens as Lens
12+import Control.Exception (catch)
1513import Control.Monad
1614import Control.Monad.IO.Class (liftIO)
17−import Data.Aeson (FromJSON, Value)
15+import Data.Aeson (Value)
16+import Data.Char (toLower)
1817import Data.Foldable
19−import Data.List.Extra
18+import Data.List
2019import Data.Rope.UTF16 (Rope)
2120import qualified Data.Rope.UTF16 as Rope
2221import Development.IDE.Core.PositionMapping (fromCurrent, toCurrent)
2322import Development.IDE.GHC.Util
2423import qualified Data.Text as T
25−import Data.Typeable
2624import Development.IDE.Spans.Common
2725import Development.IDE.Test
2826import Development.IDE.Test.Runfiles
2927import Development.IDE.Types.Location
3028import Development.Shake (getDirectoryFilesIO)
31−import Language.Haskell.LSP.Test
29+import qualified Language.Haskell.LSP.Test as LSPTest
30+import Language.Haskell.LSP.Test hiding (openDoc')
3231import Language.Haskell.LSP.Messages
3332import Language.Haskell.LSP.Types
3433import Language.Haskell.LSP.Types.Capabilities
35−import qualified Language.Haskell.LSP.Types.Lens as Lsp (diagnostics, params, message)
3634import Language.Haskell.LSP.VFS (applyChange)
3735import Network.URI
38−import System.Environment.Blank (getEnv, setEnv, unsetEnv)
36+import System.Environment.Blank (setEnv)
3937import System.FilePath
4038import System.IO.Extra
4139import System.Directory
@@ -49,35 +47,31 @@ import Test.Tasty.QuickCheck
4947import Data.Maybe
5048
5149main :: IO ()
52−main = do
53− -- We mess with env vars so run single-threaded.
54− setEnv "TASTY_NUM_THREADS" "1" True
55− defaultMainWithRerun $ testGroup "HIE"
56− [ testSession "open close" $ do
57− doc <- createDoc "Testing.hs" "haskell" ""
58− void (skipManyTill anyMessage message :: Session WorkDoneProgressCreateRequest)
59− void (skipManyTill anyMessage message :: Session WorkDoneProgressBeginNotification)
60− closeDoc doc
61− void (skipManyTill anyMessage message :: Session WorkDoneProgressEndNotification)
62− , initializeResponseTests
63− , completionTests
64− , cppTests
65− , diagnosticTests
66− , codeActionTests
67− , codeLensesTests
68− , outlineTests
69− , findDefinitionAndHoverTests
70− , pluginTests
71− , preprocessorTests
72− , thTests
73− , safeTests
74− , unitTests
75− , haddockTests
76− , positionMappingTests
77− , watchedFilesTests
78− , cradleTests
79− , dependentFileTest
80− ]
50+main = defaultMainWithRerun $ testGroup "HIE"
51+ [ testSession "open close" $ do
52+ doc <- openDoc' "Testing.hs" "haskell" ""
53+ void (skipManyTill anyMessage message :: Session WorkDoneProgressCreateRequest)
54+ void (skipManyTill anyMessage message :: Session WorkDoneProgressBeginNotification)
55+ closeDoc doc
56+ void (skipManyTill anyMessage message :: Session WorkDoneProgressEndNotification)
57+ , initializeResponseTests
58+ , completionTests
59+ , cppTests
60+ , diagnosticTests
61+ , codeActionTests
62+ , codeLensesTests
63+ , outlineTests
64+ , findDefinitionAndHoverTests
65+ , pluginTests
66+ , preprocessorTests
67+ , thTests
68+ , safeTests
69+ , unitTests
70+ , haddockTests
71+ , positionMappingTests
72+ , watchedFilesTests
73+ , cradleTests
74+ ]
8175
8276initializeResponseTests :: TestTree
8377initializeResponseTests = withResource acquire release tests where
@@ -112,7 +106,7 @@ initializeResponseTests = withResource acquire release tests where
112106 , chk "NO doc link" _documentLinkProvider Nothing
113107 , chk "NO color" _colorProvider (Just $ ColorOptionsStatic False)
114108 , chk "NO folding range" _foldingRangeProvider (Just $ FoldingRangeOptionsStatic False)
115− , che " execute command" _executeCommandProvider (Just $ ExecuteCommandOptions $ List ["typesignature.add"])
109+ , chk " execute command" _executeCommandProvider (Just $ ExecuteCommandOptions $ List ["typesignature.add"])
116110 , chk " workspace" _workspace (Just $ WorkspaceOptions (Just WorkspaceFolderOptions{_supported = Just True, _changeNotifications = Just ( WorkspaceFolderChangeNotificationsBool True )}))
117111 , chk "NO experimental" _experimental Nothing
118112 ] where
@@ -128,17 +122,8 @@ initializeResponseTests = withResource acquire release tests where
128122 chk title getActual expected =
129123 testCase title $ getInitializeResponse >>= \ir -> expected @=? (getActual . innerCaps) ir
130124
131− che :: TestName -> (InitializeResponseCapabilitiesInner -> Maybe ExecuteCommandOptions) -> Maybe ExecuteCommandOptions -> TestTree
132− che title getActual _expected = testCase title doTest
133− where
134− doTest = do
135− ir <- getInitializeResponse
136− let Just ExecuteCommandOptions {_commands = List [command]} = getActual $ innerCaps ir
137− True @=? T.isSuffixOf "typesignature.add" command
138−
139−
140125 innerCaps :: InitializeResponse -> InitializeResponseCapabilitiesInner
141− innerCaps (ResponseMessage _ _ (Right (InitializeResponseCapabilities c))) = c
126+ innerCaps (ResponseMessage _ _ (Just (InitializeResponseCapabilities c)) _) = c
142127 innerCaps _ = error "this test only expects inner capabilities"
143128
144129 acquire :: IO InitializeResponse
@@ -152,7 +137,7 @@ diagnosticTests :: TestTree
152137diagnosticTests = testGroup "diagnostics"
153138 [ testSessionWait "fix syntax error" $ do
154139 let content = T.unlines [ "module Testing wher" ]
155− doc <- createDoc "Testing.hs" "haskell" content
140+ doc <- openDoc' "Testing.hs" "haskell" content
156141 expectDiagnostics [("Testing.hs", [(DsError, (0, 15), "parse error")])]
157142 let change = TextDocumentContentChangeEvent
158143 { _range = Just (Range (Position 0 15) (Position 0 19))
@@ -163,7 +148,7 @@ diagnosticTests = testGroup "diagnostics"
163148 expectDiagnostics [("Testing.hs", [])]
164149 , testSessionWait "introduce syntax error" $ do
165150 let content = T.unlines [ "module Testing where" ]
166− doc <- createDoc "Testing.hs" "haskell" content
151+ doc <- openDoc' "Testing.hs" "haskell" content
167152 void $ skipManyTill anyMessage (message :: Session WorkDoneProgressCreateRequest)
168153 void $ skipManyTill anyMessage (message :: Session WorkDoneProgressBeginNotification)
169154 let change = TextDocumentContentChangeEvent
@@ -181,7 +166,7 @@ diagnosticTests = testGroup "diagnostics"
181166 , "bar :: Int -> Int -> Int"
182167 , "bar a b = cd + b"
183168 ]
184− _ <- createDoc "Testing.hs" "haskell" content
169+ _ <- openDoc' "Testing.hs" "haskell" content
185170 expectDiagnostics
186171 [ ( "Testing.hs"
187172 , [ (DsError, (2, 14), "Variable not in scope: ab")
@@ -195,7 +180,7 @@ diagnosticTests = testGroup "diagnostics"
195180 , "foo :: Int -> String -> Int"
196181 , "foo a b = a + b"
197182 ]
198− _ <- createDoc "Testing.hs" "haskell" content
183+ _ <- openDoc' "Testing.hs" "haskell" content
199184 expectDiagnostics
200185 [ ( "Testing.hs"
201186 , [(DsError, (2, 14), "Couldn't match type '[Char]' with 'Int'")]
@@ -207,7 +192,7 @@ diagnosticTests = testGroup "diagnostics"
207192 , "foo :: Int -> String"
208193 , "foo a = _ a"
209194 ]
210− _ <- createDoc "Testing.hs" "haskell" content
195+ _ <- openDoc' "Testing.hs" "haskell" content
211196 expectDiagnostics
212197 [ ( "Testing.hs"
213198 , [(DsError, (2, 8), "Found hole: _ :: Int -> String")]
@@ -229,23 +214,24 @@ diagnosticTests = testGroup "diagnostics"
229214 [ ("A.hs", [(DsError, (2,4), aMessage)])
230215 , ("B.hs", [(DsError, (3,4), bMessage)])]
231216 deferralTest title binding msg = testSessionWait title $ do
232− _ <- createDoc "A.hs" "haskell" $ sourceA binding
233− _ <- createDoc "B.hs" "haskell" sourceB
217+ _ <- openDoc' "A.hs" "haskell" $ sourceA binding
218+ _ <- openDoc' "B.hs" "haskell" sourceB
234219 expectDiagnostics $ expectedDs msg
235220 in
236221 [ deferralTest "type error" "True" "Couldn't match expected type"
237222 , deferralTest "typed hole" "_" "Found hole"
238223 , deferralTest "out of scope var" "unbound" "Variable not in scope"
224+ , deferralTest "message shows error" "True" "A.hs:3:5: error:"
239225 ]
240226
241227 , testSessionWait "remove required module" $ do
242228 let contentA = T.unlines [ "module ModuleA where" ]
243− docA <- createDoc "ModuleA.hs" "haskell" contentA
229+ docA <- openDoc' "ModuleA.hs" "haskell" contentA
244230 let contentB = T.unlines
245231 [ "module ModuleB where"
246232 , "import ModuleA"
247233 ]
248− _ <- createDoc "ModuleB.hs" "haskell" contentB
234+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
249235 let change = TextDocumentContentChangeEvent
250236 { _range = Just (Range (Position 0 0) (Position 0 20))
251237 , _rangeLength = Nothing
@@ -258,20 +244,20 @@ diagnosticTests = testGroup "diagnostics"
258244 [ "module ModuleB where"
259245 , "import ModuleA"
260246 ]
261− _ <- createDoc "ModuleB.hs" "haskell" contentB
247+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
262248 expectDiagnostics [("ModuleB.hs", [(DsError, (1, 7), "Could not find module")])]
263249 let contentA = T.unlines [ "module ModuleA where" ]
264− _ <- createDoc "ModuleA.hs" "haskell" contentA
250+ _ <- openDoc' "ModuleA.hs" "haskell" contentA
265251 expectDiagnostics [("ModuleB.hs", [])]
266252 , testSessionWait "add missing module (non workspace)" $ do
267253 let contentB = T.unlines
268254 [ "module ModuleB where"
269255 , "import ModuleA"
270256 ]
271− _ <- createDoc "/tmp/ModuleB.hs" "haskell" contentB
257+ _ <- openDoc'' "/tmp/ModuleB.hs" "haskell" contentB
272258 expectDiagnostics [("/tmp/ModuleB.hs", [(DsError, (1, 7), "Could not find module")])]
273259 let contentA = T.unlines [ "module ModuleA where" ]
274− _ <- createDoc "/tmp/ModuleA.hs" "haskell" contentA
260+ _ <- openDoc'' "/tmp/ModuleA.hs" "haskell" contentA
275261 expectDiagnostics [("/tmp/ModuleB.hs", [])]
276262 , testSessionWait "cyclic module dependency" $ do
277263 let contentA = T.unlines
@@ -282,8 +268,8 @@ diagnosticTests = testGroup "diagnostics"
282268 [ "module ModuleB where"
283269 , "import ModuleA"
284270 ]
285− _ <- createDoc "ModuleA.hs" "haskell" contentA
286− _ <- createDoc "ModuleB.hs" "haskell" contentB
271+ _ <- openDoc' "ModuleA.hs" "haskell" contentA
272+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
287273 expectDiagnostics
288274 [ ( "ModuleA.hs"
289275 , [(DsError, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")]
@@ -304,9 +290,9 @@ diagnosticTests = testGroup "diagnostics"
304290 let contentBboot = T.unlines
305291 [ "module ModuleB where"
306292 ]
307− _ <- createDoc "ModuleA.hs" "haskell" contentA
308− _ <- createDoc "ModuleB.hs" "haskell" contentB
309− _ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot
293+ _ <- openDoc' "ModuleA.hs" "haskell" contentA
294+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
295+ _ <- openDoc' "ModuleB.hs-boot" "haskell" contentBboot
310296 expectDiagnostics []
311297 , testSessionWait "correct reference used with hs-boot" $ do
312298 let contentB = T.unlines
@@ -328,10 +314,10 @@ diagnosticTests = testGroup "diagnostics"
328314 -- resolved to the hs-boot file
329315 , "y = x"
330316 ]
331− _ <- createDoc "ModuleB.hs" "haskell" contentB
332− _ <- createDoc "ModuleA.hs" "haskell" contentA
333− _ <- createDoc "ModuleA.hs-boot" "haskell" contentAboot
334− _ <- createDoc "ModuleC.hs" "haskell" contentC
317+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
318+ _ <- openDoc' "ModuleA.hs" "haskell" contentA
319+ _ <- openDoc' "ModuleA.hs-boot" "haskell" contentAboot
320+ _ <- openDoc' "ModuleC.hs" "haskell" contentC
335321 expectDiagnostics []
336322 , testSessionWait "redundant import" $ do
337323 let contentA = T.unlines ["module ModuleA where"]
@@ -340,8 +326,8 @@ diagnosticTests = testGroup "diagnostics"
340326 , "module ModuleB where"
341327 , "import ModuleA"
342328 ]
343− _ <- createDoc "ModuleA.hs" "haskell" contentA
344− _ <- createDoc "ModuleB.hs" "haskell" contentB
329+ _ <- openDoc' "ModuleA.hs" "haskell" contentA
330+ _ <- openDoc' "ModuleB.hs" "haskell" contentB
345331 expectDiagnostics
346332 [ ( "ModuleB.hs"
347333 , [(DsWarning, (2, 0), "The import of 'ModuleA' is redundant")]
@@ -363,8 +349,8 @@ diagnosticTests = testGroup "diagnostics"
363349 , "wrong1 = ThisList.map"
364350 , "wrong2 = BaseList.x"
365351 ]
366− _ <- createDoc "Data/List.hs" "haskell" thisDataListContent
367− _ <- createDoc "Main.hs" "haskell" mainContent
352+ _ <- openDoc' "Data/List.hs" "haskell" thisDataListContent
353+ _ <- openDoc' "Main.hs" "haskell" mainContent
368354 expectDiagnostics
369355 [ ( "Main.hs"
370356 , [(DsError, (6, 9), "Not in scope: \8216ThisList.map\8217")
@@ -379,7 +365,7 @@ diagnosticTests = testGroup "diagnostics"
379365 , "foo :: Ord a => a -> Int"
380366 , "foo a = 1"
381367 ]
382− _ <- createDoc "Foo.hs" "haskell" fooContent
368+ _ <- openDoc' "Foo.hs" "haskell" fooContent
383369 expectDiagnostics
384370 [ ( "Foo.hs"
385371 -- The test is to make sure that warnings contain unqualified names
@@ -404,14 +390,14 @@ diagnosticTests = testGroup "diagnostics"
404390 Just pathB <- pure $ uriToFilePath uriB
405391 uriB <- pure $
406392 let (drive, suffix) = splitDrive pathB
407− in filePathToUri (joinDrive (lower drive) suffix)
393+ in filePathToUri (joinDrive (map toLower drive ) suffix)
408394 liftIO $ createDirectoryIfMissing True (takeDirectory pathB)
409395 liftIO $ writeFileUTF8 pathB $ T.unpack bContent
410396 uriA <- getDocUri "A/A.hs"
411397 Just pathA <- pure $ uriToFilePath uriA
412398 uriA <- pure $
413399 let (drive, suffix) = splitDrive pathA
414− in filePathToUri (joinDrive (lower drive) suffix)
400+ in filePathToUri (joinDrive (map toLower drive ) suffix)
415401 let itemA = TextDocumentItem uriA "haskell" 0 aContent
416402 let a = TextDocumentIdentifier uriA
417403 sendNotification TextDocumentDidOpen (DidOpenTextDocumentParams itemA)
@@ -424,38 +410,6 @@ diagnosticTests = testGroup "diagnostics"
424410 liftIO $ unless ("redundant" `T.isInfixOf` msg) $
425411 assertFailure ("Expected redundant import but got " <> T.unpack msg)
426412 closeDoc a
427− , testSessionWait "haddock parse error" $ do
428− let fooContent = T.unlines
429− [ "module Foo where"
430− , "foo :: Int"
431− , "foo = 1 {-|-}"
432− ]
433− _ <- createDoc "Foo.hs" "haskell" fooContent
434− expectDiagnostics
435− [ ( "Foo.hs"
436− , [(DsError, (2, 8), "Parse error on input")
437− ]
438− )
439− ]
440− , testSessionWait "strip file path" $ do
441− let
442− name = "Testing"
443− content = T.unlines
444− [ "module " <> name <> " where"
445− , "value :: Maybe ()"
446− , "value = [()]"
447− ]
448− _ <- createDoc (T.unpack name <> ".hs") "haskell" content
449− notification <- skipManyTill anyMessage diagnostic
450− let
451− offenders =
452− Lsp.params .
453− Lsp.diagnostics .
454− Lens.folded .
455− Lsp.message .
456− Lens.filtered (T.isInfixOf ("/" <> name <> ".hs:"))
457− failure msg = liftIO $ assertFailure $ "Expected file path to be stripped but got " <> T.unpack msg
458− Lens.mapMOf_ offenders failure notification
459413 ]
460414
461415codeActionTests :: TestTree
@@ -481,26 +435,26 @@ codeLensesTests = testGroup "code lenses"
481435watchedFilesTests :: TestTree
482436watchedFilesTests = testGroup "watched files"
483437 [ testSession' "workspace files" $ \sessionDir -> do
484− liftIO $ writeFile (sessionDir </> "hie.yaml") "cradle: {direct: {arguments: [\"-isrc\"]}}"
485− _doc <- createDoc "A.hs" "haskell" "{-#LANGUAGE NoImplicitPrelude #-}\nmodule A where\nimport WatchedFilesMissingModule"
486− watchedFileRegs <- getWatchedFilesSubscriptionsUntil @PublishDiagnosticsNotification
487−
488− -- Expect 4 subscriptions (A does not get any because it's VFS):
489− -- - /path-to-workspace/WatchedFilesMissingModule.hs
490− -- - /path-to-workspace/WatchedFilesMissingModule.lhs
491− -- - /path-to-workspace/src/WatchedFilesMissingModule.hs
492− -- - /path-to-workspace/src/WatchedFilesMissingModule.lhs
493− liftIO $ length watchedFileRegs @?= 4
438+ liftIO $ writeFile (sessionDir </> "hie.yaml") $ "cradle: {direct: {arguments: [\"-isrc\"]}}"
439+ _ <- openDoc' "A.hs" "haskell" "{-#LANGUAGE NoImplicitPrelude #-}\nmodule A where\nimport B"
440+ watchedFileRegs <- getWatchedFilesSubscriptionsUntilProgressEnd
441+
442+ -- Expect 6 subscriptions (A does not get any because it's VFS):
443+ -- - /path-to-workspace/B.hs
444+ -- - /path-to-workspace/B.lhs
445+ -- - B.hs
446+ -- - B.lhs
447+ -- - src/B.hs
448+ -- - src/B.lhs
449+ liftIO $ length watchedFileRegs @?= 6
494450
495451 , testSession' "non workspace file" $ \sessionDir -> do
496− liftIO $ writeFile (sessionDir </> "hie.yaml") "cradle: {direct: {arguments: [\"-i/tmp\"]}}"
497− _doc <- createDoc "A.hs" "haskell" "{-# LANGUAGE NoImplicitPrelude#-}\nmodule A where\nimport WatchedFilesMissingModule"
498− watchedFileRegs <- getWatchedFilesSubscriptionsUntil @PublishDiagnosticsNotification
452+ liftIO $ writeFile (sessionDir </> "hie.yaml") $ "cradle: {direct: {arguments: [\"-i/tmp\"]}}"
453+ _ <- openDoc' "A.hs" "haskell" "{-# LANGUAGE NoImplicitPrelude#-}\nmodule A where\nimport B"
454+ watchedFileRegs <- getWatchedFilesSubscriptionsUntilProgressEnd
499455
500− -- Expect 2 subscriptions (/tmp does not get any as it is out of the workspace):
501− -- - /path-to-workspace/WatchedFilesMissingModule.hs
502− -- - /path-to-workspace/WatchedFilesMissingModule.lhs
503− liftIO $ length watchedFileRegs @?= 2
456+ -- Expect 4 subscriptions:
457+ liftIO $ length watchedFileRegs @?= 4
504458
505459 -- TODO add a test for didChangeWorkspaceFolder
506460 ]
@@ -513,7 +467,7 @@ renameActionTests = testGroup "rename actions"
513467 , "foo :: Int -> Int"
514468 , "foo argName = argNme"
515469 ]
516− doc <- createDoc "Testing.hs" "haskell" content
470+ doc <- openDoc' "Testing.hs" "haskell" content
517471 _ <- waitForDiagnostics
518472 action <- findCodeAction doc (Range (Position 2 14) (Position 2 20)) "Replace with ‘argName’"
519473 executeCodeAction action
@@ -531,7 +485,7 @@ renameActionTests = testGroup "rename actions"
531485 , "foo :: Maybe a -> [a]"
532486 , "foo = maybToList"
533487 ]
534− doc <- createDoc "Testing.hs" "haskell" content
488+ doc <- openDoc' "Testing.hs" "haskell" content
535489 _ <- waitForDiagnostics
536490 action <- findCodeAction doc (Range (Position 3 6) (Position 3 16)) "Replace with ‘maybeToList’"
537491 executeCodeAction action
@@ -549,7 +503,7 @@ renameActionTests = testGroup "rename actions"
549503 , "foo :: Char -> Char -> Char -> Char"
550504 , "foo argument1 argument2 argument3 = argumentX"
551505 ]
552− doc <- createDoc "Testing.hs" "haskell" content
506+ doc <- openDoc' "Testing.hs" "haskell" content
553507 _ <- waitForDiagnostics
554508 _ <- findCodeActions doc (Range (Position 2 36) (Position 2 45))
555509 ["Replace with ‘argument1’", "Replace with ‘argument2’", "Replace with ‘argument3’"]
@@ -561,7 +515,7 @@ renameActionTests = testGroup "rename actions"
561515 , "monus x y = max 0 (x - y)"
562516 , "foo x y = x `monnus` y"
563517 ]
564− doc <- createDoc "Testing.hs" "haskell" content
518+ doc <- openDoc' "Testing.hs" "haskell" content
565519 _ <- waitForDiagnostics
566520 actionsOrCommands <- getCodeActions doc (Range (Position 3 12) (Position 3 20))
567521 [fixTypo] <- pure [action | CACodeAction action@CodeAction{ _title = actionTitle } <- actionsOrCommands, "monus" `T.isInfixOf` actionTitle ]
@@ -584,7 +538,7 @@ typeWildCardActionTests = testGroup "type wildcard actions"
584538 , "func :: _"
585539 , "func x = x"
586540 ]
587− doc <- createDoc "Testing.hs" "haskell" content
541+ doc <- openDoc' "Testing.hs" "haskell" content
588542 _ <- waitForDiagnostics
589543 actionsOrCommands <- getCodeActions doc (Range (Position 2 1) (Position 2 10))
590544 let [addSignature] = [action | CACodeAction action@CodeAction { _title = actionTitle } <- actionsOrCommands
@@ -604,7 +558,7 @@ typeWildCardActionTests = testGroup "type wildcard actions"
604558 , "func :: _"
605559 , "func x y = x + y"
606560 ]
607− doc <- createDoc "Testing.hs" "haskell" content
561+ doc <- openDoc' "Testing.hs" "haskell" content
608562 _ <- waitForDiagnostics
609563 actionsOrCommands <- getCodeActions doc (Range (Position 2 1) (Position 2 10))
610564 let [addSignature] = [action | CACodeAction action@CodeAction { _title = actionTitle } <- actionsOrCommands
@@ -627,7 +581,7 @@ typeWildCardActionTests = testGroup "type wildcard actions"
627581 , " y = x * 2"
628582 , " in y"
629583 ]
630− doc <- createDoc "Testing.hs" "haskell" content
584+ doc <- openDoc' "Testing.hs" "haskell" content
631585 _ <- waitForDiagnostics
632586 actionsOrCommands <- getCodeActions doc (Range (Position 4 1) (Position 4 10))
633587 let [addSignature] = [action | CACodeAction action@CodeAction { _title = actionTitle } <- actionsOrCommands
@@ -652,7 +606,7 @@ removeImportTests = testGroup "remove import actions"
652606 let contentA = T.unlines
653607 [ "module ModuleA where"
654608 ]
655− _docA <- createDoc "ModuleA.hs" "haskell" contentA
609+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
656610 let contentB = T.unlines
657611 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
658612 , "module ModuleB where"
@@ -660,7 +614,7 @@ removeImportTests = testGroup "remove import actions"
660614 , "stuffB :: Integer"
661615 , "stuffB = 123"
662616 ]
663− docB <- createDoc "ModuleB.hs" "haskell" contentB
617+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
664618 _ <- waitForDiagnostics
665619 [CACodeAction action@CodeAction { _title = actionTitle }]
666620 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
@@ -678,7 +632,7 @@ removeImportTests = testGroup "remove import actions"
678632 let contentA = T.unlines
679633 [ "module ModuleA where"
680634 ]
681− _docA <- createDoc "ModuleA.hs" "haskell" contentA
635+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
682636 let contentB = T.unlines
683637 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
684638 , "module ModuleB where"
@@ -686,7 +640,7 @@ removeImportTests = testGroup "remove import actions"
686640 , "stuffB :: Integer"
687641 , "stuffB = 123"
688642 ]
689− docB <- createDoc "ModuleB.hs" "haskell" contentB
643+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
690644 _ <- waitForDiagnostics
691645 [CACodeAction action@CodeAction { _title = actionTitle }]
692646 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
@@ -708,14 +662,14 @@ removeImportTests = testGroup "remove import actions"
708662 , "stuffB = 123"
709663 , "stuffC = ()"
710664 ]
711− _docA <- createDoc "ModuleA.hs" "haskell" contentA
665+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
712666 let contentB = T.unlines
713667 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
714668 , "module ModuleB where"
715669 , "import ModuleA (stuffA, stuffB, stuffC, stuffA)"
716670 , "main = print stuffB"
717671 ]
718− docB <- createDoc "ModuleB.hs" "haskell" contentB
672+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
719673 _ <- waitForDiagnostics
720674 [CACodeAction action@CodeAction { _title = actionTitle }]
721675 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
@@ -737,18 +691,22 @@ removeImportTests = testGroup "remove import actions"
737691 , "stuffB :: Integer"
738692 , "stuffB = 123"
739693 ]
740− _docA <- createDoc "ModuleA.hs" "haskell" contentA
694+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
741695 let contentB = T.unlines
742696 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
743697 , "module ModuleB where"
744698 , "import qualified ModuleA as A ((<?>), stuffB, (!!))"
745699 , "main = print A.stuffB"
746700 ]
747− docB <- createDoc "ModuleB.hs" "haskell" contentB
701+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
748702 _ <- waitForDiagnostics
749703 [CACodeAction action@CodeAction { _title = actionTitle }]
750704 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
705+#if MIN_GHC_API_VERSION(8,6,0)
751706 liftIO $ "Remove !!, <?> from import" @=? actionTitle
707+#else
708+ liftIO $ "Remove A.!!, A.<?> from import" @=? actionTitle
709+#endif
752710 executeCodeAction action
753711 contentAfterAction <- documentContents docB
754712 let expectedContentAfterAction = T.unlines
@@ -765,14 +723,14 @@ removeImportTests = testGroup "remove import actions"
765723 , "stuffB :: Integer"
766724 , "stuffB = 123"
767725 ]
768− _docA <- createDoc "ModuleA.hs" "haskell" contentA
726+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
769727 let contentB = T.unlines
770728 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
771729 , "module ModuleB where"
772730 , "import ModuleA (A(..), stuffB)"
773731 , "main = print stuffB"
774732 ]
775− docB <- createDoc "ModuleB.hs" "haskell" contentB
733+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
776734 _ <- waitForDiagnostics
777735 [CACodeAction action@CodeAction { _title = actionTitle }]
778736 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
@@ -792,14 +750,14 @@ removeImportTests = testGroup "remove import actions"
792750 , "data D = A | B"
793751 , "data E = F"
794752 ]
795− _docA <- createDoc "ModuleA.hs" "haskell" contentA
753+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
796754 let contentB = T.unlines
797755 [ "{-# OPTIONS_GHC -Wunused-imports #-}"
798756 , "module ModuleB where"
799757 , "import ModuleA (D(A,B), E(F))"
800758 , "main = B"
801759 ]
802− docB <- createDoc "ModuleB.hs" "haskell" contentB
760+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
803761 _ <- waitForDiagnostics
804762 [CACodeAction action@CodeAction { _title = actionTitle }]
805763 <- getCodeActions docB (Range (Position 2 0) (Position 2 5))
@@ -940,8 +898,8 @@ extendImportTests = testGroup "extend import actions"
940898 ]
941899 where
942900 template contentA contentB range expectedAction expectedContentB = do
943− _docA <- createDoc "ModuleA.hs" "haskell" contentA
944− docB <- createDoc "ModuleB.hs" "haskell" contentB
901+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
902+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
945903 _ <- waitForDiagnostics
946904 CACodeAction action@CodeAction { _title = actionTitle } : _
947905 <- sortOn (\(CACodeAction CodeAction{_title=x}) -> x) <$>
@@ -981,8 +939,6 @@ suggestImportTests = testGroup "suggest import actions"
981939 , test True [] "f :: Typeable a => a" ["f = undefined"] "import Data.Typeable (Typeable)"
982940 , test True [] "f = pack" [] "import Data.Text (pack)"
983941 , test True [] "f :: Text" ["f = undefined"] "import Data.Text (Text)"
984− , test True [] "f = [] & id" [] "import Data.Function ((&))"
985− , test True [] "f = (&) [] id" [] "import Data.Function ((&))"
986942 ]
987943 ]
988944 where
@@ -991,20 +947,19 @@ suggestImportTests = testGroup "suggest import actions"
991947 after = T.unlines $ "module A where" : ["import " <> x | x <- imps] ++ [newImp] ++ def : other
992948 cradle = "cradle: {direct: {arguments: [-hide-all-packages, -package, base, -package, text, -package-env, -]}}"
993949 liftIO $ writeFileUTF8 (dir </> "hie.yaml") cradle
994− doc <- createDoc "Test.hs" "haskell" before
950+ doc <- openDoc' "Test.hs" "haskell" before
995951 _diags <- waitForDiagnostics
996952 let defLine = length imps + 1
997953 range = Range (Position defLine 0) (Position defLine maxBound)
998954 actions <- getCodeActions doc range
999− if wanted
1000− then do
1001− action <- liftIO $ pickActionWithTitle newImp actions
1002− executeCodeAction action
1003− contentAfterAction <- documentContents doc
1004− liftIO $ after @=? contentAfterAction
1005− else
1006− liftIO $ [_title | CACodeAction CodeAction{_title} <- actions, _title == newImp ] @?= []
1007−
955+ case wanted of
956+ False ->
957+ liftIO $ [_title | CACodeAction CodeAction{_title} <- actions, _title == newImp ] @?= []
958+ True -> do
959+ action <- liftIO $ pickActionWithTitle newImp actions
960+ executeCodeAction action
961+ contentAfterAction <- documentContents doc
962+ liftIO $ after @=? contentAfterAction
1008963
1009964addExtensionTests :: TestTree
1010965addExtensionTests = testGroup "add language extension actions"
@@ -1051,7 +1006,7 @@ addExtensionTests = testGroup "add language extension actions"
10511006 ]
10521007 where
10531008 template initialContent range expectedAction expectedContents = do
1054− doc <- createDoc "Module.hs" "haskell" initialContent
1009+ doc <- openDoc' "Module.hs" "haskell" initialContent
10551010 _ <- waitForDiagnostics
10561011 CACodeAction action@CodeAction { _title = actionTitle } : _
10571012 <- sortOn (\(CACodeAction CodeAction{_title=x}) -> x) <$>
@@ -1074,7 +1029,7 @@ insertNewDefinitionTests = testGroup "insert new definition actions"
10741029 [""
10751030 ,"someOtherCode = ()"
10761031 ]
1077− docB <- createDoc "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
1032+ docB <- openDoc' "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
10781033 _ <- waitForDiagnostics
10791034 CACodeAction action@CodeAction { _title = actionTitle } : _
10801035 <- sortOn (\(CACodeAction CodeAction{_title=x}) -> x) <$>
@@ -1098,7 +1053,7 @@ insertNewDefinitionTests = testGroup "insert new definition actions"
10981053 [""
10991054 ,"someOtherCode = ()"
11001055 ]
1101− docB <- createDoc "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
1056+ docB <- openDoc' "ModuleB.hs" "haskell" (T.unlines $ txtB ++ txtB')
11021057 _ <- waitForDiagnostics
11031058 CACodeAction action@CodeAction { _title = actionTitle } : _
11041059 <- sortOn (\(CACodeAction CodeAction{_title=x}) -> x) <$>
@@ -1137,8 +1092,8 @@ fixConstructorImportTests = testGroup "fix import actions"
11371092 ]
11381093 where
11391094 template contentA contentB range expectedAction expectedContentB = do
1140− _docA <- createDoc "ModuleA.hs" "haskell" contentA
1141− docB <- createDoc "ModuleB.hs" "haskell" contentB
1095+ _docA <- openDoc' "ModuleA.hs" "haskell" contentA
1096+ docB <- openDoc' "ModuleB.hs" "haskell" contentB
11421097 _diags <- waitForDiagnostics
11431098 CACodeAction action@CodeAction { _title = actionTitle } : _
11441099 <- sortOn (\(CACodeAction CodeAction{_title=x}) -> x) <$>
@@ -1157,7 +1112,7 @@ importRenameActionTests = testGroup "import rename actions"
11571112 [ "module Testing where"
11581113 , "import Data.Mape"
11591114 ]
1160− doc <- createDoc "Testing.hs" "haskell" content
1115+ doc <- openDoc' "Testing.hs" "haskell" content
11611116 _ <- waitForDiagnostics
11621117 actionsOrCommands <- getCodeActions doc (Range (Position 2 8) (Position 2 16))
11631118 let [changeToMap] = [action | CACodeAction action@CodeAction{ _title = actionTitle } <- actionsOrCommands, ("Data." <> modname) `T.isInfixOf` actionTitle ]
@@ -1194,7 +1149,7 @@ fillTypedHoleTests = let
11941149 newA newB newC = testSession (T.unpack actionTitle) $ do
11951150 let originalCode = sourceCode oldA oldB oldC
11961151 let expectedCode = sourceCode newA newB newC
1197− doc <- createDoc "Testing.hs" "haskell" originalCode
1152+ doc <- openDoc' "Testing.hs" "haskell" originalCode
11981153 _ <- waitForDiagnostics
11991154 actionsOrCommands <- getCodeActions doc (Range (Position 9 0) (Position 9 maxBound))
12001155 chosenAction <- liftIO $ pickActionWithTitle actionTitle actionsOrCommands
@@ -1242,7 +1197,7 @@ addSigActionTests = let
12421197 def >:: sig = testSession (T.unpack def) $ do
12431198 let originalCode = before def
12441199 let expectedCode = after' def sig
1245− doc <- createDoc "Sigs.hs" "haskell" originalCode
1200+ doc <- openDoc' "Sigs.hs" "haskell" originalCode
12461201 _ <- waitForDiagnostics
12471202 actionsOrCommands <- getCodeActions doc (Range (Position 3 1) (Position 3 maxBound))
12481203 chosenAction <- liftIO $ pickActionWithTitle ("add signature: " <> sig) actionsOrCommands
@@ -1274,7 +1229,7 @@ addSigLensesTests = let
12741229 sigSession withMissing def sig = testSession (T.unpack def) $ do
12751230 let originalCode = before withMissing def
12761231 let expectedCode = after' withMissing def sig
1277− doc <- createDoc "Sigs.hs" "haskell" originalCode
1232+ doc <- openDoc' "Sigs.hs" "haskell" originalCode
12781233 [CodeLens {_command = Just c}] <- getCodeLenses doc
12791234 executeCommand c
12801235 modifiedCode <- getDocumentEdit doc
@@ -1296,36 +1251,33 @@ addSigLensesTests = let
12961251 ]
12971252 ]
12981253
1299−checkDefs :: [Location] -> Session [Expect] -> Session ()
1300−checkDefs defs mkExpectations = traverse_ check =<< mkExpectations where
1301−
1302− check (ExpectRange expectedRange) = do
1303− assertNDefinitionsFound 1 defs
1304− assertRangeCorrect (head defs) expectedRange
1305− check (ExpectLocation expectedLocation) = do
1306− assertNDefinitionsFound 1 defs
1307− liftIO $ head defs @?= expectedLocation
1308− check ExpectNoDefinitions = do
1309− assertNDefinitionsFound 0 defs
1310− check ExpectExternFail = liftIO $ assertFailure "Expecting to fail to find in external file"
1311− check _ = pure () -- all other expectations not relevant to getDefinition
1312−
1313− assertNDefinitionsFound :: Int -> [a] -> Session ()
1314− assertNDefinitionsFound n defs = liftIO $ assertEqual "number of definitions" n (length defs)
1315−
1316− assertRangeCorrect Location{_range = foundRange} expectedRange =
1317− liftIO $ expectedRange @=? foundRange
1318−
1319−
13201254findDefinitionAndHoverTests :: TestTree
13211255findDefinitionAndHoverTests = let
13221256
1323− tst (get, check) pos targetRange title = testSessionWithExtraFiles "hover" title $ \dir -> do
1324− doc <- openTestDataDoc (dir </> sourceFilePath)
1257+ tst (get, check) pos targetRange title = testSession title $ do
1258+ doc <- openTestDataDoc sourceFilePath
13251259 found <- get doc pos
13261260 check found targetRange
13271261
1262+ checkDefs :: [Location] -> Session [Expect] -> Session ()
1263+ checkDefs defs mkExpectations = traverse_ check =<< mkExpectations where
13281264
1265+ check (ExpectRange expectedRange) = do
1266+ assertNDefinitionsFound 1 defs
1267+ assertRangeCorrect (head defs) expectedRange
1268+ check (ExpectLocation expectedLocation) = do
1269+ assertNDefinitionsFound 1 defs
1270+ liftIO $ head defs @?= expectedLocation
1271+ check ExpectNoDefinitions = do
1272+ assertNDefinitionsFound 0 defs
1273+ check ExpectExternFail = liftIO $ assertFailure "Expecting to fail to find in external file"
1274+ check _ = pure () -- all other expectations not relevant to getDefinition
1275+
1276+ assertNDefinitionsFound :: Int -> [a] -> Session ()
1277+ assertNDefinitionsFound n defs = liftIO $ assertEqual "number of definitions" n (length defs)
1278+
1279+ assertRangeCorrect Location{_range = foundRange} expectedRange =
1280+ liftIO $ expectedRange @=? foundRange
13291281
13301282 checkHover :: Maybe Hover -> Session [Expect] -> Session ()
13311283 checkHover hover expectations = traverse_ check =<< expectations where
@@ -1371,8 +1323,7 @@ findDefinitionAndHoverTests = let
13711323
13721324 mkFindTests tests = testGroup "get"
13731325 [ testGroup "definition" $ mapMaybe fst tests
1374− , testGroup "hover" $ mapMaybe snd tests
1375− , checkFileCompiles sourceFilePath ]
1326+ , testGroup "hover" $ mapMaybe snd tests ]
13761327
13771328 test runDef runHover look expect = testM runDef runHover look (return expect)
13781329
@@ -1467,17 +1418,8 @@ findDefinitionAndHoverTests = let
14671418 broken = Just . (`xfail` "known broken")
14681419 no = const Nothing -- don't run this test at all
14691420
1470−checkFileCompiles :: FilePath -> TestTree
1471−checkFileCompiles fp =
1472− testSessionWithExtraFiles "hover" ("Does " ++ fp ++ " compile") $ \dir -> do
1473− void (openTestDataDoc (dir </> fp))
1474− expectNoMoreDiagnostics 0.5
1475−
1476−
1477−
14781421pluginTests :: TestTree
1479−pluginTests = (`xfail8101` "known broken (#556)")
1480− $ testSessionWait "plugins" $ do
1422+pluginTests = testSessionWait "plugins" $ do
14811423 let content =
14821424 T.unlines
14831425 [ "{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}"
@@ -1491,7 +1433,7 @@ pluginTests = (`xfail8101` "known broken (#556)")
14911433 , "foo :: Int -> Int -> Int"
14921434 , "foo a b = a + c"
14931435 ]
1494− _ <- createDoc "Testing.hs" "haskell" content
1436+ _ <- openDoc' "Testing.hs" "haskell" content
14951437 expectDiagnostics
14961438 [ ( "Testing.hs",
14971439 [(DsError, (8, 14), "Variable not in scope: c")]
@@ -1518,7 +1460,7 @@ cppTests =
15181460 run $ expectError content (2, 1)
15191461 )
15201462 , testSessionWait "cpp-ghcide" $ do
1521− _ <- createDoc "A.hs" "haskell" $ T.unlines
1463+ _ <- openDoc' "A.hs" "haskell" $ T.unlines
15221464 ["{-# LANGUAGE CPP #-}"
15231465 ,"main ="
15241466 ,"#ifdef __GHCIDE__"
@@ -1532,7 +1474,7 @@ cppTests =
15321474 where
15331475 expectError :: T.Text -> Cursor -> Session ()
15341476 expectError content cursor = do
1535− _ <- createDoc "Testing.hs" "haskell" content
1477+ _ <- openDoc' "Testing.hs" "haskell" content
15361478 expectDiagnostics
15371479 [ ( "Testing.hs",
15381480 [(DsError, cursor, "error: unterminated")]
@@ -1548,7 +1490,7 @@ preprocessorTests = testSessionWait "preprocessor" $ do
15481490 , "module Testing where"
15491491 , "y = x + z" -- plugin replaces x with y, making this have only one diagnostic
15501492 ]
1551− _ <- createDoc "Testing.hs" "haskell" content
1493+ _ <- openDoc' "Testing.hs" "haskell" content
15521494 expectDiagnostics
15531495 [ ( "Testing.hs",
15541496 [(DsError, (2, 8), "Variable not in scope: z")]
@@ -1581,8 +1523,8 @@ safeTests =
15811523 ,"safeId = trustWorthyId"
15821524 ]
15831525
1584− _ <- createDoc "A.hs" "haskell" sourceA
1585− _ <- createDoc "B.hs" "haskell" sourceB
1526+ _ <- openDoc' "A.hs" "haskell" sourceA
1527+ _ <- openDoc' "B.hs" "haskell" sourceB
15861528 expectNoMoreDiagnostics 1 ]
15871529
15881530thTests :: TestTree
@@ -1610,8 +1552,8 @@ thTests =
16101552 "b :: Integer",
16111553 "b = $(litE $ IntegerL $ a) + n"
16121554 ]
1613− _ <- createDoc "A.hs" "haskell" sourceA
1614− _ <- createDoc "B.hs" "haskell" sourceB
1555+ _ <- openDoc' "A.hs" "haskell" sourceA
1556+ _ <- openDoc' "B.hs" "haskell" sourceB
16151557 expectDiagnostics [ ( "B.hs", [(DsError, (6, 29), "Variable not in scope: n")] ) ]
16161558 , testSessionWait "newtype-closure" $ do
16171559 let sourceA =
@@ -1631,8 +1573,8 @@ thTests =
16311573 ,"import A"
16321574 ,"b :: Int"
16331575 ,"b = $( a )" ]
1634− _ <- createDoc "A.hs" "haskell" sourceA
1635− _ <- createDoc "B.hs" "haskell" sourceB
1576+ _ <- openDoc' "A.hs" "haskell" sourceA
1577+ _ <- openDoc' "B.hs" "haskell" sourceB
16361578 return ()
16371579 ]
16381580
@@ -1641,7 +1583,7 @@ completionTests
16411583 = testGroup "completion"
16421584 [ testSessionWait "variable" $ do
16431585 let source = T.unlines ["module A where", "f = hea"]
1644− docId <- createDoc "A.hs" "haskell" source
1586+ docId <- openDoc' "A.hs" "haskell" source
16451587 compls <- getCompletions docId (Position 1 7)
16461588 liftIO $ map dropDocs compls @?=
16471589 [complItem "head" (Just CiFunction) (Just "[a] -> a")]
@@ -1653,7 +1595,7 @@ completionTests
16531595 ]
16541596 , testSessionWait "constructor" $ do
16551597 let source = T.unlines ["module A where", "f = Tru"]
1656− docId <- createDoc "A.hs" "haskell" source
1598+ docId <- openDoc' "A.hs" "haskell" source
16571599 compls <- getCompletions docId (Position 1 7)
16581600 liftIO $ map dropDocs compls @?=
16591601 [ complItem "True" (Just CiConstructor) (Just "Bool")
@@ -1665,7 +1607,7 @@ completionTests
16651607 ]
16661608 , testSessionWait "type" $ do
16671609 let source = T.unlines ["{-# OPTIONS_GHC -Wall #-}", "module A () where", "f :: ()", "f = ()"]
1668− docId <- createDoc "A.hs" "haskell" source
1610+ docId <- openDoc' "A.hs" "haskell" source
16691611 expectDiagnostics [ ("A.hs", [(DsWarning, (3,0), "not used")]) ]
16701612 changeDoc docId [TextDocumentContentChangeEvent Nothing Nothing $ T.unlines ["{-# OPTIONS_GHC -Wall #-}", "module A () where", "f :: Bo", "f = True"]]
16711613 compls <- getCompletions docId (Position 2 7)
@@ -1682,7 +1624,7 @@ completionTests
16821624 checkDocText "Bool" boolDocs [ "Defined in 'Prelude'" ]
16831625 , testSessionWait "qualified" $ do
16841626 let source = T.unlines ["{-# OPTIONS_GHC -Wunused-binds #-}", "module A () where", "f = ()"]
1685− docId <- createDoc "A.hs" "haskell" source
1627+ docId <- openDoc' "A.hs" "haskell" source
16861628 expectDiagnostics [ ("A.hs", [(DsWarning, (2, 0), "not used")]) ]
16871629 changeDoc docId [TextDocumentContentChangeEvent Nothing Nothing $ T.unlines ["{-# OPTIONS_GHC -Wunused-binds #-}", "module A () where", "f = Prelude.hea"]]
16881630 compls <- getCompletions docId (Position 2 15)
@@ -1696,7 +1638,7 @@ completionTests
16961638 ]
16971639 , testSessionWait "keyword" $ do
16981640 let source = T.unlines ["module A where", "f = newty"]
1699− docId <- createDoc "A.hs" "haskell" source
1641+ docId <- openDoc' "A.hs" "haskell" source
17001642 compls <- getCompletions docId (Position 1 9)
17011643 liftIO $ compls @?= [keywordItem "newtype"]
17021644 , testSessionWait "type context" $ do
@@ -1705,7 +1647,7 @@ completionTests
17051647 , "module A () where"
17061648 , "f = f"
17071649 ]
1708− docId <- createDoc "A.hs" "haskell" source
1650+ docId <- openDoc' "A.hs" "haskell" source
17091651 expectDiagnostics [("A.hs", [(DsWarning, (2, 0), "not used")])]
17101652 changeDoc docId
17111653 [ TextDocumentContentChangeEvent Nothing Nothing $ T.unlines
@@ -1773,7 +1715,7 @@ outlineTests = testGroup
17731715 "outline"
17741716 [ testSessionWait "type class" $ do
17751717 let source = T.unlines ["module A where", "class A a where a :: a -> Bool"]
1776− docId <- createDoc "A.hs" "haskell" source
1718+ docId <- openDoc' "A.hs" "haskell" source
17771719 symbols <- getDocumentSymbols docId
17781720 liftIO $ symbols @?= Left
17791721 [ moduleSymbol
@@ -1786,7 +1728,7 @@ outlineTests = testGroup
17861728 ]
17871729 , testSessionWait "type class instance " $ do
17881730 let source = T.unlines ["class A a where", "instance A () where"]
1789− docId <- createDoc "A.hs" "haskell" source
1731+ docId <- openDoc' "A.hs" "haskell" source
17901732 symbols <- getDocumentSymbols docId
17911733 liftIO $ symbols @?= Left
17921734 [ classSymbol "A a" (R 0 0 0 15) []
@@ -1794,7 +1736,7 @@ outlineTests = testGroup
17941736 ]
17951737 , testSessionWait "type family" $ do
17961738 let source = T.unlines ["{-# language TypeFamilies #-}", "type family A"]
1797− docId <- createDoc "A.hs" "haskell" source
1739+ docId <- openDoc' "A.hs" "haskell" source
17981740 symbols <- getDocumentSymbols docId
17991741 liftIO $ symbols @?= Left [docSymbolD "A" "type family" SkClass (R 1 0 1 13)]
18001742 , testSessionWait "type family instance " $ do
@@ -1803,7 +1745,7 @@ outlineTests = testGroup
18031745 , "type family A a"
18041746 , "type instance A () = ()"
18051747 ]
1806− docId <- createDoc "A.hs" "haskell" source
1748+ docId <- openDoc' "A.hs" "haskell" source
18071749 symbols <- getDocumentSymbols docId
18081750 liftIO $ symbols @?= Left
18091751 [ docSymbolD "A a" "type family" SkClass (R 1 0 1 15)
@@ -1811,7 +1753,7 @@ outlineTests = testGroup
18111753 ]
18121754 , testSessionWait "data family" $ do
18131755 let source = T.unlines ["{-# language TypeFamilies #-}", "data family A"]
1814− docId <- createDoc "A.hs" "haskell" source
1756+ docId <- openDoc' "A.hs" "haskell" source
18151757 symbols <- getDocumentSymbols docId
18161758 liftIO $ symbols @?= Left [docSymbolD "A" "data family" SkClass (R 1 0 1 11)]
18171759 , testSessionWait "data family instance " $ do
@@ -1820,7 +1762,7 @@ outlineTests = testGroup
18201762 , "data family A a"
18211763 , "data instance A () = A ()"
18221764 ]
1823− docId <- createDoc "A.hs" "haskell" source
1765+ docId <- openDoc' "A.hs" "haskell" source
18241766 symbols <- getDocumentSymbols docId
18251767 liftIO $ symbols @?= Left
18261768 [ docSymbolD "A a" "data family" SkClass (R 1 0 1 11)
@@ -1828,36 +1770,36 @@ outlineTests = testGroup
18281770 ]
18291771 , testSessionWait "constant" $ do
18301772 let source = T.unlines ["a = ()"]
1831− docId <- createDoc "A.hs" "haskell" source
1773+ docId <- openDoc' "A.hs" "haskell" source
18321774 symbols <- getDocumentSymbols docId
18331775 liftIO $ symbols @?= Left
18341776 [docSymbol "a" SkFunction (R 0 0 0 6)]
18351777 , testSessionWait "pattern" $ do
18361778 let source = T.unlines ["Just foo = Just 21"]
1837− docId <- createDoc "A.hs" "haskell" source
1779+ docId <- openDoc' "A.hs" "haskell" source
18381780 symbols <- getDocumentSymbols docId
18391781 liftIO $ symbols @?= Left
18401782 [docSymbol "Just foo" SkFunction (R 0 0 0 18)]
18411783 , testSessionWait "pattern with type signature" $ do
18421784 let source = T.unlines ["{-# language ScopedTypeVariables #-}", "a :: () = ()"]
1843− docId <- createDoc "A.hs" "haskell" source
1785+ docId <- openDoc' "A.hs" "haskell" source
18441786 symbols <- getDocumentSymbols docId
18451787 liftIO $ symbols @?= Left
18461788 [docSymbol "a :: ()" SkFunction (R 1 0 1 12)]
18471789 , testSessionWait "function" $ do
18481790 let source = T.unlines ["a x = ()"]
1849− docId <- createDoc "A.hs" "haskell" source
1791+ docId <- openDoc' "A.hs" "haskell" source
18501792 symbols <- getDocumentSymbols docId
18511793 liftIO $ symbols @?= Left [docSymbol "a" SkFunction (R 0 0 0 8)]
18521794 , testSessionWait "type synonym" $ do
18531795 let source = T.unlines ["type A = Bool"]
1854− docId <- createDoc "A.hs" "haskell" source
1796+ docId <- openDoc' "A.hs" "haskell" source
18551797 symbols <- getDocumentSymbols docId
18561798 liftIO $ symbols @?= Left
18571799 [docSymbol' "A" SkTypeParameter (R 0 0 0 13) (R 0 5 0 6)]
18581800 , testSessionWait "datatype" $ do
18591801 let source = T.unlines ["data A = C"]
1860− docId <- createDoc "A.hs" "haskell" source
1802+ docId <- openDoc' "A.hs" "haskell" source
18611803 symbols <- getDocumentSymbols docId
18621804 liftIO $ symbols @?= Left
18631805 [ docSymbolWithChildren "A"
@@ -1865,21 +1807,9 @@ outlineTests = testGroup
18651807 (R 0 0 0 10)
18661808 [docSymbol "C" SkConstructor (R 0 9 0 10)]
18671809 ]
1868− , testSessionWait "record fields" $ do
1869− let source = T.unlines ["data A = B {", " x :: Int", " , y :: Int}"]
1870− docId <- createDoc "A.hs" "haskell" source
1871− symbols <- getDocumentSymbols docId
1872− liftIO $ symbols @=? Left
1873− [ docSymbolWithChildren "A" SkStruct (R 0 0 2 13)
1874− [ docSymbolWithChildren' "B" SkConstructor (R 0 9 2 13) (R 0 9 0 10)
1875− [ docSymbol "x" SkField (R 1 2 1 3)
1876− , docSymbol "y" SkField (R 2 4 2 5)
1877− ]
1878− ]
1879− ]
18801810 , testSessionWait "import" $ do
18811811 let source = T.unlines ["import Data.Maybe"]
1882− docId <- createDoc "A.hs" "haskell" source
1812+ docId <- openDoc' "A.hs" "haskell" source
18831813 symbols <- getDocumentSymbols docId
18841814 liftIO $ symbols @?= Left
18851815 [docSymbolWithChildren "imports"
@@ -1890,7 +1820,7 @@ outlineTests = testGroup
18901820 ]
18911821 , testSessionWait "multiple import" $ do
18921822 let source = T.unlines ["", "import Data.Maybe", "", "import Control.Exception", ""]
1893− docId <- createDoc "A.hs" "haskell" source
1823+ docId <- openDoc' "A.hs" "haskell" source
18941824 symbols <- getDocumentSymbols docId
18951825 liftIO $ symbols @?= Left
18961826 [docSymbolWithChildren "imports"
@@ -1905,7 +1835,7 @@ outlineTests = testGroup
19051835 [ "{-# language ForeignFunctionInterface #-}"
19061836 , "foreign import ccall \"a\" a :: Int"
19071837 ]
1908− docId <- createDoc "A.hs" "haskell" source
1838+ docId <- openDoc' "A.hs" "haskell" source
19091839 symbols <- getDocumentSymbols docId
19101840 liftIO $ symbols @?= Left [docSymbolD "a" "import" SkObject (R 1 0 1 33)]
19111841 , testSessionWait "foreign export" $ do
@@ -1913,7 +1843,7 @@ outlineTests = testGroup
19131843 [ "{-# language ForeignFunctionInterface #-}"
19141844 , "foreign export ccall odd :: Int -> Bool"
19151845 ]
1916− docId <- createDoc "A.hs" "haskell" source
1846+ docId <- openDoc' "A.hs" "haskell" source
19171847 symbols <- getDocumentSymbols docId
19181848 liftIO $ symbols @?= Left [docSymbolD "odd" "export" SkObject (R 1 0 1 39)]
19191849 ]
@@ -1926,8 +1856,6 @@ outlineTests = testGroup
19261856 DocumentSymbol name (Just detail) kind Nothing loc loc Nothing
19271857 docSymbolWithChildren name kind loc cc =
19281858 DocumentSymbol name Nothing kind Nothing loc loc (Just $ List cc)
1929− docSymbolWithChildren' name kind loc selectionLoc cc =
1930− DocumentSymbol name Nothing kind Nothing loc selectionLoc (Just $ List cc)
19311859 moduleSymbol name loc cc = DocumentSymbol name
19321860 Nothing
19331861 SkFile
@@ -1949,13 +1877,6 @@ pattern R x y x' y' = Range (Position x y) (Position x' y')
19491877xfail :: TestTree -> String -> TestTree
19501878xfail = flip expectFailBecause
19511879
1952−xfail8101 :: TestTree -> String -> TestTree
1953−#if MIN_GHC_API_VERSION(8,10,0)
1954−xfail8101 = flip expectFailBecause
1955−#else
1956−xfail8101 t _ = t
1957−#endif
1958−
19591880data Expect
19601881 = ExpectRange Range -- Both gotoDef and hover should report this range
19611882 | ExpectLocation Location
@@ -2033,7 +1954,6 @@ cradleTests :: TestTree
20331954cradleTests = testGroup "cradle"
20341955 [testGroup "dependencies" [sessionDepsArePickedUp]
20351956 ,testGroup "loading" [loadCradleOnlyonce]
2036− ,testGroup "multi" [simpleMultiTest, simpleMultiTest2]
20371957 ]
20381958
20391959loadCradleOnlyonce :: TestTree
@@ -2048,53 +1968,17 @@ loadCradleOnlyonce = testGroup "load cradle only once"
20481968 test dir
20491969 implicit dir = test dir
20501970 test _dir = do
2051− doc <- createDoc "B.hs" "haskell" "module B where\nimport Data.Foo"
1971+ doc <- openDoc' "B.hs" "haskell" "module B where\nimport Data.Foo"
20521972 msgs <- someTill (skipManyTill anyMessage cradleLoadedMessage) (skipManyTill anyMessage (message @PublishDiagnosticsNotification))
20531973 liftIO $ length msgs @?= 1
20541974 changeDoc doc [TextDocumentContentChangeEvent Nothing Nothing "module B where\nimport Data.Maybe"]
20551975 msgs <- manyTill (skipManyTill anyMessage cradleLoadedMessage) (skipManyTill anyMessage (message @PublishDiagnosticsNotification))
20561976 liftIO $ length msgs @?= 0
2057− _ <- createDoc "A.hs" "haskell" "module A where\nimport LoadCradleBar"
1977+ _ <- openDoc' "A.hs" "haskell" "module A where\nimport LoadCradleBar"
20581978 msgs <- manyTill (skipManyTill anyMessage cradleLoadedMessage) (skipManyTill anyMessage (message @PublishDiagnosticsNotification))
20591979 liftIO $ length msgs @?= 0
20601980
20611981
2062−dependentFileTest :: TestTree
2063−dependentFileTest = testGroup "addDependentFile"
2064− [testGroup "file-changed" [testSession' "test" test]
2065− ]
2066− where
2067− test dir = do
2068− -- If the file contains B then no type error
2069− -- otherwise type error
2070− liftIO $ writeFile (dir </> "dep-file.txt") "A"
2071− let fooContent = T.unlines
2072− [ "{-# LANGUAGE TemplateHaskell #-}"
2073− , "module Foo where"
2074− , "import Language.Haskell.TH.Syntax"
2075− , "foo :: Int"
2076− , "foo = 1 + $(do"
2077− , " qAddDependentFile \"dep-file.txt\""
2078− , " f <- qRunIO (readFile \"dep-file.txt\")"
2079− , " if f == \"B\" then [| 1 |] else lift f)"
2080− ]
2081− let bazContent = T.unlines ["module Baz where", "import Foo"]
2082− _ <-createDoc "Foo.hs" "haskell" fooContent
2083− doc <- createDoc "Baz.hs" "haskell" bazContent
2084− expectDiagnostics
2085− [("Foo.hs", [(DsError, (4, 6), "Couldn't match expected type")])]
2086− -- Now modify the dependent file
2087− liftIO $ writeFile (dir </> "dep-file.txt") "B"
2088− let change = TextDocumentContentChangeEvent
2089− { _range = Just (Range (Position 2 0) (Position 2 6))
2090− , _rangeLength = Nothing
2091− , _text = "f = ()"
2092− }
2093− -- Modifying Baz will now trigger Foo to be rebuilt as well
2094− changeDoc doc [change]
2095− expectDiagnostics [("Foo.hs", [])]
2096−
2097−
20981982cradleLoadedMessage :: Session FromServerMessage
20991983cradleLoadedMessage = satisfy $ \case
21001984 NotCustomServer (NotificationMessage _ (CustomServerMethod m) _) -> m == cradleLoadedMethod
@@ -2103,56 +1987,6 @@ cradleLoadedMessage = satisfy $ \case
21031987cradleLoadedMethod :: T.Text
21041988cradleLoadedMethod = "ghcide/cradle/loaded"
21051989
2106−-- Stack sets this which trips up cabal in the multi-component tests.
2107−-- However, our plugin tests rely on those env vars so we unset it locally.
2108−withoutStackEnv :: IO a -> IO a
2109−withoutStackEnv s =
2110− bracket
2111− (mapM getEnv vars >>= \prevState -> mapM_ unsetEnv vars >> pure prevState)
2112− (\prevState -> mapM_ (\(var, value) -> restore var value) (zip vars prevState))
2113− (const s)
2114− where vars =
2115− [ "GHC_PACKAGE_PATH"
2116− , "GHC_ENVIRONMENT"
2117− , "HASKELL_DIST_DIR"
2118− , "HASKELL_PACKAGE_SANDBOX"
2119− , "HASKELL_PACKAGE_SANDBOXES"
2120− ]
2121− restore var Nothing = unsetEnv var
2122− restore var (Just val) = setEnv var val True
2123−
2124−simpleMultiTest :: TestTree
2125−simpleMultiTest = testCase "simple-multi-test" $ withoutStackEnv $ runWithExtraFiles "multi" $ \dir -> do
2126− let aPath = dir </> "a/A.hs"
2127− bPath = dir </> "b/B.hs"
2128− aSource <- liftIO $ readFileUtf8 aPath
2129− (TextDocumentIdentifier adoc) <- createDoc aPath "haskell" aSource
2130− expectNoMoreDiagnostics 0.5
2131− bSource <- liftIO $ readFileUtf8 bPath
2132− bdoc <- createDoc bPath "haskell" bSource
2133− expectNoMoreDiagnostics 0.5
2134− locs <- getDefinitions bdoc (Position 2 7)
2135− let fooL = mkL adoc 2 0 2 3
2136− checkDefs locs (pure [fooL])
2137− expectNoMoreDiagnostics 0.5
2138−
2139−-- Like simpleMultiTest but open the files in the other order
2140−simpleMultiTest2 :: TestTree
2141−simpleMultiTest2 = testCase "simple-multi-test2" $ withoutStackEnv $ runWithExtraFiles "multi" $ \dir -> do
2142− let aPath = dir </> "a/A.hs"
2143− bPath = dir </> "b/B.hs"
2144− bSource <- liftIO $ readFileUtf8 bPath
2145− bdoc <- createDoc bPath "haskell" bSource
2146− expectNoMoreDiagnostics 5
2147− aSource <- liftIO $ readFileUtf8 aPath
2148− (TextDocumentIdentifier adoc) <- createDoc aPath "haskell" aSource
2149− -- Need to have some delay here or the test fails
2150− expectNoMoreDiagnostics 5
2151− locs <- getDefinitions bdoc (Position 2 7)
2152− let fooL = mkL adoc 2 0 2 3
2153− checkDefs locs (pure [fooL])
2154− expectNoMoreDiagnostics 0.5
2155−
21561990sessionDepsArePickedUp :: TestTree
21571991sessionDepsArePickedUp = testSession'
21581992 "session-deps-are-picked-up"
@@ -2162,7 +1996,7 @@ sessionDepsArePickedUp = testSession'
21621996 (dir </> "hie.yaml")
21631997 "cradle: {direct: {arguments: []}}"
21641998 -- Open without OverloadedStrings and expect an error.
2165− doc <- createDoc "Foo.hs" "haskell" fooContent
1999+ doc <- openDoc' "Foo.hs" "haskell" fooContent
21662000 expectDiagnostics
21672001 [("Foo.hs", [(DsError, (3, 6), "Couldn't match expected type")])]
21682002 -- Update hie.yaml to enable OverloadedStrings.
@@ -2197,9 +2031,6 @@ sessionDepsArePickedUp = testSession'
21972031testSession :: String -> Session () -> TestTree
21982032testSession name = testCase name . run
21992033
2200−testSessionWithExtraFiles :: FilePath -> String -> (FilePath -> Session ()) -> TestTree
2201−testSessionWithExtraFiles prefix name = testCase name . runWithExtraFiles prefix
2202−
22032034testSession' :: String -> (FilePath -> Session ()) -> TestTree
22042035testSession' name = testCase name . run'
22052036
@@ -2234,19 +2065,6 @@ mkRange a b c d = Range (Position a b) (Position c d)
22342065run :: Session a -> IO a
22352066run s = withTempDir $ \dir -> runInDir dir s
22362067
2237−runWithExtraFiles :: FilePath -> (FilePath -> Session a) -> IO a
2238−runWithExtraFiles prefix s = withTempDir $ \dir -> do
2239− copyTestDataFiles dir prefix
2240− runInDir dir (s dir)
2241−
2242−copyTestDataFiles :: FilePath -> FilePath -> IO ()
2243−copyTestDataFiles dir prefix = do
2244− -- Copy all the test data files to the temporary workspace
2245− testDataFiles <- getDirectoryFilesIO ("test/data" </> prefix) ["//*"]
2246− for_ testDataFiles $ \f -> do
2247− createDirectoryIfMissing True $ dir </> takeDirectory f
2248− copyFile ("test/data" </> prefix </> f) (dir </> f)
2249−
22502068run' :: (FilePath -> Session a) -> IO a
22512069run' s = withTempDir $ \dir -> runInDir dir (s dir)
22522070
@@ -2258,6 +2076,11 @@ runInDir dir s = do
22582076 -- since the package import test creates "Data/List.hs", which otherwise has no physical home
22592077 createDirectoryIfMissing True $ dir ++ "/Data"
22602078
2079+ -- Copy all the test data files to the temporary workspace
2080+ testDataFiles <- getDirectoryFilesIO "test/data" ["//*"]
2081+ for_ testDataFiles $ \f -> do
2082+ createDirectoryIfMissing True $ dir </> takeDirectory f
2083+ copyFile ("test/data" </> f) (dir </> f)
22612084
22622085 let cmd = unwords [ghcideExe, "--lsp", "--test", "--cwd", dir]
22632086 -- HIE calls getXgdDirectory which assumes that HOME is set.
@@ -2276,7 +2099,7 @@ runInDir dir s = do
22762099openTestDataDoc :: FilePath -> Session TextDocumentIdentifier
22772100openTestDataDoc path = do
22782101 source <- liftIO $ readFileUtf8 $ "test/data" </> path
2279− createDoc path "haskell" source
2102+ openDoc' path "haskell" source
22802103
22812104findCodeActions :: TextDocumentIdentifier -> Range -> [T.Text] -> Session [CodeAction]
22822105findCodeActions doc range expectedTitles = do
@@ -2317,6 +2140,20 @@ unitTests = do
23172140 uriToFilePath' uri @?= Just ""
23182141 ]
23192142
2143+-- | Wrapper around 'LSPTest.openDoc'' that sends file creation events
2144+openDoc' :: FilePath -> String -> T.Text -> Session TextDocumentIdentifier
2145+openDoc' fp name contents = do
2146+ res@(TextDocumentIdentifier uri) <- LSPTest.openDoc' fp name contents
2147+ -- Needed as ghcide sets up and relies on WatchedFiles but lsp-test does not track them
2148+ sendNotification WorkspaceDidChangeWatchedFiles (DidChangeWatchedFilesParams $ List [FileEvent uri FcCreated])
2149+ return res
2150+
2151+-- | Version of 'LSPTest.openDoc'' that does not send WatchedFiles events for files outside the workspace
2152+openDoc'' :: FilePath -> String -> T.Text -> Session TextDocumentIdentifier
2153+-- At the moment this is just LSPTest.openDoc' but it may change in the future
2154+-- when/if lsp-test implements WatchedFiles
2155+openDoc'' = LSPTest.openDoc'
2156+
23202157positionMappingTests :: TestTree
23212158positionMappingTests =
23222159 testGroup "position mapping"
@@ -2486,11 +2323,11 @@ nthLine i r
24862323 | i >= Rope.rows r = error $ "Row number out of bounds: " <> show i <> "/" <> show (Rope.rows r)
24872324 | otherwise = Rope.takeWhile (/= '\n') $ fst $ Rope.splitAtLine 1 $ snd $ Rope.splitAtLine (i - 1) r
24882325
2489−getWatchedFilesSubscriptionsUntil :: forall end . (FromJSON end, Typeable end) => Session [Maybe Value]
2490−getWatchedFilesSubscriptionsUntil = do
2491− msgs <- manyTill (Just <$> message @RegisterCapabilityRequest <|> Nothing <$ anyMessage) (message @end)
2326+getWatchedFilesSubscriptionsUntilProgressEnd :: Session [Maybe Value]
2327+getWatchedFilesSubscriptionsUntilProgressEnd = do
2328+ msgs <- manyTill (Just <$> message @RegisterCapabilityRequest <|> Nothing <$ anyMessage) (message @WorkDoneProgressEndNotification)
24922329 return
24932330 [ args
2494− | Just RequestMessage{_params = RegistrationParams (List regs)} <- msgs
2331+ | Just (RequestMessage{_params = RegistrationParams (List regs)}) <- msgs
24952332 , Registration _id WorkspaceDidChangeWatchedFiles args <- regs
24962333 ]