packages feed

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

{-# LANGUAGE OverloadedLists #-}

module Operation.Data.TestVar where

import qualified Data.List as L
import Generator.Data
import Generator.Generic
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 Utils

varUnitTests :: TestTree
varUnitTests =
  testGroup
    "Var unit tests"
    -- logic {"var":""} data 1 => 1
    [ testCase "logic {\"var\":\"\"} data {\"x\":1}" $
        U.assertEqual
          "Simple var case is correct"
          (Right $ JsonNumber 1)
          (apply [] (JsonObject [("var", JsonString "")]) (JsonNumber 1)),
      -- logic {"var":"x"} data 1 => Null
      testCase "logic {\"var\":\"x\"} data {\"x\":1}" $
        U.assertEqual
          "Simple var case is correct"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonString "x")]) (JsonNumber 1)),
      -- logic {"var":true} data 1 => Null
      testCase "logic {\"var\":true} data {\"x\":1}" $
        U.assertEqual
          "Simple var case is correct"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonBool True)]) (JsonNumber 1)),
      -- logic {"var":"x"} data{"x":1} => 1
      testCase "logic {\"var\":\"x\"} data {\"x\":1}" $
        U.assertEqual
          "Simple var case is correct"
          (Right $ JsonNumber 1)
          (apply [] (JsonObject [("var", JsonString "x")]) (JsonObject [("x", JsonNumber 1)])),
      -- logic {"var":"x"} => Null
      testCase "logic {\"var\":\"x\"} data {}" $
        U.assertEqual
          "Empty data gives Null"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonString "x")]) JsonNull),
      -- logic {"var":"x"} data {"x":[1,2,3]} => [1,2,3]
      testCase "logic {\"var\":\"x\"} data {\"x\":[1,2,3]\"}" $
        U.assertEqual
          "Substitutes arraytype correctly"
          (Right $ JsonArray [JsonNumber 1, JsonNumber 2, JsonNumber 3])
          (apply [] (JsonObject [("var", JsonString "x")]) (JsonObject [("x", JsonArray [JsonNumber 1, JsonNumber 2, JsonNumber 3])])),
      -- logic {"var":"x.y"} data {"x":{"y":1}} => 1
      testCase "logic {\"var\":\"x.y\"} data {\"x\":{\"y\":1}\"}" $
        U.assertEqual
          "Access nested parameter 'x.y'"
          (Right $ JsonNumber 1)
          (apply [] (JsonObject [("var", JsonString "x.y")]) (JsonObject [("x", JsonObject [("y", JsonNumber 1)])])),
      -- logic {"var":"y"} data {"x":{"y":1}} => Null
      testCase "logic {\"var\":\"y\"} data {\"x\":{\"y\":1}\"}" $
        U.assertEqual
          "Parameter not accessed on correct level"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonString "y")]) $ JsonObject [("x", JsonObject [("y", JsonNumber 1)])]),
      -- logic {"var":{}} data 1 => Null
      testCase "logic {\"var\":[]} data 1 " $
        U.assertEqual
          "Indexing with an object returns null"
          (Right $ JsonNumber 1)
          (apply [] (JsonObject [("var", JsonArray [])]) $ JsonNumber 1),
      -- logic {"var":{}} data 1 => Null
      testCase "logic {\"var\":{}} data 1 " $
        U.assertEqual
          "Indexing with an object returns null"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonObject [])]) $ JsonNumber 1),
      -- logic {"var":[["y"]]} data {"y":{"y":1}} => Null
      testCase "logic {\"var\":[[\"y\"]]} data {\"y\":{\"y\":1}\"}" $
        U.assertEqual
          "Indexing with nested array gives back null"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonObject [])]) $ JsonObject [("y", JsonObject [("y", JsonNumber 1)])]),
      -- logic {"var":["", true]} data null => Null
      testCase "logic {\"var\":[\"\", true]} data null" $
        U.assertEqual
          "null value does not always return backup"
          (Right JsonNull)
          (apply [] (JsonObject [("var", JsonArray [JsonString "", JsonBool True])]) JsonNull)
    ]

varGeneratorTests :: TestTree
varGeneratorTests =
  testGroup
    "Var generator tests"
    [ hTestProperty "null, empty string, and empty array return entire data" $
        property $ do
          -- Logic that all returns the entire data
          let nullVar = JsonObject [("var", JsonNull)]
              emptyStringVar = JsonObject [("var", JsonString "")]
              emptyArrayVar = JsonObject [("var", JsonArray [])]
          dataJson <- forAll $ Gen.sized genSizedRandomJson
          -- All of them return the entire data
          Right dataJson === apply [] nullVar dataJson
          Right dataJson === apply [] emptyStringVar dataJson
          Right dataJson === apply [] emptyArrayVar dataJson,
      hTestProperty "bool, nested array, and empty object var return nothing" $
        property $ do
          -- Logic that all returns null
          boolJson <- forAll genGenericJsonBool
          arrJson <- forAll $ Gen.sized genSizedNestedJsonArray
          let boolVar = JsonObject [("var", fst boolJson)]
              arrVar = JsonObject [("var", JsonArray [arrJson])]
              objVar = JsonObject [("var", JsonObject [])]
          dataJson <- forAll $ Gen.sized genSizedRandomJson
          -- All of them return null
          Right JsonNull === apply [] boolVar dataJson
          Right JsonNull === apply [] arrVar dataJson
          Right JsonNull === apply [] objVar dataJson,
      hTestProperty "Number var returns index" $
        property $ do
          -- Insert Json data at index
          index <- forAll $ Gen.int $ Range.constant 0 15
          let logic = JsonObject [("var", JsonNumber $ fromIntegral index)]
          -- Generate random Json and random data and inject it at the index
          dataJson <- forAll $ Gen.sized genSizedRandomJson
          randomJson <- forAll $ Gen.sized genSizedRandomJsonArray
          resultJson <- forAll $ return $ insertAtPath [show index] dataJson randomJson
          -- Check that the index returns the data
          Right dataJson === apply [] logic resultJson,
      hTestProperty "String var returns item" $
        property $ do
          -- The member to index
          (indexJson, indexStr) <- forAll genGenericNonEmptyJsonString
          let logic = JsonObject [("var", indexJson)]
          -- Generate random Json and random data and inject it at the string member
          randomJson <- forAll $ Gen.sized genSizedRandomJsonArray
          dataJson <- forAll $ Gen.sized genSizedRandomJson
          resultJson <- forAll $ return $ insertAtPath [indexStr] dataJson randomJson
          -- Check that the data is found at the index
          Right dataJson === apply [] logic resultJson,
      hTestProperty "Nested indexing for strings returns item correctly" $
        property $ do
          -- Generate a list of strings denoting a path
          -- f.e ["aa", "bb"] is path "aa.bb" in Json
          recIndex <- forAll $ Gen.list (Range.constant 2 10) $ snd <$> genGenericNonEmptyJsonString
          let logic = JsonObject [("var", JsonString $ L.intercalate "." recIndex)]
          -- Generate random Json and random data and inject it at path
          randomJson <- forAll $ Gen.sized genSizedRandomJsonObject
          dataJson <- forAll $ Gen.sized genSizedRandomJson
          resultJson <- forAll $ return $ insertAtPath recIndex dataJson (JsonObject randomJson)
          -- Verify the data is found at the path in the Json
          Right dataJson === apply [] logic resultJson,
      hTestProperty "Default var takes first value if it returns a value" $
        property $ do
          -- Use var null to always convert to a valid item
          (stringJson, _) <- forAll genGenericNonEmptyJsonString
          let logic = JsonObject [("var", JsonArray [JsonNull, stringJson])]
          dataJson <- forAll $ Gen.sized genSizedRandomJsonArray
          -- Verify we get the entire data as result and not the default
          Right dataJson === apply [] logic dataJson,
      hTestProperty "Defaults correctly to second value" $
        property $ do
          -- Json bool so it always defaults to the stringJson
          (stringJson, _) <- forAll genGenericNonEmptyJsonString
          let logic = JsonObject [("var", JsonArray [JsonBool True, stringJson])]
          randomJson <- forAll $ Gen.sized genSizedRandomJsonArray
          -- Verify the default value as the result
          Right stringJson === apply [] logic randomJson
    ]