From 361131eb97737b024daa7cc7e07c89919708296c Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 4 May 2024 19:28:38 +0800 Subject: [PATCH 01/21] migrate diagnosticTests --- ghcide/test/exe/ClientSettingsTests.hs | 1 + ghcide/test/exe/CodeLensTests.hs | 1 + ghcide/test/exe/Config.hs | 15 +++++ ghcide/test/exe/DiagnosticTests.hs | 84 +++++++++++++------------- ghcide/test/exe/ExceptionTests.hs | 1 + ghcide/test/exe/OpenCloseTest.hs | 6 +- ghcide/test/exe/THTests.hs | 2 + ghcide/test/exe/TestUtils.hs | 34 +---------- ghcide/test/exe/UnitTests.hs | 1 + hls-test-utils/src/Test/Hls.hs | 8 +++ 10 files changed, 77 insertions(+), 76 deletions(-) diff --git a/ghcide/test/exe/ClientSettingsTests.hs b/ghcide/test/exe/ClientSettingsTests.hs index 6801e9fe8a..6d964d3542 100644 --- a/ghcide/test/exe/ClientSettingsTests.hs +++ b/ghcide/test/exe/ClientSettingsTests.hs @@ -14,6 +14,7 @@ import Language.LSP.Protocol.Types hiding SemanticTokensEdit (..), mkRange) import Language.LSP.Test +import Test.Hls (waitForProgressDone) import Test.Tasty import TestUtils diff --git a/ghcide/test/exe/CodeLensTests.hs b/ghcide/test/exe/CodeLensTests.hs index e6cb6a4062..6bebeda002 100644 --- a/ghcide/test/exe/CodeLensTests.hs +++ b/ghcide/test/exe/CodeLensTests.hs @@ -18,6 +18,7 @@ import Language.LSP.Protocol.Types hiding SemanticTokensEdit (..), mkRange) import Language.LSP.Test +import Test.Hls (waitForProgressDone) import Test.Tasty import Test.Tasty.HUnit import TestUtils diff --git a/ghcide/test/exe/Config.hs b/ghcide/test/exe/Config.hs index f8232de343..41cf7dd10b 100644 --- a/ghcide/test/exe/Config.hs +++ b/ghcide/test/exe/Config.hs @@ -2,10 +2,13 @@ module Config where +import Control.Lens.Setter ((.~)) import Data.Foldable (traverse_) +import Data.Function ((&)) import qualified Data.Text as T import Development.IDE.Test (canonicalizeUri) import Ide.Types (defaultPluginDescriptor) +import qualified Language.LSP.Protocol.Lens as L import Language.LSP.Protocol.Types (Null (..)) import System.FilePath (()) import Test.Hls @@ -31,9 +34,15 @@ runWithDummyPlugin' = runSessionWithServerInTmpDirCont' def dummyPlugin runWithDummyPluginAndCap :: ClientCapabilities -> Session () -> IO () runWithDummyPluginAndCap cap = runSessionWithServerAndCapsInTmpDir def dummyPlugin cap (mkIdeTestFs []) +runWithDummyPluginAndCap' :: ClientCapabilities -> (FileSystem -> Session ()) -> IO () +runWithDummyPluginAndCap' cap = runSessionWithServerAndCapsInTmpDirCont def dummyPlugin cap (mkIdeTestFs []) + testWithDummyPluginAndCap :: String -> ClientCapabilities -> Session () -> TestTree testWithDummyPluginAndCap caseName cap = testCase caseName . runWithDummyPluginAndCap cap +testWithDummyPluginAndCap' :: String -> ClientCapabilities -> (FileSystem -> Session ()) -> TestTree +testWithDummyPluginAndCap' caseName cap = testCase caseName . runWithDummyPluginAndCap' cap + -- testSessionWithCorePlugin ::(TestRunner cont ()) => TestName -> FS.VirtualFileTree -> cont -> TestTree testWithDummyPlugin :: String -> FS.VirtualFileTree -> Session () -> TestTree testWithDummyPlugin caseName vfs = testCase caseName . runWithDummyPlugin vfs @@ -114,3 +123,9 @@ defToLocation (InL (Definition (InL l))) = [l] defToLocation (InL (Definition (InR ls))) = ls defToLocation (InR (InL defLink)) = (\(DefinitionLink LocationLink{_targetUri,_targetRange}) -> Location _targetUri _targetRange) <$> defLink defToLocation (InR (InR Null)) = [] + +lspTestCaps :: ClientCapabilities +lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities (Just True) Nothing Nothing } + +lspTestCapsNoFileWatches :: ClientCapabilities +lspTestCapsNoFileWatches = lspTestCaps & L.workspace . traverse . L.didChangeWatchedFiles .~ Nothing diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index fe123c5c1d..53b8f959af 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -30,17 +30,20 @@ import System.Directory import System.FilePath import System.IO.Extra hiding (withTempDir) +import Config import Control.Lens ((^.)) import Control.Monad.Extra (whenJust) import Development.IDE.Plugin.Test (WaitForIdeRuleResult (..)) import System.Time.Extra +import Test.Hls (waitForProgressBegin, + waitForTypecheck) +import Test.Hls.FileSystem (toAbsFp) import Test.Tasty import Test.Tasty.HUnit -import TestUtils tests :: TestTree tests = testGroup "diagnostics" - [ testSessionWait "fix syntax error" $ do + [ testWithDummyPluginEmpty "fix syntax error" $ do let content = T.unlines [ "module Testing wher" ] doc <- createDoc "Testing.hs" "haskell" content expectDiagnostics [("Testing.hs", [(DiagnosticSeverity_Error, (0, 15), "parse error")])] @@ -51,7 +54,7 @@ tests = testGroup "diagnostics" } changeDoc doc [change] expectDiagnostics [("Testing.hs", [])] - , testSessionWait "introduce syntax error" $ do + , testWithDummyPluginEmpty "introduce syntax error" $ do let content = T.unlines [ "module Testing where" ] doc <- createDoc "Testing.hs" "haskell" content void $ skipManyTill anyMessage (message SMethod_WindowWorkDoneProgressCreate) @@ -63,7 +66,7 @@ tests = testGroup "diagnostics" } changeDoc doc [change] expectDiagnostics [("Testing.hs", [(DiagnosticSeverity_Error, (0, 15), "parse error")])] - , testSessionWait "update syntax error" $ do + , testWithDummyPluginEmpty "update syntax error" $ do let content = T.unlines [ "module Testing(missing) where" ] doc <- createDoc "Testing.hs" "haskell" content expectDiagnostics [("Testing.hs", [(DiagnosticSeverity_Error, (0, 15), "Not in scope: 'missing'")])] @@ -74,7 +77,7 @@ tests = testGroup "diagnostics" } changeDoc doc [change] expectDiagnostics [("Testing.hs", [(DiagnosticSeverity_Error, (0, 15), "Not in scope: 'lissing'")])] - , testSessionWait "variable not in scope" $ do + , testWithDummyPluginEmpty "variable not in scope" $ do let content = T.unlines [ "module Testing where" , "foo :: Int -> Int -> Int" @@ -90,7 +93,7 @@ tests = testGroup "diagnostics" ] ) ] - , testSessionWait "type error" $ do + , testWithDummyPluginEmpty "type error" $ do let content = T.unlines [ "module Testing where" , "foo :: Int -> String -> Int" @@ -102,7 +105,7 @@ tests = testGroup "diagnostics" , [(DiagnosticSeverity_Error, (2, 14), "Couldn't match type '[Char]' with 'Int'")] ) ] - , testSessionWait "typed hole" $ do + , testWithDummyPluginEmpty "typed hole" $ do let content = T.unlines [ "module Testing where" , "foo :: Int -> String" @@ -129,7 +132,7 @@ tests = testGroup "diagnostics" expectedDs aMessage = [ ("A.hs", [(DiagnosticSeverity_Error, (2,4), aMessage)]) , ("B.hs", [(DiagnosticSeverity_Error, (3,4), bMessage)])] - deferralTest title binding msg = testSessionWait title $ do + deferralTest title binding msg = testWithDummyPluginEmpty title $ do _ <- createDoc "A.hs" "haskell" $ sourceA binding _ <- createDoc "B.hs" "haskell" sourceB expectDiagnostics $ expectedDs msg @@ -139,7 +142,7 @@ tests = testGroup "diagnostics" , deferralTest "out of scope var" "unbound" "Variable not in scope" ] - , testSessionWait "remove required module" $ do + , testWithDummyPluginEmpty "remove required module" $ do let contentA = T.unlines [ "module ModuleA where" ] docA <- createDoc "ModuleA.hs" "haskell" contentA let contentB = T.unlines @@ -154,7 +157,7 @@ tests = testGroup "diagnostics" } changeDoc docA [change] expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Error, (1, 0), "Could not find module")])] - , testSessionWait "add missing module" $ do + , testWithDummyPluginEmpty "add missing module" $ do let contentB = T.unlines [ "module ModuleB where" , "import ModuleA ()" @@ -164,22 +167,21 @@ tests = testGroup "diagnostics" let contentA = T.unlines [ "module ModuleA where" ] _ <- createDoc "ModuleA.hs" "haskell" contentA expectDiagnostics [("ModuleB.hs", [])] - , testCase "add missing module (non workspace)" $ + , testWithDummyPluginAndCap' "add missing module (non workspace)" lspTestCapsNoFileWatches $ \tmpDir -> do -- By default lsp-test sends FileWatched notifications for all files, which we don't want -- as non workspace modules will not be watched by the LSP server. -- To work around this, we tell lsp-test that our client doesn't have the -- FileWatched capability, which is enough to disable the notifications - withTempDir $ \tmpDir -> runInDir'' lspTestCapsNoFileWatches tmpDir "." "." [] $ do let contentB = T.unlines [ "module ModuleB where" , "import ModuleA ()" ] - _ <- createDoc (tmpDir "ModuleB.hs") "haskell" contentB - expectDiagnostics [(tmpDir "ModuleB.hs", [(DiagnosticSeverity_Error, (1, 7), "Could not find module")])] + _ <- createDoc (tmpDir `toAbsFp` "ModuleB.hs") "haskell" contentB + expectDiagnostics [(tmpDir `toAbsFp` "ModuleB.hs", [(DiagnosticSeverity_Error, (1, 7), "Could not find module")])] let contentA = T.unlines [ "module ModuleA where" ] - _ <- createDoc (tmpDir "ModuleA.hs") "haskell" contentA - expectDiagnostics [(tmpDir "ModuleB.hs", [])] - , testSessionWait "cyclic module dependency" $ do + _ <- createDoc (tmpDir `toAbsFp` "ModuleA.hs") "haskell" contentA + expectDiagnostics [(tmpDir `toAbsFp` "ModuleB.hs", [])] + , testWithDummyPluginEmpty "cyclic module dependency" $ do let contentA = T.unlines [ "module ModuleA where" , "import ModuleB" @@ -198,7 +200,7 @@ tests = testGroup "diagnostics" , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")] ) ] - , testSession' "deeply nested cyclic module dependency" $ \path -> do + , testWithDummyPluginEmpty' "deeply nested cyclic module dependency" $ \path -> do let contentA = unlines [ "module ModuleA where" , "import ModuleB" ] let contentB = unlines @@ -209,17 +211,17 @@ tests = testGroup "diagnostics" [ "module ModuleD where" , "import ModuleC" ] cradle = "cradle: {direct: {arguments: [ModuleA, ModuleB, ModuleC, ModuleD]}}" - liftIO $ writeFile (path "ModuleA.hs") contentA - liftIO $ writeFile (path "ModuleB.hs") contentB - liftIO $ writeFile (path "ModuleC.hs") contentC - liftIO $ writeFile (path "hie.yaml") cradle + liftIO $ writeFile (path `toAbsFp` "ModuleA.hs") contentA + liftIO $ writeFile (path `toAbsFp` "ModuleB.hs") contentB + liftIO $ writeFile (path `toAbsFp` "ModuleC.hs") contentC + liftIO $ writeFile (path `toAbsFp` "hie.yaml") cradle _ <- createDoc "ModuleD.hs" "haskell" contentD expectDiagnostics [ ( "ModuleB.hs" , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")] ) ] - , testSessionWait "cyclic module dependency with hs-boot" $ do + , testWithDummyPluginEmpty "cyclic module dependency with hs-boot" $ do let contentA = T.unlines [ "module ModuleA where" , "import {-# SOURCE #-} ModuleB" @@ -238,7 +240,7 @@ tests = testGroup "diagnostics" _ <- createDoc "ModuleB.hs" "haskell" contentB _ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] - , testSession' "bidirectional module dependency with hs-boot" $ \path -> do + , testWithDummyPluginEmpty' "bidirectional module dependency with hs-boot" $ \path -> do let cradle = unlines [ "cradle:" , " direct: {arguments: [ModuleA, ModuleB]}" @@ -260,13 +262,13 @@ tests = testGroup "diagnostics" let contentAboot = T.unlines [ "module ModuleA where" ] - liftIO $ writeFile (path "hie.yaml") cradle + liftIO $ writeFile (path `toAbsFp` "hie.yaml") cradle _ <- createDoc "ModuleA.hs" "haskell" contentA _ <- createDoc "ModuleA.hs-boot" "haskell" contentAboot _ <- createDoc "ModuleB.hs" "haskell" contentB _ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] - , testSessionWait "correct reference used with hs-boot" $ do + , testWithDummyPluginEmpty "correct reference used with hs-boot" $ do let contentB = T.unlines [ "module ModuleB where" , "import {-# SOURCE #-} ModuleA()" @@ -292,7 +294,7 @@ tests = testGroup "diagnostics" _ <- createDoc "ModuleA.hs-boot" "haskell" contentAboot _ <- createDoc "ModuleC.hs" "haskell" contentC expectDiagnostics [("ModuleC.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] - , testSessionWait "redundant import" $ do + , testWithDummyPluginEmpty "redundant import" $ do let contentA = T.unlines ["module ModuleA where"] let contentB = T.unlines [ "{-# OPTIONS_GHC -Wunused-imports #-}" @@ -306,7 +308,7 @@ tests = testGroup "diagnostics" , [(DiagnosticSeverity_Warning, (2, 0), "The import of 'ModuleA' is redundant", Just DiagnosticTag_Unnecessary)] ) ] - , testSessionWait "redundant import even without warning" $ do + , testWithDummyPluginEmpty "redundant import even without warning" $ do let contentA = T.unlines ["module ModuleA where"] let contentB = T.unlines [ "{-# OPTIONS_GHC -Wno-unused-imports -Wmissing-signatures #-}" @@ -318,7 +320,7 @@ tests = testGroup "diagnostics" _ <- createDoc "ModuleA.hs" "haskell" contentA _ <- createDoc "ModuleB.hs" "haskell" contentB expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] - , testSessionWait "package imports" $ do + , testWithDummyPluginEmpty "package imports" $ do let thisDataListContent = T.unlines [ "module Data.List where" , "x :: Integer" @@ -356,7 +358,7 @@ tests = testGroup "diagnostics" ] ) ] - , testSessionWait "unqualified warnings" $ do + , testWithDummyPluginEmpty "unqualified warnings" $ do let fooContent = T.unlines [ "{-# OPTIONS_GHC -Wredundant-constraints #-}" , "module Foo where" @@ -374,7 +376,7 @@ tests = testGroup "diagnostics" ] ) ] - , testSessionWait "lower-case drive" $ do + , testWithDummyPluginEmpty "lower-case drive" $ do let aContent = T.unlines [ "module A.A where" , "import A.B ()" @@ -407,7 +409,7 @@ tests = testGroup "diagnostics" liftIO $ unless ("redundant" `T.isInfixOf` msg) $ assertFailure ("Expected redundant import but got " <> T.unpack msg) closeDoc a - , testSessionWait "strip file path" $ do + , testWithDummyPluginEmpty "strip file path" $ do let name = "Testing" content = T.unlines @@ -426,8 +428,8 @@ tests = testGroup "diagnostics" Lens.filtered (T.isInfixOf ("/" <> name <> ".hs:")) failure msg = liftIO $ assertFailure $ "Expected file path to be stripped but got " <> T.unpack msg Lens.mapMOf_ offenders failure notification - , testSession' "-Werror in cradle is ignored" $ \sessionDir -> do - liftIO $ writeFile (sessionDir "hie.yaml") + , testWithDummyPluginEmpty' "-Werror in cradle is ignored" $ \sessionDir -> do + liftIO $ writeFile (sessionDir `toAbsFp` "hie.yaml") "cradle: {direct: {arguments: [\"-Wall\", \"-Werror\"]}}" let fooContent = T.unlines [ "module Foo where" @@ -440,7 +442,7 @@ tests = testGroup "diagnostics" ] ) ] - , testSessionWait "-Werror in pragma is ignored" $ do + , testWithDummyPluginEmpty "-Werror in pragma is ignored" $ do let fooContent = T.unlines [ "{-# OPTIONS_GHC -Wall -Werror #-}" , "module Foo() where" @@ -455,9 +457,9 @@ tests = testGroup "diagnostics" ) ] , testCase "typecheck-all-parents-of-interest" $ runWithExtraFiles "recomp" $ \dir -> do - let bPath = dir "B.hs" - pPath = dir "P.hs" - aPath = dir "A.hs" + let bPath = dir `toAbsFp` "B.hs" + pPath = dir `toAbsFp` "P.hs" + aPath = dir `toAbsFp` "A.hs" bSource <- liftIO $ readFileUtf8 bPath -- y :: Int pSource <- liftIO $ readFileUtf8 pPath -- bar = x :: Int @@ -490,7 +492,7 @@ tests = testGroup "diagnostics" ] expectNoMoreDiagnostics 1 - , testSessionWait "deduplicate missing module diagnostics" $ do + , testWithDummyPluginEmpty "deduplicate missing module diagnostics" $ do let fooContent = T.unlines [ "module Foo() where" , "import MissingModule" ] doc <- createDoc "Foo.hs" "haskell" fooContent expectDiagnostics [("Foo.hs", [(DiagnosticSeverity_Error, (1,7), "Could not find module 'MissingModule'")])] @@ -552,7 +554,7 @@ cancellationTestGroup name edits sessionDepsOutcome parseOutcome tcOutcome = tes ] cancellationTemplate :: (TextDocumentContentChangeEvent, TextDocumentContentChangeEvent) -> Maybe (String, Bool) -> TestTree -cancellationTemplate (edit, undoEdit) mbKey = testCase (maybe "-" fst mbKey) $ runTestNoKick $ do +cancellationTemplate (edit, undoEdit) mbKey = testWithDummyPluginEmpty (maybe "-" fst mbKey) $ do doc <- createDoc "Foo.hs" "haskell" $ T.unlines [ "{-# OPTIONS_GHC -Wall #-}" , "module Foo where" @@ -578,7 +580,7 @@ cancellationTemplate (edit, undoEdit) mbKey = testCase (maybe "-" fst mbKey) $ r expectNoMoreDiagnostics 0.5 where -- similar to run except it disables kick - runTestNoKick s = withTempDir $ \dir -> runInDir' dir "." "." ["--test-no-kick"] s + -- runTestNoKick s = runWithDummyPluginEmpty dir "." "." ["--test-no-kick"] s typeCheck doc = do WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc diff --git a/ghcide/test/exe/ExceptionTests.hs b/ghcide/test/exe/ExceptionTests.hs index 0de78ee562..6d19891978 100644 --- a/ghcide/test/exe/ExceptionTests.hs +++ b/ghcide/test/exe/ExceptionTests.hs @@ -31,6 +31,7 @@ import Language.LSP.Protocol.Types hiding mkRange) import Language.LSP.Test import LogType (Log (..)) +import Test.Hls (waitForProgressDone) import Test.Tasty import Test.Tasty.HUnit import TestUtils diff --git a/ghcide/test/exe/OpenCloseTest.hs b/ghcide/test/exe/OpenCloseTest.hs index 2c7237fc28..83a85520f2 100644 --- a/ghcide/test/exe/OpenCloseTest.hs +++ b/ghcide/test/exe/OpenCloseTest.hs @@ -6,11 +6,13 @@ import Control.Monad import Language.LSP.Protocol.Message import Language.LSP.Test -- import Test.QuickCheck.Instances () +import Config (testWithDummyPluginEmpty) +import Test.Hls (waitForProgressBegin, + waitForProgressDone) import Test.Tasty -import TestUtils tests :: TestTree -tests = testSession "open close" $ do +tests = testWithDummyPluginEmpty "open close" $ do doc <- createDoc "Testing.hs" "haskell" "" void (skipManyTill anyMessage $ message SMethod_WindowWorkDoneProgressCreate) waitForProgressBegin diff --git a/ghcide/test/exe/THTests.hs b/ghcide/test/exe/THTests.hs index dc781d90d2..038de5ce21 100644 --- a/ghcide/test/exe/THTests.hs +++ b/ghcide/test/exe/THTests.hs @@ -12,6 +12,8 @@ import Language.LSP.Protocol.Types hiding (SemanticTokenAbsolute (..), SemanticTokensEdit (..), mkRange) import Language.LSP.Test import System.FilePath +import Test.Hls (waitForAllProgressDone, + waitForProgressBegin) import Test.Tasty import Test.Tasty.HUnit import TestUtils diff --git a/ghcide/test/exe/TestUtils.hs b/ghcide/test/exe/TestUtils.hs index 0a13dd9717..221fa34f0b 100644 --- a/ghcide/test/exe/TestUtils.hs +++ b/ghcide/test/exe/TestUtils.hs @@ -45,33 +45,9 @@ import Test.Tasty import Test.Tasty.ExpectedFailure import Test.Tasty.HUnit +import Config (lspTestCaps) import LogType --- | Wait for the next progress begin step -waitForProgressBegin :: Session () -waitForProgressBegin = skipManyTill anyMessage $ satisfyMaybe $ \case - FromServerMess SMethod_Progress (TNotificationMessage _ _ (ProgressParams _ v)) | Lens.is _workDoneProgressBegin v-> Just () - _ -> Nothing - --- | Wait for the first progress end step --- Also implemented in hls-test-utils Test.Hls -waitForProgressDone :: Session () -waitForProgressDone = skipManyTill anyMessage $ satisfyMaybe $ \case - FromServerMess SMethod_Progress (TNotificationMessage _ _ (ProgressParams _ v)) | Lens.is _workDoneProgressEnd v -> Just () - _ -> Nothing - --- | Wait for all progress to be done --- Needs at least one progress done notification to return --- Also implemented in hls-test-utils Test.Hls -waitForAllProgressDone :: Session () -waitForAllProgressDone = loop - where - loop = do - ~() <- skipManyTill anyMessage $ satisfyMaybe $ \case - FromServerMess SMethod_Progress (TNotificationMessage _ _ (ProgressParams _ v)) |Lens.is _workDoneProgressEnd v-> Just () - _ -> Nothing - done <- null <$> getIncompleteProgressSessions - unless done loop run :: Session a -> IO a run s = run' (const s) @@ -127,9 +103,6 @@ withTempDir f = System.IO.Extra.withTempDir $ \dir -> do dir' <- canonicalizePath dir f dir' -lspTestCaps :: ClientCapabilities -lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities (Just True) Nothing Nothing } - getConfigFromEnv :: IO SessionConfig getConfigFromEnv = do logColor <- fromMaybe True <$> checkEnv "LSP_TEST_LOG_COLOR" @@ -236,11 +209,6 @@ copyTestDataFiles dir prefix = do withLongTimeout :: IO a -> IO a withLongTimeout = bracket_ (setEnv "LSP_TIMEOUT" "120" True) (unsetEnv "LSP_TIMEOUT") - - -lspTestCapsNoFileWatches :: ClientCapabilities -lspTestCapsNoFileWatches = lspTestCaps & L.workspace . Lens._Just . L.didChangeWatchedFiles .~ Nothing - testIde :: Recorder (WithPriority Log) -> IDE.Arguments -> Session () -> IO () testIde recorder arguments session = do config <- getConfigFromEnv diff --git a/ghcide/test/exe/UnitTests.hs b/ghcide/test/exe/UnitTests.hs index b798146fb0..4900b7cae4 100644 --- a/ghcide/test/exe/UnitTests.hs +++ b/ghcide/test/exe/UnitTests.hs @@ -30,6 +30,7 @@ import Network.URI import qualified Progress import System.IO.Extra hiding (withTempDir) import System.Mem (performGC) +import Test.Hls (waitForProgressDone) import Test.Tasty import Test.Tasty.ExpectedFailure import Test.Tasty.HUnit diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index 68efc4a47d..f4f098bb0d 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -35,6 +35,7 @@ module Test.Hls runSessionWithServerInTmpDir', -- continuation version that take a FileSystem runSessionWithServerInTmpDirCont', + runSessionWithServerAndCapsInTmpDirCont, -- * Helpful re-exports PluginDescriptor, IdeState, @@ -42,6 +43,7 @@ module Test.Hls waitForProgressDone, waitForAllProgressDone, waitForBuildQueue, + waitForProgressBegin, waitForTypecheck, waitForAction, hlsConfigToClientConfig, @@ -666,6 +668,12 @@ runSessionWithServer' plugins conf sconf caps root s = withLock lock $ keepCurr putStrLn $ "Finishing canceling (took " <> showDuration t <> "s)" pure x +-- | Wait for the next progress begin step +waitForProgressBegin :: Session () +waitForProgressBegin = skipManyTill anyMessage $ satisfyMaybe $ \case + FromServerMess SMethod_Progress (TNotificationMessage _ _ (ProgressParams _ v)) | is _workDoneProgressBegin v-> Just () + _ -> Nothing + -- | Wait for the next progress end step waitForProgressDone :: Session () waitForProgressDone = skipManyTill anyMessage $ satisfyMaybe $ \case From ef077d243119dd6897bbf2e494c7248473644d8e Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 05:30:54 +0800 Subject: [PATCH 02/21] add test no kick to hls-test-utils --- ghcide/exe/Main.hs | 5 --- ghcide/src/Development/IDE/Main.hs | 9 +++- ghcide/test/exe/DiagnosticTests.hs | 10 +++-- hls-test-utils/src/Test/Hls.hs | 43 +++++++++++-------- plugins/hls-refactor-plugin/test/Main.hs | 19 ++++---- .../test/SemanticTokensTest.hs | 3 +- test/functional/Config.hs | 3 +- 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/ghcide/exe/Main.hs b/ghcide/exe/Main.hs index 823d6faba6..3344648150 100644 --- a/ghcide/exe/Main.hs +++ b/ghcide/exe/Main.hs @@ -124,12 +124,7 @@ main = withTelemetryRecorder $ \telemetryRecorder -> do , IDEMain.argsHlsPlugins = IDEMain.argsHlsPlugins arguments <> pluginDescToIdePlugins [lspRecorderPlugin] , IDEMain.argsRules = do - -- install the main and ghcide-plugin rules mainRule (cmapWithPrio LogRules recorder) def - -- install the kick action, which triggers a typecheck on every - -- Shake database restart, i.e. on every user edit. - unless argsDisableKick $ - action kick , IDEMain.argsThreads = case argsThreads of 0 -> Nothing ; i -> Just (fromIntegral i) diff --git a/ghcide/src/Development/IDE/Main.hs b/ghcide/src/Development/IDE/Main.hs index 0c7581f75d..cbb0c38df4 100644 --- a/ghcide/src/Development/IDE/Main.hs +++ b/ghcide/src/Development/IDE/Main.hs @@ -223,13 +223,14 @@ data Arguments = Arguments , argsHandleOut :: IO Handle , argsThreads :: Maybe Natural , argsMonitoring :: IO Monitoring + , argsDisableKick :: Bool -- ^ flag to disable kick used for testing } defaultArguments :: Recorder (WithPriority Log) -> IdePlugins IdeState -> Arguments defaultArguments recorder plugins = Arguments { argsProjectRoot = Nothing , argCommand = LSP - , argsRules = mainRule (cmapWithPrio LogRules recorder) def >> action kick + , argsRules = mainRule (cmapWithPrio LogRules recorder) def , argsGhcidePlugin = mempty , argsHlsPlugins = pluginDescToIdePlugins (GhcIde.descriptors (cmapWithPrio LogGhcIde recorder)) <> plugins , argsSessionLoadingOptions = def @@ -258,6 +259,7 @@ defaultArguments recorder plugins = Arguments putStr " " >> hFlush stdout return newStdout , argsMonitoring = OpenTelemetry.monitoring + , argsDisableKick = False } @@ -293,7 +295,10 @@ defaultMain recorder Arguments{..} = withHeapStats (cmapWithPrio LogHeapStats re plugins = hlsPlugin <> argsGhcidePlugin options = argsLspOptions { LSP.optExecuteCommandCommands = LSP.optExecuteCommandCommands argsLspOptions <> Just hlsCommands } argsParseConfig = getConfigFromNotification argsHlsPlugins - rules = argsRules >> pluginRules plugins + rules = argsRules >> (unless argsDisableKick $ action kick) >> pluginRules plugins + -- install the main and ghcide-plugin rules + -- install the kick action, which triggers a typecheck on every + -- Shake database restart, i.e. on every user edit. debouncer <- argsDebouncer inH <- argsHandleIn diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 53b8f959af..54d896c37a 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -33,9 +33,12 @@ import System.IO.Extra hiding (withTempDir) import Config import Control.Lens ((^.)) import Control.Monad.Extra (whenJust) +import Data.Default (def) import Development.IDE.Plugin.Test (WaitForIdeRuleResult (..)) import System.Time.Extra -import Test.Hls (waitForProgressBegin, +import Test.Hls (runSessionWithServer', + runSessionWithServerInTmpDirCont, + waitForProgressBegin, waitForTypecheck) import Test.Hls.FileSystem (toAbsFp) import Test.Tasty @@ -554,7 +557,7 @@ cancellationTestGroup name edits sessionDepsOutcome parseOutcome tcOutcome = tes ] cancellationTemplate :: (TextDocumentContentChangeEvent, TextDocumentContentChangeEvent) -> Maybe (String, Bool) -> TestTree -cancellationTemplate (edit, undoEdit) mbKey = testWithDummyPluginEmpty (maybe "-" fst mbKey) $ do +cancellationTemplate (edit, undoEdit) mbKey = testCase (maybe "-" fst mbKey) $ runTestNoKick $ do doc <- createDoc "Foo.hs" "haskell" $ T.unlines [ "{-# OPTIONS_GHC -Wall #-}" , "module Foo where" @@ -580,7 +583,8 @@ cancellationTemplate (edit, undoEdit) mbKey = testWithDummyPluginEmpty (maybe "- expectNoMoreDiagnostics 0.5 where -- similar to run except it disables kick - -- runTestNoKick s = runWithDummyPluginEmpty dir "." "." ["--test-no-kick"] s + runTestNoKick s = runSessionWithServerInTmpDirCont True dummyPlugin def def def (mkIdeTestFs []) (const s) + -- runWithDummyPluginEmpty dir "." "." ["--test-no-kick"] s typeCheck doc = do WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index f4f098bb0d..3327b953b9 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -34,6 +34,7 @@ module Test.Hls runSessionWithServer', runSessionWithServerInTmpDir', -- continuation version that take a FileSystem + runSessionWithServerInTmpDirCont, runSessionWithServerInTmpDirCont', runSessionWithServerAndCapsInTmpDirCont, -- * Helpful re-exports @@ -341,7 +342,8 @@ mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- @ pluginTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) pluginTestRecorder = do - initialiseTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", "HLS_TEST_LOG_STDERR"] + initialiseTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", + "LSP_TEST_LOG_STDERR", "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] -- | Generic recorder initialisation for plugins and the HLS server for test-cases. -- @@ -376,20 +378,18 @@ runSessionWithServerAndCapsInTmpDir config plugin caps tree act = runSessionWith runSessionWithServerInTmpDirCont' :: Pretty b => Config -> PluginTestDescriptor b -> VirtualFileTree -> (FileSystem -> Session a) -> IO a runSessionWithServerInTmpDirCont' config plugin tree act = do - recorder <- pluginTestRecorder - runSessionWithServerInTmpDirCont (plugin recorder) config def fullCaps tree act + runSessionWithServerInTmpDirCont False plugin config def fullCaps tree act runSessionWithServerAndCapsInTmpDirCont :: Pretty b => Config -> PluginTestDescriptor b -> ClientCapabilities -> VirtualFileTree -> (FileSystem -> Session a) -> IO a runSessionWithServerAndCapsInTmpDirCont config plugin caps tree act = do - recorder <- pluginTestRecorder - runSessionWithServerInTmpDirCont (plugin recorder) config def caps tree act + runSessionWithServerInTmpDirCont False plugin config def caps tree act runSessionWithServerInTmpDir' :: -- | Plugins to load on the server. -- -- For improved logging, make sure these plugins have been initalised with -- the recorder produced by @pluginTestRecorder@. - IdePlugins IdeState -> + Pretty b => PluginTestDescriptor b -> -- | lsp config for the server Config -> -- | config for the test session @@ -397,7 +397,7 @@ runSessionWithServerInTmpDir' :: ClientCapabilities -> VirtualFileTree -> Session a -> IO a -runSessionWithServerInTmpDir' plugins conf sessConf caps tree act = runSessionWithServerInTmpDirCont plugins conf sessConf caps tree (const act) +runSessionWithServerInTmpDir' plugins conf sessConf caps tree act = runSessionWithServerInTmpDirCont False plugins conf sessConf caps tree (const act) -- | Host a server, and run a test session on it. -- @@ -421,11 +421,14 @@ runSessionWithServerInTmpDir' plugins conf sessConf caps tree act = runSessionWi -- -- Note: cwd will be shifted into a temporary directory in @Session a@ runSessionWithServerInTmpDirCont :: + Pretty b => + -- | whether we disable the kick action or not + Bool -> -- | Plugins to load on the server. -- -- For improved logging, make sure these plugins have been initalised with -- the recorder produced by @pluginTestRecorder@. - IdePlugins IdeState -> + PluginTestDescriptor b -> -- | lsp config for the server Config -> -- | config for the test session @@ -433,10 +436,9 @@ runSessionWithServerInTmpDirCont :: ClientCapabilities -> VirtualFileTree -> (FileSystem -> Session a) -> IO a -runSessionWithServerInTmpDirCont plugins conf sessConf caps tree act = withLock lockForTempDirs $ do +runSessionWithServerInTmpDirCont disableKick plugins conf sessConf caps tree act = withLock lockForTempDirs $ do testRoot <- setupTestEnvironment - recorder <- initialiseTestRecorder - ["LSP_TEST_LOG_STDERR", "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] + recorder <- pluginTestRecorder -- Do not clean up the temporary directory if this variable is set to anything but '0'. -- Aids debugging. @@ -460,17 +462,15 @@ runSessionWithServerInTmpDirCont plugins conf sessConf caps tree act = withLock tmpDir <- canonicalizePath tmpDir' logWith recorder Info $ LogTestDir tmpDir fs <- FS.materialiseVFT tmpDir tree - runSessionWithServer' plugins conf sessConf caps tmpDir (act fs) + runSessionWithServer' disableKick plugins conf sessConf caps tmpDir (act fs) runSessionWithServer :: Pretty b => Config -> PluginTestDescriptor b -> FilePath -> Session a -> IO a runSessionWithServer config plugin fp act = do - recorder <- pluginTestRecorder - runSessionWithServer' (plugin recorder) config def fullCaps fp act + runSessionWithServer' False plugin config def fullCaps fp act runSessionWithServerAndCaps :: Pretty b => Config -> PluginTestDescriptor b -> ClientCapabilities -> FilePath -> Session a -> IO a runSessionWithServerAndCaps config plugin caps fp act = do - recorder <- pluginTestRecorder - runSessionWithServer' (plugin recorder) config def caps fp act + runSessionWithServer' False plugin config def caps fp act -- | Setup the test environment for isolated tests. @@ -607,11 +607,14 @@ lockForTempDirs = unsafePerformIO newLock -- | Host a server, and run a test session on it -- Note: cwd will be shifted into @root@ in @Session a@ runSessionWithServer' :: + (Pretty b) => + -- | whether we disable the kick action or not + Bool -> -- | Plugins to load on the server. -- -- For improved logging, make sure these plugins have been initalised with -- the recorder produced by @pluginTestRecorder@. - IdePlugins IdeState -> + PluginTestDescriptor b -> -- | lsp config for the server Config -> -- | config for the test session @@ -620,7 +623,10 @@ runSessionWithServer' :: FilePath -> Session a -> IO a -runSessionWithServer' plugins conf sconf caps root s = withLock lock $ keepCurrentDirectory $ do +runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock lock $ keepCurrentDirectory $ do + recorder <- pluginTestRecorder + let plugins = pluginsDp recorder + (inR, inW) <- createPipe (outR, outW) <- createPipe @@ -656,6 +662,7 @@ runSessionWithServer' plugins conf sconf caps root s = withLock lock $ keepCurr , argsDefaultHlsConfig = conf , argsIdeOptions = ideOptions , argsProjectRoot = Just root + , argsDisableKick = disableKick } x <- runSessionWithHandles inW outR sconf' caps root s diff --git a/plugins/hls-refactor-plugin/test/Main.hs b/plugins/hls-refactor-plugin/test/Main.hs index 092cd6ef0b..947ef299f4 100644 --- a/plugins/hls-refactor-plugin/test/Main.hs +++ b/plugins/hls-refactor-plugin/test/Main.hs @@ -55,17 +55,14 @@ import qualified Test.AddArgument main :: IO () main = defaultTestRunner tests -refactorPlugin :: IO (IdePlugins IdeState) +-- refactorPlugin :: IO (IdePlugins IdeState) refactorPlugin = do - exactprintLog <- pluginTestRecorder - ghcideLog <- pluginTestRecorder - pure $ IdePlugins $ - [ Refactor.iePluginDescriptor exactprintLog "ghcide-code-actions-imports-exports" - , Refactor.typeSigsPluginDescriptor exactprintLog "ghcide-code-actions-type-signatures" - , Refactor.bindingsPluginDescriptor exactprintLog "ghcide-code-actions-bindings" - , Refactor.fillHolePluginDescriptor exactprintLog "ghcide-code-actions-fill-holes" - , Refactor.extendImportPluginDescriptor exactprintLog "ghcide-completions-1" - ] ++ GhcIde.descriptors ghcideLog + return $ mkPluginTestDescriptor Refactor.iePluginDescriptor "ghcide-code-actions-imports-exports" + <> mkPluginTestDescriptor Refactor.typeSigsPluginDescriptor "ghcide-code-actions-type-signatures" + <> mkPluginTestDescriptor Refactor.bindingsPluginDescriptor "ghcide-code-actions-bindings" + <> mkPluginTestDescriptor Refactor.fillHolePluginDescriptor "ghcide-code-actions-fill-holes" + <> mkPluginTestDescriptor Refactor.extendImportPluginDescriptor "ghcide-completions-1" + tests :: TestTree tests = @@ -3757,7 +3754,7 @@ run' s = withTempDir $ \dir -> runInDir dir (s dir) runInDir :: FilePath -> Session a -> IO a runInDir dir act = do plugin <- refactorPlugin - runSessionWithServer' plugin def def lspTestCaps dir act + runSessionWithServerAndCaps def plugin lspTestCaps dir act lspTestCaps :: ClientCapabilities lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities (Just True) Nothing Nothing } diff --git a/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs b/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs index 2cac6e597c..b8a631a91e 100644 --- a/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs +++ b/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs @@ -157,9 +157,8 @@ semanticTokensConfigTest = var :: String var = "variable" do - recorder <- pluginTestRecorder Test.Hls.runSessionWithServerInTmpDir' - (semanticTokensPlugin recorder) + semanticTokensPlugin (mkSemanticConfig funcVar) def {ignoreConfigurationRequests = False} fullCaps diff --git a/test/functional/Config.hs b/test/functional/Config.hs index 89aa466a0f..1dbf12c64c 100644 --- a/test/functional/Config.hs +++ b/test/functional/Config.hs @@ -68,8 +68,7 @@ genericConfigTests = testGroup "generic plugin config" testPluginDiagnostics = [("Foo.hs", [(DiagnosticSeverity_Error, (0,0), "testplugin")])] runConfigSession subdir session = do - recorder <- pluginTestRecorder - failIfSessionTimeout $ runSessionWithServer' @() (plugin recorder) def (def {ignoreConfigurationRequests=False}) fullCaps ("test/testdata" subdir) session + failIfSessionTimeout $ runSessionWithServer' @() False plugin def (def {ignoreConfigurationRequests=False}) fullCaps ("test/testdata" subdir) session testPluginId = "testplugin" -- A disabled-by-default plugin that creates diagnostics From cc7d3cb493022867ad5e16b9f12154fe7d15bb2a Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 06:03:43 +0800 Subject: [PATCH 03/21] clean up ghcide config --- ghcide/test/exe/CompletionTests.hs | 4 +-- ghcide/test/exe/Config.hs | 37 +++++++++++++++------- ghcide/test/exe/DiagnosticTests.hs | 2 -- ghcide/test/exe/InitializeResponseTests.hs | 2 +- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/ghcide/test/exe/CompletionTests.hs b/ghcide/test/exe/CompletionTests.hs index 856598bf60..590f0b707a 100644 --- a/ghcide/test/exe/CompletionTests.hs +++ b/ghcide/test/exe/CompletionTests.hs @@ -49,10 +49,10 @@ tests ] testSessionEmpty :: TestName -> Session () -> TestTree -testSessionEmpty name = testCase name . runWithDummyPlugin (mkIdeTestFs [FS.directCradle ["A.hs"]]) +testSessionEmpty name = testWithDummyPlugin name (mkIdeTestFs [FS.directCradle ["A.hs"]]) testSessionEmptyWithCradle :: TestName -> T.Text -> Session () -> TestTree -testSessionEmptyWithCradle name cradle = testCase name . runWithDummyPlugin (mkIdeTestFs [file "hie.yaml" (text cradle)]) +testSessionEmptyWithCradle name cradle = testWithDummyPlugin name (mkIdeTestFs [file "hie.yaml" (text cradle)]) testSessionSingleFile :: TestName -> FilePath -> T.Text -> Session () -> TestTree testSessionSingleFile testName fp txt session = diff --git a/ghcide/test/exe/Config.hs b/ghcide/test/exe/Config.hs index 41cf7dd10b..540e0b2451 100644 --- a/ghcide/test/exe/Config.hs +++ b/ghcide/test/exe/Config.hs @@ -1,6 +1,29 @@ {-# LANGUAGE PatternSynonyms #-} -module Config where +module Config( + -- * basic config for ghcIde testing + mkIdeTestFs + , dummyPlugin + + -- * runners for testing with dummy plugin + , runWithDummyPlugin + , testWithDummyPlugin + , testWithDummyPluginEmpty + , testWithDummyPlugin' + , testWithDummyPluginEmpty' + , testWithDummyPluginAndCap' + , runWithExtraFiles + , testWithExtraFiles + + -- * utilities for testing definition and hover + , Expect(..) + , pattern R + , mkR + , checkDefs + , mkL + , lspTestCaps + , lspTestCapsNoFileWatches + ) where import Control.Lens.Setter ((.~)) import Data.Foldable (traverse_) @@ -31,28 +54,18 @@ runWithDummyPlugin = runSessionWithServerInTmpDir def dummyPlugin runWithDummyPlugin' :: FS.VirtualFileTree -> (FileSystem -> Session a) -> IO a runWithDummyPlugin' = runSessionWithServerInTmpDirCont' def dummyPlugin -runWithDummyPluginAndCap :: ClientCapabilities -> Session () -> IO () -runWithDummyPluginAndCap cap = runSessionWithServerAndCapsInTmpDir def dummyPlugin cap (mkIdeTestFs []) - runWithDummyPluginAndCap' :: ClientCapabilities -> (FileSystem -> Session ()) -> IO () runWithDummyPluginAndCap' cap = runSessionWithServerAndCapsInTmpDirCont def dummyPlugin cap (mkIdeTestFs []) -testWithDummyPluginAndCap :: String -> ClientCapabilities -> Session () -> TestTree -testWithDummyPluginAndCap caseName cap = testCase caseName . runWithDummyPluginAndCap cap - testWithDummyPluginAndCap' :: String -> ClientCapabilities -> (FileSystem -> Session ()) -> TestTree testWithDummyPluginAndCap' caseName cap = testCase caseName . runWithDummyPluginAndCap' cap --- testSessionWithCorePlugin ::(TestRunner cont ()) => TestName -> FS.VirtualFileTree -> cont -> TestTree testWithDummyPlugin :: String -> FS.VirtualFileTree -> Session () -> TestTree -testWithDummyPlugin caseName vfs = testCase caseName . runWithDummyPlugin vfs +testWithDummyPlugin caseName vfs = testWithDummyPlugin' caseName vfs . const testWithDummyPlugin' :: String -> FS.VirtualFileTree -> (FileSystem -> Session ()) -> TestTree testWithDummyPlugin' caseName vfs = testCase caseName . runWithDummyPlugin' vfs -runWithDummyPluginEmpty :: Session a -> IO a -runWithDummyPluginEmpty = runWithDummyPlugin $ mkIdeTestFs [] - testWithDummyPluginEmpty :: String -> Session () -> TestTree testWithDummyPluginEmpty caseName = testWithDummyPlugin caseName $ mkIdeTestFs [] diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 54d896c37a..1dfedd164a 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -584,8 +584,6 @@ cancellationTemplate (edit, undoEdit) mbKey = testCase (maybe "-" fst mbKey) $ r where -- similar to run except it disables kick runTestNoKick s = runSessionWithServerInTmpDirCont True dummyPlugin def def def (mkIdeTestFs []) (const s) - -- runWithDummyPluginEmpty dir "." "." ["--test-no-kick"] s - typeCheck doc = do WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc liftIO $ assertBool "The file should typecheck" ideResultSuccess diff --git a/ghcide/test/exe/InitializeResponseTests.hs b/ghcide/test/exe/InitializeResponseTests.hs index bccf124c09..16e4e4b6f4 100644 --- a/ghcide/test/exe/InitializeResponseTests.hs +++ b/ghcide/test/exe/InitializeResponseTests.hs @@ -87,7 +87,7 @@ tests = withResource acquire release tests where innerCaps (TResponseMessage _ _ (Left _)) = error "Initialization error" acquire :: IO (TResponseMessage Method_Initialize) - acquire = runWithDummyPluginEmpty initializeResponse + acquire = runWithDummyPlugin (mkIdeTestFs []) initializeResponse release :: TResponseMessage Method_Initialize -> IO () release = mempty From b887243c8e6741398f786199c7666da26d3debfc Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 06:26:36 +0800 Subject: [PATCH 04/21] use fs --- ghcide/test/exe/DiagnosticTests.hs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 1dfedd164a..1101cb9c51 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -40,7 +40,7 @@ import Test.Hls (runSessionWithServer', runSessionWithServerInTmpDirCont, waitForProgressBegin, waitForTypecheck) -import Test.Hls.FileSystem (toAbsFp) +import Test.Hls.FileSystem (file, text, toAbsFp) import Test.Tasty import Test.Tasty.HUnit @@ -203,21 +203,18 @@ tests = testGroup "diagnostics" , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")] ) ] - , testWithDummyPluginEmpty' "deeply nested cyclic module dependency" $ \path -> do - let contentA = unlines - [ "module ModuleA where" , "import ModuleB" ] - let contentB = unlines - [ "module ModuleB where" , "import ModuleA" ] - let contentC = unlines - [ "module ModuleC where" , "import ModuleB" ] - let contentD = T.unlines - [ "module ModuleD where" , "import ModuleC" ] - cradle = - "cradle: {direct: {arguments: [ModuleA, ModuleB, ModuleC, ModuleD]}}" - liftIO $ writeFile (path `toAbsFp` "ModuleA.hs") contentA - liftIO $ writeFile (path `toAbsFp` "ModuleB.hs") contentB - liftIO $ writeFile (path `toAbsFp` "ModuleC.hs") contentC - liftIO $ writeFile (path `toAbsFp` "hie.yaml") cradle + , let contentA = T.unlines [ "module ModuleA where" , "import ModuleB" ] + contentB = T.unlines [ "module ModuleB where" , "import ModuleA" ] + contentC = T.unlines [ "module ModuleC where" , "import ModuleB" ] + contentD = T.unlines [ "module ModuleD where" , "import ModuleC" ] + cradle = "cradle: {direct: {arguments: [ModuleA, ModuleB, ModuleC, ModuleD]}}" + in testWithDummyPlugin "deeply nested cyclic module dependency" + (mkIdeTestFs [ + file "ModuleA.hs" (text contentA) + ,file "ModuleB.hs" (text contentB) + ,file "ModuleC.hs" (text contentC) + ,file "hie.yaml" (text cradle) + ]) $ do _ <- createDoc "ModuleD.hs" "haskell" contentD expectDiagnostics [ ( "ModuleB.hs" From 158caa9d5d05b54a5c911937755d17177c51a1f6 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 06:49:22 +0800 Subject: [PATCH 05/21] reduce write file --- ghcide/test/exe/DiagnosticTests.hs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 1101cb9c51..26013acc55 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -240,11 +240,9 @@ tests = testGroup "diagnostics" _ <- createDoc "ModuleB.hs" "haskell" contentB _ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] - , testWithDummyPluginEmpty' "bidirectional module dependency with hs-boot" $ \path -> do - let cradle = unlines - [ "cradle:" - , " direct: {arguments: [ModuleA, ModuleB]}" - ] + , testWithDummyPlugin "bidirectional module dependency with hs-boot" + (mkIdeTestFs [file "hie.yaml" $ text $ T.unlines ["cradle:", " direct: {arguments: [ModuleA, ModuleB]}"]]) + $ do let contentA = T.unlines [ "module ModuleA where" , "import {-# SOURCE #-} ModuleB" @@ -262,7 +260,6 @@ tests = testGroup "diagnostics" let contentAboot = T.unlines [ "module ModuleA where" ] - liftIO $ writeFile (path `toAbsFp` "hie.yaml") cradle _ <- createDoc "ModuleA.hs" "haskell" contentA _ <- createDoc "ModuleA.hs-boot" "haskell" contentAboot _ <- createDoc "ModuleB.hs" "haskell" contentB @@ -428,9 +425,9 @@ tests = testGroup "diagnostics" Lens.filtered (T.isInfixOf ("/" <> name <> ".hs:")) failure msg = liftIO $ assertFailure $ "Expected file path to be stripped but got " <> T.unpack msg Lens.mapMOf_ offenders failure notification - , testWithDummyPluginEmpty' "-Werror in cradle is ignored" $ \sessionDir -> do - liftIO $ writeFile (sessionDir `toAbsFp` "hie.yaml") - "cradle: {direct: {arguments: [\"-Wall\", \"-Werror\"]}}" + , testWithDummyPlugin "-Werror in cradle is ignored" + (mkIdeTestFs [file "hie.yaml" $ text "cradle: {direct: {arguments: [\"-Wall\", \"-Werror\"]}}" ]) + $ do let fooContent = T.unlines [ "module Foo where" , "foo = ()" From 56195f5b32af3cf788b462ebf80e2cd9b639413e Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 09:13:13 +0800 Subject: [PATCH 06/21] fix up --- hls-test-utils/src/Test/Hls.hs | 26 +++++++++---------- .../test/SemanticTokensTest.hs | 1 - 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index 3327b953b9..a2bdc91ba7 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -326,8 +326,14 @@ mkPluginTestDescriptor' mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- | Initialise a recorder that can be instructed to write to stderr by --- setting the environment variable "HLS_TEST_PLUGIN_LOG_STDERR=1" before --- running the tests. +-- setting the environment variable "HLS_TEST_PLUGIN_LOG_STDERR|LSP_TEST_LOG_STDERR +-- |LSP_TEST_LOG_STDERR|HLS_TEST_LOG_STDERR=1" before running the tests. +-- +-- Because "LSP_TEST_LOG_STDERR" has been used before, +-- (thus, backwards compatibility) and "HLS_TEST_HARNESS_STDERR" because it +-- uses a more descriptive name to be used with "HLS_TEST_HARNESS_NO_TESTDIR_CLEANUP". +-- "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins +-- under test. -- -- On the cli, use for example: -- @@ -385,11 +391,12 @@ runSessionWithServerAndCapsInTmpDirCont config plugin caps tree act = do runSessionWithServerInTmpDirCont False plugin config def caps tree act runSessionWithServerInTmpDir' :: + Pretty b => -- | Plugins to load on the server. -- -- For improved logging, make sure these plugins have been initalised with -- the recorder produced by @pluginTestRecorder@. - Pretty b => PluginTestDescriptor b -> + PluginTestDescriptor b -> -- | lsp config for the server Config -> -- | config for the test session @@ -624,20 +631,11 @@ runSessionWithServer' :: Session a -> IO a runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock lock $ keepCurrentDirectory $ do - recorder <- pluginTestRecorder - let plugins = pluginsDp recorder - (inR, inW) <- createPipe (outR, outW) <- createPipe - -- Allow three environment variables, because "LSP_TEST_LOG_STDERR" has been used before, - -- (thus, backwards compatibility) and "HLS_TEST_SERVER_LOG_STDERR" because it - -- uses a more descriptive name. - -- It is also in better accordance with 'pluginTestRecorder' which uses "HLS_TEST_PLUGIN_LOG_STDERR". - -- At last, "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins - -- under test. - recorder <- initialiseTestRecorder - ["LSP_TEST_LOG_STDERR", "HLS_TEST_SERVER_LOG_STDERR", "HLS_TEST_LOG_STDERR"] + recorder <- pluginTestRecorder + let plugins = pluginsDp recorder let sconf' = sconf { lspConfig = hlsConfigToClientConfig conf } diff --git a/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs b/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs index b8a631a91e..906319ed2a 100644 --- a/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs +++ b/plugins/hls-semantic-tokens-plugin/test/SemanticTokensTest.hs @@ -40,7 +40,6 @@ import Test.Hls (HasCallStack, documentContents, fullCaps, goldenGitDiff, mkPluginTestDescriptor, - pluginTestRecorder, runSessionWithServerInTmpDir, runSessionWithServerInTmpDir', testCase, testGroup, From b8c6ca99180fe4900c5051c37fb934db76723912 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 09:23:29 +0800 Subject: [PATCH 07/21] fix ide log --- hls-test-utils/src/Test/Hls.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index a2bdc91ba7..1b6047fad7 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -636,6 +636,7 @@ runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock l recorder <- pluginTestRecorder let plugins = pluginsDp recorder + recorderIde <- pluginTestRecorder let sconf' = sconf { lspConfig = hlsConfigToClientConfig conf } @@ -643,7 +644,7 @@ runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock l hlsPlugins = IdePlugins [Test.blockCommandDescriptor "block-command"] <> plugins arguments@Arguments{ argsIdeOptions } = - testing (cmapWithPrio LogIDEMain recorder) hlsPlugins + testing (cmapWithPrio LogIDEMain recorderIde) hlsPlugins ideOptions config ghcSession = let defIdeOptions = argsIdeOptions config ghcSession @@ -653,7 +654,7 @@ runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock l } server <- async $ - IDEMain.defaultMain (cmapWithPrio LogIDEMain recorder) + IDEMain.defaultMain (cmapWithPrio LogIDEMain recorderIde) arguments { argsHandleIn = pure inR , argsHandleOut = pure outW From 46b5f04212505fdfd84933b04008cfccb19bb255 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 10 May 2024 10:26:19 +0800 Subject: [PATCH 08/21] fix --- plugins/hls-refactor-plugin/test/Main.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/hls-refactor-plugin/test/Main.hs b/plugins/hls-refactor-plugin/test/Main.hs index 947ef299f4..1670f99de9 100644 --- a/plugins/hls-refactor-plugin/test/Main.hs +++ b/plugins/hls-refactor-plugin/test/Main.hs @@ -27,7 +27,6 @@ import Development.IDE.Plugin.Completions.Types (extendImportCommandId import Development.IDE.Test import Development.IDE.Types.Location import Development.Shake (getDirectoryFilesIO) -import Ide.Types import qualified Language.LSP.Protocol.Lens as L import Language.LSP.Protocol.Message import Language.LSP.Protocol.Types hiding @@ -48,14 +47,14 @@ import Text.Regex.TDFA ((=~)) import Development.IDE.Plugin.CodeAction (matchRegExMultipleImports) import Test.Hls +import qualified Development.IDE.GHC.ExactPrint import qualified Development.IDE.Plugin.CodeAction as Refactor -import qualified Development.IDE.Plugin.HLS.GhcIde as GhcIde import qualified Test.AddArgument main :: IO () main = defaultTestRunner tests --- refactorPlugin :: IO (IdePlugins IdeState) +refactorPlugin :: IO (PluginTestDescriptor Development.IDE.GHC.ExactPrint.Log) refactorPlugin = do return $ mkPluginTestDescriptor Refactor.iePluginDescriptor "ghcide-code-actions-imports-exports" <> mkPluginTestDescriptor Refactor.typeSigsPluginDescriptor "ghcide-code-actions-type-signatures" From 1554f8769f176b52828efe5d155d0ce5d6a7ee3f Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:21:40 +0800 Subject: [PATCH 09/21] Update ghcide/src/Development/IDE/Main.hs Co-authored-by: fendor --- ghcide/src/Development/IDE/Main.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ghcide/src/Development/IDE/Main.hs b/ghcide/src/Development/IDE/Main.hs index cbb0c38df4..62b1aa6be7 100644 --- a/ghcide/src/Development/IDE/Main.hs +++ b/ghcide/src/Development/IDE/Main.hs @@ -295,7 +295,10 @@ defaultMain recorder Arguments{..} = withHeapStats (cmapWithPrio LogHeapStats re plugins = hlsPlugin <> argsGhcidePlugin options = argsLspOptions { LSP.optExecuteCommandCommands = LSP.optExecuteCommandCommands argsLspOptions <> Just hlsCommands } argsParseConfig = getConfigFromNotification argsHlsPlugins - rules = argsRules >> (unless argsDisableKick $ action kick) >> pluginRules plugins + rules = do + argsRules + unless argsDisableKick $ action kick + pluginRules plugins -- install the main and ghcide-plugin rules -- install the kick action, which triggers a typecheck on every -- Shake database restart, i.e. on every user edit. From 4388ac0c0b2324b6488ac6e1e89684f2bbd500de Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:22:02 +0800 Subject: [PATCH 10/21] Update ghcide/test/exe/DiagnosticTests.hs Co-authored-by: fendor --- ghcide/test/exe/DiagnosticTests.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 26013acc55..060abf2bae 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -426,7 +426,7 @@ tests = testGroup "diagnostics" failure msg = liftIO $ assertFailure $ "Expected file path to be stripped but got " <> T.unpack msg Lens.mapMOf_ offenders failure notification , testWithDummyPlugin "-Werror in cradle is ignored" - (mkIdeTestFs [file "hie.yaml" $ text "cradle: {direct: {arguments: [\"-Wall\", \"-Werror\"]}}" ]) + (mkIdeTestFs [directCradle ["-Wall", "-Werror"]]) $ do let fooContent = T.unlines [ "module Foo where" From f6a7f48f095a46a2e9b394279ee68f99e521f26c Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:22:48 +0800 Subject: [PATCH 11/21] Update hls-test-utils/src/Test/Hls.hs Co-authored-by: fendor --- hls-test-utils/src/Test/Hls.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index 1b6047fad7..abab0168aa 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -326,8 +326,12 @@ mkPluginTestDescriptor' mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- | Initialise a recorder that can be instructed to write to stderr by --- setting the environment variable "HLS_TEST_PLUGIN_LOG_STDERR|LSP_TEST_LOG_STDERR --- |LSP_TEST_LOG_STDERR|HLS_TEST_LOG_STDERR=1" before running the tests. +-- setting one of the environment variables: +-- +-- * HLS_TEST_PLUGIN_LOG_STDERR=1 +-- * HLS_TEST_LOG_STDERR=1 +-- +-- before running the tests. -- -- Because "LSP_TEST_LOG_STDERR" has been used before, -- (thus, backwards compatibility) and "HLS_TEST_HARNESS_STDERR" because it From aee5c53cccf1a255cb690e4d82944e01223c8564 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:23:50 +0800 Subject: [PATCH 12/21] Update plugins/hls-refactor-plugin/test/Main.hs Co-authored-by: fendor --- plugins/hls-refactor-plugin/test/Main.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hls-refactor-plugin/test/Main.hs b/plugins/hls-refactor-plugin/test/Main.hs index 1670f99de9..f7776c396c 100644 --- a/plugins/hls-refactor-plugin/test/Main.hs +++ b/plugins/hls-refactor-plugin/test/Main.hs @@ -56,7 +56,7 @@ main = defaultTestRunner tests refactorPlugin :: IO (PluginTestDescriptor Development.IDE.GHC.ExactPrint.Log) refactorPlugin = do - return $ mkPluginTestDescriptor Refactor.iePluginDescriptor "ghcide-code-actions-imports-exports" + mkPluginTestDescriptor Refactor.iePluginDescriptor "ghcide-code-actions-imports-exports" <> mkPluginTestDescriptor Refactor.typeSigsPluginDescriptor "ghcide-code-actions-type-signatures" <> mkPluginTestDescriptor Refactor.bindingsPluginDescriptor "ghcide-code-actions-bindings" <> mkPluginTestDescriptor Refactor.fillHolePluginDescriptor "ghcide-code-actions-fill-holes" From 8aa41f359571c9aa39999eea68a0d1596bcb4d12 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:24:03 +0800 Subject: [PATCH 13/21] Update plugins/hls-refactor-plugin/test/Main.hs Co-authored-by: fendor --- plugins/hls-refactor-plugin/test/Main.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hls-refactor-plugin/test/Main.hs b/plugins/hls-refactor-plugin/test/Main.hs index f7776c396c..b92336a4bc 100644 --- a/plugins/hls-refactor-plugin/test/Main.hs +++ b/plugins/hls-refactor-plugin/test/Main.hs @@ -54,7 +54,7 @@ import qualified Test.AddArgument main :: IO () main = defaultTestRunner tests -refactorPlugin :: IO (PluginTestDescriptor Development.IDE.GHC.ExactPrint.Log) +refactorPlugin :: PluginTestDescriptor Development.IDE.GHC.ExactPrint.Log refactorPlugin = do mkPluginTestDescriptor Refactor.iePluginDescriptor "ghcide-code-actions-imports-exports" <> mkPluginTestDescriptor Refactor.typeSigsPluginDescriptor "ghcide-code-actions-type-signatures" From 7d22fb76193602e07cd6820dd7ce40cc0fb543e8 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Sat, 11 May 2024 00:27:37 +0800 Subject: [PATCH 14/21] Update ghcide/test/exe/DiagnosticTests.hs Co-authored-by: fendor --- ghcide/test/exe/DiagnosticTests.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 060abf2bae..49f86d15ef 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -241,7 +241,7 @@ tests = testGroup "diagnostics" _ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])] , testWithDummyPlugin "bidirectional module dependency with hs-boot" - (mkIdeTestFs [file "hie.yaml" $ text $ T.unlines ["cradle:", " direct: {arguments: [ModuleA, ModuleB]}"]]) + (mkIdeTestFs [directCradle ["ModuleA", "ModuleB"]]) $ do let contentA = T.unlines [ "module ModuleA where" From cfd3f53094dcde721a3ca711ab5a7c0b5bd1f791 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 11 May 2024 01:56:07 +0800 Subject: [PATCH 15/21] update recorder --- hls-test-utils/src/Test/Hls.hs | 50 +++++++++++------------- plugins/hls-refactor-plugin/test/Main.hs | 4 +- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index abab0168aa..2fabd4ac81 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -54,7 +54,7 @@ module Test.Hls waitForKickStart, -- * Plugin descriptor helper functions for tests PluginTestDescriptor, - pluginTestRecorder, + hlsPluginTestRecorder, mkPluginTestDescriptor, mkPluginTestDescriptor', -- * Re-export logger types @@ -325,6 +325,15 @@ mkPluginTestDescriptor' -> PluginTestDescriptor b mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] +-- | Initialise a recorder that can be instructed to write to stderr by +-- setting one of the environment variables: +-- "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR" + +hlsHelperTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) +hlsHelperTestRecorder = do + initializeTestRecorder ["HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] + + -- | Initialise a recorder that can be instructed to write to stderr by -- setting one of the environment variables: -- @@ -333,9 +342,6 @@ mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- -- before running the tests. -- --- Because "LSP_TEST_LOG_STDERR" has been used before, --- (thus, backwards compatibility) and "HLS_TEST_HARNESS_STDERR" because it --- uses a more descriptive name to be used with "HLS_TEST_HARNESS_NO_TESTDIR_CLEANUP". -- "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins -- under test. -- @@ -350,10 +356,9 @@ mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- @ -- HLS_TEST_LOG_STDERR=1 cabal test -- @ -pluginTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) -pluginTestRecorder = do - initialiseTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", - "LSP_TEST_LOG_STDERR", "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] +hlsPluginTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) +hlsPluginTestRecorder = do + initializeTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", "HLS_TEST_LOG_STDERR"] -- | Generic recorder initialisation for plugins and the HLS server for test-cases. -- @@ -364,11 +369,11 @@ pluginTestRecorder = do -- -- We have to return the base logger function for HLS server logging initialisation. -- See 'runSessionWithServer'' for details. -initialiseTestRecorder :: Pretty a => [String] -> IO (Recorder (WithPriority a)) -initialiseTestRecorder envVars = do +initializeTestRecorder :: Pretty a => [String] -> IO (Recorder (WithPriority a)) +initializeTestRecorder envVars = do docWithPriorityRecorder <- makeDefaultStderrRecorder (Just $ ThreadIdColumn : defaultLoggingColumns) -- There are potentially multiple environment variables that enable this logger - definedEnvVars <- forM envVars (\var -> fromMaybe "0" <$> lookupEnv var) + definedEnvVars <- forM envVars (fmap (fromMaybe "0") . lookupEnv) let logStdErr = any (/= "0") definedEnvVars docWithFilteredPriorityRecorder = @@ -397,9 +402,6 @@ runSessionWithServerAndCapsInTmpDirCont config plugin caps tree act = do runSessionWithServerInTmpDir' :: Pretty b => -- | Plugins to load on the server. - -- - -- For improved logging, make sure these plugins have been initalised with - -- the recorder produced by @pluginTestRecorder@. PluginTestDescriptor b -> -- | lsp config for the server Config -> @@ -436,9 +438,6 @@ runSessionWithServerInTmpDirCont :: -- | whether we disable the kick action or not Bool -> -- | Plugins to load on the server. - -- - -- For improved logging, make sure these plugins have been initalised with - -- the recorder produced by @pluginTestRecorder@. PluginTestDescriptor b -> -- | lsp config for the server Config -> @@ -449,7 +448,7 @@ runSessionWithServerInTmpDirCont :: (FileSystem -> Session a) -> IO a runSessionWithServerInTmpDirCont disableKick plugins conf sessConf caps tree act = withLock lockForTempDirs $ do testRoot <- setupTestEnvironment - recorder <- pluginTestRecorder + helperRecorder <- hlsHelperTestRecorder -- Do not clean up the temporary directory if this variable is set to anything but '0'. -- Aids debugging. @@ -458,20 +457,20 @@ runSessionWithServerInTmpDirCont disableKick plugins conf sessConf caps tree act Just val | val /= "0" -> do (tempDir, _) <- newTempDirWithin testRoot a <- action tempDir - logWith recorder Debug LogNoCleanup + logWith helperRecorder Debug LogNoCleanup pure a _ -> do (tempDir, cleanup) <- newTempDirWithin testRoot a <- action tempDir `finally` cleanup - logWith recorder Debug LogCleanup + logWith helperRecorder Debug LogCleanup pure a runTestInDir $ \tmpDir' -> do -- we canonicalize the path, so that we do not need to do -- cannibalization during the test when we compare two paths tmpDir <- canonicalizePath tmpDir' - logWith recorder Info $ LogTestDir tmpDir + logWith helperRecorder Info $ LogTestDir tmpDir fs <- FS.materialiseVFT tmpDir tree runSessionWithServer' disableKick plugins conf sessConf caps tmpDir (act fs) @@ -621,10 +620,7 @@ runSessionWithServer' :: (Pretty b) => -- | whether we disable the kick action or not Bool -> - -- | Plugins to load on the server. - -- - -- For improved logging, make sure these plugins have been initalised with - -- the recorder produced by @pluginTestRecorder@. + -- | Plugin to load on the server. PluginTestDescriptor b -> -- | lsp config for the server Config -> @@ -638,9 +634,9 @@ runSessionWithServer' disableKick pluginsDp conf sconf caps root s = withLock l (inR, inW) <- createPipe (outR, outW) <- createPipe - recorder <- pluginTestRecorder + recorder <- hlsPluginTestRecorder let plugins = pluginsDp recorder - recorderIde <- pluginTestRecorder + recorderIde <- hlsHelperTestRecorder let sconf' = sconf { lspConfig = hlsConfigToClientConfig conf } diff --git a/plugins/hls-refactor-plugin/test/Main.hs b/plugins/hls-refactor-plugin/test/Main.hs index b92336a4bc..3670a3b398 100644 --- a/plugins/hls-refactor-plugin/test/Main.hs +++ b/plugins/hls-refactor-plugin/test/Main.hs @@ -3751,9 +3751,7 @@ run' :: (FilePath -> Session a) -> IO a run' s = withTempDir $ \dir -> runInDir dir (s dir) runInDir :: FilePath -> Session a -> IO a -runInDir dir act = do - plugin <- refactorPlugin - runSessionWithServerAndCaps def plugin lspTestCaps dir act +runInDir dir act = runSessionWithServerAndCaps def refactorPlugin lspTestCaps dir act lspTestCaps :: ClientCapabilities lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities (Just True) Nothing Nothing } From d40c643a90b9e834770e1b90815e2b2b86093a84 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 11 May 2024 01:57:48 +0800 Subject: [PATCH 16/21] fix --- ghcide/test/exe/DiagnosticTests.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 49f86d15ef..9a8a29f7a1 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -40,7 +40,8 @@ import Test.Hls (runSessionWithServer', runSessionWithServerInTmpDirCont, waitForProgressBegin, waitForTypecheck) -import Test.Hls.FileSystem (file, text, toAbsFp) +import Test.Hls.FileSystem (directCradle, file, text, + toAbsFp) import Test.Tasty import Test.Tasty.HUnit From a03aa22721acc53167a2c0d5c075d7f0929f7cae Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 11 May 2024 03:07:03 +0800 Subject: [PATCH 17/21] cleanup --- hls-test-utils/src/Test/Hls.hs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index 2fabd4ac81..a87fec7294 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -325,16 +325,18 @@ mkPluginTestDescriptor' -> PluginTestDescriptor b mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] --- | Initialise a recorder that can be instructed to write to stderr by +-- | Initialize a recorder that can be instructed to write to stderr by -- setting one of the environment variables: -- "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR" +-- +-- "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins +-- under test. hlsHelperTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) -hlsHelperTestRecorder = do - initializeTestRecorder ["HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] +hlsHelperTestRecorder = initializeTestRecorder ["HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"] --- | Initialise a recorder that can be instructed to write to stderr by +-- | Initialize a recorder that can be instructed to write to stderr by -- setting one of the environment variables: -- -- * HLS_TEST_PLUGIN_LOG_STDERR=1 @@ -357,10 +359,9 @@ hlsHelperTestRecorder = do -- HLS_TEST_LOG_STDERR=1 cabal test -- @ hlsPluginTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) -hlsPluginTestRecorder = do - initializeTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", "HLS_TEST_LOG_STDERR"] +hlsPluginTestRecorder = initializeTestRecorder ["HLS_TEST_PLUGIN_LOG_STDERR", "HLS_TEST_LOG_STDERR"] --- | Generic recorder initialisation for plugins and the HLS server for test-cases. +-- | Generic recorder initialization for plugins and the HLS server for test-cases. -- -- The created recorder writes to stderr if any of the given environment variables -- have been set to a value different to @0@. From c8aa5ca3aaaa76d324b5e8fb7503f0fc2a3346bf Mon Sep 17 00:00:00 2001 From: Patrick Date: Sun, 12 May 2024 05:35:38 +0800 Subject: [PATCH 18/21] fix --- ghcide/test/exe/DiagnosticTests.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 9a8a29f7a1..22a4d9003a 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -218,9 +218,8 @@ tests = testGroup "diagnostics" ]) $ do _ <- createDoc "ModuleD.hs" "haskell" contentD expectDiagnostics - [ ( "ModuleB.hs" - , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")] - ) + [ ( "ModuleB.hs" , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")]) + , ( "ModuleA.hs" , [(DiagnosticSeverity_Error, (1, 7), "Cyclic module dependency between ModuleA, ModuleB")]) ] , testWithDummyPluginEmpty "cyclic module dependency with hs-boot" $ do let contentA = T.unlines From d08228daf7638391b60564790f52453c8388b669 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 13 May 2024 06:20:49 +0800 Subject: [PATCH 19/21] nitpick --- ghcide/test/exe/DiagnosticTests.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ghcide/test/exe/DiagnosticTests.hs b/ghcide/test/exe/DiagnosticTests.hs index 22a4d9003a..c0678aaf18 100644 --- a/ghcide/test/exe/DiagnosticTests.hs +++ b/ghcide/test/exe/DiagnosticTests.hs @@ -208,13 +208,13 @@ tests = testGroup "diagnostics" contentB = T.unlines [ "module ModuleB where" , "import ModuleA" ] contentC = T.unlines [ "module ModuleC where" , "import ModuleB" ] contentD = T.unlines [ "module ModuleD where" , "import ModuleC" ] - cradle = "cradle: {direct: {arguments: [ModuleA, ModuleB, ModuleC, ModuleD]}}" + cradle = directCradle ["ModuleA", "ModuleB", "ModuleC", "ModuleD"] in testWithDummyPlugin "deeply nested cyclic module dependency" (mkIdeTestFs [ file "ModuleA.hs" (text contentA) ,file "ModuleB.hs" (text contentB) ,file "ModuleC.hs" (text contentC) - ,file "hie.yaml" (text cradle) + ,cradle ]) $ do _ <- createDoc "ModuleD.hs" "haskell" contentD expectDiagnostics From 354854e06f7a8c2adffec3de0af0cd041a11ba5b Mon Sep 17 00:00:00 2001 From: soulomoon Date: Mon, 13 May 2024 06:21:33 +0800 Subject: [PATCH 20/21] Update hls-test-utils/src/Test/Hls.hs Co-authored-by: fendor --- hls-test-utils/src/Test/Hls.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index a87fec7294..78124bc048 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -327,7 +327,7 @@ mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- | Initialize a recorder that can be instructed to write to stderr by -- setting one of the environment variables: --- "HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR" +-- "HLS_TEST_HARNESS_STDERR=1", "HLS_TEST_LOG_STDERR=1" -- -- "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins -- under test. From 726a88d1b53d146ce3f9d66179f3f691bb0e7406 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 13 May 2024 06:23:35 +0800 Subject: [PATCH 21/21] add variable --- hls-test-utils/src/Test/Hls.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hls-test-utils/src/Test/Hls.hs b/hls-test-utils/src/Test/Hls.hs index 78124bc048..840ff6829e 100644 --- a/hls-test-utils/src/Test/Hls.hs +++ b/hls-test-utils/src/Test/Hls.hs @@ -327,11 +327,12 @@ mkPluginTestDescriptor' pluginDesc plId _recorder = IdePlugins [pluginDesc plId] -- | Initialize a recorder that can be instructed to write to stderr by -- setting one of the environment variables: --- "HLS_TEST_HARNESS_STDERR=1", "HLS_TEST_LOG_STDERR=1" +-- +-- * HLS_TEST_HARNESS_STDERR=1 +-- * HLS_TEST_LOG_STDERR=1 -- -- "HLS_TEST_LOG_STDERR" is intended to enable all logging for the server and the plugins -- under test. - hlsHelperTestRecorder :: Pretty a => IO (Recorder (WithPriority a)) hlsHelperTestRecorder = initializeTestRecorder ["HLS_TEST_HARNESS_STDERR", "HLS_TEST_LOG_STDERR"]