packages feed

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)