The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use Test::More import => ['!pass'], tests => 21;
use Dancer qw(:syntax);
use Dancer::Test;

use URI;
use XML::XPath;
use Dancer::Plugin::DBIC qw(schema);
use Capture::Tiny qw(capture);

BEGIN {
    set atombus => {
        db => {
            dsn => 'dbi:SQLite:dbname=:memory:',
        }
    };
}

use AtomBus;

my $xml = q{
    <entry>
        <title>title%s</title>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">content%s</div>
        </content>
    </entry>
};

# Confirm that feed doesn't exist yet.
capture { # Silence output from schema->deploy in before filter.
    response_status_is [ GET => "/feeds/foo" ], 404;
};

# Create one entry and examine result.
my $res = dancer_response POST => "/feeds/foo", { body => sprintf($xml, 1, 1) };
is $res->{status}=> 201, 'Status was 201';
my $etag = new URI($res->{headers}->{etag}, 'urn');
my $location = new URI($res->{headers}->{location}, 'http');
my $id_nss = $location;
($id_nss) =~ s,^.*/,,;
is $location->path => "/feeds/foo/entries/$id_nss", 'Location header is well-structured.';
is $etag->as_string => "urn:uuid:$id_nss", 'ETag was contained in location header.';
$res = dancer_response GET => $location->path;
is $res->{status}=> 200, 'Entry was GETtable with status 200';

# Create additional entries.
foreach my $i (2 .. 10) {
    dancer_response POST => "/feeds/foo", { body => sprintf($xml, $i, $i) };
}

$res = dancer_response GET => "/feeds/foo";
my $xp = XML::XPath->new(xml => $res->{content});
my @entries = $xp->findnodes('/feed/entry');
is $res->{status}=> 200, 'Status was 200';
is @entries => 10, 'There are 10 entries';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 1 .. 10 ],
    "All 10 entries are in order.";

my $id = $entries[4]->find('./id'); # this is the 5th entry
$res = dancer_response GET => "/feeds/foo", { params => { start_at => $id } };
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 6, 'Got 6 entries when starting at the 5th one.';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 5 .. 10 ],
    "All 6 entries are in order.";

$res = dancer_response GET => "/feeds/foo", { params => {start_after => $id} };
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 5, 'Got 5 entries when starting after the 5th one.';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 6 .. 10 ],
    "All 5 entries are in order.";

$res = dancer_response GET => "/feeds/foo",
    { headers => [ 'If-None-Match' => $id ] };
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 5, 'Got 5 entries when If-None-Match is 5th element.';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 6 .. 10 ],
    "All 5 entries are in order.";

$res = dancer_response GET => "/feeds/foo",
    { headers => [ 'If-None-Match' => 'foo' ] };
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 10, 'Got all entries when If-None-Match is an unkown id.';

$id = $entries[-1]->find('./id'); # this is the last entry
$res = dancer_response GET => "/feeds/foo",
    { headers => [ 'If-None-Match' => $id] };
is $res->{status}, 304, "Status is 304 when If-None-Match is the last id";
is $res->{content}, '', "Body is empty when If-None-Match is the last id";

config->{atombus}{page_size} = 7;

$res = dancer_response GET => "/feeds/foo";
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 7, 'There are 7 entries with page_size = 7.';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 1 .. 7 ],
    "All 7 entries are in order.";

$id = $entries[-1]->find('./id');
$res = dancer_response GET => "/feeds/foo", { params => {start_after => $id} };
$xp = XML::XPath->new(xml => $res->{content});
@entries = $xp->findnodes('/feed/entry');
is @entries => 3, 'Got rest of entries on last (second) page.';
is_deeply
    [ map $_->findvalue('./content/div'), @entries ],
    [ map "content$_", 8 .. 10 ],
    "All 3 entries are in order.";

done_testing;