#!/usr/bin/perl use strict; use warnings; use Test::More; use Data::BitStream; my @encodings = qw| Unary Unary1 Gamma Delta Omega Fibonacci EvenRodeh Levenstein Golomb(10) Golomb(16) Golomb(14000) Rice(2) Rice(9) GammaGolomb(3) GammaGolomb(128) ExpGolomb(5) BoldiVigna(2) Baer(0) Baer(-2) Baer(2) StartStepStop(3-3-99) StartStop(1-0-1-0-2-12-99) Comma(2) Comma(5) BlockTaboo(10) BlockTaboo(101001) ARice(2) |; plan tests => 3*12*3 - 2*3 + 3*5*3 + 5*3 + 1*3 + scalar @encodings * 2 + scalar @encodings * 7 + 10*3; my $s = Data::BitStream->new; my $v; foreach my $nzeros (16,48,280) { # For our first set of tests, we're going to write some zeros, then try to # read Unary and codes using unary bases, and verify that we get the right # error code as well as leave the position unchanged. $s->erase_for_write; $s->write($nzeros, 0); $s->rewind_for_read; foreach my $code (qw|Unary Gamma Delta Fibonacci Rice(2) Golomb(10) GammaGolomb(3) ExpGolomb(5) ARice(2) BoldiVigna(2) Binword(32) Comma(2)|) { next if $code =~ /Binword/ and $nzeros > 32; # Set position to a little way in $s->rewind; $s->skip(3); die "Position error" unless $s->pos == 3; eval { $s->code_get($code); }; like($@, qr/read off end of stream/i, "$code off $nzeros-bit stream"); is($s->pos, 3, "$code read off $nzeros-bit stream left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } foreach my $nzeros (16,48,280) { # Next, do the same with 1's. $s->erase_for_write; $s->write(32, 0xFFFFFFFF) for (1 .. $nzeros/32); $s->write($nzeros % 32, 0xFFFFFFFF); $s->rewind_for_read; foreach my $code (qw|Unary1 Omega Levenstein Baer(-2) BlockTaboo(100)|) { # Set position to a little way in $s->rewind; $s->skip(3); die "Position error" unless $s->pos == 3; eval { $s->code_get($code); }; if ( ($nzeros > 32) && ($code =~ /Omega/i) ) { like($@, qr/code error/i, "$code off $nzeros-bit stream"); } elsif ( ($nzeros > 32) && ($code =~ /BlockTaboo/i) ) { like($@, qr/(code error|read off end of stream)/i, "$code off $nzeros-bit stream"); } else { like($@, qr/read off end of stream/i, "$code off $nzeros-bit stream"); } is($s->pos, 3, "$code read off $nzeros-bit stream left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } { # Now we'll write a bogus unary base and see how the codes handle getting # invalid bases. This is a lot harder to handle. $s->erase_for_write; $s->write(7, 0xFFFFFFFF); $s->put_unary(259); $s->write(32, 0xFFFFFFFF); $s->rewind_for_read; foreach my $code (qw|Gamma Delta GammaGolomb(3) ExpGolomb(5) ARice(2)|) { # Set position to a little way in $s->rewind; $s->skip(7); die "Position error" unless $s->pos == 7; eval { $s->code_get($code); }; like($@, qr/code error/i, "$code bad base"); is($s->pos, 7, "Bad $code read left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } { # Same but using bogus gamma base. $s->erase_for_write; $s->write(7, 0xFFFFFFFF); $s->put_gamma(259); $s->write(32, 0xFFFFFFFF); $s->rewind_for_read; foreach my $code (qw|Delta|) { # Set position to a little way in $s->rewind; $s->skip(7); die "Position error" unless $s->pos == 7; eval { $s->code_get($code); }; like($@, qr/code error/i, "$code bad base"); is($s->pos, 7, "Bad $code read left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } { # Something a little different: read from an empty stream. $s->erase_for_write; $s->rewind_for_read; foreach my $code (@encodings) { $s->rewind; my $v = $s->code_get($code); is($v, undef, "Empty stream returned undef for $code"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } { # Write negative and undefined values foreach my $code (@encodings) { $s->erase_for_write; my $v; eval { $v = $s->code_put($code, -5); }; like($@, qr/value must be >= 0/i, "$code write negative value"); is($v, undef, "Got undef for $code writing negative value"); is($s->pos, 0, "$code writing negative value left position unchanged"); eval { $v = $s->code_put($code, undef); }; like($@, qr/value must be >= 0/i, "$code write undef value"); is($v, undef, "Got undef for $code writing undef"); is($s->pos, 0, "$code writing undef left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } { # Write a normal unary start code, then end the stream. Read with various # codes that use a unary prefix and see if it fails gracefully. $s->erase_for_write; $s->write(8, 1); $s->rewind_for_read; foreach my $code (qw|Gamma Delta Fibonacci Rice(2) Golomb(10) GammaGolomb(3) ExpGolomb(5) ARice(2) BoldiVigna(2) Binword(32)|) { # Set position to a little way in $s->rewind; $s->skip(3); die "Position error" unless $s->pos == 3; eval { $s->code_get($code); }; like($@, qr/read off end of stream/i, "$code after partial stream"); is($s->pos, 3, "$code after partial stream left position unchanged"); is($s->code_pos_is_set(), undef, "$code error position cleanup"); } } # TODO: off stream after base # TODO: invalid string (XS allows 0 and anything # TODO: EvenRodeh, StartStepStop, StartStop # TODO: Better off-stream tests for Omega and BlockTaboo