module Test.Expr.Math
( mathTests
)
where
import Data.Bits ((.&.), (.|.))
import qualified Data.Bits as Bits
import Data.Int (Int32)
import GHC.Stack (withFrozenCallStack)
import Hedgehog ((===))
import qualified Hedgehog as HH
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import qualified Orville.PostgreSQL as Orville
import qualified Orville.PostgreSQL.Expr as Expr
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue
import qualified Test.Property as Property
mathTests :: Orville.ConnectionPool -> Property.Group
mathTests pool =
Property.group
"Expr - Math"
[ prop_plus pool
, prop_minus pool
, prop_multiply pool
, prop_divide pool
, prop_exponentiate pool
, prop_bitwiseAnd pool
, prop_bitwiseOr pool
, prop_bitwiseXor pool
, prop_bitwiseShiftLeft pool
, prop_bitwiseShiftRight pool
]
prop_plus :: Property.NamedDBProperty
prop_plus =
Property.namedDBProperty "plus" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
m <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
result <-
evaluateIntegerExpression pool $
Expr.plus
(int32Expression n)
(int32Expression m)
result === (n + m)
prop_minus :: Property.NamedDBProperty
prop_minus =
Property.namedDBProperty "minus" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
m <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
result <-
evaluateIntegerExpression pool $
Expr.minus
(int32Expression n)
(int32Expression m)
result === (n - m)
prop_multiply :: Property.NamedDBProperty
prop_multiply =
Property.namedDBProperty "multiply" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
m <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
result <-
evaluateIntegerExpression pool $
Expr.multiply
(int32Expression n)
(int32Expression m)
result === (n * m)
prop_divide :: Property.NamedDBProperty
prop_divide =
Property.namedDBProperty "divide" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linearFrom 0 (-100) 100))
m <- HH.forAll (Gen.filter (/= 0) (Gen.integral (Range.linearFrom 0 (-100) 100)))
result <-
evaluateIntegerExpression pool $
Expr.divide
(int32Expression n)
(int32Expression m)
result === (n `quot` m)
prop_exponentiate :: Property.NamedDBProperty
prop_exponentiate =
Property.namedDBProperty "exponentiate" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 10))
m <- HH.forAll (Gen.integral (Range.linear 0 10))
result <-
evaluateIntegerExpression pool $
Expr.exponentiate
(int32Expression n)
(int32Expression m)
result === (n ^ m)
prop_bitwiseAnd :: Property.NamedDBProperty
prop_bitwiseAnd =
Property.namedDBProperty "bitwiseAnd" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
m <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
result <-
evaluateIntegerExpression pool $
Expr.bitwiseAnd
(int32Expression n)
(int32Expression m)
result === (n .&. m)
prop_bitwiseOr :: Property.NamedDBProperty
prop_bitwiseOr =
Property.namedDBProperty "bitwiseOr" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
m <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
result <-
evaluateIntegerExpression pool $
Expr.bitwiseOr
(int32Expression n)
(int32Expression m)
result === (n .|. m)
prop_bitwiseXor :: Property.NamedDBProperty
prop_bitwiseXor =
Property.namedDBProperty "bitwiseXor" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
m <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
result <-
evaluateIntegerExpression pool $
Expr.bitwiseXor
(int32Expression n)
(int32Expression m)
result === Bits.xor n m
prop_bitwiseShiftLeft :: Property.NamedDBProperty
prop_bitwiseShiftLeft =
Property.namedDBProperty "bitwiseShiftLeft" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
m <- HH.forAll (Gen.integral (Range.linear 0 64))
result <-
evaluateIntegerExpression pool $
Expr.bitwiseShiftLeft
(int32Expression n)
(intExpression m)
result === Bits.shiftL n (m `mod` 32)
prop_bitwiseShiftRight :: Property.NamedDBProperty
prop_bitwiseShiftRight =
Property.namedDBProperty "bitwiseShiftRight" $ \pool -> do
n <- HH.forAll (Gen.integral (Range.linear 0 0xFFFFFFF))
m <- HH.forAll (Gen.integral (Range.linear 0 64))
result <-
evaluateIntegerExpression pool $
Expr.bitwiseShiftRight
(int32Expression n)
(intExpression m)
result === Bits.shiftR n (m `mod` 32)
int32Expression :: Int32 -> Expr.ValueExpression
int32Expression n =
Expr.cast (Expr.valueExpression (SqlValue.fromInt32 n)) Expr.int
intExpression :: Int -> Expr.ValueExpression
intExpression n =
Expr.cast (Expr.valueExpression (SqlValue.fromInt n)) Expr.int
evaluateIntegerExpression ::
Orville.ConnectionPool ->
Expr.ValueExpression ->
HH.PropertyT IO Int32
evaluateIntegerExpression pool expression = do
let
sql =
Expr.queryExpr
(Expr.selectClause (Expr.selectExpr Nothing))
( Expr.selectDerivedColumns
[ Expr.deriveColumnAs expression (Expr.columnName "result")
]
)
Nothing
marshaller =
Orville.annotateSqlMarshallerEmptyAnnotation $
Orville.marshallField id (Orville.integerField "result")
results <-
HH.evalIO $
Orville.runOrville pool $
Orville.executeAndDecode Orville.SelectQuery sql marshaller
case results of
[result] ->
pure result
_ ->
withFrozenCallStack $ do
HH.annotate $ "Expected exactly 1 row in result, but got the rows: " <> show results
HH.failure