packages feed

jsonpath-0.1.0.0: test/Data/JSONPathSpec.hs

{-# 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

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)