packages feed

jsonpath-0.1.0.1: test/Data/JSONPathSpec.hs

{-# LANGUAGE CPP               #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE TemplateHaskell   #-}
module Data.JSONPathSpec where

import Data.Aeson
import Data.Aeson.Casing
import Data.Aeson.Text
import Data.Aeson.TH
import Data.Attoparsec.Text
import Data.Either
import Data.FileEmbed
import Data.JSONPath
import Data.Text             (Text, unpack)
import GHC.Generics
import Test.Hspec
import Test.Hspec.Attoparsec

#if !MIN_VERSION_base (4,11,0)
import Data.Semigroup ((<>))
#endif

import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text.Lazy       as LazyText
import qualified Data.Vector          as V

data Test = Test { path   :: Text
                 , result :: Value
                 }
            deriving (Eq, Show, Generic)

data TestGroup = TestGroup { groupTitle :: Text
                           , groupData  :: Value
                           , groupTests :: [Test]
                           }
               deriving (Eq, Show, Generic)

$(deriveJSON defaultOptions ''Test)
$(deriveJSON (aesonPrefix snakeCase) ''TestGroup)

spec :: Spec
spec =
  let testFiles = map snd $(embedDir "test/resources/json-path-tests")
      testVals :: Either String [TestGroup]
      testVals = sequenceA $ map (eitherDecode . LBS.fromStrict) testFiles
  in case testVals of
       Left e -> describe "JSONPath Tests"
                  $ it "shouldn't fail to parse test files"
                  $ expectationFailure ("failed to parse test files with error: \n" <> e)
       Right gs -> describe "JSONPath"
                   $ do
                     mapM_ group gs
                     describe "Parser" $ do
                       it "should parse basic things" $ do
                         (".foo" :: Text) ~> (jsonPathElement <* endOfInput)
                           `shouldParse` KeyChild "foo"
                         ("$.foo" :: Text) ~> (jsonPath <* endOfInput)
                           `shouldParse` [KeyChild "foo"]

parseJSONPath :: Text -> Either String [JSONPathElement]
parseJSONPath = parseOnly (jsonPath <* endOfInput)

group :: TestGroup -> Spec
group TestGroup{..} = describe (unpack groupTitle)
                      $ mapM_ (test groupData) groupTests

test :: Value -> Test -> Spec
test testData (Test path expected) =
  let result = parseJSONPath path >>= (flip executeJSONPathEither testData)
  in it (unpack path) $
     case expected of
       Array a -> case result of
         Left err -> expectationFailure $ "Unexpected Left: " <> err
         Right r  -> r `shouldMatchList` (V.toList a)
       Bool False -> result `shouldSatisfy` isLeft
       v -> expectationFailure $ "Invalid result in test data " <> (LazyText.unpack $ encodeToLazyText v)