Skip to content

Commit 12a7ffe

Browse files
copilot-core: Increase test coverage of Copilot.Core.Type. Refs #502.
The test coverage of copilot-core is currently reported at 25% by Hackage. This commit includes tests for all top-level functions in Copilot.Core.Type, except uTypeType. We cannot generate random values of type-level literals, so any tests involving struct field types and array types with specific lengths use hard-coded values.
1 parent fbe9d59 commit 12a7ffe

File tree

1 file changed

+242
-3
lines changed
  • copilot-core/tests/Test/Copilot/Core

1 file changed

+242
-3
lines changed

copilot-core/tests/Test/Copilot/Core/Type.hs

Lines changed: 242 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1+
{-# LANGUAGE DataKinds #-}
12
-- | Test copilot-core:Copilot.Core.Type.
23
module Test.Copilot.Core.Type where
34

45
-- External imports
6+
import Data.Int (Int16, Int32, Int64, Int8)
7+
import Data.Maybe (isJust)
8+
import Data.Type.Equality (testEquality)
9+
import Data.Word (Word16, Word32, Word64, Word8)
510
import Test.Framework (Test, testGroup)
611
import Test.Framework.Providers.QuickCheck2 (testProperty)
7-
import Test.QuickCheck (Gen, Property, elements,
8-
forAllBlind, shuffle, (==>))
12+
import Test.QuickCheck (Gen, Property, arbitrary, elements,
13+
expectFailure, forAll, forAllBlind,
14+
property, shuffle, (==>))
915

1016
-- Internal imports: library modules being tested
11-
import Copilot.Core.Type (SimpleType (..), Type(..), simpleType)
17+
import Copilot.Core.Type (Field (..), SimpleType (..), Struct (..),
18+
Type (..), Typed, UType (..), Value (..),
19+
accessorName, fieldName, simpleType, typeLength,
20+
typeOf, typeSize)
21+
import Copilot.Core.Type.Array (Array)
1222

1323
-- | All unit tests for copilot-core:Copilot.Core.Type.
1424
tests :: Test.Framework.Test
@@ -24,6 +34,38 @@ tests =
2434
testSimpleTypesEqualityTransitive
2535
, testProperty "uniqueness of equality of simple types"
2636
testSimpleTypesEqualityUniqueness
37+
, testProperty "typeLength matches array size for 1-dimensional arrays"
38+
testTypeLength1
39+
, testProperty "typeLength matches array size for 2-dimensional arrays"
40+
testTypeLength2
41+
, testProperty "typeSize matches full array size for 1-dimensional arrays"
42+
testTypeSize1
43+
, testProperty "typeSize matches full array size for 2-dimensional arrays"
44+
testTypeSize2
45+
, testProperty "equality of types"
46+
testUTypesEqualitySymmetric
47+
, testProperty "equality of utype"
48+
testUTypesEq
49+
, testProperty "inequality of utype"
50+
testUTypesInequality
51+
, testProperty "inequality of utype via typeOf"
52+
testUTypesTypeOfInequality
53+
, testProperty "fieldName matches field name (positive)"
54+
testFieldNameOk
55+
, testProperty "fieldName matches field name (negative)"
56+
testFieldNameFail
57+
, testProperty "Show field name"
58+
testShowField
59+
, testProperty "Show struct"
60+
testShowStruct
61+
, testProperty "accessorName matches field name (positive)"
62+
testAccessorNameOk
63+
, testProperty "accessorName matches field name (negative)"
64+
testAccessorNameFail
65+
, testProperty "typeName matches struct type name (positive)"
66+
testTypeNameOk
67+
, testProperty "typeName matches struct type name (negative)"
68+
testTypeNameFail
2769
]
2870

2971
-- | Test that the function simpleTypes preserves inequality, that is, it
@@ -53,6 +95,8 @@ testSimpleTypesInequality = forAllBlind twoDiffTypes $ \(t1, t2) ->
5395
, simpleType Word64
5496
, simpleType Float
5597
, simpleType Double
98+
, simpleType (Array Int8 :: Type (Array 3 Int8))
99+
, simpleType (Struct (S (Field 0)))
56100
]
57101

58102
-- | Test that the equality relation for simple types is reflexive.
@@ -97,4 +141,199 @@ simpleTypes =
97141
, SFloat
98142
, SDouble
99143
, SStruct
144+
, SArray Int8
145+
, SArray Int16
100146
]
147+
148+
-- | Test that the length of an array is as expected.
149+
testTypeLength1 :: Property
150+
testTypeLength1 = property $ typeLength a == 3
151+
where
152+
a :: Type (Array 3 Int8)
153+
a = Array Int8
154+
155+
-- | Test that the length of an multi-dimensional array is as expected.
156+
testTypeLength2 :: Property
157+
testTypeLength2 = property $ typeLength a == 3
158+
where
159+
a :: Type (Array 3 (Array 12 Int8))
160+
a = Array (Array Int8)
161+
162+
-- | Test that the size of an array is as expected.
163+
testTypeSize1 :: Property
164+
testTypeSize1 = property $ typeLength a == 3
165+
where
166+
a :: Type (Array 3 Int8)
167+
a = Array Int8
168+
169+
-- | Test that the size of a multi-dimensional array is as expected (flattens
170+
-- the array).
171+
testTypeSize2 :: Property
172+
testTypeSize2 = property $ typeSize a == 36
173+
where
174+
a :: Type (Array 3 (Array 12 Int8))
175+
a = Array (Array Int8)
176+
177+
-- | Test that equality is symmetric for UTypes via testEquality.
178+
testUTypesEqualitySymmetric :: Property
179+
testUTypesEqualitySymmetric =
180+
forAllBlind (elements utypes) $ \(UType t1) -> isJust (testEquality t1 t1)
181+
182+
-- | Test that testEquality implies equality for UTypes.
183+
testUTypesEq :: Property
184+
testUTypesEq =
185+
forAllBlind (elements utypes) $ \t@(UType t1) -> isJust (testEquality t1 t1) ==> t == t
186+
187+
-- | Test that any two different UTypes are not equal.
188+
--
189+
-- This function pre-selects two UTypes from a list of different UTypes, which
190+
-- guarantees that they will be different.
191+
testUTypesInequality :: Property
192+
testUTypesInequality = forAllBlind twoDiffTypes $ \(t1, t2) ->
193+
t1 /= t2
194+
where
195+
twoDiffTypes :: Gen (UType, UType)
196+
twoDiffTypes = do
197+
shuffled <- shuffle utypes
198+
case shuffled of
199+
(t1:t2:_) -> return (t1, t2)
200+
_ -> return (UType Bool, UType Bool)
201+
202+
-- | Different UTypes.
203+
utypes :: [UType]
204+
utypes =
205+
[ UType Bool
206+
, UType Int8
207+
, UType Int16
208+
, UType Int32
209+
, UType Int64
210+
, UType Word8
211+
, UType Word16
212+
, UType Word32
213+
, UType Word64
214+
, UType Float
215+
, UType Double
216+
, UType a
217+
, UType b
218+
, UType c
219+
]
220+
where
221+
a :: Type (Array 3 Int8)
222+
a = Array Int8
223+
224+
b :: Type (Array 4 Int8)
225+
b = Array Int8
226+
227+
c :: Type S
228+
c = Struct (S (Field 0))
229+
230+
-- | Test that any two different UTypes are not equal.
231+
--
232+
-- This function pre-selects two UTypes from a list of different UTypes built
233+
-- via the function typeOf, which guarantees that they will be different.
234+
testUTypesTypeOfInequality :: Property
235+
testUTypesTypeOfInequality = forAllBlind twoDiffTypes $ \(t1@(UType t1'), t2@(UType t2')) ->
236+
-- The seqs are important: otherwise, the coverage goes down drastically
237+
-- because the typeOf function is not really executed.
238+
t1' `seq` t2' `seq` t1 /= t2
239+
where
240+
twoDiffTypes :: Gen (UType, UType)
241+
twoDiffTypes = do
242+
shuffled <- shuffle uTypesTypeOf
243+
case shuffled of
244+
(t1:t2:_) -> t1 `seq` t2 `seq` return (t1, t2)
245+
_ -> return (UType Bool, UType Bool)
246+
247+
-- | Different UTypes, produced by using the function typeOf.
248+
uTypesTypeOf :: [UType]
249+
uTypesTypeOf =
250+
[ UType (typeOf :: Type Bool)
251+
, UType (typeOf :: Type Int8)
252+
, UType (typeOf :: Type Int16)
253+
, UType (typeOf :: Type Int32)
254+
, UType (typeOf :: Type Int64)
255+
, UType (typeOf :: Type Word8)
256+
, UType (typeOf :: Type Word16)
257+
, UType (typeOf :: Type Word32)
258+
, UType (typeOf :: Type Word64)
259+
, UType (typeOf :: Type Float)
260+
, UType (typeOf :: Type Double)
261+
, UType (typeOf :: Type (Array 3 Int8))
262+
, UType (typeOf :: Type S)
263+
]
264+
265+
-- | Test the fieldName function (should succeed).
266+
testFieldNameOk :: Property
267+
testFieldNameOk = forAll arbitrary $ \k ->
268+
fieldName (s1 (S (Field k))) == s1FieldName
269+
where
270+
s1FieldName = "field"
271+
272+
-- | Test the fieldName function (should fail).
273+
testFieldNameFail :: Property
274+
testFieldNameFail = expectFailure $ property $
275+
fieldName (s1 sampleS) == s1FieldName
276+
where
277+
sampleS = S (Field 0)
278+
s1FieldName = "Field"
279+
280+
-- | Test showing a field of a struct.
281+
testShowField :: Property
282+
testShowField = forAll arbitrary $ \k ->
283+
show (s1 (S (Field k))) == ("field:" ++ show k)
284+
285+
-- | Test showing a struct.
286+
testShowStruct :: Property
287+
testShowStruct = forAll arbitrary $ \k ->
288+
show (S (Field k)) == "<field:" ++ show k ++ ">"
289+
290+
-- | Test the accessorName of a field of a struct (should succeed).
291+
testAccessorNameOk :: Property
292+
testAccessorNameOk = property $
293+
accessorName s1 == s1FieldName
294+
where
295+
s1FieldName = "field"
296+
297+
-- | Test the accessorName of a field of a struct (should fail).
298+
testAccessorNameFail :: Property
299+
testAccessorNameFail = expectFailure $ property $
300+
accessorName s1 == s1FieldName
301+
where
302+
s1FieldName = "Field"
303+
304+
-- | Test the typeName of a struct (should succeed).
305+
testTypeNameOk :: Property
306+
testTypeNameOk = property $
307+
typeName sampleS == s1TypeName
308+
309+
where
310+
311+
sampleS :: S
312+
sampleS = S (Field 0)
313+
314+
s1TypeName :: String
315+
s1TypeName = "S"
316+
317+
-- | Test the typeName of a struct (should fail).
318+
testTypeNameFail :: Property
319+
testTypeNameFail = expectFailure $ property $
320+
typeName sampleS == s1TypeName
321+
322+
where
323+
324+
sampleS :: S
325+
sampleS = S (Field 0)
326+
327+
s1TypeName :: String
328+
s1TypeName = "s"
329+
330+
-- | Auxiliary struct defined for testing purposes.
331+
data S = S { s1 :: Field "field" Int8 }
332+
333+
instance Struct S where
334+
typeName _ = "S"
335+
336+
toValues s = [ Value Int8 (s1 s) ]
337+
338+
instance Typed S where
339+
typeOf = Struct (S (Field 0))

0 commit comments

Comments
 (0)