{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PackageImports #-} module Data.Swagger.Schema.GeneratorSpec where import Prelude () import Prelude.Compat import Data.Swagger import Data.Swagger.Schema.Generator import Control.Lens.Operators import Data.Aeson import Data.Hashable (Hashable) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import "unordered-containers" Data.HashSet (HashSet) import qualified "unordered-containers" Data.HashSet as HashSet import Data.Int import Data.IntMap (IntMap) import Data.List.NonEmpty.Compat (NonEmpty (..), nonEmpty) import Data.Map (Map, fromList) import Data.Monoid (mempty) import Data.Proxy import Data.Proxy import Data.Set (Set) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Data.Time import Data.Version (Version) import Data.Word import GHC.Generics import Test.Hspec import Test.Hspec.QuickCheck import Test.QuickCheck shouldValidate :: (FromJSON a, ToSchema a) => Proxy a -> Property shouldValidate = validateFromJSON shouldNotValidate :: (FromJSON a, ToSchema a) => Proxy a -> Property shouldNotValidate = expectFailure . shouldValidate spec :: Spec spec = do describe "FromJSON validation" $ do prop "Bool" $ shouldValidate (Proxy :: Proxy Bool) prop "Char" $ shouldValidate (Proxy :: Proxy Char) prop "Double" $ shouldValidate (Proxy :: Proxy Double) prop "Float" $ shouldValidate (Proxy :: Proxy Float) prop "Int" $ shouldValidate (Proxy :: Proxy Int) prop "Int8" $ shouldValidate (Proxy :: Proxy Int8) prop "Int16" $ shouldValidate (Proxy :: Proxy Int16) prop "Int32" $ shouldValidate (Proxy :: Proxy Int32) prop "Int64" $ shouldValidate (Proxy :: Proxy Int64) prop "Integer" $ shouldValidate (Proxy :: Proxy Integer) prop "Word" $ shouldValidate (Proxy :: Proxy Word) prop "Word8" $ shouldValidate (Proxy :: Proxy Word8) prop "Word16" $ shouldValidate (Proxy :: Proxy Word16) prop "Word32" $ shouldValidate (Proxy :: Proxy Word32) prop "Word64" $ shouldValidate (Proxy :: Proxy Word64) prop "String" $ shouldValidate (Proxy :: Proxy String) prop "()" $ shouldValidate (Proxy :: Proxy ()) -- prop "ZonedTime" $ shouldValidate (Proxy :: Proxy ZonedTime) -- prop "UTCTime" $ shouldValidate (Proxy :: Proxy UTCTime) prop "T.Text" $ shouldValidate (Proxy :: Proxy T.Text) prop "TL.Text" $ shouldValidate (Proxy :: Proxy TL.Text) prop "[String]" $ shouldValidate (Proxy :: Proxy [String]) -- prop "(Maybe [Int])" $ shouldValidate (Proxy :: Proxy (Maybe [Int])) prop "(IntMap String)" $ shouldValidate (Proxy :: Proxy (IntMap String)) prop "(Set Bool)" $ shouldValidate (Proxy :: Proxy (Set Bool)) prop "(NonEmpty Bool)" $ shouldValidate (Proxy :: Proxy (NonEmpty Bool)) prop "(HashSet Bool)" $ shouldValidate (Proxy :: Proxy (HashSet Bool)) prop "(Either Int String)" $ shouldValidate (Proxy :: Proxy (Either Int String)) prop "(Int, String)" $ shouldValidate (Proxy :: Proxy (Int, String)) prop "(Map String Int)" $ shouldValidate (Proxy :: Proxy (Map String Int)) prop "(Map T.Text Int)" $ shouldValidate (Proxy :: Proxy (Map T.Text Int)) prop "(Map TL.Text Bool)" $ shouldValidate (Proxy :: Proxy (Map TL.Text Bool)) prop "(HashMap String Int)" $ shouldValidate (Proxy :: Proxy (HashMap String Int)) prop "(HashMap T.Text Int)" $ shouldValidate (Proxy :: Proxy (HashMap T.Text Int)) prop "(HashMap TL.Text Bool)" $ shouldValidate (Proxy :: Proxy (HashMap TL.Text Bool)) prop "Object" $ shouldValidate (Proxy :: Proxy Object) prop "(Int, String, Double)" $ shouldValidate (Proxy :: Proxy (Int, String, Double)) prop "(Int, String, Double, [Int])" $ shouldValidate (Proxy :: Proxy (Int, String, Double, [Int])) prop "(Int, String, Double, [Int], Int)" $ shouldValidate (Proxy :: Proxy (Int, String, Double, [Int], Int)) describe "Invalid FromJSON validation" $ do prop "WrongType" $ shouldNotValidate (Proxy :: Proxy WrongType) prop "MissingRequired" $ shouldNotValidate (Proxy :: Proxy MissingRequired) prop "MissingProperty" $ shouldNotValidate (Proxy :: Proxy MissingProperty) prop "WrongPropType" $ shouldNotValidate (Proxy :: Proxy WrongPropType) -- ============================= -- Data types and bunk instances -- ============================= data WrongType = WrongType Bool instance FromJSON WrongType where parseJSON = withBool "WrongType" $ return . WrongType instance ToSchema WrongType where declareNamedSchema _ = return . NamedSchema (Just "WrongType") $ mempty & type_ .~ SwaggerObject data MissingRequired = MissingRequired { propA :: String , propB :: Bool } instance FromJSON MissingRequired where parseJSON = withObject "MissingRequired" $ \o -> MissingRequired <$> o .: "propA" <*> o .: "propB" instance ToSchema MissingRequired where declareNamedSchema _ = do stringSchema <- declareSchemaRef (Proxy :: Proxy String) boolSchema <- declareSchemaRef (Proxy :: Proxy Bool) return . NamedSchema (Just "MissingRequired") $ mempty & type_ .~ SwaggerObject & properties .~ [("propA", stringSchema) ,("propB", boolSchema) ] & required .~ ["propA"] data MissingProperty = MissingProperty { propC :: String , propD :: Bool } instance FromJSON MissingProperty where parseJSON = withObject "MissingProperty" $ \o -> MissingProperty <$> o .: "propC" <*> o .: "propD" instance ToSchema MissingProperty where declareNamedSchema _ = do stringSchema <- declareSchemaRef (Proxy :: Proxy String) return . NamedSchema (Just "MissingProperty") $ mempty & type_ .~ SwaggerObject & properties .~ [("propC", stringSchema)] & required .~ ["propC"] data WrongPropType = WrongPropType { propE :: String } instance FromJSON WrongPropType where parseJSON = withObject "WrongPropType" $ \o -> WrongPropType <$> o .: "propE" instance ToSchema WrongPropType where declareNamedSchema _ = do boolSchema <- declareSchemaRef (Proxy :: Proxy Bool) return . NamedSchema (Just "WrongPropType") $ mempty & type_ .~ SwaggerObject & properties .~ [("propE", boolSchema)] & required .~ ["propE"]