@@ -29,6 +29,7 @@ spec :: Spec
29spec = describe "Servant.Server.Internal.Router" $ do
29spec = describe "Servant.Server.Internal.Router" $ do
30 routerSpec
30 routerSpec
31 distributivitySpec
31 distributivitySpec
33routerSpec :: Spec
34routerSpec :: Spec
34routerSpec = do
35routerSpec = do
@@ -103,12 +104,30 @@ distributivitySpec =
103 it "properly handles mixing static paths at different levels" $ do
104 it "properly handles mixing static paths at different levels" $ do
104 level `shouldHaveSameStructureAs` levelRef
105 level `shouldHaveSameStructureAs` levelRef
107+serverLayoutSpec :: Spec
109+ describe "serverLayout" $ do
110+ it "correctly represents the example API" $ do
111+ exampleLayout `shouldHaveLayout` expectedExampleLayout
112+ it "aggregates capture hints when different" $ do
113+ captureDifferentTypes `shouldHaveLayout` expectedCaptureDifferentTypes
114+ it "nubs capture hints when equal" $ do
115+ captureSameType `shouldHaveLayout` expectedCaptureSameType
116+ it "properly displays CaptureAll hints" $ do
117+ captureAllLayout `shouldHaveLayout` expectedCaptureAllLayout
106shouldHaveSameStructureAs ::
119shouldHaveSameStructureAs ::
107 (HasServer api1 '[], HasServer api2 '[]) => Proxy api1 -> Proxy api2 -> Expectation
120 (HasServer api1 '[], HasServer api2 '[]) => Proxy api1 -> Proxy api2 -> Expectation
108shouldHaveSameStructureAs p1 p2 =
121shouldHaveSameStructureAs p1 p2 =
109 unless (sameStructure (makeTrivialRouter p1) (makeTrivialRouter p2)) $
122 unless (sameStructure (makeTrivialRouter p1) (makeTrivialRouter p2)) $
110 expectationFailure ("expected:\n" ++ unpack (layout p2) ++ "\nbut got:\n" ++ unpack (layout p1))
123 expectationFailure ("expected:\n" ++ unpack (layout p2) ++ "\nbut got:\n" ++ unpack (layout p1))
126+ (HasServer api '[]) => Proxy api -> Text -> Expectation
127+shouldHaveLayout p l =
128+ unless (routerLayout (makeTrivialRouter p) == l) $
129+ expectationFailure ("expected:\n" ++ unpack l ++ "\nbut got:\n" ++ unpack (layout p))
112makeTrivialRouter :: (HasServer layout '[]) => Proxy layout -> Router ()
131makeTrivialRouter :: (HasServer layout '[]) => Proxy layout -> Router ()
113makeTrivialRouter p =
132makeTrivialRouter p =
114 route p EmptyContext (emptyDelayed (FailFatal err501))
133 route p EmptyContext (emptyDelayed (FailFatal err501))
@@ -344,3 +363,100 @@ level = Proxy
345levelRef :: Proxy LevelRef
364levelRef :: Proxy LevelRef
346levelRef = Proxy
365levelRef = Proxy
367+-- The example API for the 'layout' function.
368+-- Should get factorized by the 'choice' smart constructor.
370+ "a" :> "d" :> Get '[JSON] NoContent
371+ :<|> "b" :> Capture "x" Int :> Get '[JSON] Bool
372+ :<|> "c" :> Put '[JSON] Bool
373+ :<|> "a" :> "e" :> Get '[JSON] Int
374+ :<|> "b" :> Capture "x" Int :> Put '[JSON] Bool
377+exampleLayout :: Proxy ExampleLayout
378+exampleLayout = Proxy
380+-- The expected representation of the example API layout
382+expectedExampleLayout :: Text
383+expectedExampleLayout =
400+-- A capture API with all capture types being the same
402+type CaptureSameType =
403+ "a" :> Capture "foo" Int :> "b" :> End
404+ :<|> "a" :> Capture "foo" Int :> "c" :> End
405+ :<|> "a" :> Capture "foo" Int :> "d" :> End
407+captureSameType :: Proxy CaptureSameType
408+captureSameType = Proxy
410+-- The expected representation of the CaptureSameType API layout.
412+expectedCaptureSameType :: Text
413+expectedCaptureSameType =
424+-- A capture API capturing different types
426+type CaptureDifferentTypes =
427+ "a" :> Capture "foo" Int :> "b" :> End
428+ :<|> "a" :> Capture "bar" Bool :> "c" :> End
429+ :<|> "a" :> Capture "baz" Char :> "d" :> End
431+captureDifferentTypes :: Proxy CaptureDifferentTypes
432+captureDifferentTypes = Proxy
434+-- The expected representation of the CaptureDifferentTypes API layout.
436+expectedCaptureDifferentTypes :: Text
437+expectedCaptureDifferentTypes =
440+ \ └─ <foo::Int|bar::Bool|baz::Char>/\n\
448+-- An API with a CaptureAll part
450+type CaptureAllLayout = "a" :> CaptureAll "foos" Int :> End
452+captureAllLayout :: Proxy CaptureAllLayout
453+captureAllLayout = Proxy
455+-- The expected representation of the CaptureAllLayout API.
457+expectedCaptureAllLayout :: Text
458+expectedCaptureAllLayout =
461+ \ └─ <foos::[Int]>/\n\