@@ -16,10 +16,13 @@ module Test.Hls
1616 defaultTestRunner ,
1717 goldenGitDiff ,
1818 goldenWithHaskellDoc ,
19+ goldenWithHaskellDocAndRecorder ,
1920 goldenWithHaskellDocFormatter ,
2021 goldenWithCabalDocFormatter ,
2122 def ,
23+ pluginTestRecorder ,
2224 runSessionWithServer ,
25+ runSessionWithServerAndRecorder ,
2326 runSessionWithServerFormatter ,
2427 runSessionWithCabalServerFormatter ,
2528 runSessionWithServer' ,
@@ -34,6 +37,11 @@ module Test.Hls
3437 getLastBuildKeys ,
3538 waitForKickDone ,
3639 waitForKickStart ,
40+ -- * Re-export logger types
41+ -- Avoids slightly annoying ghcide imports when they are unnecessary.
42+ WithPriority (.. ),
43+ Recorder ,
44+ Priority (.. ),
3745 )
3846where
3947
@@ -98,6 +106,8 @@ import Test.Tasty.Golden
98106import Test.Tasty.HUnit
99107import Test.Tasty.Ingredients.Rerun
100108import Test.Tasty.Runners (NumThreads (.. ))
109+ import Control.Monad.Extra (forM )
110+ import Development.IDE.Types.Logger (Doc )
101111
102112newtype Log = LogIDEMain IDEMain. Log
103113
@@ -134,10 +144,34 @@ goldenWithHaskellDoc plugin title testDataDir path desc ext act =
134144 act doc
135145 documentContents doc
136146
147+ goldenWithHaskellDocAndRecorder
148+ :: Pretty a
149+ => (Recorder (WithPriority a ) -> PluginDescriptor IdeState )
150+ -> TestName
151+ -> FilePath
152+ -> FilePath
153+ -> FilePath
154+ -> FilePath
155+ -> (TextDocumentIdentifier -> Session () )
156+ -> TestTree
157+ goldenWithHaskellDocAndRecorder plugin title testDataDir path desc ext act =
158+ goldenGitDiff title (testDataDir </> path <.> desc <.> ext)
159+ $ runSessionWithServerAndRecorder plugin testDataDir
160+ $ TL. encodeUtf8 . TL. fromStrict
161+ <$> do
162+ doc <- openDoc (path <.> ext) " haskell"
163+ void waitForBuildQueue
164+ act doc
165+ documentContents doc
137166
138167runSessionWithServer :: PluginDescriptor IdeState -> FilePath -> Session a -> IO a
139168runSessionWithServer plugin = runSessionWithServer' [plugin] def def fullCaps
140169
170+ runSessionWithServerAndRecorder :: Pretty b => (Recorder (WithPriority b ) -> PluginDescriptor IdeState ) -> FilePath -> Session a -> IO a
171+ runSessionWithServerAndRecorder pluginF fp act = do
172+ recorder <- pluginTestRecorder
173+ runSessionWithServer' [pluginF recorder] def def fullCaps fp act
174+
141175runSessionWithServerFormatter :: PluginDescriptor IdeState -> String -> PluginConfig -> FilePath -> Session a -> IO a
142176runSessionWithServerFormatter plugin formatter conf =
143177 runSessionWithServer'
@@ -211,6 +245,46 @@ keepCurrentDirectory = bracket getCurrentDirectory setCurrentDirectory . const
211245lock :: Lock
212246lock = unsafePerformIO newLock
213247
248+ -- | Initialise a recorder that can be instructed to write to stderr by
249+ -- setting the environment variable "HLS_TEST_PLUGIN_LOG_STDERR=1" before
250+ -- running the tests.
251+ --
252+ -- On the cli, use for example:
253+ --
254+ -- @
255+ -- HLS_TEST_PLUGIN_LOG_STDERR=1 cabal test <test-suite-of-plugin>
256+ -- @
257+ --
258+ -- to write all logs to stderr.
259+ pluginTestRecorder :: Pretty a => IO (Recorder (WithPriority a ))
260+ pluginTestRecorder = do
261+ (recorder, _) <- initialiseTestRecorder [" HLS_TEST_PLUGIN_LOG_STDERR" ]
262+ pure recorder
263+
264+ -- | Generic recorder initialisation for plugins and the HLS server for test-cases.
265+ --
266+ -- The created recorder writes to stderr if any of the given environment variables
267+ -- have been set to a value different to @0@.
268+ -- We allow multiple values, to make it possible to define a single environment variable
269+ -- that instructs all recorders in the test-suite to write to stderr.
270+ --
271+ -- We have to return the base logger function for HLS server logging initialisation.
272+ -- See 'runSessionWithServer'' for details.
273+ initialiseTestRecorder :: Pretty a => [String ] -> IO (Recorder (WithPriority a ), WithPriority (Doc ann ) -> IO () )
274+ initialiseTestRecorder envVars = do
275+ docWithPriorityRecorder <- makeDefaultStderrRecorder Nothing Debug
276+ -- There are potentially multiple environment variables that enable this logger
277+ definedEnvVars <- forM envVars (\ var -> fromMaybe " 0" <$> lookupEnv var)
278+ let logStdErr = any (/= " 0" ) definedEnvVars
279+
280+ docWithFilteredPriorityRecorder =
281+ if logStdErr then mempty
282+ else cfilter (\ WithPriority { priority } -> priority >= Debug ) docWithPriorityRecorder
283+
284+ Recorder {logger_} = docWithFilteredPriorityRecorder
285+
286+ pure (cmapWithPrio pretty docWithFilteredPriorityRecorder, logger_)
287+
214288
215289-- | Host a server, and run a test session on it
216290-- Note: cwd will be shifted into @root@ in @Session a@
@@ -229,20 +303,16 @@ runSessionWithServer' plugins conf sconf caps root s = withLock lock $ keepCurre
229303 (inR, inW) <- createPipe
230304 (outR, outW) <- createPipe
231305
232- docWithPriorityRecorder <- makeDefaultStderrRecorder Nothing Debug
233-
234- logStdErr <- fromMaybe " 0" <$> lookupEnv " LSP_TEST_LOG_STDERR"
306+ -- Allow two environment variables, because "LSP_TEST_LOG_STDERR" has been used before,
307+ -- (thus, backwards compatibility) and "HLS_TEST_SERVER_LOG_STDERR" because it
308+ -- uses a more descriptive name.
309+ -- It is also in better accordance with 'pluginTestRecorder' which uses "HLS_TEST_PLUGIN_LOG_STDERR"
310+ (recorder, logger_) <- initialiseTestRecorder [" LSP_TEST_LOG_STDERR" , " HLS_TEST_SERVER_LOG_STDERR" ]
235311
236312 let
237- docWithFilteredPriorityRecorder@ Recorder { logger_ } =
238- if logStdErr == " 0" then mempty
239- else cfilter (\ WithPriority { priority } -> priority >= Debug ) docWithPriorityRecorder
240-
241313 -- exists until old logging style is phased out
242314 logger = Logger $ \ p m -> logger_ (WithPriority p emptyCallStack (pretty m))
243315
244- recorder = cmapWithPrio pretty docWithFilteredPriorityRecorder
245-
246316 arguments@ Arguments { argsHlsPlugins, argsIdeOptions, argsLogger } = defaultArguments (cmapWithPrio LogIDEMain recorder) logger
247317
248318 hlsPlugins =
0 commit comments