{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Data.Aeson.AutoType.Test (
arbitraryTopValue
) where
import Data.Aeson.AutoType.Pretty ()
import Control.Applicative ((<$>), (<*>))
import Data.Aeson
import Data.Function (on)
import Data.Hashable (Hashable)
import Data.Generics.Uniplate.Data
import Data.List
import Data.Scientific
import qualified Data.Text as Text
import Data.Text (Text)
import qualified Data.Vector as V
import qualified Data.HashMap.Strict as Map
import GHC.Generics
import Test.QuickCheck.Arbitrary
import Test.QuickCheck
import Test.SmallCheck.Series
instance Arbitrary Text where
arbitrary = Text.pack <$> sized (`vectorOf` alphabetic)
where
alphabetic = choose ('a', 'z')
instance (Arbitrary a) => Arbitrary (V.Vector a) where
arbitrary = V.fromList <$> arbitrary
instance (Arbitrary v) => Arbitrary (Map.HashMap Text v) where
arbitrary = makeMap <$> arbitrary
makeMap :: (Ord a, Hashable a) =>[(a, b)] -> Map.HashMap a b
makeMap = Map.fromList
. nubBy ((==) `on` fst)
. sortBy (compare `on` fst)
instance Arbitrary Scientific where
arbitrary = scientific <$> arbitrary <*> arbitrary
instance Arbitrary Value where
arbitrary = sized arb
where
arb n | n < 0 = error "Negative size!"
arb 0 = return Null
arb 1 = oneof simpleGens
arb i = oneof $ complexGens (i - 1) ++ simpleGens
simpleGens = [Number <$> arbitrary
,Bool <$> arbitrary
,String <$> arbitrary]
shrink = concatMap simpleShrink
. universe
simpleShrink :: Value -> [Value]
simpleShrink (Array a) = map (Array . V.fromList) $ shrink $ V.toList a
simpleShrink (Object o) = map (Object . Map.fromList) $ shrink $ Map.toList o
simpleShrink _ = []
complexGens :: Int -> [Gen Value]
complexGens i = [Object . Map.fromList <$> resize i arbitrary,
Array <$> resize i arbitrary]
arbitraryTopValue :: Gen Value
arbitraryTopValue = sized $ oneof . complexGens
instance Monad m => Serial m Text where
series = newtypeCons Text.pack
instance Monad m => Serial m Scientific where
series = cons2 scientific
instance Serial m a => Serial m (V.Vector a) where
series = newtypeCons V.fromList
instance Serial m v => Serial m (Map.HashMap Text v) where
series = newtypeCons makeMap
instance Monad m => Serial m Value