1use strict;
2use warnings;
3use utf8;
4use Test::More;
5use Plack::Test;
6use Encode 'encode_utf8';
7use HTTP::Request::Common;
8
9subtest 'Query parameters' => sub {
10    {
11        package App::Basic; ## no critic
12        use Dancer2;
13        get '/' => sub {
14            my $params = query_parameters;
15            ::isa_ok(
16                $params,
17                'Hash::MultiValue',
18                'parameters keyword',
19            );
20
21            ::is( $params->get('foo'), 'bar', 'Got single value' );
22            ::is(
23                $params->get('bar'),
24                'quux',
25                'Got single value from multi key',
26            );
27
28            ::is_deeply(
29                [ $params->get_all('bar') ],
30                ['baz', 'quux'],
31                'Got multi value from multi key',
32            );
33
34            ::is(
35                $params->get('baz'),
36                'הלו',
37                'HMV interface returns encoded values',
38            );
39
40            ::is(
41                params->{'baz'},
42                'הלו',
43                'Regular interface returns encoded values'
44            );
45        };
46    }
47
48    my $app = Plack::Test->create( App::Basic->to_app );
49    my $res = $app->request( GET '/?foo=bar&bar=baz&bar=quux&baz=הלו' );
50    ok( $res->is_success, 'Successful request' );
51};
52
53subtest 'Body parameters' => sub {
54    {
55        package App::Body; ## no critic
56        use Dancer2;
57        post '/' => sub {
58            my $params = body_parameters;
59            ::isa_ok(
60                $params,
61                'Hash::MultiValue',
62                'parameters keyword',
63            );
64
65            ::is( $params->get('foo'), 'bar', 'Got single value' );
66            ::is(
67                $params->get('bar'),
68                'quux',
69                'Got single value from multi key',
70            );
71
72            my $z = [ $params->get_all('bar') ];
73            ::is_deeply(
74                [ $params->get_all('bar') ],
75                ['baz', 'quux'],
76                'Got multi value from multi key',
77            );
78
79            ::is(
80                $params->get('baz'),
81                'הלו',
82                'HMV interface returns encoded values',
83            );
84
85            ::is(
86                params->{'baz'},
87                'הלו',
88                'Regular interface returns encoded values'
89            );
90        };
91    }
92
93    my $app = Plack::Test->create( App::Body->to_app );
94    my $res = $app->request(
95        POST '/',
96        Content => [foo => 'bar', bar => 'baz', bar => 'quux', baz => 'הלו']
97    );
98    ok( $res->is_success, 'Successful request' );
99};
100
101subtest 'Body parameters with serialized data' => sub {
102    {
103        package App::Body::JSON; ## no critic
104        use Dancer2;
105        set serializer => 'JSON';
106        post '/' => sub {
107            my $params = body_parameters;
108            ::isa_ok(
109                $params,
110                'Hash::MultiValue',
111                'parameters keyword',
112            );
113
114            ::is( $params->get('foo'), 'bar', 'Got single value' );
115            ::is(
116                $params->get('bar'),
117                'quux',
118                'Got single value from multi key',
119            );
120
121            my $z = [ $params->get_all('bar') ];
122            ::is_deeply(
123                [ $params->get_all('bar') ],
124                ['baz', 'quux'],
125                'Got multi value from multi key',
126            );
127
128            ::is(
129                $params->get('baz'),
130                'הלו',
131                'HMV interface returns encoded values',
132            );
133
134            ::is(
135                params->{'baz'},
136                'הלו',
137                'Regular interface returns encoded values'
138            );
139
140            return { ok => 1 };
141        };
142    }
143
144    my $app = Plack::Test->create( App::Body::JSON->to_app );
145    my $baz = encode_utf8('הלו');
146    my $res = $app->request(
147        POST '/', Content => qq{{"foo":"bar","bar":["baz","quux"],"baz":"$baz"}}
148    );
149    ok( $res->is_success, 'Successful request' );
150};
151
152subtest 'Route parameters' => sub {
153    {
154        package App::Route; ## no critic
155        use Dancer2;
156        get '/:foo' => sub {
157            my $params = route_parameters;
158            ::isa_ok(
159                $params,
160                'Hash::MultiValue',
161                'parameters keyword',
162            );
163
164            ::is( $params->get('foo'), 'bar', 'Got keyed value' );
165        };
166
167        get '/:name/:value' => sub {
168            my $params = route_parameters;
169            ::isa_ok(
170                $params,
171                'Hash::MultiValue',
172                'parameters keyword returns Hash::MultiValue object',
173            );
174
175            ::is( $params->get('name'), 'foo', 'Got first value' );
176            ::is( $params->get('value'), 'הלו', 'Got second value' );
177            ::is(
178                params->{'value'},
179                'הלו',
180                'Regular interface returns encoded values'
181            );
182        };
183    }
184
185    my $app = Plack::Test->create( App::Route->to_app );
186
187    {
188        my $res = $app->request( GET '/bar' );
189        ok( $res->is_success, 'Successful request' );
190    }
191
192    {
193        my $res = $app->request( GET '/foo/הלו' );
194        ok( $res->is_success, 'Successful request' );
195    }
196};
197
198subtest 'Splat and megasplat route parameters' => sub {
199    {
200        package App::Route::Splat; ## no critic
201        use Dancer2;
202        get '/*' => sub {
203            my $params = route_parameters;
204            ::isa_ok(
205                $params,
206                'Hash::MultiValue',
207                'parameters keyword',
208            );
209
210            ::is_deeply(
211                { %{$params} },
212                {},
213                'All route parameters are empty',
214            );
215
216            ::is_deeply(
217                [ splat ],
218                [ 'foo' ],
219                'Got splat values',
220            );
221        };
222
223        get '/*/*' => sub {
224            my $params = route_parameters;
225            ::isa_ok(
226                $params,
227                'Hash::MultiValue',
228                'parameters keyword returns Hash::MultiValue object',
229            );
230
231
232            ::is_deeply(
233                { %{$params} },
234                {},
235                'All route parameters are empty',
236            );
237
238            ::is_deeply(
239                [ splat ],
240                [ qw<foo bar> ],
241                'Got splat values',
242            );
243        };
244
245        # /foo/bar/baz/quux/quuks
246        get '/*/*/*/**' => sub {
247            my $params = route_parameters;
248            ::isa_ok(
249                $params,
250                'Hash::MultiValue',
251                'parameters keyword returns Hash::MultiValue object',
252            );
253
254
255            ::is_deeply(
256                { %{$params} },
257                {},
258                'All route parameters are empty',
259            );
260
261            ::is_deeply(
262                [ splat ],
263                [ qw<foo bar baz>, [ qw<quux quuks> ] ],
264                'Got splat values',
265            );
266        };
267
268        # /foo/bar/baz
269        get '/*/:foo/**' => sub {
270            my $params = route_parameters;
271            ::isa_ok(
272                $params,
273                'Hash::MultiValue',
274                'parameters keyword returns Hash::MultiValue object',
275            );
276
277            ::is( $params->get('foo'), 'bar', 'Correct route parameter' );
278
279            ::is_deeply(
280                [ splat ],
281                [ 'foo', ['baz', ''] ],
282                'Got splat values',
283            );
284        };
285    }
286
287    my $app = Plack::Test->create( App::Route::Splat->to_app );
288
289    {
290        my $res = $app->request( GET '/foo' );
291        ok( $res->is_success, 'Successful request' );
292    }
293
294    {
295        my $res = $app->request( GET '/foo/bar' );
296        ok( $res->is_success, 'Successful request' );
297    }
298
299    {
300        my $res = $app->request( GET '/foo/bar/baz/quux/quuks' );
301        ok( $res->is_success, 'Successful request' );
302    }
303
304    {
305        my $res = $app->request( GET '/foo/bar/baz/' );
306        ok( $res->is_success, 'Successful request' );
307    }
308};
309
310subtest 'Captured route parameters' => sub {
311    {
312        package App::Route::Capture; ## no critic
313        use Dancer2;
314        get qr{^/foo/([^/]+)$} => sub {
315            my $params = route_parameters;
316            ::isa_ok(
317                $params,
318                'Hash::MultiValue',
319                'parameters keyword',
320            );
321
322            ::is_deeply(
323                { %{$params} },
324                {},
325                'All route parameters are empty',
326            );
327
328            ::is_deeply(
329                [ splat ],
330                ['bar'],
331                'Correct splat values',
332            );
333
334            ::is_deeply(
335                captures(),
336                +{},
337                'capture values are empty',
338            );
339        };
340    }
341
342    my $app = Plack::Test->create( App::Route::Capture->to_app );
343
344    {
345        my $res = $app->request( GET '/foo/bar' );
346        ok( $res->is_success, 'Successful request' );
347    }
348};
349
350SKIP: {
351    Test::More::skip "named captures not available until 5.10", 1
352      if !$^V or $^V lt v5.10;
353
354    subtest 'Named captured route parameters' => sub {
355        {
356            package App::Route::NamedCapture; ## no critic
357            use Dancer2;
358            my $re = '^/bar/(?<baz>[^/]+)$';
359            get qr{$re} => sub {
360                my $params = route_parameters;
361
362                ::isa_ok(
363                    $params,
364                    'Hash::MultiValue',
365                    'parameters keyword',
366                );
367
368                ::is_deeply(
369                    { %{$params} },
370                    {},
371                    'All route parameters are empty',
372                );
373
374                ::is_deeply(
375                    [ splat ],
376                    [],
377                    'splat values are empty',
378                );
379
380                ::is_deeply(
381                    captures(),
382                    { baz => 'quux' },
383                    'Correct capture values',
384                );
385            };
386        }
387
388        my $app = Plack::Test->create( App::Route::NamedCapture->to_app );
389
390        {
391            my $res = $app->request( GET '/bar/quux' );
392            ok( $res->is_success, 'Successful request' );
393        };
394    };
395};
396done_testing();
397