jsonlogic-0.1.0.0: test/Generator/Logic.hs
module Generator.Logic where
import Data.Fixed as F
import qualified Data.Map as M
import Generator.Generic
import Generator.Utils
import Hedgehog
import Hedgehog.Gen
import JsonLogic.Json
genArithmeticOperator :: Gen (Double -> Double -> Double, [Char])
genArithmeticOperator = element [((+), "+"), ((-), "-"), ((*), "*"), ((/), "/"), (F.mod', "%")]
genComparisonOperator :: Gen (Double -> Double -> Bool, [Char])
genComparisonOperator = element [((<), "<"), ((>), ">"), ((<=), "<="), ((>=), ">=")]
genBetweenOperator :: Gen (Double -> Double -> Bool, [Char])
genBetweenOperator = element [((<), "<"), ((<=), "<=")]
genLogicOperator :: Gen (Bool -> Bool -> Bool, [Char])
genLogicOperator = element [((&&), "and"), ((||), "or"), ((==), "==="), ((/=), "!==")]
genArrayOperator :: Gen ([Double] -> Double, [Char])
genArrayOperator = element [(minimum, "min"), (maximum, "max"), (sum, "sum")]
-- Generator for a Json object that evaluates to a number
genNumericJson :: Gen (Json, Double)
genNumericJson = sized sizedGenNumericJson
sizedGenNumericJson :: Size -> Gen (Json, Double)
sizedGenNumericJson s@(Size size)
| size <= 0 = genGenericJsonNumber
| otherwise =
choice
[ createNumericObject "+" (Prelude.+) s,
createNumericObject "-" (Prelude.-) s,
createNumericObject "*" (Prelude.*) s,
createNumericObject "/" (Prelude./) s
]
-- Creates numeric Json generator given the operator
createNumericObject :: String -> (Double -> Double -> a) -> Size -> Gen (Json, a)
createNumericObject str op size = do
(s1, s2) <- genUnbalancedSizes size
(j1, x1) <- sizedGenNumericJson s1
(j2, x2) <- sizedGenNumericJson s2
return (JsonObject (M.fromList [(str, JsonArray [j1, j2])]), x1 `op` x2)
-- Generator for a Json object that evaluates to a boolean and only contains comparisons
genComparisonJson :: Gen (Json, Bool)
genComparisonJson = sized sizedGenComparisonJson
sizedGenComparisonJson :: Size -> Gen (Json, Bool)
sizedGenComparisonJson s@(Size size)
| size <= 0 = genGenericJsonBool
| otherwise =
choice
[ createNumericObject "<" (Prelude.<) s,
createNumericObject ">" (Prelude.>) s,
createNumericObject "<=" (Prelude.<=) s,
createNumericObject ">=" (Prelude.>=) s
]
-- Generator for a Json object that evaluates to a boolean and only contains logic operations
genLogicJson :: Gen (Json, Bool)
genLogicJson = sized sizedGenLogicJson
sizedGenLogicJson :: Size -> Gen (Json, Bool)
sizedGenLogicJson s@(Size size)
| size <= 0 = genGenericJsonBool
| otherwise =
choice
[ createLogicObject "&&" (Prelude.&&) s,
createLogicObject "||" (Prelude.||) s,
createLogicObject "!==" (Prelude./=) s,
createLogicObject "===" (Prelude.==) s
]
-- Creates the Logic generator given the operator
createLogicObject :: String -> (Bool -> Bool -> Bool) -> Size -> Gen (Json, Bool)
createLogicObject str op size = do
(s1, s2) <- genUnbalancedSizes size
(j1, x1) <- sizedGenLogicJson s1
(j2, x2) <- sizedGenLogicJson s2
return (JsonObject (M.fromList [(str, JsonArray [j1, j2])]), x1 `op` x2)
-- Generates Json that evaluates to a boolean. Contains both logic and comparison operators
genBoolJson :: Gen (Json, Bool)
genBoolJson = sized sizedGenBoolJson
sizedGenBoolJson :: Size -> Gen (Json, Bool)
sizedGenBoolJson s@(Size size)
| size <= 0 = genGenericJsonBool
| otherwise =
choice
[ createBoolObject "&&" (Prelude.&&) s,
createBoolObject "||" (Prelude.||) s,
createBoolObject "!==" (Prelude./=) s,
createBoolObject "===" (Prelude.==) s,
createBoolObject "<" (Prelude.<) s,
createBoolObject ">" (Prelude.>) s,
createBoolObject "<=" (Prelude.<=) s,
createBoolObject ">=" (Prelude.>=) s
]
-- Creates a generator for json logic given an operator. Can contain out of logic and comparison operators
createBoolObject :: String -> (Bool -> Bool -> Bool) -> Size -> Gen (Json, Bool)
createBoolObject str op size = do
(s1, s2) <- genUnbalancedSizes size
(j1, x1) <- choice [sizedGenLogicJson s1, sizedGenComparisonJson s1]
(j2, x2) <- choice [sizedGenLogicJson s2, sizedGenComparisonJson s2]
return (JsonObject (M.fromList [(str, JsonArray [j1, j2])]), x1 `op` x2)