1+ {-# LANGUAGE DataKinds #-}
12-- The following warning is disabled due to a necessary instance of SatResult
23-- defined in this module.
34{-# OPTIONS_GHC -fno-warn-orphans #-}
@@ -6,17 +7,22 @@ module Test.Copilot.Theorem.What4 where
67
78-- External imports
89import Data.Int (Int8 )
10+ import Data.Word (Word32 )
911import Test.Framework (Test , testGroup )
1012import Test.Framework.Providers.QuickCheck2 (testProperty )
11- import Test.QuickCheck (Property , arbitrary , forAll )
13+ import Test.QuickCheck (Arbitrary (arbitrary ), Property ,
14+ arbitrary , forAll )
1215import Test.QuickCheck.Monadic (monadicIO , run )
1316
1417-- External imports: Copilot
15- import Copilot.Core.Expr (Expr (Const , Op2 ))
16- import Copilot.Core.Operators (Op2 (.. ))
18+ import Copilot.Core.Expr (Expr (Const , Op1 , Op2 ))
19+ import Copilot.Core.Operators (Op1 ( .. ), Op2 (.. ))
1720import Copilot.Core.Spec (Spec (.. ))
1821import qualified Copilot.Core.Spec as Copilot
19- import Copilot.Core.Type (Typed (typeOf ))
22+ import Copilot.Core.Type (Field (.. ),
23+ Struct (toValues , typeName ),
24+ Type (Struct ), Typed (typeOf ),
25+ Value (.. ))
2026
2127-- Internal imports: Modules being tested
2228import Copilot.Theorem.What4 (SatResult (.. ), Solver (.. ), prove )
@@ -30,6 +36,7 @@ tests =
3036 [ testProperty " Prove via Z3 that true is valid" testProveZ3True
3137 , testProperty " Prove via Z3 that false is invalid" testProveZ3False
3238 , testProperty " Prove via Z3 that x == x is valid" testProveZ3EqConst
39+ , testProperty " Prove via Z3 that a struct update is valid" testProveZ3StructUpdate
3340 ]
3441
3542-- * Individual tests
@@ -77,6 +84,54 @@ testProveZ3EqConst = forAll arbitrary $ \x ->
7784 spec x = propSpec propName $
7885 Op2 (Eq typeOf) (Const typeOf x) (Const typeOf x)
7986
87+ -- | Test that Z3 is able to prove the following expresion valid:
88+ -- @
89+ -- for all (s :: MyStruct),
90+ -- ((s ## testField =$ (+1)) # testField) == ((s # testField) + 1)
91+ -- @
92+ testProveZ3StructUpdate :: Property
93+ testProveZ3StructUpdate = forAll arbitrary $ \ x ->
94+ monadicIO $ run $ checkResult Z3 propName (spec x) Valid
95+ where
96+ propName :: String
97+ propName = " prop"
98+
99+ spec :: TestStruct -> Spec
100+ spec s = propSpec propName $
101+ Op2
102+ (Eq typeOf)
103+ (getField
104+ (Op2
105+ (UpdateField typeOf typeOf testField)
106+ sExpr
107+ (add1 (getField sExpr))))
108+ (add1 (getField sExpr))
109+ where
110+ sExpr :: Expr TestStruct
111+ sExpr = Const typeOf s
112+
113+ getField :: Expr TestStruct -> Expr Word32
114+ getField = Op1 (GetField typeOf typeOf testField)
115+
116+ add1 :: Expr Word32 -> Expr Word32
117+ add1 x = Op2 (Add typeOf) x (Const typeOf 1 )
118+
119+ -- | A simple data type with a 'Struct' instance and a 'Field'. This is only
120+ -- used as part of 'testProveZ3StructUpdate'.
121+ newtype TestStruct = TestStruct { testField :: Field " testField" Word32 }
122+
123+ instance Arbitrary TestStruct where
124+ arbitrary = do
125+ w32 <- arbitrary
126+ return (TestStruct (Field w32))
127+
128+ instance Struct TestStruct where
129+ typeName _ = " testStruct"
130+ toValues s = [Value typeOf (testField s)]
131+
132+ instance Typed TestStruct where
133+ typeOf = Struct (TestStruct (Field 0 ))
134+
80135-- | Check that the solver's satisfiability result for the given property in
81136-- the given spec matches the expectation.
82137checkResult :: Solver -> String -> Spec -> SatResult -> IO Bool
0 commit comments