@@ -37,6 +37,7 @@ import Servant.Client(ClientEnv, mkClientEnv, baseUrlPort, parseBaseUrl,HasClien
37import Network.Wai(Application)
37import Network.Wai(Application)
38import qualified Network.Wai.Handler.Warp as Warp
38import qualified Network.Wai.Handler.Warp as Warp
39import Network.HTTP.Client (newManager, defaultManagerSettings)
39import Network.HTTP.Client (newManager, defaultManagerSettings)
40+import Control.Monad((>=>))
41main :: IO ()
42main :: IO ()
42main = hspec spec
43main = hspec spec
@@ -47,15 +48,15 @@ fuzzBoth
47 HasClient ClientM a)
48 HasClient ClientM a)
48 => String -> Server a -> R.Config -> (Maybe R.Report -> IO ()) -> Spec
49 => String -> Server a -> R.Config -> (Maybe R.Report -> IO ()) -> Spec
49fuzzBoth name server config condition = do
50fuzzBoth name server config condition = do
50− it (name <> " via server") $ do
51+ it (name <> " via server") $
51 RS.fuzz @a server config >>= condition
52 RS.fuzz @a server config >>= condition
53− around (withServer (serve (Proxy :: Proxy a) server)) $ do
54+ around (withServer (serve (Proxy :: Proxy a) server)) $
54 it (name <> " via client") $ \(clientEnv::ClientEnv) -> do
55 it (name <> " via client") $ \(clientEnv::ClientEnv) -> do
55− RC.fuzz @a clientEnv config >>= condition
56+ RC.fuzz @a clientEnv config >>= condition
57withServer :: Application -> ActionWith ClientEnv -> IO ()
58withServer :: Application -> ActionWith ClientEnv -> IO ()
58−withServer app action = Warp.testWithApplication (pure app) (\p -> genClientEnv p >>= action)
59+withServer app action = Warp.testWithApplication (pure app) (genClientEnv >=> action)
59 where genClientEnv port = do
60 where genClientEnv port = do
60 baseUrl <- parseBaseUrl "http://localhost"
61 baseUrl <- parseBaseUrl "http://localhost"
61 manager <- newManager defaultManagerSettings
62 manager <- newManager defaultManagerSettings
@@ -74,14 +75,14 @@ spec = do
74 Just (R.InsufficientCoverage _) -> True
75 Just (R.InsufficientCoverage _) -> True
75 _ -> False
76 _ -> False
77− describe "posted body" $ do
78+ describe "posted body" $
78 fuzzBoth @Post.Api "passes a coverage check using a posted body" Post.server R.defaultConfig {R.coverageThreshold = 0.99}
79 fuzzBoth @Post.Api "passes a coverage check using a posted body" Post.server R.defaultConfig {R.coverageThreshold = 0.99}
79− (`shouldSatisfy` isNothing)
80+ (`shouldSatisfy` isNothing)
82− describe "PUTted body" $ do
83+ describe "PUTted body" $
83 fuzzBoth @Put.Api "passes a coverage check using a posted body" Put.server R.defaultConfig {R.coverageThreshold = 0.99}
84 fuzzBoth @Put.Api "passes a coverage check using a posted body" Put.server R.defaultConfig {R.coverageThreshold = 0.99}
84− (`shouldSatisfy` isNothing)
85+ (`shouldSatisfy` isNothing)
87 describe "seeded" $ do
88 describe "seeded" $ do
@@ -90,31 +91,29 @@ spec = do
90 (R.defaultConfig {R.seed = [(toDyn res, hash res)]})
91 (R.defaultConfig {R.seed = [(toDyn res, hash res)]})
91 (`shouldSatisfy` isNothing)
92 (`shouldSatisfy` isNothing)
93− describe "Foo" $ do
94+ describe "Foo" $
94 fuzzBoth @Foo.Api "finds an error in a basic app" Foo.server R.defaultConfig (`shouldSatisfy` serverFailure)
95 fuzzBoth @Foo.Api "finds an error in a basic app" Foo.server R.defaultConfig (`shouldSatisfy` serverFailure)
96− describe "QueryParams" $ do
97+ describe "QueryParams" $
97 fuzzBoth @QueryParams.Api "can handle query params" QueryParams.server R.defaultConfig { R.seed = [R.hashedDyn (12::Int)] }
98 fuzzBoth @QueryParams.Api "can handle query params" QueryParams.server R.defaultConfig { R.seed = [R.hashedDyn (12::Int)] }
98− (`shouldSatisfy` isNothing)
99+ (`shouldSatisfy` isNothing)
100 describe "BuildFrom" $ do
101 describe "BuildFrom" $ do
101− describe "headers (and sum types)" $ do
102+ describe "headers (and sum types)" $
102 fuzzBoth @Headers.Api "should find a failure that's dependent on using header info" Headers.server R.defaultConfig
103 fuzzBoth @Headers.Api "should find a failure that's dependent on using header info" Headers.server R.defaultConfig
103− (`shouldSatisfy` serverFailure)
104+ (`shouldSatisfy` serverFailure)
104− describe "product types" $ do
105+ describe "product types" $
105 fuzzBoth @Product.Api "should find a failure that's dependent on creating a product" Product.server
106 fuzzBoth @Product.Api "should find a failure that's dependent on creating a product" Product.server
106− R.defaultConfig {R.seed = [R.hashedDyn 'a', R.hashedDyn (1 :: Int)]}
107+ R.defaultConfig {R.seed = [R.hashedDyn 'a', R.hashedDyn (1 :: Int)]}
107− (`shouldSatisfy` serverFailure)
108+ (`shouldSatisfy` serverFailure)
108 describe "Breakdown" $ do
109 describe "Breakdown" $ do
109 fuzzBoth @Breakdown.ProductApi "handles products" Breakdown.productServer R.defaultConfig
110 fuzzBoth @Breakdown.ProductApi "handles products" Breakdown.productServer R.defaultConfig
110 (`shouldSatisfy` serverFailure)
111 (`shouldSatisfy` serverFailure)
111 fuzzBoth @Breakdown.SumApi "handles sums" Breakdown.sumServer R.defaultConfig
112 fuzzBoth @Breakdown.SumApi "handles sums" Breakdown.sumServer R.defaultConfig
112 (`shouldSatisfy` serverFailure)
113 (`shouldSatisfy` serverFailure)
113− describe "flattening" $ do
114+ describe "flattening" $
114− -- we don't actually do much here, this is just here to document the appropriate response
115− -- if you get a type error with a nested api.
116 fuzzBoth @Nested.FlatApi "can handle nested apis" Nested.server R.defaultConfig {R.coverageThreshold = 0.99}
115 fuzzBoth @Nested.FlatApi "can handle nested apis" Nested.server R.defaultConfig {R.coverageThreshold = 0.99}
117− (`shouldSatisfy` isNothing)
116+ (`shouldSatisfy` isNothing)
119serverFailure :: Maybe R.Report -> Bool
118serverFailure :: Maybe R.Report -> Bool
120serverFailure = \case
119serverFailure = \case
@@ -159,7 +158,7 @@ shouldFail =
161 { itemExample = \p a cb -> do
160 { itemExample = \p a cb -> do
162− r <- (itemExample i) p a cb
161+ r <- itemExample i p a cb
165 { resultStatus = case resultStatus r of
164 { resultStatus = case resultStatus r of