forked from haskell/haskell-language-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.hs
176 lines (162 loc) · 7.83 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
module Main
( main
) where
import Control.Lens (Prism', prism', (^.), (^..),
(^?))
import Control.Monad (void)
import Data.Maybe
import Data.Row ((.==))
import qualified Data.Text as T
import Development.IDE.Core.Compile (sourceTypecheck)
import qualified Ide.Plugin.Class as Class
import qualified Language.LSP.Protocol.Lens as L
import Language.LSP.Protocol.Message
import System.FilePath
import Test.Hls
main :: IO ()
main = defaultTestRunner tests
classPlugin :: PluginTestDescriptor Class.Log
classPlugin = mkPluginTestDescriptor Class.descriptor "class"
tests :: TestTree
tests = testGroup
"class"
[ codeActionTests
, codeLensTests
]
codeActionTests :: TestTree
codeActionTests = testGroup
"code actions"
[ expectCodeActionsAvailable "Produces addMinimalMethodPlaceholders code actions for one instance" "T1"
[ "Add placeholders for '=='"
, "Add placeholders for '==' with signature(s)"
, "Add placeholders for '/='"
, "Add placeholders for '/=' with signature(s)"
, "Add placeholders for all missing methods"
, "Add placeholders for all missing methods with signature(s)"
]
, goldenWithClass "Creates a placeholder for '=='" "T1" "eq" $ \(eqAction:_) -> do
executeCodeAction eqAction
, goldenWithClass "Creates a placeholder for '/='" "T1" "ne" $ \(_:_:neAction:_) -> do
executeCodeAction neAction
, goldenWithClass "Creates a placeholder for both '==' and '/='" "T1" "all" $ \(_:_:_:_:allMethodsAction:_) -> do
executeCodeAction allMethodsAction
, goldenWithClass "Creates a placeholder for 'fmap'" "T2" "fmap" $ \(_:_:_:_:_:_:fmapAction:_) -> do
executeCodeAction fmapAction
, goldenWithClass "Creates a placeholder for multiple methods 1" "T3" "1" $ \(mmAction:_) -> do
executeCodeAction mmAction
, goldenWithClass "Creates a placeholder for multiple methods 2" "T3" "2" $ \(_:_:mmAction:_) -> do
executeCodeAction mmAction
, goldenWithClass "Creates a placeholder for a method starting with '_'" "T4" "" $ \(_fAction:_) -> do
executeCodeAction _fAction
, goldenWithClass "Creates a placeholder for '==' with extra lines" "T5" "" $ \(eqAction:_) -> do
executeCodeAction eqAction
, goldenWithClass "Creates a placeholder for only the unimplemented methods of multiple methods" "T6" "1" $ \(gAction:_) -> do
executeCodeAction gAction
, goldenWithClass "Creates a placeholder for other two methods" "T6" "2" $ \(_:_:ghAction:_) -> do
executeCodeAction ghAction
, onlyRunForGhcVersions [GHC92, GHC94] "Only ghc-9.2+ enabled GHC2021 implicitly" $
goldenWithClass "Don't insert pragma with GHC2021" "InsertWithGHC2021Enabled" "" $ \(_:eqWithSig:_) -> do
executeCodeAction eqWithSig
, goldenWithClass "Insert pragma if not exist" "InsertWithoutPragma" "" $ \(_:eqWithSig:_) -> do
executeCodeAction eqWithSig
, goldenWithClass "Don't insert pragma if exist" "InsertWithPragma" "" $ \(_:eqWithSig:_) -> do
executeCodeAction eqWithSig
, goldenWithClass "Only insert pragma once" "InsertPragmaOnce" "" $ \(_:multi:_) -> do
executeCodeAction multi
, expectCodeActionsAvailable "No code action available when minimal requirements meet" "MinimalDefinitionMeet" []
, expectCodeActionsAvailable "Add placeholders for all missing methods is unavailable when all methods are required" "AllMethodsRequired"
[ "Add placeholders for 'f','g'"
, "Add placeholders for 'f','g' with signature(s)"
]
, testCase "Update text document version" $ runSessionWithServer classPlugin testDataDir $ do
doc <- createDoc "Version.hs" "haskell" "module Version where"
ver1 <- (^. L.version) <$> getVersionedDoc doc
liftIO $ ver1 @?= 0
-- Change the doc to ensure the version is not 0
changeDoc doc
[ TextDocumentContentChangeEvent . InR . (.==) #text $
T.unlines ["module Version where", "data A a = A a", "instance Functor A where"]
]
ver2 <- (^. L.version) <$> getVersionedDoc doc
_ <- waitForDiagnostics
liftIO $ ver2 @?= 1
-- Execute the action and see what the version is
action <- head . concatMap (^.. _CACodeAction) <$> getAllCodeActions doc
executeCodeAction action
_ <- waitForDiagnostics
-- TODO: uncomment this after lsp-test fixed
-- ver3 <- (^.J.version) <$> getVersionedDoc doc
-- liftIO $ ver3 @?= Just 3
pure mempty
]
codeLensTests :: TestTree
codeLensTests = testGroup
"code lens"
[ testCase "Has code lens" $ do
runSessionWithServer classPlugin testDataDir $ do
doc <- openDoc "CodeLensSimple.hs" "haskell"
lens <- getCodeLenses doc
let titles = map (^. L.title) $ mapMaybe (^. L.command) lens
liftIO $ titles @?=
[ "(==) :: B -> B -> Bool"
, "(==) :: A -> A -> Bool"
]
, testCase "No lens for TH" $ do
runSessionWithServer classPlugin testDataDir $ do
doc <- openDoc "TH.hs" "haskell"
lens <- getCodeLenses doc
liftIO $ length lens @?= 0
, goldenCodeLens "Apply code lens" "CodeLensSimple" 1
, goldenCodeLens "Apply code lens for local class" "LocalClassDefine" 0
, goldenCodeLens "Apply code lens on the same line" "Inline" 0
, goldenCodeLens "Don't insert pragma while existing" "CodeLensWithPragma" 0
, onlyRunForGhcVersions [GHC92, GHC94] "Only ghc-9.2+ enabled GHC2021 implicitly" $
goldenCodeLens "Don't insert pragma while GHC2021 enabled" "CodeLensWithGHC2021" 0
, goldenCodeLens "Qualified name" "Qualified" 0
, goldenCodeLens "Type family" "TypeFamily" 0
, testCase "keep stale lens" $ do
runSessionWithServer classPlugin testDataDir $ do
doc <- openDoc "Stale.hs" "haskell"
oldLens <- getCodeLenses doc
let edit = TextEdit (mkRange 4 11 4 12) "" -- Remove the `_`
_ <- applyEdit doc edit
newLens <- getCodeLenses doc
liftIO $ newLens @?= oldLens
]
_CACodeAction :: Prism' (Command |? CodeAction) CodeAction
_CACodeAction = prism' InR $ \case
InR action -> Just action
_ -> Nothing
goldenCodeLens :: TestName -> FilePath -> Int -> TestTree
goldenCodeLens title path idx =
goldenWithHaskellDoc classPlugin title testDataDir path "expected" "hs" $ \doc -> do
lens <- getCodeLenses doc
executeCommand $ fromJust $ (lens !! idx) ^. L.command
void $ skipManyTill anyMessage (message SMethod_WorkspaceApplyEdit)
goldenWithClass ::TestName -> FilePath -> FilePath -> ([CodeAction] -> Session ()) -> TestTree
goldenWithClass title path desc act =
goldenWithHaskellDoc classPlugin title testDataDir path (desc <.> "expected") "hs" $ \doc -> do
_ <- waitForDiagnosticsFromSource doc (T.unpack sourceTypecheck)
actions <- concatMap (^.. _CACodeAction) <$> getAllCodeActions doc
act actions
void $ skipManyTill anyMessage (getDocumentEdit doc)
expectCodeActionsAvailable :: TestName -> FilePath -> [T.Text] -> TestTree
expectCodeActionsAvailable title path actionTitles =
testCase title $ do
runSessionWithServer classPlugin testDataDir $ do
doc <- openDoc (path <.> "hs") "haskell"
_ <- waitForDiagnosticsFromSource doc (T.unpack sourceTypecheck)
caResults <- getAllCodeActions doc
liftIO $ map (^? _CACodeAction . L.title) caResults
@?= expectedActions
where
expectedActions = Just <$> actionTitles
testDataDir :: FilePath
testDataDir = "test" </> "testdata"