@@ -0,0 +1,124 @@
1+{-# LANGUAGE PackageImports #-}
2+module Data.Swagger.Schema.ValidationSpec where
3+
4+import Control.Applicative
5+import Control.Monad.Reader
6+import Data.Aeson
7+import Data.Int
8+import Data.IntMap (IntMap)
9+import qualified Data.IntMap as IntMap
10+import Data.IntSet (IntSet)
11+import Data.Hashable (Hashable)
12+import "unordered-containers" Data.HashSet (HashSet)
13+import qualified "unordered-containers" Data.HashSet as HashSet
14+import Data.HashMap.Strict (HashMap)
15+import qualified Data.HashMap.Strict as HashMap
16+import Data.Map (Map)
17+import qualified Data.Map as Map
18+import Data.Proxy
19+import Data.Time
20+import qualified Data.Text as T
21+import qualified Data.Text.Lazy as TL
22+import Data.Set (Set)
23+import qualified Data.Set as Set
24+import Data.Word
25+
26+import Data.Swagger
27+import Data.Swagger.Schema.Validation
28+
29+import SpecCommon
30+import Test.Hspec
31+import Test.Hspec.QuickCheck
32+import Test.QuickCheck
33+
34+shouldValidate :: (ToJSON a, ToSchema a) => Proxy a -> a -> Bool
35+shouldValidate proxy x = res == ValidationPassed ()
36+ where
37+ res = flip runReaderT mempty . runValidation $ do
38+ validateWithSchema (toSchema proxy) (toJSON x)
39+
40+spec :: Spec
41+spec = do
42+ describe "Validation" $ do
43+ prop "Bool" $ shouldValidate (Proxy :: Proxy Bool)
44+ prop "Char" $ shouldValidate (Proxy :: Proxy Char)
45+ prop "Double" $ shouldValidate (Proxy :: Proxy Double)
46+ prop "Float" $ shouldValidate (Proxy :: Proxy Float)
47+ prop "Int" $ shouldValidate (Proxy :: Proxy Int)
48+ prop "Int8" $ shouldValidate (Proxy :: Proxy Int8)
49+ prop "Int16" $ shouldValidate (Proxy :: Proxy Int16)
50+ prop "Int32" $ shouldValidate (Proxy :: Proxy Int32)
51+ prop "Int64" $ shouldValidate (Proxy :: Proxy Int64)
52+ prop "Integer" $ shouldValidate (Proxy :: Proxy Integer)
53+ prop "Word" $ shouldValidate (Proxy :: Proxy Word)
54+ prop "Word8" $ shouldValidate (Proxy :: Proxy Word8)
55+ prop "Word16" $ shouldValidate (Proxy :: Proxy Word16)
56+ prop "Word32" $ shouldValidate (Proxy :: Proxy Word32)
57+ prop "Word64" $ shouldValidate (Proxy :: Proxy Word64)
58+ prop "String" $ shouldValidate (Proxy :: Proxy String)
59+ prop "()" $ shouldValidate (Proxy :: Proxy ())
60+ prop "ZonedTime" $ shouldValidate (Proxy :: Proxy ZonedTime)
61+ prop "UTCTime" $ shouldValidate (Proxy :: Proxy UTCTime)
62+ prop "T.Text" $ shouldValidate (Proxy :: Proxy T.Text)
63+ prop "TL.Text" $ shouldValidate (Proxy :: Proxy TL.Text)
64+ prop "[String]" $ shouldValidate (Proxy :: Proxy [String])
65+ prop "(Maybe [Int])" $ shouldValidate (Proxy :: Proxy (Maybe [Int]))
66+ prop "(IntMap String)" $ shouldValidate (Proxy :: Proxy (IntMap String))
67+ prop "(Set Bool)" $ shouldValidate (Proxy :: Proxy (Set Bool))
68+ prop "(HashSet Bool)" $ shouldValidate (Proxy :: Proxy (HashSet Bool))
69+ prop "(Either Int String)" $ shouldValidate (Proxy :: Proxy (Either Int String))
70+ prop "(Int, String)" $ shouldValidate (Proxy :: Proxy (Int, String))
71+ prop "(Map String Int)" $ shouldValidate (Proxy :: Proxy (Map String Int))
72+ prop "(Map T.Text Int)" $ shouldValidate (Proxy :: Proxy (Map T.Text Int))
73+ prop "(Map TL.Text Bool)" $ shouldValidate (Proxy :: Proxy (Map TL.Text Bool))
74+ prop "(HashMap String Int)" $ shouldValidate (Proxy :: Proxy (HashMap String Int))
75+ prop "(HashMap T.Text Int)" $ shouldValidate (Proxy :: Proxy (HashMap T.Text Int))
76+ prop "(HashMap TL.Text Bool)" $ shouldValidate (Proxy :: Proxy (HashMap TL.Text Bool))
77+ prop "(Int, String, Double)" $ shouldValidate (Proxy :: Proxy (Int, String, Double))
78+ prop "(Int, String, Double, [Int])" $ shouldValidate (Proxy :: Proxy (Int, String, Double, [Int]))
79+ prop "(Int, String, Double, [Int], Int)" $ shouldValidate (Proxy :: Proxy (Int, String, Double, [Int], Int))
80+
81+main :: IO ()
82+main = hspec spec
83+
84+
85+instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v) where
86+ arbitrary = Map.fromList <$> arbitrary
87+
88+instance (Eq k, Hashable k, Arbitrary k, Arbitrary v) => Arbitrary (HashMap k v) where
89+ arbitrary = HashMap.fromList <$> arbitrary
90+
91+instance Arbitrary a => Arbitrary (IntMap a) where
92+ arbitrary = IntMap.fromList <$> arbitrary
93+
94+instance (Ord a, Arbitrary a) => Arbitrary (Set a) where
95+ arbitrary = Set.fromList <$> arbitrary
96+
97+instance (Eq a, Hashable a, Arbitrary a) => Arbitrary (HashSet a) where
98+ arbitrary = HashSet.fromList <$> arbitrary
99+
100+instance Arbitrary T.Text where
101+ arbitrary = T.pack <$> arbitrary
102+
103+instance Arbitrary TL.Text where
104+ arbitrary = TL.pack <$> arbitrary
105+
106+instance Arbitrary Day where
107+ arbitrary = liftA3 fromGregorian (fmap abs arbitrary) arbitrary arbitrary
108+
109+instance Arbitrary LocalTime where
110+ arbitrary = LocalTime
111+ <$> arbitrary
112+ <*> liftA3 TimeOfDay (choose (0, 23)) (choose (0, 59)) (fromInteger <$> choose (0, 60))
113+
114+instance Eq ZonedTime where
115+ ZonedTime t (TimeZone x _ _) == ZonedTime t' (TimeZone y _ _) = t == t' && x == y
116+
117+instance Arbitrary ZonedTime where
118+ arbitrary = ZonedTime
119+ <$> arbitrary
120+ <*> liftA3 TimeZone arbitrary arbitrary (vectorOf 3 (elements ['A'..'Z']))
121+
122+instance Arbitrary UTCTime where
123+ arbitrary = UTCTime <$> arbitrary <*> fmap fromInteger (choose (0, 86400))
124+