Skip to content

Commit 33cf5b2

Browse files
committed
[experiment] bring lsp-test
1 parent 28c39d0 commit 33cf5b2

File tree

33 files changed

+3590
-0
lines changed

33 files changed

+3590
-0
lines changed

cabal.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ packages:
33
./hie-compat
44
./shake-bench
55
./ghcide
6+
./lsp-test
67
./hls-plugin-api
78
./hls-test-utils
89
./plugins/hls-tactics-plugin

lsp-test/ChangeLog.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Revision history for lsp-test
2+
3+
## 0.13.0.0 -- 2021-03-26
4+
5+
* Update for lsp-types-1.2 (@wz1000)
6+
* Limit diagnostics by range in getCodeActions (@aufarg)
7+
* Kill timeout thread to avoid building up thousands of old TimeoutMessages (@wz1000)
8+
9+
## 0.13.0.0 -- 2021-02-14
10+
11+
* Add support for lsp-types-1.1 (@wz1000)
12+
* Automatically respond to `workspace/applyEdit` and
13+
`window/workDoneProgress/create` messages (@wz1000)
14+
15+
## 0.12.0.0 -- 2021-01-25
16+
* Add `getIncompleteProgressSessions` to track ongoing progress sessions
17+
(@wz1000)
18+
19+
## 0.11.0.0 -- 2020-05-14
20+
21+
* Replace `openDoc'` with `createDoc` which now sends
22+
`workspace/didChangeWatchedFiles` notifications if the server has registered
23+
for it
24+
* Add `getRegisteredCapabilities`
25+
26+
## 0.10.3.0 -- 2020-05-04
27+
28+
* Build with new haskell-lsp-0.22
29+
30+
## 0.10.2.0 -- 2020-03-21
31+
32+
* Bump constraints for new haskell-lsp
33+
34+
## 0.10.1.0 -- 2020-02-04
35+
36+
* Bump constraints for new haskell-lsp
37+
38+
## 0.10.0.0 -- 2019-12-29
39+
40+
* Account for messages received between the initialize request and response.
41+
(Though it will throw an exception if the message received is an illegal one)
42+
43+
## 0.9.0.0 -- 2019-12-1
44+
45+
* Add `ignoreLogNotifications` config option
46+
* Add ability to override `logStdErr` and `logMessages` config options with
47+
the `LSP_TEST_LOG_STDERR` and `LOG_TEST_LOG_MESSAGES` environment variables
48+
* Update for haskell-lsp-0.19.0.0 (@mpickering)
49+
50+
## 0.8.2.0 -- 2019-11-17
51+
52+
* Expose `satisfyMaybe` (@cocreature)
53+
54+
## 0.8.1.0 -- 2019-11-17
55+
56+
* Update to haskell-lsp-0.18.0.0 (@mpickering, @alanz)
57+
* Tests now require hie-bios based hie
58+
59+
## 0.8.0.0 -- 2019-10-18
60+
61+
* Make `Session` a newtype
62+
* Update for haskell-lsp-0.17.0.0 (@cocreature)
63+
64+
## 0.7.0.0 -- 2019-09-08
65+
66+
* Update for haskell-lsp-0.16.0.0
67+
68+
## 0.6.1.0 -- 2019-08-24
69+
70+
* Add `satisfyMaybe` (@cocreature)
71+
72+
## 0.6.0.0 -- 2019-07-04
73+
74+
* Update to haskell-lsp-0.15.0.0 (@lorenzo)
75+
76+
## 0.5.4.0 -- 2019-06-13
77+
78+
* Fix `getDefinitions` for SingleLoc (@cocreature)
79+
* Add `getCodeLenses` (@cocreature)
80+
81+
## 0.5.3.0 -- 2019-06-13
82+
83+
* Update to haskell-lsp-0.14.0.0 (@cocreature)
84+
* Support `TextDocumentDidChange` (@cocreature)
85+
* Add non-file based `openDoc` (@cocreature)
86+
87+
## 0.5.2.0 -- 2019-04-28
88+
89+
* Add `satisfy` parser combinator
90+
91+
## 0.5.1.0 -- 2019-04-22
92+
93+
* Fix unhandled `window/progress` server notifications
94+
95+
## 0.5.1.0 -- 2019-04-07
96+
97+
* Add getTypeDefinitions (@fendor)
98+
99+
## 0.5.0.2 -- 2018-12-05
100+
101+
* Fix loose threads when exceptions are thrown
102+
103+
## 0.5.0.0 -- 2018-11-13
104+
105+
* Add lspConfig option in config
106+
* GHC 8.6.2 support
107+
108+
## 0.4.0.0 -- 2018-09-08
109+
110+
* Update to haskell-lsp-0.8.0.0
111+
112+
## 0.3.0.0 -- 2018-09-0t
113+
114+
* Update to haskell-lsp-0.7.0.0
115+
116+
## 0.2.1.0 -- 2018-08-14
117+
118+
* Add getCodeActions
119+
* Add getCurrentDiagnostics
120+
121+
## 0.2.0.0 -- 2018-08-06
122+
123+
* Update to haskell-lsp 0.6.0.0

lsp-test/LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Copyright Luke Lau 2018-2020.
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above
11+
copyright notice, this list of conditions and the following
12+
disclaimer in the documentation and/or other materials provided
13+
with the distribution.
14+
15+
* Neither the name of Luke Lau nor the names of other
16+
contributors may be used to endorse or promote products derived
17+
from this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

lsp-test/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# lsp-test
2+
3+
lsp-test is a functional testing framework for Language Server Protocol servers.
4+
5+
It is part of the [lsp](https://github.com/haskell/lsp) family of
6+
packages, along with [lsp](https://hackage.haskell.org/package/lsp)
7+
and [lsp-types](https://hackage.haskell.org/package/lsp-types)
8+
9+
```haskell
10+
import Language.LSP.Test
11+
main = runSession "hie" fullCaps "proj/dir" $ do
12+
doc <- openDoc "Foo.hs" "haskell"
13+
skipMany anyNotification
14+
symbols <- getDocumentSymbols doc
15+
```
16+
17+
## Examples
18+
19+
### Unit tests with HSpec
20+
```haskell
21+
describe "diagnostics" $
22+
it "report errors" $ runSession "hie" fullCaps "test/data" $ do
23+
openDoc "Error.hs" "haskell"
24+
[diag] <- waitForDiagnosticsSource "ghcmod"
25+
liftIO $ do
26+
diag ^. severity `shouldBe` Just DsError
27+
diag ^. source `shouldBe` Just "ghcmod"
28+
```
29+
30+
### Replaying captured session
31+
```haskell
32+
replaySession "hie" "test/data/renamePass"
33+
```
34+
35+
### Parsing with combinators
36+
```haskell
37+
skipManyTill loggingNotification publishDiagnosticsNotification
38+
count 4 (message :: Session ApplyWorkspaceEditRequest)
39+
anyRequest <|> anyResponse
40+
```
41+
42+
Try out the example tests in the `example` directory with `cabal test`.
43+
For more examples see this [introductory blog post](https://lukelau.me/haskell/posts/lsp-test/).
44+
45+
Whilst writing your tests you may want to debug them to see what's going wrong.
46+
You can set the `logMessages` and `logStdErr` options in `SessionConfig` to see what the server is up to.
47+
There are also corresponding environment variables so you can turn them on from the command line:
48+
```
49+
LSP_TEST_LOG_MESSAGES=1 LSP_TEST_LOG_STDERR=1 cabal test
50+
```
51+
52+
## Developing
53+
The tests for lsp-test use a dummy server found in `test/dummy-server/`.
54+
Run the tests with `cabal test` or `stack test`.
55+
Tip: If you want to filter the tests, use `cabal run test:tests -- -m "foo"`
56+
57+
## Troubleshooting
58+
Seeing funny stuff when running lsp-test via stack? If your server is built upon Haskell tooling, [keep in mind that stack sets some environment variables related to GHC, and you may want to unset them.](https://github.com/alanz/haskell-ide-engine/blob/bfb16324d396da71000ef81d51acbebbdaa854ab/test/utils/TestUtils.hs#L290-L298)

lsp-test/bench/SimpleBench.hs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{-# LANGUAGE RankNTypes #-}
2+
{-# LANGUAGE GADTs, OverloadedStrings #-}
3+
module Main where
4+
5+
import Language.LSP.Server
6+
import qualified Language.LSP.Test as Test
7+
import Language.LSP.Types
8+
import Control.Monad.IO.Class
9+
import Control.Monad
10+
import System.Process
11+
import System.Environment
12+
import System.Time.Extra
13+
import Control.Concurrent
14+
import Data.IORef
15+
16+
handlers :: Handlers (LspM ())
17+
handlers = mconcat
18+
[ requestHandler STextDocumentHover $ \req responder -> do
19+
let RequestMessage _ _ _ (HoverParams _doc pos _workDone) = req
20+
Position _l _c' = pos
21+
rsp = Hover ms (Just range)
22+
ms = HoverContents $ markedUpContent "lsp-demo-simple-server" "Hello world"
23+
range = Range pos pos
24+
responder (Right $ Just rsp)
25+
, requestHandler STextDocumentDefinition $ \req responder -> do
26+
let RequestMessage _ _ _ (DefinitionParams (TextDocumentIdentifier doc) pos _ _) = req
27+
responder (Right $ InL $ Location doc $ Range pos pos)
28+
]
29+
30+
server :: ServerDefinition ()
31+
server = ServerDefinition
32+
{ onConfigurationChange = const $ const $ Right ()
33+
, defaultConfig = ()
34+
, doInitialize = \env _req -> pure $ Right env
35+
, staticHandlers = handlers
36+
, interpretHandler = \env -> Iso (runLspT env) liftIO
37+
, options = defaultOptions
38+
}
39+
40+
main :: IO ()
41+
main = do
42+
(hinRead, hinWrite) <- createPipe
43+
(houtRead, houtWrite) <- createPipe
44+
45+
n <- read . head <$> getArgs
46+
47+
forkIO $ void $ runServerWithHandles hinRead houtWrite server
48+
liftIO $ putStrLn $ "Starting " <> show n <> " rounds"
49+
50+
i <- newIORef 0
51+
52+
Test.runSessionWithHandles hinWrite houtRead Test.defaultConfig Test.fullCaps "." $ do
53+
start <- liftIO offsetTime
54+
replicateM_ n $ do
55+
n <- liftIO $ readIORef i
56+
liftIO $ when (n `mod` 1000 == 0) $ putStrLn $ show n
57+
ResponseMessage{_result=Right (Just _)} <- Test.request STextDocumentHover $
58+
HoverParams (TextDocumentIdentifier $ Uri "test") (Position 1 100) Nothing
59+
ResponseMessage{_result=Right (InL _)} <- Test.request STextDocumentDefinition $
60+
DefinitionParams (TextDocumentIdentifier $ Uri "test") (Position 1000 100) Nothing Nothing
61+
62+
liftIO $ modifyIORef' i (+1)
63+
pure ()
64+
end <- liftIO start
65+
liftIO $ putStrLn $ "Completed " <> show n <> " rounds in " <> showDuration end
66+

lsp-test/example/Test.hs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
import Control.Applicative.Combinators
3+
import Control.Monad.IO.Class
4+
import Language.LSP.Test
5+
import Language.LSP.Types
6+
7+
main = runSession "lsp-demo-reactor-server" fullCaps "test/data/" $ do
8+
doc <- openDoc "Rename.hs" "haskell"
9+
10+
-- Use your favourite favourite combinators.
11+
skipManyTill loggingNotification (count 1 publishDiagnosticsNotification)
12+
13+
-- Send requests and notifications and receive responses
14+
rsp <- request STextDocumentDocumentSymbol $
15+
DocumentSymbolParams Nothing Nothing doc
16+
liftIO $ print rsp
17+
18+
-- Or use one of the helper functions
19+
getDocumentSymbols doc >>= liftIO . print
20+

0 commit comments

Comments
 (0)