@@ -21,9 +21,7 @@ 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
26−import qualified QueryParams
27import qualified Roboservant as R
25import qualified Roboservant as R
28import qualified Roboservant.Server as RS
26import qualified Roboservant.Server as RS
29import qualified Roboservant.Client as RC
27import qualified Roboservant.Client as RC
@@ -37,26 +35,26 @@ import Servant.Client(ClientEnv, mkClientEnv, baseUrlPort, parseBaseUrl,HasClien
37import Network.Wai(Application)
35import Network.Wai(Application)
38import qualified Network.Wai.Handler.Warp as Warp
36import qualified Network.Wai.Handler.Warp as Warp
39import Network.HTTP.Client (newManager, defaultManagerSettings)
37import Network.HTTP.Client (newManager, defaultManagerSettings)
40−import Control.Monad((>=>))
38+import Servant(Endpoints,HasServer)
42main :: IO ()
40main :: IO ()
43main = hspec spec
41main = hspec spec
46− :: forall a .
44+ :: forall a .
47 (R.ToReifiedApi (Endpoints a), HasServer a '[], RS.FlattenServer a, RC.ToReifiedClientApi (Endpoints a), RC.FlattenClient a,
45 (R.ToReifiedApi (Endpoints a), HasServer a '[], RS.FlattenServer a, RC.ToReifiedClientApi (Endpoints a), RC.FlattenClient a,
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,45 +73,37 @@ 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)
78+ (`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)
88 describe "seeded" $ do
80 describe "seeded" $ do
89 let res = Seeded.Seed 1
81 let res = Seeded.Seed 1
90 shouldFail $ fuzzBoth @Seeded.Api "finds an error using information passed in" Seeded.server
82 shouldFail $ fuzzBoth @Seeded.Api "finds an error using information passed in" Seeded.server
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" $
98− fuzzBoth @QueryParams.Api "can handle query params" QueryParams.server R.defaultConfig { R.seed = [R.hashedDyn (12::Int)] }
99− (`shouldSatisfy` isNothing)
101 describe "BuildFrom" $ do
89 describe "BuildFrom" $ do
102− describe "headers (and sum types)" $
90+ 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
91 fuzzBoth @Headers.Api "should find a failure that's dependent on using header info" Headers.server R.defaultConfig
104− (`shouldSatisfy` serverFailure)
92+ (`shouldSatisfy` serverFailure)
105− describe "product types" $
93+ describe "product types" $ do
106− fuzzBoth @Product.Api "should find a failure that's dependent on creating a product" Product.server
94+ 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)]}
95+ R.defaultConfig {R.seed = [R.hashedDyn 'a', R.hashedDyn (1 :: Int)]}
108− (`shouldSatisfy` serverFailure)
96+ (`shouldSatisfy` serverFailure)
109 describe "Breakdown" $ do
97 describe "Breakdown" $ do
110 fuzzBoth @Breakdown.ProductApi "handles products" Breakdown.productServer R.defaultConfig
98 fuzzBoth @Breakdown.ProductApi "handles products" Breakdown.productServer R.defaultConfig
111 (`shouldSatisfy` serverFailure)
99 (`shouldSatisfy` serverFailure)
112 fuzzBoth @Breakdown.SumApi "handles sums" Breakdown.sumServer R.defaultConfig
100 fuzzBoth @Breakdown.SumApi "handles sums" Breakdown.sumServer R.defaultConfig
113 (`shouldSatisfy` serverFailure)
101 (`shouldSatisfy` serverFailure)
114− describe "flattening" $
102+ describe "flattening" $ do
103+ -- we don't actually do much here, this is just here to document the appropriate response
104+ -- 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}
105 fuzzBoth @Nested.FlatApi "can handle nested apis" Nested.server R.defaultConfig {R.coverageThreshold = 0.99}
116− (`shouldSatisfy` isNothing)
106+ (`shouldSatisfy` isNothing)
118serverFailure :: Maybe R.Report -> Bool
108serverFailure :: Maybe R.Report -> Bool
119serverFailure = \case
109serverFailure = \case
@@ -137,12 +127,8 @@ deriving via (R.Atom Seeded.Seed) instance R.BuildFrom Seeded.Seed
137deriving via (R.Atom Void) instance R.BuildFrom Void
127deriving via (R.Atom Void) instance R.BuildFrom Void
139deriving via (R.Atom Post.FooPost) instance R.Breakdown Post.FooPost
129deriving 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
131+deriving via (R.Atom Post.FooPost) instance R.BuildFrom Post.FooPost
147deriving via (R.Compound Breakdown.Foo) instance R.Breakdown Breakdown.Foo
133deriving via (R.Compound Breakdown.Foo) instance R.Breakdown Breakdown.Foo
@@ -158,7 +144,7 @@ shouldFail =
160 { itemExample = \p a cb -> do
146 { itemExample = \p a cb -> do
161− r <- itemExample i p a cb
147+ r <- (itemExample i) p a cb
164 { resultStatus = case resultStatus r of
150 { resultStatus = case resultStatus r of