Skip to content

Commit 89030cb

Browse files
committed
Add spec for serverLayout
1 parent a8ffbf0 commit 89030cb

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

servant-server/test/Servant/Server/RouterSpec.hs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ spec :: Spec
2727
spec = describe "Servant.Server.Internal.Router" $ do
2828
routerSpec
2929
distributivitySpec
30+
serverLayoutSpec
3031

3132
routerSpec :: Spec
3233
routerSpec = do
@@ -101,12 +102,28 @@ distributivitySpec =
101102
it "properly handles mixing static paths at different levels" $ do
102103
level `shouldHaveSameStructureAs` levelRef
103104

105+
serverLayoutSpec :: Spec
106+
serverLayoutSpec =
107+
describe "serverLayout" $ do
108+
it "correctly represents the example API" $ do
109+
exampleLayout `shouldHaveLayout` expectedExampleLayout
110+
it "aggregates capture hints when different" $ do
111+
dynamic `shouldHaveLayout` expectedDynamicLayout
112+
it "nubs capture hints when equal" $ do
113+
dynamicSameType `shouldHaveLayout` expectedDynamicSameTypeLayout
114+
104115
shouldHaveSameStructureAs ::
105116
(HasServer api1 '[], HasServer api2 '[]) => Proxy api1 -> Proxy api2 -> Expectation
106117
shouldHaveSameStructureAs p1 p2 =
107118
unless (sameStructure (makeTrivialRouter p1) (makeTrivialRouter p2)) $
108119
expectationFailure ("expected:\n" ++ unpack (layout p2) ++ "\nbut got:\n" ++ unpack (layout p1))
109120

121+
shouldHaveLayout ::
122+
(HasServer api '[]) => Proxy api -> Text -> Expectation
123+
shouldHaveLayout p l =
124+
unless (routerLayout (makeTrivialRouter p) == l) $
125+
expectationFailure ("expected:\n" ++ unpack l ++ "\nbut got:\n" ++ unpack (layout p))
126+
110127
makeTrivialRouter :: (HasServer layout '[]) => Proxy layout -> Router ()
111128
makeTrivialRouter p =
112129
route p EmptyContext (emptyDelayed (FailFatal err501))
@@ -342,3 +359,74 @@ level = Proxy
342359

343360
levelRef :: Proxy LevelRef
344361
levelRef = Proxy
362+
363+
-- The example API for the 'layout' function.
364+
-- Should get factorized by the 'choice' smart constructor.
365+
type ExampleLayout =
366+
"a" :> "d" :> Get '[JSON] NoContent
367+
:<|> "b" :> Capture "x" Int :> Get '[JSON] Bool
368+
:<|> "c" :> Put '[JSON] Bool
369+
:<|> "a" :> "e" :> Get '[JSON] Int
370+
:<|> "b" :> Capture "x" Int :> Put '[JSON] Bool
371+
:<|> Raw
372+
373+
exampleLayout :: Proxy ExampleLayout
374+
exampleLayout = Proxy
375+
376+
-- The expected representation of the example API layout
377+
--
378+
expectedExampleLayout :: Text
379+
expectedExampleLayout =
380+
"/\n\
381+
\├─ a/\n\
382+
\│ ├─ d/\n\
383+
\│ │ └─•\n\
384+
\│ └─ e/\n\
385+
\│ └─•\n\
386+
\├─ b/\n\
387+
\│ └─ <x::CaptureSingle>/\n\
388+
\│ ├─•\n\
389+
\│ ┆\n\
390+
\│ └─•\n\
391+
\├─ c/\n\
392+
\│ └─•\n\
393+
\┆\n\
394+
\└─ <raw>\n"
395+
396+
-- The expected representation of the Dynamic API layout.
397+
--
398+
expectedDynamicLayout :: Text
399+
expectedDynamicLayout =
400+
"/\n\
401+
\└─ a/\n\
402+
\ └─ <foo::CaptureSingle|bar::CaptureSingle|baz::CaptureSingle>/\n\
403+
\ ├─ b/\n\
404+
\ │ └─•\n\
405+
\ ├─ c/\n\
406+
\ │ └─•\n\
407+
\ └─ d/\n\
408+
\ └─•\n"
409+
410+
-- The same Dynamic API as above, except that the captured
411+
-- values have the same hints
412+
type DynamicSameType =
413+
"a" :> Capture "foo" Int :> "b" :> End
414+
:<|> "a" :> Capture "foo" Int :> "c" :> End
415+
:<|> "a" :> Capture "foo" Int :> "d" :> End
416+
417+
dynamicSameType :: Proxy DynamicSameType
418+
dynamicSameType = Proxy
419+
420+
-- The expected representation of the DynamicSameType API layout.
421+
--
422+
expectedDynamicSameTypeLayout :: Text
423+
expectedDynamicSameTypeLayout =
424+
"/\n\
425+
\└─ a/\n\
426+
\ └─ <foo::CaptureSingle>/\n\
427+
\ ├─ b/\n\
428+
\ │ └─•\n\
429+
\ ├─ c/\n\
430+
\ │ └─•\n\
431+
\ └─ d/\n\
432+
\ └─•\n"

0 commit comments

Comments
 (0)