{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} import Control.Applicative import Data.Aeson.Quick import Data.ByteString.Lazy (ByteString) import Data.Either import Lens.Micro import Test.Tasty import Test.Tasty.HUnit main :: IO () main = defaultMain $ testGroup "Tests" [ oneKey , multipleKeys , deepKey , keyInArray , complex , optionalKey , nonExistentKey , asLens , parseInvalid , showStructure ] oneKey :: TestTree oneKey = testGroup "oneKey" [ testCase "get" $ val .! "{a}" @?= one , testCase "set" $ "{a}" .% Null `jt` "{\"a\":null}" ] where val = d "{\"a\":1}" multipleKeys :: TestTree multipleKeys = testGroup "multipleKeys" [ testCase "get" $ multiple .! "{a,b}" @?= (one,two) , testCase "set" $ build "{a,b}" multiple (two,[one,one]) `jt` "{\"a\":2,\"b\":[1,1]}" ] where multiple = d "{\"a\":1,\"b\":2}" deepKey :: TestTree deepKey = testGroup "deepKey" [ testCase "get" $ multilevel .! "{a:{b}}" @?= Just one , testCase "set" $ build "{a:{b}}" multilevel two `jt` "{\"a\":{\"b\":2}}" ] where multilevel = d "{\"a\":{\"b\":1}}" keyInArray :: TestTree keyInArray = testGroup "keyInArray" [ testCase "get" $ many .! "[{a}]" @?= [one,two] , testCase "set" $ build "[{a}]" many [True,False] `jt` "[{\"a\":true},{\"a\":false}]" ] where many = d "[{\"a\":1},{\"a\":2}]" complex :: TestTree complex = testGroup "complex" [ testCase "get" $ val .! "{a,b:[{a}]}" @?= (one,[[two,one]]) , testCase "set" $ build "{a,b:[{a}]}" val (two,[[one]]) `jt` "{\"a\":2,\"b\":[{\"a\":[1]}]}" ] where val = d "{\"a\":1,\"b\":[{\"a\":[2,1]}]}" optionalKey :: TestTree optionalKey = testGroup "optionalKey" [ testCase "get" $ val .! "{a?,b?}" @?= (Just one, Nothing :: Maybe Int) ] where val = d "{\"a\":1}" nonExistentKey :: TestTree nonExistentKey = testGroup "nonExistentKey" [ testCase "get" $ val .? "{b}" @?= (Nothing :: Maybe Int) , testCase "set" $ build "{a}" (d "{}") Null `jt` "{\"a\":null}" , testCase "setDeep" $ "{a:[{b}]}" .% Null `jt` "{\"a\":[{\"b\":null}]}" , testCase "setDeepArray" $ "[{a}]" .% [one,two] `jt` "[{\"a\":1},{\"a\":2}]" , testCase "setDeepMany" $ let v = (1,[(10,11)]) :: (Int,[(Int,Int)]) in "{my,complex:[{data,structure}]}" .% v @?= d "{\"my\":1,\"complex\":[{\"data\":10,\"structure\":11}]}" ] where val = d "{\"a\":1}" asLens :: TestTree asLens = testGroup "asLens" [ testCase "get" $ let l = queLens "{a,b}" :: Lens' Value (Int,Int) in val ^. l . _2 @?= two , testCase "getDoesNotExist" $ -- doesn't work, make a Traversal? --d "{}" ^? queLens "{a}" @?= (Nothing :: Maybe (Int,Int)) putStr "SKIPPED " >> pure () , testCase "set" $ (val & (queLens "{a,b}") .~ (two,one)) `jt` "{\"a\":2,\"b\":1}" ] where val = d "{\"a\":1,\"b\":2}" queLens :: (FromJSON a, ToJSON a) => Structure -> Lens' Value a queLens s = lens (.!s) (build s) parseInvalid :: TestTree parseInvalid = testGroup "parseInvalid" [ testCase "noKey" $ isLeft (parseStructure "{a,{b}}") @?= True ] showStructure :: TestTree showStructure = testGroup "showStructure" [ testCase "all" $ show ("[{a:[{b?,c}]}]"::Structure) @?= "[{a:[{b?,c}]}]" ] one, two :: Int one = 1 two = 2 jt :: Value -> ByteString -> IO () jt v b = encode v @?= b d :: ByteString -> Value d s = case decode s of Just v -> v Nothing -> error $ "Coult not decode JSON: " ++ show s