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;