1 {-# OPTIONS_GHC -fno-warn-incomplete-patterns
3 -fno-warn-unused-binds #-} --FIXME
4 module UnitTests
.Distribution
.Version
(versionTests
) where
6 import Distribution
.Compat
.Prelude
.Internal
9 import Distribution
.Parsec
(simpleParsec
)
10 import Distribution
.Pretty
11 import Distribution
.Types
.VersionRange
.Internal
12 import Distribution
.Utils
.Generic
13 import Distribution
.Version
16 import Data
.Maybe (fromJust)
17 import Data
.Typeable
(typeOf
)
18 import Test
.QuickCheck
(Arbitrary
(..), NonEmptyList
(..), NonNegative
(..), Property
, Testable
, counterexample
, property
, (===), (==>), vectorOf
, sized
, choose
, arbitrarySizedNatural
)
19 import Test
.QuickCheck
.Instances
.Cabal
()
20 import Test
.Tasty
(TestTree
)
21 import Test
.Tasty
.QuickCheck
(testProperty
)
23 import qualified Distribution
.Types
.VersionInterval
as New
24 import qualified Distribution
.Types
.VersionInterval
.Legacy
as Old
25 import qualified Text
.PrettyPrint
as Disp
27 versionTests
:: [TestTree
]
29 -- test 'Version' type
30 [ tp
"versionNumbers . mkVersion = id @[NonNegative Int]" prop_VersionId
31 , tp
"versionNumbers . mkVersion = id @Base.Version" prop_VersionId2
32 , tp
"(==) = (==) `on` versionNumbers" prop_VersionEq
33 , tp
"(==) = (==) `on` mkVersion" prop_VersionEq2
34 , tp
"compare = compare `on` versionNumbers" prop_VersionOrd
35 , tp
"compare = compare `on` mkVersion" prop_VersionOrd2
37 , tp
"readMaybe . show = Just" prop_ShowRead
38 , tp
"read example" prop_ShowRead_example
40 , tp
"parsec . prettyShow involutive" prop_parsec_disp_inv
42 , tp
"normaliseVersionRange involutive" prop_normalise_inv
43 , tp
"normaliseVersionRange equivalent" prop_normalise_equiv
44 , tp
"normaliseVersionRange caretequiv" prop_normalise_caret_equiv
45 , tp
"normaliseVersionRange model" prop_normalise_model
47 , tp
"simplifyVersionRange involutive" prop_simplify_inv
48 , tp
"simplifyVersionRange equivalent" prop_simplify_equiv
49 -- , tp "simplifyVersionRange caretequiv" prop_simplify_caret_equiv
51 , tp
"simpleParsec . prettyShow = Just" prop_parse_disp
56 (\n (rep
, p
) -> testProperty
("Range Property " ++ show n
++ " (" ++ show rep
++ ")") p
)
58 -- properties to validate the test framework
59 [ typProperty prop_nonNull
60 , typProperty prop_gen_intervals1
61 , typProperty prop_gen_intervals2
63 , typProperty prop_anyVersion
64 , typProperty prop_noVersion
65 , typProperty prop_thisVersion
66 , typProperty prop_notThisVersion
67 , typProperty prop_laterVersion
68 , typProperty prop_orLaterVersion
69 , typProperty prop_earlierVersion
70 , typProperty prop_orEarlierVersion
71 , typProperty prop_unionVersionRanges
72 , typProperty prop_intersectVersionRanges
73 , typProperty prop_withinVersion
74 , typProperty prop_foldVersionRange
76 -- converting between version ranges and version intervals
77 , typProperty prop_to_from_intervals
80 tp
:: Testable p
=> String -> p
-> TestTree
83 typProperty p
= (typeOf p
, property p
)
85 -------------------------------------------------------------------------------
86 -- Arbitrary for inputs of mkVersion
87 -------------------------------------------------------------------------------
89 newtype VersionArb
= VersionArb
[Int]
90 deriving (Eq
,Ord
,Show)
92 -- | 'Version' instance as used by QC 2.9
93 instance Arbitrary VersionArb
where
94 arbitrary
= sized
$ \n ->
95 do k
<- choose
(0, log2 n
)
96 xs
<- vectorOf
(k
+1) arbitrarySizedNatural
97 return (VersionArb xs
)
101 |
otherwise = 1 + log2
(n `
div`
2)
103 shrink
(VersionArb xs
) =
110 ---------------------
111 -- Version properties
114 prop_VersionId
:: [NonNegative
Int] -> Bool
115 prop_VersionId lst0
=
116 (versionNumbers
. mkVersion
) lst
== lst
118 lst
= map getNonNegative lst0
120 prop_VersionId2
:: VersionArb
-> Bool
121 prop_VersionId2
(VersionArb lst
) =
122 (versionNumbers
. mkVersion
) lst
== lst
124 prop_VersionEq
:: Version
-> Version
-> Bool
125 prop_VersionEq v1 v2
= (==) v1 v2
== ((==) `on` versionNumbers
) v1 v2
127 prop_VersionEq2
:: VersionArb
-> VersionArb
-> Bool
128 prop_VersionEq2
(VersionArb v1
) (VersionArb v2
) =
129 (==) v1 v2
== ((==) `on` mkVersion
) v1 v2
131 prop_VersionOrd
:: Version
-> Version
-> Bool
132 prop_VersionOrd v1 v2
=
133 compare v1 v2
== (compare `on` versionNumbers
) v1 v2
135 prop_VersionOrd2
:: VersionArb
-> VersionArb
-> Bool
136 prop_VersionOrd2
(VersionArb v1
) (VersionArb v2
) =
137 (==) v1 v2
== ((==) `on` mkVersion
) v1 v2
139 prop_ShowRead
:: Version
-> Property
140 prop_ShowRead v
= Just v
=== readMaybe
(show v
)
142 prop_ShowRead_example
:: Bool
143 prop_ShowRead_example
= show (mkVersion
[1,2,3]) == "mkVersion [1,2,3]"
145 ---------------------------
146 -- VersionRange properties
149 prop_normalise_inv
:: VersionRange
-> Property
150 prop_normalise_inv vr
= normaliseVersionRange vr
=== normaliseVersionRange
(normaliseVersionRange vr
)
152 prop_normalise_equiv
:: VersionRange
-> Version
-> Property
153 prop_normalise_equiv vr
=
154 prop_equivalentVersionRange vr
(normaliseVersionRange vr
)
156 prop_normalise_caret_equiv
:: VersionRange
-> Version
-> Property
157 prop_normalise_caret_equiv vr
= prop_equivalentVersionRange
158 (transformCaretUpper vr
)
159 (transformCaretUpper
(normaliseVersionRange vr
))
161 prop_normalise_model
:: VersionRange
-> Property
162 prop_normalise_model vr
=
163 oldNormaliseVersionRange vr
' === newNormaliseVersionRange vr
'
165 vr
' = transformCaret vr
167 oldNormaliseVersionRange
:: VersionRange
-> VersionRange
168 oldNormaliseVersionRange
= Old
.fromVersionIntervals
. Old
.toVersionIntervals
170 newNormaliseVersionRange
:: VersionRange
-> VersionRange
171 newNormaliseVersionRange
= New
.normaliseVersionRange2
173 prop_simplify_inv
:: VersionRange
-> Property
174 prop_simplify_inv vr
=
175 simplifyVersionRange vr
=== simplifyVersionRange
(simplifyVersionRange vr
)
177 prop_simplify_equiv
:: VersionRange
-> Version
-> Property
178 prop_simplify_equiv vr v
=
179 counterexample
(show vr
') $ prop_equivalentVersionRange vr vr
' v
181 vr
' = simplifyVersionRange vr
183 -- TODO: Doesn't hold yet
184 -- prop_simplify_caret_equiv :: VersionRange -> Version -> Property
185 -- prop_simplify_caret_equiv vr = prop_equivalentVersionRange
186 -- (transformCaretUpper vr)
187 -- (transformCaretUpper (simplifyVersionRange vr))
189 prop_nonNull
:: Version
-> Bool
190 prop_nonNull
= (/= nullVersion
)
192 prop_anyVersion
:: Version
-> Bool
194 withinRange v
' anyVersion
196 prop_noVersion
:: Version
-> Bool
198 withinRange v
' noVersion
== False
200 prop_thisVersion
:: Version
-> Version
-> Bool
201 prop_thisVersion v v
' =
202 withinRange v
' (thisVersion v
)
205 prop_notThisVersion
:: Version
-> Version
-> Bool
206 prop_notThisVersion v v
' =
207 withinRange v
' (notThisVersion v
)
210 prop_laterVersion
:: Version
-> Version
-> Bool
211 prop_laterVersion v v
' =
212 withinRange v
' (laterVersion v
)
215 prop_orLaterVersion
:: Version
-> Version
-> Bool
216 prop_orLaterVersion v v
' =
217 withinRange v
' (orLaterVersion v
)
220 prop_earlierVersion
:: Version
-> Version
-> Bool
221 prop_earlierVersion v v
' =
222 withinRange v
' (earlierVersion v
)
225 prop_orEarlierVersion
:: Version
-> Version
-> Bool
226 prop_orEarlierVersion v v
' =
227 withinRange v
' (orEarlierVersion v
)
230 prop_unionVersionRanges
:: VersionRange
-> VersionRange
-> Version
-> Bool
231 prop_unionVersionRanges vr1 vr2 v
' =
232 withinRange v
' (unionVersionRanges vr1 vr2
)
233 == (withinRange v
' vr1 || withinRange v
' vr2
)
235 prop_intersectVersionRanges
:: VersionRange
-> VersionRange
-> Version
-> Bool
236 prop_intersectVersionRanges vr1 vr2 v
' =
237 withinRange v
' (intersectVersionRanges vr1 vr2
)
238 == (withinRange v
' vr1
&& withinRange v
' vr2
)
240 prop_withinVersion
:: Version
-> Version
-> Property
241 prop_withinVersion v v
' =
242 withinRange v
' (withinVersion v
)
244 (v
' >= v
&& v
' < upper v
)
246 upper
= alterVersion
$ \numbers
-> case unsnoc numbers
of
248 Just
(xs
, x
) -> xs
++ [x
+ 1]
250 prop_foldVersionRange
:: VersionRange
-> Property
251 prop_foldVersionRange
range =
253 === foldVersionRange anyVersion thisVersion
254 laterVersion earlierVersion
255 unionVersionRanges intersectVersionRanges
258 expandVR
(MajorBoundVersion v
) =
259 intersectVersionRanges
(expandVR
(orLaterVersion v
)) (earlierVersion
(majorUpperBound v
))
260 expandVR
(OrEarlierVersion v
) =
261 unionVersionRanges
(thisVersion v
) (earlierVersion v
)
262 expandVR
(OrLaterVersion v
) =
263 unionVersionRanges
(thisVersion v
) (laterVersion v
)
264 expandVR
(UnionVersionRanges v1 v2
) =
265 UnionVersionRanges
(expandVR v1
) (expandVR v2
)
266 expandVR
(IntersectVersionRanges v1 v2
) =
267 IntersectVersionRanges
(expandVR v1
) (expandVR v2
)
270 upper
= alterVersion
$ \numbers
-> case unsnoc numbers
of
272 Just
(xs
, x
) -> xs
++ [x
+ 1]
274 prop_isAnyVersion1
:: VersionRange
-> Version
-> Property
275 prop_isAnyVersion1
range version
=
276 isAnyVersion
range ==> withinRange version
range
278 prop_isAnyVersion2
:: VersionRange
-> Property
279 prop_isAnyVersion2
range =
280 isAnyVersion
range ==>
281 foldVersionRange
True (\_
-> False) (\_
-> False) (\_
-> False)
282 (\_ _
-> False) (\_ _
-> False)
283 (simplifyVersionRange
range)
285 prop_isNoVersion
:: VersionRange
-> Version
-> Property
286 prop_isNoVersion
range version
=
287 isNoVersion
range ==> not (withinRange version
range)
289 prop_isSpecificVersion1
:: VersionRange
-> NonEmptyList Version
-> Property
290 prop_isSpecificVersion1
range (NonEmpty versions
) =
291 isJust version
&& not (null versions
') ==>
292 allEqual
(fromJust version
) versions
'
294 version
= isSpecificVersion
range
295 versions
' = filter (`withinRange`
range) versions
296 allEqual x xs
= and (zipWith (==) (x
:xs
) xs
)
298 prop_isSpecificVersion2
:: VersionRange
-> Property
299 prop_isSpecificVersion2
range =
301 foldVersionRange Nothing Just
(\_
-> Nothing
) (\_
-> Nothing
)
302 (\_ _
-> Nothing
) (\_ _
-> Nothing
)
303 (simplifyVersionRange
range)
307 version
= isSpecificVersion
range
309 -- | Check that our VersionIntervals' arbitrary instance generates intervals
310 -- that satisfies the invariant.
312 prop_gen_intervals1
:: VersionIntervals
-> Property
313 prop_gen_intervals1
= property
. New
.invariantVersionIntervals
315 -- | Check that constructing our intervals type and converting it to a
316 -- 'VersionRange' and then into the true intervals type gives us back
317 -- the exact same sequence of intervals. This tells us that our arbitrary
318 -- instance for 'VersionIntervals'' is ok.
320 prop_gen_intervals2
:: VersionIntervals
-> Property
321 prop_gen_intervals2 intervals
=
322 toVersionIntervals
(fromVersionIntervals intervals
) === intervals
324 -- | @'toVersionIntervals' . 'fromVersionIntervals'@ is an exact identity on
325 -- 'VersionIntervals'.
327 prop_to_from_intervals
:: VersionIntervals
-> Bool
328 prop_to_from_intervals intervals
=
329 toVersionIntervals
(fromVersionIntervals intervals
) == intervals
331 --------------------------------
332 -- equivalentVersionRange helper
334 prop_equivalentVersionRange
335 :: VersionRange
-> VersionRange
-> Version
-> Property
336 prop_equivalentVersionRange
range range' version
=
337 withinRange version
range === withinRange version
range'
339 --------------------------------
340 -- Parsing and pretty printing
342 prop_parsec_disp_inv
:: VersionRange
-> Property
343 prop_parsec_disp_inv vr
=
344 parseDisp vr
=== (parseDisp vr
>>= parseDisp
)
346 parseDisp
= simpleParsec
. prettyShow
348 prop_parse_disp
:: VersionRange
-> Property
349 prop_parse_disp vr
= counterexample
(show (prettyShow vr
')) $
350 fmap s
(simpleParsec
(prettyShow vr
')) === Just vr
'
352 -- we have to strip parens, because arbitrary 'VersionRange' may have
353 -- too little parens constructors.
354 s
= stripParensVersionRange
357 prop_parse_disp1
:: VersionRange
-> Bool
358 prop_parse_disp1 vr
=
359 simpleParsec
(prettyShow vr
) == Just
(normaliseVersionRange vr
)
361 prop_parse_disp2
:: VersionRange
-> Property
362 prop_parse_disp2 vr
=
363 let b
= fmap (prettyShow
:: VersionRange
-> String) (simpleParsec
(prettyShow vr
))
364 a
= Just
(prettyShow vr
)
366 counterexample
("Expected: " ++ show a
) $
367 counterexample
("But got: " ++ show b
) $
370 prop_parse_disp3
:: VersionRange
-> Property
371 prop_parse_disp3 vr
=
372 let a
= Just
(prettyShow vr
)
373 b
= fmap displayRaw
(simpleParsec
(prettyShow vr
))
375 counterexample
("Expected: " ++ show a
) $
376 counterexample
("But got: " ++ show b
) $
379 prop_parse_disp4
:: VersionRange
-> Property
380 prop_parse_disp4 vr
=
382 b
= (simpleParsec
(prettyShow vr
))
384 counterexample
("Expected: " ++ show a
) $
385 counterexample
("But got: " ++ show b
) $
388 prop_parse_disp5
:: VersionRange
-> Property
389 prop_parse_disp5 vr
=
391 b
= simpleParsec
(displayRaw vr
)
393 counterexample
("Expected: " ++ show a
) $
394 counterexample
("But got: " ++ show b
) $
397 displayRaw
:: VersionRange
-> String
400 . cataVersionRange alg
. normaliseVersionRange
404 -- All the same as the usual pretty printer, except for the parens
405 alg
(ThisVersionF v
) = Disp
.text
"==" <<>> pretty v
406 alg
(LaterVersionF v
) = Disp
.char
'>' <<>> pretty v
407 alg
(EarlierVersionF v
) = Disp
.char
'<' <<>> pretty v
408 alg
(OrLaterVersionF v
) = Disp
.text
">=" <<>> pretty v
409 alg
(OrEarlierVersionF v
) = Disp
.text
"<=" <<>> pretty v
410 alg
(MajorBoundVersionF v
) = Disp
.text
"^>=" <<>> pretty v
411 alg
(UnionVersionRangesF r1 r2
) = r1
<+> Disp
.text
"||" <+> r2
412 alg
(IntersectVersionRangesF r1 r2
) = r1
<+> Disp
.text
"&&" <+> r2
415 Disp
.hcat
(Disp
.punctuate
(Disp
.char
'.')
416 (map Disp
.int
(versionNumbers v
)))