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;
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();