Skip to content

Commit cc5a46b

Browse files
committed
Add tests for nested NamedRoutes links
1 parent 5c1c376 commit cc5a46b

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

servant/test/Servant/LinksSpec.hs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{-# LANGUAGE ConstraintKinds #-}
22
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE DeriveGeneric #-}
34
{-# LANGUAGE PolyKinds #-}
45
{-# LANGUAGE ScopedTypeVariables #-}
56
{-# LANGUAGE TypeOperators #-}
67
module Servant.LinksSpec where
78

9+
import GHC.Generics
10+
(Generic)
811
import Data.Proxy
912
(Proxy (..))
1013
import Data.String
@@ -44,17 +47,51 @@ type LinkableApi =
4447
"all" :> CaptureAll "names" String :> Get '[JSON] NoContent
4548
:<|> "get" :> Get '[JSON] NoContent
4649

47-
4850
apiLink :: (IsElem endpoint TestApi, HasLink endpoint)
4951
=> Proxy endpoint -> MkLink endpoint Link
5052
apiLink = safeLink (Proxy :: Proxy TestApi)
5153

54+
55+
newtype QuuxRoutes mode = QuuxRoutes
56+
{ corge :: mode :- "corge" :> Post '[PlainText] NoContent
57+
} deriving Generic
58+
59+
newtype WaldoRoutes mode = WaldoRoutes
60+
{ waldo :: mode :- "waldo" :> Get '[JSON] NoContent
61+
} deriving Generic
62+
63+
data FooRoutes mode = FooRoutes
64+
{ baz :: mode :- "baz" :> Get '[JSON] NoContent
65+
, qux :: mode :- "qux" :> NamedRoutes QuuxRoutes
66+
, quux :: mode :- "quux" :> QueryParam "grault" String :> Get '[JSON] NoContent
67+
, garply :: mode :- "garply" :> Capture "garply" String
68+
:> Capture "garplyNum" Int :> NamedRoutes WaldoRoutes
69+
} deriving Generic
70+
71+
data BaseRoutes mode = BaseRoutes
72+
{ foo :: mode :- "foo" :> NamedRoutes FooRoutes
73+
, bar :: mode :- "bar" :> Get '[JSON] NoContent
74+
} deriving Generic
75+
76+
recordApiLink
77+
:: (IsElem endpoint (NamedRoutes BaseRoutes), HasLink endpoint)
78+
=> Proxy endpoint -> MkLink endpoint Link
79+
recordApiLink = safeLink (Proxy :: Proxy (NamedRoutes BaseRoutes))
80+
5281
-- | Convert a link to a URI and ensure that this maps to the given string
5382
-- given string
5483
shouldBeLink :: Link -> String -> Expectation
5584
shouldBeLink link expected =
5685
toUrlPiece link `shouldBe` fromString expected
5786

87+
(//) :: a -> (a -> b) -> b
88+
x // f = f x
89+
infixl 1 //
90+
91+
(/:) :: (a -> b -> c) -> b -> a -> c
92+
(/:) = flip
93+
infixl 2 /:
94+
5895
spec :: Spec
5996
spec = describe "Servant.Links" $ do
6097
it "generates correct links for capture query params" $ do
@@ -106,6 +143,33 @@ spec = describe "Servant.Links" $ do
106143
let firstLink :<|> _ = allLinks comprehensiveAPIWithoutRaw
107144
firstLink `shouldBeLink` ""
108145

146+
it "Generate links from record fields accessors" $ do
147+
fieldLink bar `shouldBeLink` "bar"
148+
(fieldLink foo // baz) `shouldBeLink` "foo/baz"
149+
(fieldLink foo // qux // corge) `shouldBeLink` "foo/qux/corge"
150+
(fieldLink foo // quux /: Nothing) `shouldBeLink` "foo/quux"
151+
(fieldLink foo // quux /: Just "floop") `shouldBeLink` "foo/quux?grault=floop"
152+
(fieldLink foo // garply /: "captureme" /: 42 // waldo)
153+
`shouldBeLink` "foo/garply/captureme/42/waldo"
154+
155+
it "Check links from record fields" $ do
156+
let sub1 = Proxy :: Proxy ("bar" :> Get '[JSON] NoContent)
157+
recordApiLink sub1 `shouldBeLink` "bar"
158+
159+
let sub2 = Proxy :: Proxy ("foo" :> "baz" :> Get '[JSON] NoContent)
160+
recordApiLink sub2 `shouldBeLink` "foo/baz"
161+
162+
let sub3 = Proxy :: Proxy ("foo" :> "quux" :> QueryParam "grault" String
163+
:> Get '[JSON] NoContent)
164+
recordApiLink sub3 (Just "floop") `shouldBeLink` "foo/quux?grault=floop"
165+
166+
let sub4 :: Proxy ("foo" :> "garply" :> Capture "garplyText" String
167+
:> Capture "garplyInt" Int :> "waldo"
168+
:> Get '[JSON] NoContent)
169+
sub4 = Proxy
170+
recordApiLink sub4 "captureme" 42
171+
`shouldBeLink` "foo/garply/captureme/42/waldo"
172+
109173
-- The doctests below aren't run on CI, setting that up is tricky.
110174
-- They are run by makefile rule, however.
111175

0 commit comments

Comments
 (0)