blob: 2e9b542a1ba1da0743a2618d3172a43dc486e5c7 [file] [log] [blame]
# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*-
package TestAPRlib::bucket;
# a mix of APR::Bucket and APR::BucketType tests
use strict;
use warnings FATAL => 'all';
use Apache::Test;
use Apache::TestUtil;
use TestCommon::Utils;
use APR::Pool ();
use APR::Bucket ();
use APR::BucketAlloc ();
use APR::BucketType ();
use APR::Table ();
use APR::Const -compile => 'SUCCESS';
sub num_of_tests {
return 21;
}
sub test {
my $pool = APR::Pool->new();
my $ba = APR::BucketAlloc->new($pool);
# new: basic
{
my $data = "foobar";
my $b = APR::Bucket->new($ba, $data);
t_debug('$b is defined');
ok defined $b;
t_debug('$b ISA APR::Bucket object');
ok $b->isa('APR::Bucket');
my $type = $b->type;
ok t_cmp $type->name, 'mod_perl SV bucket', "type";
ok t_cmp $b->length, length($data), "modperl b->length";
}
# new: offset
{
my $data = "foobartar";
my $offset = 3;
my $real = substr $data, $offset;
my $b = APR::Bucket->new($ba, $data, $offset);
my $rlen = $b->read(my $read);
ok t_cmp $read, $real, 'new($data, $offset)/buffer';
ok t_cmp $rlen, length($read), 'new($data, $offset)/len';
ok t_cmp $b->start, $offset, 'offset';
}
# new: offset+len
{
my $data = "foobartar";
my $offset = 3;
my $len = 3;
my $real = substr $data, $offset, $len;
my $b = APR::Bucket->new($ba, $data, $offset, $len);
my $rlen = $b->read(my $read);
ok t_cmp $read, $real, 'new($data, $offset, $len)/buffer';
ok t_cmp $rlen, length($read), 'new($data, $offse, $lent)/len';
}
# new: offset+ too big len
{
my $data = "foobartar";
my $offset = 3;
my $len = 10;
my $real = substr $data, $offset, $len;
my $b = eval { APR::Bucket->new($ba, $data, $offset, $len) };
ok t_cmp $@,
qr/the length argument can't be bigger than the total/,
'new($data, $offset, $len_too_big)';
}
# modification of the source variable, affects the data
# inside the bucket
{
my $data = "A" x 10;
my $orig = $data;
my $b = APR::Bucket->new($ba, $data);
$data =~ s/^..../BBBB/;
$b->read(my $read);
ok t_cmp $read, $data,
"data inside the bucket should get affected by " .
"the changes to the Perl variable it's created from";
}
# APR::Bucket->new() with the argument PADTMP (which happens when
# some function is re-entered) and the same SV is passed to
# different buckets, which must be detected and copied away.
{
my @buckets = ();
my @data = qw(ABCD EF);
my @received = ();
for my $str (@data) {
my $b = func($ba, $str);
push @buckets, $b;
}
# the creating of buckets and reading from them is done
# separately on purpose
for my $b (@buckets) {
$b->read(my $out);
push @received, $out;
}
# here we used to get: two pv: "ef\0d"\0, "ef"\0, as you can see
# the first bucket had corrupted data.
my @expected = map { lc } @data;
ok t_cmp \@received, \@expected, "new(PADTMP SV)";
# this function will pass the same SV to new(), causing two
# buckets point to the same SV, and having the latest bucket's
# data override the previous one
sub func {
my $ba = shift;
my $data = shift;
return APR::Bucket->new($ba, lc $data);
}
}
# read data is tainted
{
my $data = "xxx";
my $b = APR::Bucket->new($ba, $data);
$b->read(my $read);
ok t_cmp $read, $data, 'new($data)';
ok TestCommon::Utils::is_tainted($read);
}
# remove/destroy
{
my $b = APR::Bucket->new($ba, "aaa");
# remove $b when it's not attached to anything (not sure if
# that should be an error)
$b->remove;
ok 1;
# a dangling bucket needs to be destroyed
$b->destroy;
ok 1;
# real remove from bb is tested in many other filter tests
}
# setaside
{
my $data = "A" x 10;
my $expected = $data;
my $b = APR::Bucket->new($ba, $data);
my $status = $b->setaside($pool);
ok t_cmp $status, APR::Const::SUCCESS, "setaside status";
$data =~ s/^..../BBBB/;
$b->read(my $read);
ok t_cmp $read, $expected,
"data inside the setaside bucket is unaffected by " .
"changes to the Perl variable it's created from";
$b->destroy;
}
# alloc_create on out-of-scope pools
{
# later may move that into a dedicated bucket_alloc test
my $ba = APR::BucketAlloc->new(APR::Pool->new);
# here if the pool is gone of scope destroy() will segfault
$ba->destroy;
ok 1;
}
# setaside on out-of-scope pools
{
# note that at the moment APR internally handles the situation
# when the pool goes out of scope, so modperl doesn't need to do
# any special handling of the pool object passed to setaside()
# to insure that it survives as long as $b is alive
#
# to make sure that this doesn't change internally in APR, the
# sub-test remains here
my $data = "A" x 10;
my $orig = $data;
my $b = APR::Bucket->new($ba, $data);
my $status = $b->setaside(APR::Pool->new);
ok t_cmp $status, APR::Const::SUCCESS, "setaside status";
# try to overwrite the temp pool data
my $table = APR::Table::make(APR::Pool->new, 50);
$table->set($_ => $_) for 'aa'..'za';
# now test that we are still OK
$b->read(my $read);
ok t_cmp $read, $data,
"data inside the setaside bucket is not corrupted";
$b->destroy;
}
$ba->destroy;
}
1;