packages feed

json-query-0.2.3.0: test/Main.hs

{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Arrow ((>>>))
import Data.Bifunctor (first)
import Data.Bytes (Bytes)
import Data.Word (Word32, Word64)
import Json.Error (Error (Error))
import Json.Path (Path (Index, Key, Nil))
import Test.Hspec
import Test.Tasty (TestTree, defaultMain, testGroup)
import Test.Tasty.HUnit ((@=?))
import Test.Tasty.Hspec

import qualified Data.Bytes.Text.Ascii as Ascii
import qualified Data.Number.Scientific as SCI
import qualified GHC.Exts as Exts
import qualified Json
import qualified Json.Arrow as A
import qualified Json.Context as Ctx
import qualified Json.Error as JE
import qualified Json.Errors as JES
import qualified Json.Parser as P
import qualified Json.Path as Path
import qualified Test.Tasty.HUnit as THU

import qualified Arrowy
import qualified DogHouse
import qualified Monadic

main :: IO ()
main = do
  hSpecGroup <- testSpec "Hspec Tests" hSpecTests
  defaultMain $ testGroup "All Tests" [hSpecGroup, hUnitTests]

hSpecTests :: Spec
hSpecTests =
  describe "Parser" $ do
    describe "word32" $ do
      context "when value is negative" $ do
        it "should fail" $ do
          let input = SCI.small (-1) 0
          let actual = P.runParser (P.word32 input) Ctx.Top
          let expected = Left (JES.singleton JE.Error {JE.message = "expected number in range [0,2^32)", JE.context = Ctx.Top})
          actual `shouldBe` expected

      context "when value is zero" $ do
        it "should succeed" $ do
          let input = SCI.small 0 0
          let actual = P.runParser (P.word32 input) Ctx.Top
          let expected = Right 0
          actual `shouldBe` expected

      context "when value is upper bound" $ do
        it "should succeed" $ do
          let input = SCI.fromWord32 (maxBound :: Word32)
          let actual = P.runParser (P.word32 input) Ctx.Top
          let expected = Right (maxBound :: Word32)
          actual `shouldBe` expected

      context "when value is greater than upper bound" $ do
        it "should fail" $ do
          let large :: Word64 = fromIntegral (maxBound :: Word32) + 1
          let input = SCI.fromWord64 large
          let actual = P.runParser (P.word32 input) Ctx.Top
          let expected = Left (JES.singleton JE.Error {JE.message = "expected number in range [0,2^32)", JE.context = Ctx.Top})
          actual `shouldBe` expected

hUnitTests :: TestTree
hUnitTests =
  testGroup
    "HUnit Tests"
    [ THU.testCase "Json.Path.query-A" $
        case Json.decode (Ascii.fromString "{\"bla\": true, \"foo\" : [ 55 , { \"bar\": false } ] }") of
          Left _ -> fail "failed to parse into syntax tree"
          Right v ->
            Just Json.False
              @=? Path.query (Key "foo" $ Index 1 $ Key "bar" Nil) v
    , THU.testCase "Json.Path.encode-A" $
        "$.foo[1].bar"
          @=? Path.encode (Key "foo" $ Index 1 $ Key "bar" Nil)
    , THU.testCase "DogHouse-Monadic-A" $ case Json.decode DogHouse.sampleGood of
        Left _ -> fail "failed to parse into syntax tree"
        Right val ->
          Right DogHouse.expectationGood
            @=? Monadic.decode val
    , THU.testCase "DogHouse-Monadic-B" $ case Json.decode DogHouse.sampleBad of
        Left _ -> fail "failed to parse into syntax tree"
        Right val ->
          Monadic.expectationBad
            @=? Monadic.decode val
    , THU.testCase "DogHouse-Arrowy-A" $ case Json.decode DogHouse.sampleGood of
        Left _ -> fail "failed to parse into syntax tree"
        Right val ->
          Right DogHouse.expectationGood
            @=? Arrowy.decode val
    , THU.testCase "DogHouse-Arrowy-B" $ case Json.decode DogHouse.sampleBad of
        Left _ -> fail "failed to parse into syntax tree"
        Right val ->
          Left Arrowy.badErrors
            @=? Arrowy.decode val
    , THU.testCase "Arrowy-strings-A" $ case Json.decode sampleArrowyStrings of
        Left _ -> fail "failed to parse into syntax tree"
        Right val ->
          Left
            ( Exts.fromList
                [ Error
                    { context = Ctx.Index 2 (Ctx.Key "foo" Ctx.Top)
                    , message = "expected string"
                    }
                ]
            )
            @=? first JES.toSmallArray (A.run (A.object >>> A.member "foo" >>> A.strings) val)
    , THU.testCase "Arrowy-encode-errors" $
        "$.dogs[1].age: expected number, $.dogs[1].age: expected null"
          @=? JES.encode Arrowy.badErrors
    ]

sampleArrowyStrings :: Bytes
sampleArrowyStrings =
  Ascii.fromString
    "{\"bla\": true, \"foo\" : [ \"bar\", \"baz\", null, \"hey\"] }"