packages feed

jsop-0.1.0.0: test/Parse.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications, QuasiQuotes #-}

module Parse where

import Data.Aeson
import Data.Aeson.Lens
import qualified Data.Text as T
import Generics.SOP
import JSOP.Parse
import Protolude hiding (All, optional, (:*:))
import Test.Tasty.Hspec (Spec, describe, it, shouldBe)
import Data.Maybe (fromJust)
import Data.String.Interpolate 

jSOP'
  :: (All Typeable xs, IsProductType a xs)
  => NP (Parser Text) xs
  -> Value
  -> Either ParseGIssue a
jSOP' = jSOP $ T.splitOn " / " 

decodeU :: Text -> Value 
decodeU = fromJust . decode . toS

spec_generic :: Spec
spec_generic = do
  describe "generic parsers" do
    it "can parse an Int in an object" $ shouldBe
      do
        jSOP'
          do required "a number" _Integral :* Nil
          do object ["a number" .= Number 2]
      do Right (Identity (2 :: Int))
    it "can parse an Int in an nested object" $ shouldBe
      do
        jSOP'
          do required "object / a number" _Integral :* Nil
          do
            object
              [ "object" .= object ["a number" .= Number 2]
              ]
      do Right (Identity (2 :: Int))
    it "can parse String and Integer" $ shouldBe
      do
        jSOP'
          do
            required "a string" _String
              :* required "a number" _Integral
              :* Nil
          do
            object
              [ "a number" .= Number 2
              , "a string" .= ("ciao" :: Text)
              ]
      do Right ("ciao", 2 :: Int)
    it "can parse String and Int down different paths" $ shouldBe
      do
        jSOP 
          do T.splitOn " / " 
          do
            required "object 1 / a string" _String
              :* required "object 2 / a number" _Integral
              :* Nil
          do decodeU [i| 
              {
                "object 1": 
                  { "a string": "ciao"
                  , "ignore me" : 34
                  }
              , "object 2": 
                  { "a number": 2
                  , "object 3": {}
                  }
              }
              |]
      do Right ("ciao", 2 :: Int)
    it "can parse String and Int and Optional Int down different paths" $ shouldBe
      do
        jSOP 
          do T.splitOn " / " 
          do
            required "object 1 / a string" _String
              :* required "object 2 / a number" _Integral
              :* optional "object 4 / a number" 42 _Integral
              :* Nil
          do decodeU [i| 
              {
                "object 1": 
                  { "a string": "ciao"
                  , "ignore me" : 34
                  }
              , "object 2": 
                  { "a number": 2
                  , "object 3": {}
                  }
              , "object 4": {
                  "a plumber" :43
                  } 
              }
              |]
      do Right ("ciao", 2 :: Int, 42 :: Int )