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