1+ {-# LANGUAGE DataKinds #-}
12-- | Test copilot-core:Copilot.Core.Type.
23module 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 )
510import Test.Framework (Test , testGroup )
611import 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.
1424tests :: 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