The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!/usr/bin/perl -w
use strict;
$| = 1;
my $data;
my $string;
my $s;
my $s1;
ok( UBInt16("foo")->parse("\x01\x02") == 258, "Primitive: Parse: UBInt16");
ok( ULInt16("foo")->parse("\x01\x02") == 513, "Primitive: Parse: ULInt16");
ok( UBInt16("foo")->build(31337) eq 'zi', "Primitive: Build: UBInt16");
ok( SBInt16("foo")->build(-31337) eq "\x85\x97", "Primitive: Build: SBInt16");
ok( SLInt16("foo")->build(-31337) eq "\x97\x85", "Primitive: Build: SLInt16");
ok( BFloat32("foo")->build(5) eq "\x40\xa0\0\0", "Primitive: Build: BFloat32");
ok( LFloat32("foo")->build(5) eq "\0\0\xa0\x40", "Primitive: Build: LFloat32");
ok( BFloat32("foo")->parse("\x40\xa0\0\0") == 5, "Primitive: Parse: BFloat32");
ok( LFloat64("foo")->build(5) eq "\0\0\0\0\0\0\x14\x40", "Primitive: Build: LFloat64");
ok( LFloat64("foo")->parse("\0\0\0\0\0\0\x14\x40") == 5, "Primitive: Build: LFloat64");
$s = Struct("foo",
UBInt8("a"),
SLInt16("b")
);
$data = {a => 7, b => 256};
$string = "\x07\x00\x01";
is_deeply($s->parse($string), $data, "Struct: Parse: correct");
ok( $s->build($data) eq $string, "Struct: Build: Rebuild1");
$data->{b} = 5000;
ok( $s->build($data) eq "\x07\x88\x13", "Struct: Build: Rebuild2");
$s = Struct("foo",
UBInt8("a"),
UBInt16("b"),
Struct("bar",
UBInt8("a"),
UBInt16("b"),
)
);
$data = {a=>65, b=>16962, bar=>{ a=>97, b=> 25186}};
$string = "ABBabb";
is_deeply($s->parse($string), $data, "Nested Struct: Parse: correct");
ok( $s->build($data) eq $string, "Nested Struct: Build: Rebuild1");
$s = Sequence("foo",
UBInt8("a"),
UBInt16("b")
);
$data = [97, 25186];
$string = "abb";
is_deeply($s->parse($string), $data, "Sequence: Parse: correct");
ok( $s->build($data) eq $string, "Sequence: Build: Rebuild1");
ok( $s->build([1,2]) eq "\x01\x00\x02", "Sequence: Build: correct");
$s = Sequence("foo",
UBInt8("a"),
UBInt16("b"),
Sequence("bar",
UBInt8("a"),
UBInt16("b"),
)
);
$data = [65, 16962, [97, 25186]];
$string = "ABBabb";
is_deeply($s->parse($string), $data, "Nested Sequence: Parse: correct");
ok( $s->build($data) eq $string, "Nested Sequence: Build: correct");
$s = Array(4, UBInt8("foo"));
$data = $s->parse("\x01\x02\x03\x04");
is_deeply( $s->parse("\x01\x02\x03\x04"), [1..4], "StrictRepeater: Parse: correct elements1");
eval { $data = $s->parse("\x01\x02\x03") };
ok( $@ , "StrictRepeater: Parse: Die on too few elements");
is_deeply( $s->parse("\x01\x02\x03\x04\x05"), [1..4], "StrictRepeater: Parse: correct elements2");
ok( $s->build([5,6,7,8]) eq "\x05\x06\x07\x08", "StrictRepeater: Build: normal build");
eval { $s->build([5,6,7,8,9]) };
ok( $@, "StrictRepeater: Build: dies on too many elements");
$s = Array(5, Array(2, UBInt8("foo")));
$data = [[97,97], [98,98], [99,99], [100,100], [101,101]];
$string = "aabbccddee";
is_deeply($s->parse($string), $data, "Nested StrictRepeater: Parse: correct");
ok( $s->build($data) eq $string, "Nested StrictRepeater: Build: correct");
$s = Struct("foo",
Padding(2),
Flag("myflag"),
Padding(5),
);
$data = {myflag => 1};
$string = "\x00\x00\x01\x00\x00\x00\x00\x00";
is_deeply($s->parse($string), $data, "Struct with Padding, Flag: Parse: correct");
ok( $s->build($data) eq $string, "Struct with Padding, Flag: Build: correct");
$s = BitStruct("foo",
Padding(2),
Flag("myflag"),
Padding(5),
);
$data = {myflag => 1};
$string = "\x20";
is_deeply($s->parse($string), $data, "BitStruct with Padding, Flag: Parse: correct");
ok( $s->build($data) eq $string, "BitStruct with Padding, Flag: Build: correct");
$s = BitStruct("foo",
BitField("a", 3),
Flag("b"),
Padding(3),
Nibble("c"),
BitField("d", 5),
);
$data = {a=>7, b=>0, c=>8, d=>31};
$string = "\xe1\x1f";
is_deeply($s->parse($string), $data, "BitStruct: Parse: correct");
ok( $s->build($data) eq $string, "BitStruct: Build: correct");
$s = BitStruct("foo",
BitField("a", 3),
Flag("b"),
Padding(3),
Nibble("c"),
Struct("bar",
Nibble("d"),
Bit("e"),
)
);
$data = { a=>7, b=>0, c=>8, bar=>{ d=>15, e=>1 } };
$string = "\xe1\x1f";
is_deeply($s->parse($string), $data, "Nested BitStruct: Parse: correct");
ok($s->build($data) eq $string, "Nested BitStruct: Build: correct");
$s = BitStruct("foo",
BitField("a", 3),
Flag("b"),
Byte("c"),
);
$data = { a=>7, b=>0, c=>59 };
$string = "\xe3\xb0";
is_deeply($s->parse($string), $data, "BitStruct with Byte: Parse: correct");
ok( $s->build($data) eq $string, "BitStruct with Byte: Build: correct");
$s = Enum(Byte("protocol"),
TCP => 6,
UDP => 17,
);
ok( $s->parse("\x06") eq 'TCP', "Enum: correct1");
ok( $s->parse("\x11") eq 'UDP', "Enum: correct1");
eval { $s->parse("\x12") };
ok( $@, "Enum: dies on undeclared value with default");
ok( $s->build("TCP") eq "\x06", "Enum: build 1");
ok( $s->build("UDP") eq "\x11", "Enum: build 2");
$s = Enum(Byte("protocol"),
TCP => 6,
UDP => 17,
_default_ => blah => 99,
);
ok( $s->parse("\x11") eq 'UDP', "Enum with default: correct1");
ok( $s->parse("\x12") eq 'blah', "Enum with default: correct2");
ok( $s->build("TCP") eq "\x06", "Enum with default: build 1");
ok( $s->build("blah") eq "\x63", "Enum with default: build default");
$s = Enum(Byte("protocol"),
TCP => 6,
UDP => 17,
_default_ => $DefaultPass,
);
ok( $s->parse("\x11") eq 'UDP', "Enum with pass: correct1");
ok( $s->parse("\x12") == 18, "Enum with pass: correct2");
ok( $s->parse("\xff") == 255, "Enum with pass: correct3");
ok( $s->build("TCP") eq "\x06", "Enum with pass: build 1");
ok( $s->build(18) eq "\x12", "Enum with pass: build 2");
ok( $s->build(255) eq "\xff", "Enum with pass: build 3");
ok( OneOf(UBInt8("foo"), [4,5,6,7])->parse("\x05") == 5, "OneOf: Parse: passing");
eval { OneOf(UBInt8("foo"), [4,5,6,7])->parse("\x08") };
ok( $@, "OneOf: Parse: blocking");
ok( OneOf(UBInt8("foo"), [4,5,6,7])->build(5) eq "\x05", "OneOf: Build: passing");
eval { OneOf(UBInt8("foo"), [4,5,6,7])->build(8) };
ok( $@, "OneOf: Build: blocking");
ok( NoneOf(UBInt8("foo"), [4,5,6,7])->parse("\x08") == 8, "NoneOf: Parse: passing");
eval { NoneOf(UBInt8("foo"), [4,5,6,7])->parse("\x06") };
ok( $@, "NoneOf: Parse: blocking");
ok( NoneOf(UBInt8("foo"), [4,5,6,7])->build(8) eq "\x08", "NoneOf: Build: passing");
eval { NoneOf(UBInt8("foo"), [4,5,6,7])->build(6) };
ok( $@, "NoneOf: Build: blocking");
$s = Struct("foo",
Byte("length"),
Field("data", sub { $_->ctx->{length} }),
);
$data = {data=> 'ABC', length => 3};
$string = "\x03ABC";
is_deeply( $s->parse($string), $data, "MetaField: Parse: correct1");
ok( $s->build($data) eq $string, "MetaField: Build: correct1");
$data = {data=> 'ABCD', length => 4};
$string = "\x04ABCD";
is_deeply( $s->parse($string), $data, "MetaField: Parse: correct2");
ok( $s->build($data) eq $string, "MetaField: Build: correct2");
ok( Field("foo", 3)->parse("ABCD") eq "ABC", "Field: Parse: route to StaticField");
ok( Field("foo", sub {return 3})->parse("ABCD") eq "ABC", "Field: Parse: route to MetaField");
$s = Struct("foo",
Byte("length"),
Array(sub { $_->ctx->{length}}, UBInt16("data")),
);
$data = {length => 3, data => [1,2,3]};
$string = "\x03\x00\x01\x00\x02\x00\x03";
is_deeply( $s->parse($string), $data, "MetaRepeater: Parse: correct");
ok( $s->build($data) eq $string, "MetaRepeater: Build: correct");
$s = RepeatUntil(sub {$_->obj eq "\x00"}, Field("data", 1));
$data = [ split('', "abcdef\x00") ];
$string = "abcdef\x00this is another string";
is_deeply( $s->parse($string), $data, "RepeatUntil: Parse: correct");
$string = "abcdef\x00";
ok( $s->build($data) eq $string, "RepeatUntil: Build: correct");
$s = Struct("foo",
Enum(Byte("type"),
INT1 => 1,
INT2 => 2,
INT4 => 3,
STRING => 4,
),
Switch("data", sub { $_->ctx->{type} },
{
"INT1" => UBInt8("spam"),
"INT2" => UBInt16("spam"),
"INT4" => UBInt32("spam"),
"STRING" => String("spam", 6),
}
)
);
$data = {type => 'INT1', data => 18};
$string = "\x01\x12";
is_deeply( $s->parse($string), $data, "Switch: Parse: correct1");
ok( $s->build($data) eq $string, "Switch: Build: correct1");
$data = {type => 'INT2', data => 4660};
$string = "\x02\x12\x34";
is_deeply( $s->parse($string), $data, "Switch: Parse: correct2");
ok( $s->build($data) eq $string, "Switch: Build: correct2");
$data = {type => 'INT4', data => 305419896};
$string = "\x03\x12\x34\x56\x78";
is_deeply( $s->parse($string), $data, "Switch: Parse: correct3");
ok( $s->build($data) eq $string, "Switch: Build: correct3");
$data = {type => 'STRING', data => 'abcdef'};
$string = "\x04abcdef";
is_deeply( $s->parse($string), $data, "Switch: Parse: correct4");
ok( $s->build($data) eq $string, "Switch: Build: correct4");
$s = Struct("foo",
Byte("type"),
Switch("data", sub { $_->ctx->{type} },
{
1 => UBInt8("spam"),
2 => UBInt16("spam"),
},
default => UBInt8("spam")
)
);
$data = {type => 1, data => 255};
$string = "\x01\xff";
is_deeply( $s->parse($string), $data, "Switch with default: Parse: correct1");
ok( $s->build($data) eq $string, "Switch with default: Build: correct1");
$data = {type => 2, data => 65535};
$string = "\x02\xff\xff";
is_deeply( $s->parse($string), $data, "Switch with default: Parse: correct2");
ok( $s->build($data) eq $string, "Switch with default: Build: correct2");
$data = {type => 3, data => 255};
$string = "\x03\xff\xff"; # <-- uses the default construct
is_deeply( $s->parse($string), $data, "Switch with default: Parse: correct3");
ok( $s->build($data) eq "\x03\xff", "Switch with default: Build: correct3");
$s = Struct("foo",
Byte("type"),
Switch("data", sub { $_->ctx->{type} },
{
1 => UBInt8("spam"),
2 => UBInt16("spam"),
},
default => $DefaultPass,
)
);
$data = {type => 1, data => 255};
$string = "\x01\xff";
is_deeply( $s->parse($string), $data, "Switch with pass: Parse: correct1");
ok( $s->build($data) eq $string, "Switch with pass: Build: correct1");
$data = {type => 2, data => 65535};
$string = "\x02\xff\xff";
is_deeply( $s->parse($string), $data, "Switch with pass: Parse: correct2");
ok( $s->build($data) eq $string, "Switch with pass: Build: correct2");
$data = {type => 3, data => undef};
$string = "\x03\xff\xff"; # <-- uses the default construct
is_deeply( $s->parse($string), $data, "Switch with pass: Parse: correct3");
ok( $s->build($data) eq "\x03", "Switch with pass: Build: correct3");
$s = Struct("foo",
Pointer(sub { 4 }, Byte("data1")), # <-- data1 is at (absolute) position 4
Pointer(sub { 7 }, Byte("data2")), # <-- data2 is at (absolute) position 7
);
$data = {data1 => 1, data2=> 2};
$string = "\x00\x00\x00\x00\x01\x00\x00\x02";
is_deeply( $s->parse($string), $data, "Pointer: Parse: correct");
ok( $s->build($data) eq $string, "Pointer: Build: Empty");
$s = Struct("foo",
Byte("padding_length"),
Padding(sub { $_->ctx->{padding_length} } ),
Byte("relative_offset"),
Anchor("absolute_position"),
Pointer(sub { $_->ctx->{absolute_position} + $_->ctx->{relative_offset} }, Byte("data")),
);
$data = {relative_offset=>3, absolute_position=>7, data=>255, padding_length=>5};
$string = "\x05\x00\x00\x00\x00\x00\x03\x00\x00\x00\xff";
is_deeply( $s->parse($string), $data, "Pointer n Anchor: Parse: Correct");
ok(( $s->build($data) eq $string ), "Pointer n Anchor: Build: Correct");
$s = Struct("foo",
Byte("padding_length"),
Padding(sub { $_->ctx->{padding_length} } ),
Byte("relative_offset"),
Pointer(sub { $_->stream->tell + $_->ctx->{relative_offset} }, Byte("data")),
);
$data = {relative_offset=>3, data=>255, padding_length=>5};
$string = "\x05\x00\x00\x00\x00\x00\x03\x00\x00\x00\xff";
is_deeply( $s->parse($string), $data, "Pointer n Anchor: Parse: Correct");
ok(( $s->build($data) eq $string ), "Pointer n Anchor: Build: Correct");
ok(( String("foo", 5)->parse("hello") eq "hello"), "String: Parse: Simple");
$s = String("foo", 10, padchar => "X", paddir => "right");
ok(( $s->parse("helloXXXXX") eq 'hello' ), "Padded String: Parse: Simple");
ok(( $s->build("hello") eq 'helloXXXXX' ), "Padded String: Build: Simple");
$s = PascalString("foo");
ok(( $s->parse("\x05hello") eq 'hello'), "PascalString: Parse: Simple");
ok(( $s->build("hello world") eq "\x0bhello world"), "PascalString: Build: Simple");
$s = PascalString("foo", \&UBInt16);
ok(( $s->parse("\x00\x05hello") eq 'hello'), "PascalString: Parse: With cutsom length type");
ok(( $s->build("hello") eq "\x00\x05hello"), "PascalString: Build: With cutsom length type");
$s = CString("foo");
ok(( $s->parse("hello\x00") eq 'hello' ), "CString: Parse: Simple");
ok(( $s->build("hello") eq "hello\x00" ), "CString: Build: Simple");
$s = CString("foo", terminators => "XYZ");
ok(( $s->parse("helloX") eq 'hello' ), "CString: Parse: custom terminator1");
ok(( $s->parse("helloY") eq 'hello' ), "CString: Parse: custom terminator2");
ok(( $s->parse("helloZ") eq 'hello' ), "CString: Parse: custom terminator3");
ok(( $s->build("hello") eq "helloX" ), "CString: Build: custom terminator");
$s = Struct("foo",
UBInt8("width"),
UBInt8("height"),
Value("total_pixels", sub { $_->ctx->{width} * $_->ctx->{height}}),
);
is_deeply( $s->parse("\x05\x05"), { width => 5, height => 5, total_pixels => 25 }, "Value: Parse: Simple");
$data = { width => 5, height => 5 };
ok(( $s->build($data) eq "\x05\x05"), "Value: Parse: Ignored");
is_deeply( $data, { width => 5, height => 5, total_pixels => 25 }, "Value: Parse: Added to hash");
$s = Struct("foo",
Flag("has_options"),
If(sub { $_->ctx->{has_options} },
Bytes("options", 5)
)
);
is_deeply( $s->parse("\x01hello"), {options => 'hello', has_options => 1 }, "If: Parse: True");
is_deeply( $s->parse("\x00hello"), {options => undef, has_options => 0 }, "If: Parse: False");
ok(( $s->build({options => undef, has_options => 0 }) eq "\0"), "If: Build: False");
ok(( $s->build({options => 'hello', has_options => 1 }) eq "\x01hello"), "If: Build: True");
$s = Struct("foo",
Flag("long_options"),
IfThenElse("options", sub { $_->ctx->{long_options} },
Bytes("Long Options", 5),
Bytes("Short Options", 3),
),
);
is_deeply( $s->parse("\x01hello"), {options => 'hello', long_options => 1 }, "IfThenElse: Parse: True");
is_deeply( $s->parse("\x00hello"), {options => 'hel', long_options => 0 }, "IfThenElse: Parse: False");
ok(( $s->build({options => 'hel', long_options => 0 }) eq "\0hel"), "IfThenElse: Build: False");
ok(( $s->build({options => 'hello', long_options => 1 }) eq "\x01hello"), "IfThenElse: Build: True");
$s = Struct("foo",
Flag("has_next"),
If(sub { $_->ctx->{has_next} }, LazyBound("next", sub { $s })),
);
$data = { has_next => 1, next => { has_next => 1, next => { has_next => 1, next => { has_next => 0, next => undef } } } };
$string = "\x01\x01\x01\x00";
is_deeply( $s->parse($string), $data, "LazyBound: Parse: Correct");
ok(( $s->build($data) eq $string), "LazyBound: Build: Correct");
$s = Struct("foo",
Byte("a"),
Peek(Byte("b")),
Byte("c"),
);
is_deeply( $s->parse("\x01\x02"), {a=>1, b=>2, c=>2}, "Peek: Parse: Simple");
ok(( $s->build({a=>1, b=>222, c=>2}) eq "\x01\x02"), "Peek: Build: Ignored");
$s = Struct("foo",
Byte("a"),
Peek(Byte("b"), 3),
UBInt16("c"),
Byte("d"),
Byte("e"),
);
$string = "\x01\xaa\xbb\x03\x04";
$data = {a=>1, c=>43707, d=>3, e=>4};
is_deeply( $s->parse($string), {%$data, b=>4}, "Far Peek: Parse: Simple");
ok(( $s->build($data) eq $string), "Far Peek: Build: Ignored");
$s = Const(Bytes("magic", 6), "FOOBAR");
ok(($s->parse("FOOBAR") eq "FOOBAR"), "Const: Parse: OK");
eval { $s->parse("FOOBAX") };
ok( $@, "Const: Parse: Dies");
ok(( $s->build("FOOBAR") eq "FOOBAR"), "Const: Build: OK");
eval { $s->build("FOOBAX") };
ok( $@, "Const: Build: Dies");
$s = Terminator();
ok(( not defined $s->parse("")), "Terminator: Parse: ok");
eval { $s->parse("x") };
ok( $@, "Terminator: Parse: dies");
ok(( $s->build({}) eq ""), "Terminator: Build: Empty");
$s = Struct("foo",
Byte("a"),
Alias("b", "a"),
);
is_deeply( $s->parse("\x03"), {a=>3, b=>3}, "Alias: Parse: Simple");
$data = {a=>3};
ok(( $s->build($data) eq "\x03"), "Alias: Build: OK");
is_deeply($data, {a=>3, b=>3}, "Alias: Build: Add value");
$data = {a=>3, b=>5};
ok(( $s->build($data) eq "\x03"), "Alias: Build: Ignore b");
$s = Union("foo",
UBInt32("a"),
UBInt16("b")
);
is_deeply( $s->parse("\xaa\xbb\xcc\xdd"), { a => 2864434397, b => 43707 }, "Union: Parse: Simple");
ok(( $s->build( { a=> 2864434397 } ) eq "\xaa\xbb\xcc\xdd" ), "Union: Build: a");
ok(( $s->build( { b => 43707 } ) eq "\xaa\xbb\0\0" ), "Union: Build: b");
$s = Struct("foo", Aligned(Byte("bbb"), 8), Byte("aaa"));
$data = { bbb => 99, aaa=>5 };
$string = "c\0\0\0\0\0\0\0\5";
is_deeply( $s->parse($string), $data, "Aligned: Parse: Correct");
ok(( $s->build($data) eq $string), "Aligned: Build: Correct");
$s = Bitwise(Struct("foo",
Padding(2),
Flag("myflag"),
Padding(5),
));
$data = {myflag => 1};
$string = "\x20";
is_deeply($s->parse($string), $data, "Bitwise eq BitStruct: Parse: correct");
ok( $s->build($data) eq $string, "Bitwise eq BitStruct: Build: correct");
$s = Struct("foo1",
Byte("a"),
Select(
Const(Byte("b1"), 4),
Const(Byte("b2"), 2),
),
Byte("c"),
);
$s1 = Struct("foo1",
Byte("a"),
Select(
Const(Byte("b1"), 4),
Const(Byte("b2"), 2),
$DefaultPass,
),
Byte("c"),
);
$string = "\3\4\xb0";
$data = { a=>3, b1=>4, c=>176};
is_deeply($s->parse($string), $data, "Select: Parse: OK1");
ok( $s->build($data) eq $string, "Select: Build: OK1");
is_deeply($s1->parse($string), $data, "Select with Pass: Parse: OK1");
ok( $s1->build($data) eq $string, "Select with Pass: Build: OK1");
$string = "\3\2\xb0";
$data = { a=>3, b2=>2, c=>176};
is_deeply($s->parse($string), $data, "Select: Parse: OK2");
ok( $s->build($data) eq $string, "Select: Build: OK2");
is_deeply($s1->parse($string), $data, "Select with Pass: Parse: OK2");
ok( $s1->build($data) eq $string, "Select with Pass: Build: OK2");
$string = "\3\3\xb0";
$data = { a=>3, b2=>3, c=>176};
eval { $s->parse($string) };
ok( $@, "Select: Parse: Failed");
eval { $s->build($data) };
ok( $@, "Select: Build: Failed");
$data = { a=>3, c=>3};
is_deeply($s1->parse($string), $data, "Select with Pass: Parse: Pass");
ok( $s1->build($data) eq "\3\3", "Select with Pass: Build: Pass");
$s = FlagsEnum(ULInt16("characteristics"),
RELOCS_STRIPPED => 0x0001,
EXECUTABLE_IMAGE => 0x0002,
LINE_NUMS_STRIPPED => 0x0004,
LOCAL_SYMS_STRIPPED => 0x0008,
AGGRESSIVE_WS_TRIM => 0x0010,
LARGE_ADDRESS_AWARE => 0x0020,
MACHINE_16BIT => 0x0040,
BYTES_REVERSED_LO => 0x0080,
MACHINE_32BIT => 0x0100,
DEBUG_STRIPPED => 0x0200,
REMOVABLE_RUN_FROM_SWAP => 0x0400,
SYSTEM => 0x1000,
DLL => 0x2000,
UNIPROCESSOR_ONLY => 0x4000,
BIG_ENDIAN_MACHINE => 0x8000,
);
$data = {};
$string = "\0\0";
is_deeply($s->parse($string), $data, "FlagsEnum: Parse: Empty");
ok( $s->build($data) eq $string, "FlagsEnum: Build: Empty");
$data = {EXECUTABLE_IMAGE => 1, REMOVABLE_RUN_FROM_SWAP=>1};
$string = "\2\4";
is_deeply($s->parse($string), $data, "FlagsEnum: Parse: Pass");
ok( $s->build($data) eq $string, "FlagsEnum: Build: Pass");
$string = "PNG";
$s = Magic($string);
ok( $s->build({ }) eq $string, "Magic: Build: Pass");
eval { $s->parse($string) };
ok( (not $@), "Magic: Parse: OK");
eval { $s->parse("PXNG") };
ok( $@, "Magic: Parse: Dies");
$s = ReversedBitStruct("foo",
BitField("a", 3),
Flag("b"),
Byte("c"),
);
$data = { a=>7, b=>0, c=>236 };
$string = pack "B*", "0111011100000011";
is_deeply($s->parse($string), $data, "ReversedBitStruct: Parse: correct");
ok( $s->build($data) eq $string, "ReversedBitStruct: Build: correct");
$s = ReversedBitStruct("foo",
BitField("a", 3),
Flag("b"),
ReversedBitField("c", 8),
);
$data = { a=>7, b=>0, c=>236 };
$string = pack "B*", "1100011100001110";
is_deeply($s->parse($string), $data, "ReversedBitStruct with ReversedBitField: Parse: correct");
ok( $s->build($data) eq $string, "ReversedBitStruct with ReversedBitField: Build: correct");
#print Dumper($data);
done_testing();