The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
################################################################################
#
# $Project: /Convert-Binary-C $
# $Author: mhx $
# $Date: 2011/04/10 12:32:25 +0200 $
# $Revision: 12 $
# $Source: /tests/227_flexarray.t $
#
################################################################################
#
# Copyright (c) 2002-2011 Marcus Holland-Moritz. All rights reserved.
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
################################################################################

use Test;
use Convert::Binary::C @ARGV;

$^W = 1;

BEGIN { plan tests => 49 }

my $c = new Convert::Binary::C IntSize => 4, ShortSize => 2, Alignment => 4;

$c->parse(<<ENDC);

struct flex1 {

  int   a;
  char  b;

  struct {
    char  a;
    short b;
    char  c;
    int   d[][4];
  }     c;

  char  d[5];

  struct {
    char  a;
    short b[][4];
  }     e[];

};

struct flex2 {

  int  a;
  struct {
    char  a[2];
    short b;
  } b[];

};

struct flex3 {
  int a;
  int b[][2][3][4];
};

typedef int incomplete[];
typedef int incomplete2[1];

ENDC

ok($c->sizeof('flex1'), 24);
ok($c->offsetof('flex1', 'e[1].a'), 24);
ok($c->offsetof('flex1', 'e[0].b[0][0]'), 24);

ok($c->sizeof('flex2'), 4);
ok($c->offsetof('flex2', 'b[0].b'), 6);

ok($c->sizeof('flex3'), 4);
ok($c->sizeof('flex3.b'), 0);
ok($c->sizeof('flex3.b[0]'), 96);
ok($c->sizeof('flex3.b[0][1]'), 48);
ok($c->sizeof('flex3.b[0][1][2]'), 16);
ok($c->sizeof('flex3.b[0][1][2][3]'), 4);
ok($c->offsetof('flex3', 'b[0]'), 4);
ok($c->offsetof('flex3', 'b[0][0]'), 4);
ok($c->offsetof('flex3', 'b[0][0][0]'), 4);
ok($c->offsetof('flex3', 'b[0][0][0][0]'), 4);
ok($c->offsetof('flex3', 'b[1]'), 100);
ok($c->offsetof('flex3', 'b[0][1]'), 52);
ok($c->offsetof('flex3', 'b[0][0][1]'), 20);
ok($c->offsetof('flex3', 'b[0][0][0][1]'), 8);

ok($c->sizeof('incomplete'), 0);
ok($c->offsetof('incomplete', '[10]'), 40);

my($u, $p);

my $d = pack 'C*', 1 .. 4;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 0);

$d .= pack 'C', 5;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 1);
ok(scalar @{$u->{b}[0]{a}}, 2);
ok($u->{b}[0]{a}[0], 5);
ok(not defined $u->{b}[0]{b});

$d .= pack 'C', 6;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 1);
ok(scalar @{$u->{b}[0]{a}}, 2);
ok($u->{b}[0]{a}[0], 5);
ok($u->{b}[0]{a}[1], 6);
ok(not defined $u->{b}[0]{b});

$d .= pack 'C', 7;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 1);
ok(scalar @{$u->{b}[0]{a}}, 2);
ok($u->{b}[0]{a}[0], 5);
ok($u->{b}[0]{a}[1], 6);
ok(exists $u->{b}[0]{b});
ok(not defined $u->{b}[0]{b});

$d .= pack 'C', 8;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 1);
ok(scalar @{$u->{b}[0]{a}}, 2);
ok($u->{b}[0]{a}[0], 5);
ok($u->{b}[0]{a}[1], 6);
ok(exists $u->{b}[0]{b});
ok(defined $u->{b}[0]{b});

$d .= pack 'C', 9;
$u = $c->unpack('flex2', $d);
ok(scalar @{$u->{b}}, 2);

$d = pack 'C*', map { $_ % 256 } 1 .. (10*$c->sizeof('flex3.b[0]'));
$u = $c->unpack('flex3.b', $d);
$p = $c->pack('flex3.b', $u);
ok($d, $p);

for my $member (qw( b[0] b[0][1] b[0][1][2] b[0][1][2][3] )) {
  $d = pack 'C*', 1 .. $c->sizeof("flex3.$member");
  $u = $c->unpack("flex3.$member", $d);
  $p = $c->pack("flex3.$member", $u);
  ok($d, $p);
}