@@ -29,6 +29,7 @@ spec :: Spec
2929spec = describe " Servant.Server.Internal.Router" $ do
3030 routerSpec
3131 distributivitySpec
32+ serverLayoutSpec
3233
3334routerSpec :: Spec
3435routerSpec = do
@@ -103,12 +104,30 @@ distributivitySpec =
103104 it " properly handles mixing static paths at different levels" $ do
104105 level `shouldHaveSameStructureAs` levelRef
105106
107+ serverLayoutSpec :: Spec
108+ serverLayoutSpec =
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+ dynamic `shouldHaveLayout` expectedDynamicLayout
114+ it " nubs capture hints when equal" $ do
115+ dynamicSameType `shouldHaveLayout` expectedDynamicSameTypeLayout
116+ it " properly displays CaptureAll hints" $ do
117+ captureAllLayout `shouldHaveLayout` expectedCaptureAllLayout
118+
106119shouldHaveSameStructureAs ::
107120 (HasServer api1 '[] , HasServer api2 '[] ) => Proxy api1 -> Proxy api2 -> Expectation
108121shouldHaveSameStructureAs p1 p2 =
109122 unless (sameStructure (makeTrivialRouter p1) (makeTrivialRouter p2)) $
110123 expectationFailure (" expected:\n " ++ unpack (layout p2) ++ " \n but got:\n " ++ unpack (layout p1))
111124
125+ shouldHaveLayout ::
126+ (HasServer api '[] ) => Proxy api -> Text -> Expectation
127+ shouldHaveLayout p l =
128+ unless (routerLayout (makeTrivialRouter p) == l) $
129+ expectationFailure (" expected:\n " ++ unpack l ++ " \n but got:\n " ++ unpack (layout p))
130+
112131makeTrivialRouter :: (HasServer layout '[] ) => Proxy layout -> Router ()
113132makeTrivialRouter p =
114133 route p EmptyContext (emptyDelayed (FailFatal err501))
@@ -344,3 +363,90 @@ level = Proxy
344363
345364levelRef :: Proxy LevelRef
346365levelRef = Proxy
366+
367+ -- The example API for the 'layout' function.
368+ -- Should get factorized by the 'choice' smart constructor.
369+ type ExampleLayout =
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
375+ :<|> Raw
376+
377+ exampleLayout :: Proxy ExampleLayout
378+ exampleLayout = Proxy
379+
380+ -- The expected representation of the example API layout
381+ --
382+ expectedExampleLayout :: Text
383+ expectedExampleLayout =
384+ " /\n \
385+ \├─ a/\n \
386+ \│ ├─ d/\n \
387+ \│ │ └─•\n \
388+ \│ └─ e/\n \
389+ \│ └─•\n \
390+ \├─ b/\n \
391+ \│ └─ <x::Int>/\n \
392+ \│ ├─•\n \
393+ \│ ┆\n \
394+ \│ └─•\n \
395+ \├─ c/\n \
396+ \│ └─•\n \
397+ \┆\n \
398+ \└─ <raw>\n "
399+
400+ -- The expected representation of the Dynamic API layout.
401+ --
402+ expectedDynamicLayout :: Text
403+ expectedDynamicLayout =
404+ " /\n \
405+ \└─ a/\n \
406+ \ └─ <foo::Int|bar::Bool|baz::Char>/\n \
407+ \ ├─ b/\n \
408+ \ │ └─•\n \
409+ \ ├─ c/\n \
410+ \ │ └─•\n \
411+ \ └─ d/\n \
412+ \ └─•\n "
413+
414+ -- The same Dynamic API as above, except that the captured
415+ -- values have the same hints
416+ type DynamicSameType =
417+ " a" :> Capture " foo" Int :> " b" :> End
418+ :<|> " a" :> Capture " foo" Int :> " c" :> End
419+ :<|> " a" :> Capture " foo" Int :> " d" :> End
420+
421+ dynamicSameType :: Proxy DynamicSameType
422+ dynamicSameType = Proxy
423+
424+ -- The expected representation of the DynamicSameType API layout.
425+ --
426+ expectedDynamicSameTypeLayout :: Text
427+ expectedDynamicSameTypeLayout =
428+ " /\n \
429+ \└─ a/\n \
430+ \ └─ <foo::Int>/\n \
431+ \ ├─ b/\n \
432+ \ │ └─•\n \
433+ \ ├─ c/\n \
434+ \ │ └─•\n \
435+ \ └─ d/\n \
436+ \ └─•\n "
437+
438+ -- An API with a CaptureAll part
439+
440+ type CaptureAllLayout = " a" :> CaptureAll " foos" Int :> End
441+
442+ captureAllLayout :: Proxy CaptureAllLayout
443+ captureAllLayout = Proxy
444+
445+ -- The expected representation of the CaptureAllLayout API.
446+ --
447+ expectedCaptureAllLayout :: Text
448+ expectedCaptureAllLayout =
449+ " /\n \
450+ \└─ a/\n \
451+ \ └─ <foos::[Int]>/\n \
452+ \ └─•\n "
0 commit comments