10 import Test
.Tasty
.Golden
.Advanced
(goldenTest
)
11 import Test
.Tasty
.HUnit
13 import Control
.Monad
(unless, void
)
14 import Data
.Algorithm
.Diff
(PolyDiff
(..), getGroupedDiff
)
15 import Data
.Maybe (isNothing)
16 import Distribution
.Fields
(runParseResult
)
17 import Distribution
.PackageDescription
(GenericPackageDescription
)
18 import Distribution
.PackageDescription
.Parsec
(parseGenericPackageDescription
)
19 import Distribution
.PackageDescription
.PrettyPrint
(showGenericPackageDescription
)
20 import Distribution
.Parsec
(PWarnType
(..), PWarning
(..), showPError
, showPWarning
)
21 import Distribution
.Pretty
(prettyShow
)
22 import Distribution
.Utils
.Generic
(fromUTF8BS
, toUTF8BS
)
23 import System
.Directory
(setCurrentDirectory)
24 import System
.Environment
(getArgs, withArgs
)
25 import System
.FilePath (replaceExtension
, (</>))
27 import qualified Data
.ByteString
as BS
28 import qualified Data
.ByteString
.Char8
as BS8
29 import qualified Data
.List
.NonEmpty
as NE
31 import qualified Distribution
.InstalledPackageInfo
as IPI
33 #ifdef MIN_VERSION_tree_diff
34 import Data
.TreeDiff
(ansiWlEditExpr
, ediff
, toExpr
)
35 import Data
.TreeDiff
.Golden
(ediffGolden
)
36 import Data
.TreeDiff
.Instances
.Cabal
()
40 tests
= testGroup
"parsec tests"
47 -------------------------------------------------------------------------------
49 -------------------------------------------------------------------------------
51 -- Verify that we trigger warnings
52 warningTests
:: TestTree
53 warningTests
= testGroup
"warnings triggered"
54 [ warningTest PWTLexBOM
"bom.cabal"
55 , warningTest PWTLexNBSP
"nbsp.cabal"
56 , warningTest PWTLexTab
"tab.cabal"
57 , warningTest PWTUTF
"utf8.cabal"
58 , warningTest PWTBoolCase
"bool.cabal"
59 , warningTest PWTVersionTag
"versiontag.cabal"
60 , warningTest PWTNewSyntax
"newsyntax.cabal"
61 , warningTest PWTOldSyntax
"oldsyntax.cabal"
62 , warningTest PWTDeprecatedField
"deprecatedfield.cabal"
63 , warningTest PWTInvalidSubsection
"subsection.cabal"
64 , warningTest PWTUnknownField
"unknownfield.cabal"
65 , warningTest PWTUnknownSection
"unknownsection.cabal"
66 , warningTest PWTTrailingFields
"trailingfield.cabal"
67 , warningTest PWTDoubleDash
"doubledash.cabal"
68 , warningTest PWTMultipleSingularField
"multiplesingular.cabal"
69 , warningTest PWTVersionWildcard
"wildcard.cabal"
70 , warningTest PWTVersionOperator
"operator.cabal"
71 , warningTest PWTSpecVersion
"specversion-a.cabal"
72 , warningTest PWTSpecVersion
"specversion-b.cabal"
73 , warningTest PWTSpecVersion
"specversion-c.cabal"
74 -- TODO: not implemented yet
75 -- , warningTest PWTExtraTestModule "extratestmodule.cabal"
78 warningTest
:: PWarnType
-> FilePath -> TestTree
79 warningTest wt fp
= testCase
(show wt
) $ do
80 contents
<- BS
.readFile $ "tests" </> "ParserTests" </> "warnings" </> fp
82 let res
= parseGenericPackageDescription contents
83 let (warns
, x
) = runParseResult res
85 assertBool
("should parse successfully: " ++ show x
) $ isRight x
88 [PWarning wt
' _ _
] -> assertEqual
"warning type" wt wt
'
89 [] -> assertFailure
"got no warnings"
90 _
-> assertFailure
$ "got multiple warnings: " ++ show warns
92 isRight
(Right _
) = True
95 -------------------------------------------------------------------------------
97 -------------------------------------------------------------------------------
99 errorTests
:: TestTree
100 errorTests
= testGroup
"errors"
101 [ errorTest
"common1.cabal"
102 , errorTest
"common2.cabal"
103 , errorTest
"common3.cabal"
104 , errorTest
"leading-comma.cabal"
105 , errorTest
"leading-comma-2.cabal"
106 , errorTest
"leading-comma-2b.cabal"
107 , errorTest
"leading-comma-2c.cabal"
108 , errorTest
"range-ge-wild.cabal"
109 , errorTest
"forward-compat.cabal"
110 , errorTest
"forward-compat2.cabal"
111 , errorTest
"forward-compat3.cabal"
112 , errorTest
"issue-5055.cabal"
113 , errorTest
"issue-5055-2.cabal"
114 , errorTest
"noVersion.cabal"
115 , errorTest
"noVersion2.cabal"
116 , errorTest
"multiple-libs.cabal"
117 , errorTest
"spdx-1.cabal"
118 , errorTest
"spdx-2.cabal"
119 , errorTest
"spdx-3.cabal"
120 , errorTest
"removed-fields.cabal"
121 , errorTest
"version-sets-1.cabal"
122 , errorTest
"version-sets-2.cabal"
123 , errorTest
"version-sets-3.cabal"
124 , errorTest
"version-sets-4.cabal"
125 , errorTest
"undefined-flag.cabal"
126 , errorTest
"mixin-1.cabal"
127 , errorTest
"mixin-2.cabal"
128 , errorTest
"libpq1.cabal"
129 , errorTest
"libpq2.cabal"
130 , errorTest
"MiniAgda.cabal"
131 , errorTest
"big-version.cabal"
132 , errorTest
"anynone.cabal"
135 errorTest
:: FilePath -> TestTree
136 errorTest fp
= cabalGoldenTest fp correct
$ do
137 contents
<- BS
.readFile input
138 let res
= parseGenericPackageDescription contents
139 let (_
, x
) = runParseResult res
141 return $ toUTF8BS
$ case x
of
143 "UNXPECTED SUCCESS\n" ++
144 showGenericPackageDescription gpd
146 unlines $ ("VERSION: " ++ show v
) : map (showPError fp
) (NE
.toList errs
)
148 input
= "tests" </> "ParserTests" </> "errors" </> fp
149 correct
= replaceExtension input
"errors"
151 -------------------------------------------------------------------------------
153 -------------------------------------------------------------------------------
155 regressionTests
:: TestTree
156 regressionTests
= testGroup
"regressions"
157 [ regressionTest
"encoding-0.8.cabal"
158 , regressionTest
"Octree-0.5.cabal"
159 , regressionTest
"nothing-unicode.cabal"
160 , regressionTest
"multiple-libs-2.cabal"
161 , regressionTest
"issue-774.cabal"
162 , regressionTest
"generics-sop.cabal"
163 , regressionTest
"elif.cabal"
164 , regressionTest
"elif2.cabal"
165 , regressionTest
"shake.cabal"
166 , regressionTest
"common.cabal"
167 , regressionTest
"common2.cabal"
168 , regressionTest
"common3.cabal"
169 , regressionTest
"common-conditional.cabal"
170 , regressionTest
"leading-comma.cabal"
171 , regressionTest
"leading-comma-2.cabal"
172 , regressionTest
"wl-pprint-indef.cabal"
173 , regressionTest
"th-lift-instances.cabal"
174 , regressionTest
"issue-5055.cabal"
175 , regressionTest
"issue-6083-pkg-pkg.cabal"
176 , regressionTest
"issue-6083-a.cabal"
177 , regressionTest
"issue-6083-b.cabal"
178 , regressionTest
"issue-6083-c.cabal"
179 , regressionTest
"noVersion.cabal"
180 , regressionTest
"spdx-1.cabal"
181 , regressionTest
"spdx-2.cabal"
182 , regressionTest
"spdx-3.cabal"
183 , regressionTest
"hidden-main-lib.cabal"
184 , regressionTest
"jaeger-flamegraph.cabal"
185 , regressionTest
"version-sets.cabal"
186 , regressionTest
"mixin-1.cabal"
187 , regressionTest
"mixin-2.cabal"
188 , regressionTest
"mixin-3.cabal"
189 , regressionTest
"libpq1.cabal"
190 , regressionTest
"libpq2.cabal"
191 , regressionTest
"issue-5846.cabal"
192 , regressionTest
"indentation.cabal"
193 , regressionTest
"indentation2.cabal"
194 , regressionTest
"indentation3.cabal"
195 , regressionTest
"big-version.cabal"
196 , regressionTest
"anynone.cabal"
197 , regressionTest
"monad-param.cabal"
198 , regressionTest
"hasktorch.cabal"
201 regressionTest
:: FilePath -> TestTree
202 regressionTest fp
= testGroup fp
203 [ formatGoldenTest fp
204 , formatRoundTripTest fp
205 #ifdef MIN_VERSION_tree_diff
206 , treeDiffGoldenTest fp
210 formatGoldenTest
:: FilePath -> TestTree
211 formatGoldenTest fp
= cabalGoldenTest
"format" correct
$ do
212 contents
<- BS
.readFile input
213 let res
= parseGenericPackageDescription contents
214 let (warns
, x
) = runParseResult res
216 return $ toUTF8BS
$ case x
of
218 unlines (map (showPWarning fp
) warns
)
219 ++ showGenericPackageDescription gpd
223 maybe "unknown-version" prettyShow csv
:
224 map (showPError fp
) (NE
.toList errs
)
226 input
= "tests" </> "ParserTests" </> "regressions" </> fp
227 correct
= replaceExtension input
"format"
229 #ifdef MIN_VERSION_tree_diff
230 treeDiffGoldenTest
:: FilePath -> TestTree
231 treeDiffGoldenTest fp
= ediffGolden goldenTest
"expr" exprFile
$ do
232 contents
<- BS
.readFile input
233 let res
= parseGenericPackageDescription contents
234 let (_
, x
) = runParseResult res
236 Right gpd
-> pure
(toExpr gpd
)
237 Left
(_
, errs
) -> fail $ unlines $ "ERROR" : map (showPError fp
) (NE
.toList errs
)
239 input
= "tests" </> "ParserTests" </> "regressions" </> fp
240 exprFile
= replaceExtension input
"expr"
243 formatRoundTripTest
:: FilePath -> TestTree
244 formatRoundTripTest fp
= testCase
"roundtrip" $ do
245 contents
<- BS
.readFile input
247 let contents
' = showGenericPackageDescription x
248 y
<- parse
(toUTF8BS contents
')
249 -- previously we mangled licenses a bit
252 #ifdef MIN_VERSION_tree_diff
253 assertFailure
$ unlines
254 [ "re-parsed doesn't match"
255 , show $ ansiWlEditExpr
$ ediff x y
258 assertFailure
$ unlines
259 [ "re-parsed doesn't match"
267 parse
:: BS
.ByteString
-> IO GenericPackageDescription
269 let (_
, x
') = runParseResult
$ parseGenericPackageDescription c
271 Right gpd
-> pure gpd
273 void
$ assertFailure
$ unlines (map (showPError fp
) $ NE
.toList errs
)
275 input
= "tests" </> "ParserTests" </> "regressions" </> fp
277 -------------------------------------------------------------------------------
278 -- InstalledPackageInfo regressions
279 -------------------------------------------------------------------------------
282 ipiTests
= testGroup
"ipis"
283 [ ipiTest
"transformers.cabal"
284 , ipiTest
"Includes2.cabal"
285 , ipiTest
"issue-2276-ghc-9885.cabal"
286 , ipiTest
"internal-preprocessor-test.cabal"
289 ipiTest
:: FilePath -> TestTree
290 ipiTest fp
= testGroup fp
$
291 #ifdef MIN_VERSION_tree_diff
292 [ ipiTreeDiffGoldenTest fp
] ++
294 [ ipiFormatGoldenTest fp
295 , ipiFormatRoundTripTest fp
298 ipiFormatGoldenTest
:: FilePath -> TestTree
299 ipiFormatGoldenTest fp
= cabalGoldenTest
"format" correct
$ do
300 contents
<- BS
.readFile input
301 let res
= IPI
.parseInstalledPackageInfo contents
302 return $ toUTF8BS
$ case res
of
303 Left err
-> "ERROR " ++ show err
305 unlines ws
++ IPI
.showInstalledPackageInfo ipi
307 input
= "tests" </> "ParserTests" </> "ipi" </> fp
308 correct
= replaceExtension input
"format"
310 #ifdef MIN_VERSION_tree_diff
311 ipiTreeDiffGoldenTest
:: FilePath -> TestTree
312 ipiTreeDiffGoldenTest fp
= ediffGolden goldenTest
"expr" exprFile
$ do
313 contents
<- BS
.readFile input
314 let res
= IPI
.parseInstalledPackageInfo contents
316 Left err
-> fail $ "ERROR " ++ show err
317 Right
(_ws
, ipi
) -> pure
(toExpr ipi
)
319 input
= "tests" </> "ParserTests" </> "ipi" </> fp
320 exprFile
= replaceExtension input
"expr"
323 ipiFormatRoundTripTest
:: FilePath -> TestTree
324 ipiFormatRoundTripTest fp
= testCase
"roundtrip" $ do
325 contents
<- BS
.readFile input
327 let contents
' = IPI
.showInstalledPackageInfo x
328 y
<- parse
(toUTF8BS contents
')
330 -- ghc-pkg prints pkgroot itself, based on cli arguments!
331 let x
' = x
{ IPI
.pkgRoot
= Nothing
}
333 assertBool
"pkgRoot isn't shown" (isNothing (IPI
.pkgRoot y
))
334 assertEqual
"re-parsed doesn't match" x
' y
'
336 -- Complete round-trip
337 let contents2
= IPI
.showFullInstalledPackageInfo x
338 z
<- parse
(toUTF8BS contents2
)
339 assertEqual
"re-parsed doesn't match" x z
342 parse
:: BS
.ByteString
-> IO IPI
.InstalledPackageInfo
344 case IPI
.parseInstalledPackageInfo c
of
345 Right
(_
, ipi
) -> return ipi
347 void
$ assertFailure
$ show err
349 input
= "tests" </> "ParserTests" </> "ipi" </> fp
351 -------------------------------------------------------------------------------
353 -------------------------------------------------------------------------------
359 ("--cwd" : cwd
: args
') -> do
360 setCurrentDirectory cwd
361 withArgs args
' $ defaultMain tests
362 _
-> defaultMain tests
364 cabalGoldenTest
:: TestName
-> FilePath -> IO BS
.ByteString
-> TestTree
365 cabalGoldenTest name ref act
= goldenTest name
(BS
.readFile ref
) act cmp upd
367 upd
= BS
.writeFile ref
368 cmp x y | x
== y
= return Nothing
369 cmp x y
= return $ Just
$ unlines $
370 concatMap f
(getGroupedDiff
(BS8
.lines x
) (BS8
.lines y
))
372 f
(First xs
) = map (cons3
'-' . fromUTF8BS
) xs
373 f
(Second ys
) = map (cons3
'+' . fromUTF8BS
) ys
374 -- we print unchanged lines too. It shouldn't be a problem while we have
375 -- reasonably small examples
376 f
(Both xs _
) = map (cons3
' ' . fromUTF8BS
) xs
377 -- we add three characters, so the changed lines are easier to spot
378 cons3 c cs
= c
: c
: c
: ' ' : cs