1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE ScopedTypeVariables #-}
12import Data.Aeson (FromJSON(..), Value, json)
13import Data.Aeson.Types (Parser)
14import Data.Aeson.Parser (eitherDecodeWith)
15import Data.Aeson.Internal (formatError, iparse)
16import Data.Algorithm.Diff (PolyDiff (..), getGroupedDiff)
17import Data.Proxy (Proxy(..))
18import Data.Semigroup ((<>))
19import Data.Sequence (Seq)
21import Numeric.Natural (Natural)
22import Test.Tasty (TestTree, TestName)
23import Test.Tasty.Golden.Advanced (goldenTest)
24import qualified Data.ByteString.Lazy.Char8 as L
25import qualified Data.HashMap.Strict as HM
32 [ aesonGoldenTest "simple" "tests/golden/simple.expected" output
33 , aesonGoldenTest "generic" "tests/golden/generic.expected" (outputGeneric G)
38 [ testFor "Int" (Proxy :: Proxy Int)
45 , testFor "Integer" (Proxy :: Proxy Integer)
49 , testFor "Natural" (Proxy :: Proxy Natural)
54 , testFor "String" (Proxy :: Proxy String)
61 , testFor "HashMap" (Proxy :: Proxy (HM.HashMap String Int))
67 , testFor "Either" (Proxy :: Proxy (Int, Either (Int, Bool) ()))
68 [ "[1,{\"Left\":[2,3]}]"
72 , testFor "Seq" (Proxy :: Proxy (Seq Int))
79outputGeneric :: Choice -> Output
80outputGeneric choice = concat
81 [ testWith "OneConstructor"
83 thOneConstructorParseJSONDefault
84 gOneConstructorParseJSONDefault)
91 thNullaryParseJSONString
92 gNullaryParseJSONString)
97 , testWithSomeType "SomeType (tagged)"
99 thSomeTypeParseJSONTaggedObject
100 gSomeTypeParseJSONTaggedObject)
101 [ "{\"tag\": \"unary\", \"contents\": true}"
102 , "{\"tag\": \"unary\"}"
103 , "{\"tag\": \"record\"}"
104 , "{\"tag\": \"record\", \"testone\": true, \"testtwo\": null, \"testthree\": null}"
110 , testWithSomeType "SomeType (single-field)"
112 thSomeTypeParseJSONObjectWithSingleField
113 gSomeTypeParseJSONObjectWithSingleField)
117 , "{\"record\": {}, \"W\":{}}"
125 , testWithSomeType "SomeType (two-element array)"
127 thSomeTypeParseJSON2ElemArray
128 gSomeTypeParseJSON2ElemArray)
129 [ "[\"unary\", true]"
130 , "[\"record\", null]"
139 , testWith "EitherTextInt"
141 thEitherTextIntParseJSONUntaggedValue
142 gEitherTextIntParseJSONUntaggedValue)
147 , testWith "Product2 Int Bool"
157 select a b = case choice of
161-- Test infrastructure
163type Output = [String]
165outputLine :: String -> Output
168aesonGoldenTest :: TestName -> FilePath -> Output -> TestTree
169aesonGoldenTest name ref out = goldenTest name (L.readFile ref) act cmp upd
171 act = pure (L.pack (unlines out))
172 upd = L.writeFile ref
173 cmp x y | x == y = return Nothing
174 cmp x y = return $ Just $ unlines $
175 concatMap f (getGroupedDiff (L.lines x) (L.lines y))
177 f (First xs) = map (cons3 '-' . L.unpack) xs
178 f (Second ys) = map (cons3 '+' . L.unpack) ys
179 -- we print unchanged lines too. It shouldn't be a problem while we have
180 -- reasonably small examples
181 f (Both xs _) = map (cons3 ' ' . L.unpack) xs
182 -- we add three characters, so the changed lines are easier to spot
183 cons3 c cs = c : c : c : ' ' : cs
185testWith :: Show a => String -> (Value -> Parser a) -> [L.ByteString] -> Output
186testWith name parser ts =
189 case eitherDecodeWith json (iparse parser) s of
190 Left err -> outputLine $ uncurry formatError err
191 Right a -> outputLine $ show a) ts
193testFor :: forall a proxy. (FromJSON a, Show a)
194 => String -> proxy a -> [L.ByteString] -> Output
195testFor name _ = testWith name (parseJSON :: Value -> Parser a)
197testWithSomeType :: String -> (Value -> Parser (SomeType Int)) -> [L.ByteString] -> Output
198testWithSomeType = testWith
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list