|
1 | 1 | {-# LANGUAGE ConstraintKinds #-}
|
2 | 2 | {-# LANGUAGE DataKinds #-}
|
| 3 | +{-# LANGUAGE DeriveGeneric #-} |
3 | 4 | {-# LANGUAGE PolyKinds #-}
|
4 | 5 | {-# LANGUAGE ScopedTypeVariables #-}
|
5 | 6 | {-# LANGUAGE TypeOperators #-}
|
6 | 7 | module Servant.LinksSpec where
|
7 | 8 |
|
| 9 | +import GHC.Generics |
| 10 | + (Generic) |
8 | 11 | import Data.Proxy
|
9 | 12 | (Proxy (..))
|
10 | 13 | import Data.String
|
@@ -44,17 +47,51 @@ type LinkableApi =
|
44 | 47 | "all" :> CaptureAll "names" String :> Get '[JSON] NoContent
|
45 | 48 | :<|> "get" :> Get '[JSON] NoContent
|
46 | 49 |
|
47 |
| - |
48 | 50 | apiLink :: (IsElem endpoint TestApi, HasLink endpoint)
|
49 | 51 | => Proxy endpoint -> MkLink endpoint Link
|
50 | 52 | apiLink = safeLink (Proxy :: Proxy TestApi)
|
51 | 53 |
|
| 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 | + |
52 | 81 | -- | Convert a link to a URI and ensure that this maps to the given string
|
53 | 82 | -- given string
|
54 | 83 | shouldBeLink :: Link -> String -> Expectation
|
55 | 84 | shouldBeLink link expected =
|
56 | 85 | toUrlPiece link `shouldBe` fromString expected
|
57 | 86 |
|
| 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 | + |
58 | 95 | spec :: Spec
|
59 | 96 | spec = describe "Servant.Links" $ do
|
60 | 97 | it "generates correct links for capture query params" $ do
|
@@ -106,6 +143,33 @@ spec = describe "Servant.Links" $ do
|
106 | 143 | let firstLink :<|> _ = allLinks comprehensiveAPIWithoutRaw
|
107 | 144 | firstLink `shouldBeLink` ""
|
108 | 145 |
|
| 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 | + |
109 | 173 | -- The doctests below aren't run on CI, setting that up is tricky.
|
110 | 174 | -- They are run by makefile rule, however.
|
111 | 175 |
|
|
0 commit comments