packages feed

jsonlogic-0.1.0.0: test/Operation/Data/TestMissing.hs

module Operation.Data.TestMissing where

import qualified Data.Map as M
import Generator.Data
import Generator.Generic
import Generator.Utils
import Hedgehog (forAll, property, (===))
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import JsonLogic.Json
import JsonLogic.Pure.Evaluator
import Test.Tasty
import Test.Tasty.HUnit as U
import Text.Read (readMaybe)
import Utils

missingUnitTests :: TestTree
missingUnitTests =
  testGroup
    "missing unit tests"
    [ testCase "logic {\"missing\":[]} data {} => []" $
        U.assertEqual
          "empty case"
          (Right $ jArr [])
          (apply [] (jObj [("missing", jArr [])]) (jObj [])),
      testCase "logic {\"missing\":[\"a\", \"b\"]} data {\"a\":\"apple\", \"c\":\"carrot\"} => [\"b\"]" $
        U.assertEqual
          "first test case on site"
          (Right $ jArr [jStr "b"])
          (apply [] (jObj [("missing", jArr [jStr "a", jStr "b"])]) (jObj [("a", jStr "apple"), ("c", jStr "carrot")])),
      testCase "logic {\"missing\":[\"a\", \"b\"]} data {\"a\":\"apple\", \"b\":\"banana\"} => []" $
        U.assertEqual
          "second test case on site"
          (Right $ jArr [])
          (apply [] (jObj [("missing", jArr [jStr "a", jStr "b"])]) (jObj [("a", jStr "apple"), ("b", jStr "banana")])),
      testCase "logic {\"missing\":[0, 1]} data [\"apple\", \"banana\"] => []" $
        U.assertEqual
          "missing in lists"
          (Right $ jArr [])
          (apply [] (jObj [("missing", jArr [jNum 0, jNum 1])]) (jArr [jStr "apple", jStr "banana"])),
      testCase "logic {\"missing\":[0, 1]} data [\"apple\"] => [1]" $
        U.assertEqual
          "missing in lists"
          (Right $ jArr [jNum 1])
          (apply [] (jObj [("missing", jArr [jNum 0, jNum 1])]) (jArr [jStr "apple"])),
      testCase "logic {\"if\":[{\"missing\":[\"a\", \"b\"]}, \"Not enough fruit\", \"OK to proceed\"]} data {\"a\":\"apple\", \"b\":\"banana\"} => \"Ok to proceed\"" $
        U.assertEqual
          "third test case on site"
          (Right $ jStr "OK to proceed")
          (apply [] (jObj [("if", jArr [jObj [("missing", jArr [jStr "a", jStr "b"])], jStr "Not enough fruit", jStr "OK to proceed"])]) (jObj [("a", jStr "apple"), ("b", jStr "banana")]))
    ]

missingGeneratorTests :: TestTree
missingGeneratorTests =
  testGroup
    "missing generator tests"
    [ hTestProperty "missing over emty" $
        property $ do
          -- Create rule and data
          let missingEmpty = jObj [("missing", jArr [])]
          dataJsonArray <- forAll $ Gen.sized genSizedRandomJsonArray
          dataJsonObject <- forAll $ Gen.sized genSizedRandomJsonObject
          -- Empty rule over any data returns empty array
          Right (jArr []) === apply [] missingEmpty dataJsonArray
          Right (jArr []) === apply [] missingEmpty (JsonObject dataJsonObject),
      hTestProperty "Using integer index on array" $
        property $ do
          -- Generate random data
          jsonData <- forAll $ Gen.sized genSizedRandomJson
          -- Create the rule
          x <- forAll $ Gen.int $ Range.constant 0 30
          let rule = jObj [("missing", jArr [jNum $ fromIntegral x])]
          -- Only returns empty array if the index is missing
          case jsonData of
            (JsonArray js) | x < length js -> Right (jArr []) === apply [] rule jsonData
            (JsonString s) | x < length s -> Right (jArr []) === apply [] rule jsonData
            -- If the index is a number and that index is in the dict it is indexed
            (JsonObject o) | M.member (show x) o -> Right (jArr []) === apply [] rule jsonData
            _ -> Right (jArr [jNum $ fromIntegral x]) === apply [] rule jsonData,
      hTestProperty "Using string index on array" $
        property $ do
          -- Generate random array
          jsonData@(JsonArray js) <- forAll $ Gen.sized genSizedRandomJsonArray
          (indexJson, indexStr) <- forAll genGenericNonEmptyJsonString
          -- Item should be in result since it cannot be present
          let rule = jObj [("missing", jArr [indexJson])]
          case readMaybe indexStr :: Maybe Int of
            -- The string is by chance a number, if it is within the range the index is succesful
            Just i | i >= 0 && i < length js -> Right (jArr []) === apply [] rule jsonData
            -- Index is not present since it is a string or outside the range
            _ -> Right (jArr [indexJson]) === apply [] rule jsonData,
      hTestProperty "Using string index on object" $
        property $ do
          -- Generate data
          jsonData <- forAll $ increaseSizeBy 1 $ Gen.sized genSizedRandomJsonObject
          -- Choose a random item from the object
          indexStr <- forAll $ Gen.element $ M.keys jsonData
          let rule = jObj [("missing", jArr [jStr indexStr])]
          -- The item should not be missing
          Right (jArr []) === apply [] rule (JsonObject jsonData),
      hTestProperty "Using integer index on object" $
        property $ do
          -- Random data
          jsonData <- forAll $ Gen.sized genSizedRandomJsonObject
          -- Generate random index
          x <- forAll $ Gen.int $ Range.constant 0 30
          let rule = jObj [("missing", jArr [jNum $ fromIntegral x])]
          -- Item should be missing
          if M.member (show x) jsonData
            then Right (jArr []) === apply [] rule (JsonObject jsonData)
            else Right (jArr [jNum $ fromIntegral x]) === apply [] rule (JsonObject jsonData)
    ]