Skip to content

Commit 2186df0

Browse files
authored
Merge pull request #152 from Ailrun/introduce-golden-testing
Introduce golden testing
2 parents 84b0073 + 34eb232 commit 2186df0

16 files changed

+161
-125
lines changed

Diff for: haskell-language-server.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ test-suite func-test
246246
, ghcide:ghcide-test-preprocessor
247247
build-depends: base >=4.7 && <5
248248
, aeson
249+
, bytestring
249250
, data-default
250251
, directory
251252
, filepath
@@ -258,6 +259,7 @@ test-suite func-test
258259
, tasty
259260
, tasty-ant-xml >= 1.1.6
260261
, tasty-expected-failure
262+
, tasty-golden
261263
, tasty-hunit
262264
, tasty-rerun
263265
, text

Diff for: test/functional/Format.hs

+40-125
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,28 @@ module Format (tests) where
33

44
import Control.Monad.IO.Class
55
import Data.Aeson
6+
import qualified Data.ByteString.Lazy as BS
67
import qualified Data.Text as T
8+
import qualified Data.Text.Encoding as T
79
import Language.Haskell.LSP.Test
810
import Language.Haskell.LSP.Types
911
import Test.Hls.Util
1012
import Test.Tasty
1113
import Test.Tasty.ExpectedFailure (ignoreTestBecause)
14+
import Test.Tasty.Golden
1215
import Test.Tasty.HUnit
1316
import Test.Hspec.Expectations
1417

1518
tests :: TestTree
1619
tests = testGroup "format document" [
17-
ignoreTestBecause "Broken" $ testCase "works" $ runSession hieCommand fullCaps "test/testdata" $ do
20+
goldenVsStringDiff "works" goldenGitDiff "test/testdata/Format.formatted_document.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
1821
doc <- openDoc "Format.hs" "haskell"
1922
formatDoc doc (FormattingOptions 2 True)
20-
documentContents doc >>= liftIO . (`shouldBe` formattedDocTabSize2)
21-
, ignoreTestBecause "Broken" $ testCase "works with custom tab size" $ runSession hieCommand fullCaps "test/testdata" $ do
23+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
24+
, goldenVsStringDiff "works with custom tab size" goldenGitDiff "test/testdata/Format.formatted_document_with_tabsize.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
2225
doc <- openDoc "Format.hs" "haskell"
2326
formatDoc doc (FormattingOptions 5 True)
24-
documentContents doc >>= liftIO . (`shouldBe` formattedDocTabSize5)
27+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
2528
, rangeTests
2629
, providerTests
2730
, stylishHaskellTests
@@ -31,14 +34,14 @@ tests = testGroup "format document" [
3134

3235
rangeTests :: TestTree
3336
rangeTests = testGroup "format range" [
34-
ignoreTestBecause "Broken" $ testCase "works" $ runSession hieCommand fullCaps "test/testdata" $ do
37+
goldenVsStringDiff "works" goldenGitDiff "test/testdata/Format.formatted_range.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
3538
doc <- openDoc "Format.hs" "haskell"
3639
formatRange doc (FormattingOptions 2 True) (Range (Position 1 0) (Position 3 10))
37-
documentContents doc >>= liftIO . (`shouldBe` formattedRangeTabSize2)
38-
, ignoreTestBecause "Broken" $ testCase "works with custom tab size" $ runSession hieCommand fullCaps "test/testdata" $ do
40+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
41+
, goldenVsStringDiff "works with custom tab size" goldenGitDiff "test/testdata/Format.formatted_range_with_tabsize.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
3942
doc <- openDoc "Format.hs" "haskell"
4043
formatRange doc (FormattingOptions 5 True) (Range (Position 4 0) (Position 7 19))
41-
documentContents doc >>= liftIO . (`shouldBe` formattedRangeTabSize5)
44+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
4245
]
4346

4447
providerTests :: TestTree
@@ -58,7 +61,7 @@ providerTests = testGroup "formatting provider" [
5861

5962
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "brittany"))
6063
formatDoc doc (FormattingOptions 2 True)
61-
documentContents doc >>= liftIO . (`shouldBe` formattedDocTabSize2)
64+
documentContents doc >>= liftIO . (`shouldBe` formattedBrittany)
6265

6366
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "floskell"))
6467
formatDoc doc (FormattingOptions 2 True)
@@ -71,84 +74,58 @@ providerTests = testGroup "formatting provider" [
7174

7275
stylishHaskellTests :: TestTree
7376
stylishHaskellTests = testGroup "stylish-haskell" [
74-
testCase "formats a file" $ runSession hieCommand fullCaps "test/testdata" $ do
77+
goldenVsStringDiff "formats a document" goldenGitDiff "test/testdata/StylishHaksell.formatted_document.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
7578
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell"))
7679
doc <- openDoc "StylishHaskell.hs" "haskell"
7780
formatDoc doc (FormattingOptions 2 True)
78-
contents <- documentContents doc
79-
liftIO $ contents `shouldBe`
80-
"import Data.Char\n\
81-
\import qualified Data.List\n\
82-
\import Data.String\n\
83-
\\n\
84-
\bar :: Maybe (Either String Integer) -> Integer\n\
85-
\bar Nothing = 0\n\
86-
\bar (Just (Left _)) = 0\n\
87-
\bar (Just (Right x)) = x\n"
88-
, testCase "formats a range" $ runSession hieCommand fullCaps "test/testdata" $ do
81+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
82+
, goldenVsStringDiff "formats a range" goldenGitDiff "test/testdata/StylishHaksell.formatted_range.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
8983
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "stylish-haskell"))
9084
doc <- openDoc "StylishHaskell.hs" "haskell"
9185
formatRange doc (FormattingOptions 2 True) (Range (Position 0 0) (Position 2 21))
92-
contents <- documentContents doc
93-
liftIO $ contents `shouldBe`
94-
"import Data.Char\n\
95-
\import qualified Data.List\n\
96-
\import Data.String\n\
97-
\\n\
98-
\bar :: Maybe (Either String Integer) -> Integer\n\
99-
\bar Nothing = 0\n\
100-
\bar (Just (Left _)) = 0\n\
101-
\bar (Just (Right x)) = x\n"
86+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
10287
]
10388

10489
brittanyTests :: TestTree
10590
brittanyTests = testGroup "brittany" [
106-
ignoreTestBecause "Broken" $ testCase "formats a document with LF endings" $ runSession hieCommand fullCaps "test/testdata" $ do
91+
goldenVsStringDiff "formats a document with LF endings" goldenGitDiff "test/testdata/BrittanyLF.formatted_document.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
10792
doc <- openDoc "BrittanyLF.hs" "haskell"
108-
let opts = DocumentFormattingParams doc (FormattingOptions 4 True) Nothing
109-
ResponseMessage _ _ (Right edits) <- request TextDocumentFormatting opts
110-
liftIO $ edits `shouldBe` [TextEdit (Range (Position 0 0) (Position 3 0))
111-
"foo :: Int -> String -> IO ()\nfoo x y = do\n print x\n return 42\n"]
93+
formatDoc doc (FormattingOptions 4 True)
94+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
11295

113-
, ignoreTestBecause "Broken" $ testCase "formats a document with CRLF endings" $ runSession hieCommand fullCaps "test/testdata" $ do
96+
, goldenVsStringDiff "formats a document with CRLF endings" goldenGitDiff "test/testdata/BrittanyCRLF.formatted_document.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
11497
doc <- openDoc "BrittanyCRLF.hs" "haskell"
115-
let opts = DocumentFormattingParams doc (FormattingOptions 4 True) Nothing
116-
ResponseMessage _ _ (Right edits) <- request TextDocumentFormatting opts
117-
liftIO $ edits `shouldBe` [TextEdit (Range (Position 0 0) (Position 3 0))
118-
"foo :: Int -> String -> IO ()\nfoo x y = do\n print x\n return 42\n"]
98+
formatDoc doc (FormattingOptions 4 True)
99+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
119100

120-
, ignoreTestBecause "Broken" $ testCase "formats a range with LF endings" $ runSession hieCommand fullCaps "test/testdata" $ do
101+
, goldenVsStringDiff "formats a range with LF endings" goldenGitDiff "test/testdata/BrittanyLF.formatted_range.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
121102
doc <- openDoc "BrittanyLF.hs" "haskell"
122103
let range = Range (Position 1 0) (Position 2 22)
123-
opts = DocumentRangeFormattingParams doc range (FormattingOptions 4 True) Nothing
124-
ResponseMessage _ _ (Right edits) <- request TextDocumentRangeFormatting opts
125-
liftIO $ edits `shouldBe` [TextEdit (Range (Position 1 0) (Position 3 0))
126-
"foo x y = do\n print x\n return 42\n"]
104+
formatRange doc (FormattingOptions 4 True) range
105+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
127106

128-
, ignoreTestBecause "Broken" $ testCase "formats a range with CRLF endings" $ runSession hieCommand fullCaps "test/testdata" $ do
107+
, goldenVsStringDiff "formats a range with CRLF endings" goldenGitDiff "test/testdata/BrittanyCRLF.formatted_range.hs" $ runSession hieCommand fullCaps "test/testdata" $ do
129108
doc <- openDoc "BrittanyCRLF.hs" "haskell"
130109
let range = Range (Position 1 0) (Position 2 22)
131-
opts = DocumentRangeFormattingParams doc range (FormattingOptions 4 True) Nothing
132-
ResponseMessage _ _ (Right edits) <- request TextDocumentRangeFormatting opts
133-
liftIO $ edits `shouldBe` [TextEdit (Range (Position 1 0) (Position 3 0))
134-
"foo x y = do\n print x\n return 42\n"]
110+
formatRange doc (FormattingOptions 4 True) range
111+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
135112
]
136113

137114
ormoluTests :: TestTree
138115
ormoluTests = testGroup "ormolu" [
139-
ignoreTestBecause "Broken" $ testCase "formats correctly" $ runSession hieCommand fullCaps "test/testdata" $ do
116+
goldenVsStringDiff "formats correctly" goldenGitDiff ("test/testdata/Format.ormolu." ++ ormoluGoldenSuffix ++ ".hs") $ runSession hieCommand fullCaps "test/testdata" $ do
140117
let formatLspConfig provider =
141118
object [ "languageServerHaskell" .= object ["formattingProvider" .= (provider :: Value)] ]
142119
sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams (formatLspConfig "ormolu"))
143120
doc <- openDoc "Format.hs" "haskell"
144121
formatDoc doc (FormattingOptions 2 True)
145-
docContent <- documentContents doc
146-
let formatted = liftIO $ docContent `shouldBe` formattedOrmolu
147-
case ghcVersion of
148-
GHC88 -> formatted
149-
GHC86 -> formatted
150-
_ -> liftIO $ docContent `shouldBe` unchangedOrmolu
122+
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
151123
]
124+
where
125+
ormoluGoldenSuffix = case ghcVersion of
126+
GHC88 -> "formatted"
127+
GHC86 -> "formatted"
128+
_ -> "unchanged"
152129

153130

154131
formatLspConfig :: Value -> Value
@@ -157,9 +134,12 @@ formatLspConfig provider = object [ "languageServerHaskell" .= object ["formatti
157134
formatConfig :: Value -> SessionConfig
158135
formatConfig provider = defaultConfig { lspConfig = Just (formatLspConfig provider) }
159136

137+
goldenGitDiff :: FilePath -> FilePath -> [String]
138+
goldenGitDiff fRef fNew = ["git", "diff", "--no-index", "--text", "--exit-code", fRef, fNew]
160139

161-
formattedDocTabSize2 :: T.Text
162-
formattedDocTabSize2 =
140+
141+
formattedBrittany :: T.Text
142+
formattedBrittany =
163143
"module Format where\n\
164144
\foo :: Int -> Int\n\
165145
\foo 3 = 2\n\
@@ -170,44 +150,6 @@ formattedDocTabSize2 =
170150
\ return \"asdf\"\n\n\
171151
\data Baz = Baz { a :: Int, b :: String }\n\n"
172152

173-
formattedDocTabSize5 :: T.Text
174-
formattedDocTabSize5 =
175-
"module Format where\n\
176-
\foo :: Int -> Int\n\
177-
\foo 3 = 2\n\
178-
\foo x = x\n\
179-
\bar :: String -> IO String\n\
180-
\bar s = do\n\
181-
\ x <- return \"hello\"\n\
182-
\ return \"asdf\"\n\n\
183-
\data Baz = Baz { a :: Int, b :: String }\n\n"
184-
185-
formattedRangeTabSize2 :: T.Text
186-
formattedRangeTabSize2 =
187-
"module Format where\n\
188-
\foo :: Int -> Int\n\
189-
\foo 3 = 2\n\
190-
\foo x = x\n\
191-
\bar :: String -> IO String\n\
192-
\bar s = do\n\
193-
\ x <- return \"hello\"\n\
194-
\ return \"asdf\"\n\
195-
\\n\
196-
\data Baz = Baz { a :: Int, b :: String }\n\n"
197-
198-
formattedRangeTabSize5 :: T.Text
199-
formattedRangeTabSize5 =
200-
"module Format where\n\
201-
\foo :: Int -> Int\n\
202-
\foo 3 = 2\n\
203-
\foo x = x\n\
204-
\bar :: String -> IO String\n\
205-
\bar s = do\n\
206-
\ x <- return \"hello\"\n\
207-
\ return \"asdf\"\n\
208-
\\n\
209-
\data Baz = Baz { a :: Int, b :: String }\n\n"
210-
211153
formattedFloskell :: T.Text
212154
formattedFloskell =
213155
"module Format where\n\
@@ -235,30 +177,3 @@ formattedBrittanyPostFloskell =
235177
\ x <- return \"hello\"\n\
236178
\ return \"asdf\"\n\n\
237179
\data Baz = Baz { a :: Int, b :: String }\n\n"
238-
239-
formattedOrmolu :: T.Text
240-
formattedOrmolu =
241-
"module Format where\n\
242-
\\n\
243-
\foo :: Int -> Int\n\
244-
\foo 3 = 2\n\
245-
\foo x = x\n\
246-
\\n\
247-
\bar :: String -> IO String\n\
248-
\bar s = do\n\
249-
\ x <- return \"hello\"\n\
250-
\ return \"asdf\"\n\n\
251-
\data Baz = Baz {a :: Int, b :: String}\n"
252-
253-
unchangedOrmolu :: T.Text
254-
unchangedOrmolu =
255-
"module Format where\n\
256-
\foo :: Int -> Int\n\
257-
\foo 3 = 2\n\
258-
\foo x = x\n\
259-
\bar :: String -> IO String\n\
260-
\bar s = do\n\
261-
\ x <- return \"hello\"\n\
262-
\ return \"asdf\"\n\
263-
\\n\
264-
\data Baz = Baz { a :: Int, b :: String }\n\n"

Diff for: test/testdata/BrittanyCRLF.formatted_document.hs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo :: Int -> String -> IO ()
2+
foo x y = do
3+
print x
4+
return 42

Diff for: test/testdata/BrittanyCRLF.formatted_range.hs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo :: Int -> String -> IO ()
2+
foo x y = do
3+
print x
4+
return 42

Diff for: test/testdata/BrittanyLF.formatted_document.hs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo :: Int -> String -> IO ()
2+
foo x y = do
3+
print x
4+
return 42

Diff for: test/testdata/BrittanyLF.formatted_range.hs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo :: Int -> String -> IO ()
2+
foo x y = do
3+
print x
4+
return 42

Diff for: test/testdata/Format.formatted_document.hs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Format where
2+
3+
foo :: Int -> Int
4+
foo 3 = 2
5+
foo x = x
6+
bar :: String -> IO String
7+
bar s = do
8+
x <- return "hello"
9+
return "asdf"
10+
11+
data Baz = Baz {a :: Int, b :: String}
12+
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Format where
2+
3+
foo :: Int -> Int
4+
foo 3 = 2
5+
foo x = x
6+
bar :: String -> IO String
7+
bar s = do
8+
x <- return "hello"
9+
return "asdf"
10+
11+
data Baz = Baz {a :: Int, b :: String}
12+

Diff for: test/testdata/Format.formatted_range.hs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Format where
2+
3+
foo :: Int -> Int
4+
foo 3 = 2
5+
foo x = x
6+
bar :: String -> IO String
7+
bar s = do
8+
x <- return "hello"
9+
return "asdf"
10+
11+
data Baz = Baz { a :: Int, b :: String }
12+

Diff for: test/testdata/Format.formatted_range_with_tabsize.hs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Format where
2+
foo :: Int -> Int
3+
foo 3 = 2
4+
foo x = x
5+
bar :: String -> IO String
6+
bar s = do
7+
x <- return "hello"
8+
return "asdf"
9+
10+
11+
data Baz = Baz { a :: Int, b :: String }
12+

Diff for: test/testdata/Format.ormolu.formatted.hs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Format where
2+
3+
foo :: Int -> Int
4+
foo 3 = 2
5+
foo x = x
6+
bar :: String -> IO String
7+
bar s = do
8+
x <- return "hello"
9+
return "asdf"
10+
11+
data Baz = Baz {a :: Int, b :: String}
12+

Diff for: test/testdata/Format.ormolu.unchanged.hs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Format where
2+
foo :: Int -> Int
3+
foo 3 = 2
4+
foo x = x
5+
bar :: String -> IO String
6+
bar s = do
7+
x <- return "hello"
8+
return "asdf"
9+
10+
data Baz = Baz { a :: Int, b :: String }
11+

Diff for: test/testdata/StylishHaksell.format_document.hs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Data.Char
2+
import qualified Data.List
3+
import Data.String
4+
5+
bar :: Maybe (Either String Integer) -> Integer
6+
bar Nothing = 0
7+
bar (Just (Left _)) = 0
8+
bar (Just (Right x)) = x

Diff for: test/testdata/StylishHaksell.format_range.hs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Data.Char
2+
import qualified Data.List
3+
import Data.String
4+
5+
bar :: Maybe (Either String Integer) -> Integer
6+
bar Nothing = 0
7+
bar (Just (Left _)) = 0
8+
bar (Just (Right x)) = x

0 commit comments

Comments
 (0)