#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
my @types = qw(string wordvec xs);
plan tests => scalar @types;
# We require the string implementation, and will test the Vec and BitVec
# versions if they're available.
use Data::BitStream::String;
my %stream_constructors = (
'string', sub { return Data::BitStream::String->new(); },
);
#if (eval {require Data::BitStream::Vec}) {
# $stream_constructors{'vector'} = sub { return Data::BitStream::Vec->new(); };
#}
#if (eval {require Data::BitStream::BitVec}) {
# $stream_constructors{'bitvector'} = sub { return Data::BitStream::BitVec->new(); };
#}
if (eval {require Data::BitStream::WordVec}) {
$stream_constructors{'wordvec'} = sub { return Data::BitStream::WordVec->new(); };
}
if (eval {require Data::BitStream::XS}) {
$stream_constructors{'xs'} = sub { return Data::BitStream::XS->new(); };
}
sub new_stream {
my $type = lc shift;
$type =~ s/[^a-z]//g;
my $constructor = $stream_constructors{$type};
return unless defined $constructor;
$constructor->();
}
sub test_type {
my $type = shift;
my $stream = shift;
die unless defined $type and defined $stream;
my $status;
my $v;
# Test basic operations that should succeed
ok($stream->maxbits >= 32, "maxbits >= 32");
$status = ($stream->writing) && ($stream->len == 0) && ($stream->pos == 0);
ok($status, "newly opened stream");
$stream->write(1,1);
$stream->write(3,5);
$status = $stream->writing && $stream->len == 4;
ok($status, "simple write");
$stream->write_close;
$status = !$stream->writing && $stream->len == 4 && $stream->pos == 4;
ok($status, "write close");
$stream->rewind;
$status = !$stream->writing && $stream->len == 4 && $stream->pos == 0;
ok($status, "rewind");
$v = $stream->read(4);
is($v, 0xD, "read value correctly");
$status = !$stream->writing && $stream->len == 4 && $stream->pos == 4;
ok($status, "read status");
$stream->rewind;
$stream->write_open;
$status = $stream->writing && $stream->len == 4;
ok($status, "write open");
$stream->put_unary(4);
$status = $stream->writing && $stream->len == 9;
ok($status, "write unary");
$stream->rewind_for_read;
$status = !$stream->writing && $stream->len == 9 && $stream->pos == 0;
ok($status, "rewind for read");
$v = $stream->readahead(2);
is($v, 3, "readahead value");
$status = !$stream->writing && $stream->len == 9 && $stream->pos == 0;
ok($status, "readahead status");
# Unary is 000..1
$v = $stream->read(9);
is($v, 0x1A1, "read value");
$status = !$stream->writing && $stream->len == 9 && $stream->pos == 9;
ok($status, "read status");
$stream->rewind_for_read;
$v = $stream->read_string(9);
is($v, '110100001', "read_string value");
$stream->erase_for_write;
$status = $stream->writing && $stream->len == 0;
ok($status, "erase for write");
$stream->put_unary1(7);
$status = $stream->writing && $stream->len == 8;
ok($status, "write unary1");
$stream->rewind_for_read;
$status = !$stream->writing && $stream->len == 8 && $stream->pos == 0;
ok($status, "rewind for read");
# Unary1 is 111..0
$v = $stream->get_unary1(-1);
is($v, 7, "read value");
$status = !$stream->writing && $stream->len == 8 && $stream->pos == 8;
ok($status, "read status");
$stream->erase_for_write;
$status = $stream->writing && $stream->len == 0;
ok($status, "erase for write");
$stream->put_gamma(13);
$status = $stream->writing && $stream->len == 7;
ok($status, "put gamma 13");
{
my $str = $stream->to_string;
is($str, '0001110', "to string returned '0001110'");
$status = !$stream->writing && $stream->len == 7;
ok($status, "to string status");
}
{
my $vec = $stream->to_raw;
# the '0001110' comes back as '0001110[0...]'
#printf "veclen = %d (want 1) vec = '%s' 0x%x (want 0x1C)\n",
# length($vec), unpack("b8", $vec), vec($vec,0,8);
$status = (length($vec) >= 1) && (length($vec) <= 4)
&& (vec($vec,0,8) == 0x1C)
&& !$stream->writing && $stream->len == 7;
ok($status, "to raw returned 0x0E");
}
$stream->from_string('000000011111010');
$status = !$stream->writing && $stream->len == 15 && $stream->pos == 0;
ok($status, "from string '000000011111010'");
$stream->rewind_for_read;
$v = $stream->get_gamma;
is($v, 249, "read gamma returned 249");
$status = !$stream->writing && $stream->len == 15 && $stream->pos == 15;
ok($status, "read gamma status");
{
my $vec = '';
vec($vec, 0, 8) = 0xC5;
$stream->from_raw($vec, 8);
$status = !$stream->writing && $stream->len == 8 && $stream->pos == 0;
ok($status, "from raw 0xC5 (8)");
$vec = $stream->to_raw;
cmp_ok( length($vec), '>=', 1, "to raw length is at least 1" );
cmp_ok( length($vec), '<=', 4, "to raw length is no more than 4");
is( vec($vec,0,8), 0xC5, "to raw returned 0xC5 (8)" );
$status = !$stream->writing && $stream->len == 8;
ok($status, "to raw status");
}
{
my $success = 1;
$stream->erase_for_write;
foreach my $n (0 .. 65) {
$stream->put_unary( 2*$n+0 );
$stream->put_gamma( 2*$n+1 );
}
$status = $stream->len == 5106;
ok($stream->len == 5106, "put sequence of numbers using unary and gamma");
$stream->rewind_for_read;
foreach my $n (0 .. 65) {
if ($stream->get_unary() != (2*$n+0)) { $success = 0; last; }
if ($stream->get_gamma() != (2*$n+1)) { $success = 0; last; }
}
ok($success, "correctly read sequence");
}
done_testing();
}
foreach my $type (@types) {
SKIP: {
my $stream = new_stream($type);
skip "$type implementation not available", 1 unless defined $stream;
subtest "$type implementation" => sub { test_type($type, $stream) };
}
}
done_testing();