Solution: Dancer Calculator
examples/dancer/calc/app.psgi
package App; use Dancer2; use Scalar::Util qw(looks_like_number); get '/' => sub { return <<'HTML'; <form action="/calc" method="POST"> <input type="text" name="x"> <select name="op"> <option value="add">+</option> <option value="deduct">-</option> <option value="div">/</option> <option value="multiply">*</option> </select> <input type="text" name="y"> <input type="submit" value="Calculate"> </form> HTML }; post '/calc' => sub { my $x = body_parameters->get('x'); my $y = body_parameters->get('y'); my $op = body_parameters->get('op'); my %valid_ops = map { $_ => 1 } qw(add deduct multiply div); if (not looks_like_number($x) or not looks_like_number($y) or not defined $op or not exists $valid_ops{$op}) { status 'bad_request'; return 'Invalid input'; } my $result; if ($op eq 'div' and $y == 0) { status 'bad_request'; return 'Cannot divide by 0'; } $result = $x + $y if $op eq 'add'; $result = $x - $y if $op eq 'deduct'; $result = $x * $y if $op eq 'multiply'; $result = $x / $y if $op eq 'div'; return "The result is $result"; }; App->to_app;
examples/dancer/calc/test.t
use strict; use warnings; use Test::More; use Plack::Test; use Plack::Util; use HTTP::Request::Common; my $app = Plack::Util::load_psgi './app.psgi'; my $test = Plack::Test->create($app); subtest main => sub { my $res = $test->request(GET '/'); is $res->status_line, '200 OK', 'Status'; like $res->content, qr{<form action="/calc" method="POST">}, 'Content'; }; subtest calc => sub { my @cases = ( [{ x => '10', y => '2', op => 'add'}, '12'], [{ x => '10', y => '2', op => 'multiply'}, '20'], [{ x => '10', y => '2', op => 'deduct'}, '8'], [{ x => '10', y => '2', op => 'div'}, '5'], ); for my $case (@cases) { my $res = $test->request(POST '/calc', $case->[0]); is $res->status_line, '200 OK', "Status x=$case->[0]{x} y=$case->[0]{y} op=$case->[0]{op}"; is $res->content, "The result is $case->[1]", 'Content'; } my @bad_cases = ( [{ x => 'hello', y => '2', op => 'add'}, 'Invalid input'], [{ x => '', y => '2', op => 'add'}, 'Invalid input'], [{ y => '2', op => 'add'}, 'Invalid input'], [{ x => '2', y => 'world', op => 'add'}, 'Invalid input'], [{ x => '2', y => 'world', op => 'add'}, 'Invalid input'], [{ x => '2', y => '', op => 'add'}, 'Invalid input'], [{ x => '2', op => 'add'}, 'Invalid input'], [{ x => '10', y => '2', op => 'else'}, 'Invalid input'], [{ x => '10', y => '2', op => ''}, 'Invalid input'], [{ x => '10', y => '2'}, 'Invalid input'], ); for my $case (@bad_cases) { my $res = $test->request(POST '/calc', $case->[0]); no warnings 'uninitialized'; is $res->status_line, '400 Bad Request', "Status x=$case->[0]{x} y=$case->[0]{y} op=$case->[0]{op}"; is $res->content, $case->[1], "Content x=$case->[0]{x} y=$case->[0]{y} op=$case->[0]{op}"; } my $res = $test->request(POST '/calc', { x => '3', y => '0', op => 'div'}); is $res->status_line, '400 Bad Request', 'Status'; is $res->content, 'Cannot divide by 0', 'Content'; }; done_testing();