################################################################################
#
# Copyright (c) 2002-2015 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 => 98 }
my $CCCFG = require 'tests/include/config.pl';
eval {
$orig = new Convert::Binary::C %$CCCFG;
@clone = map { new Convert::Binary::C %$CCCFG } 1 .. 2;
};
ok($@,'',"failed to create Convert::Binary::C objects");
eval {
$orig->parse_file( 'tests/include/include.c' );
$orig->parse( <<ENDPARSE );
enum __foobar__;
enum __undefined__;
typedef int _int_2_, _int_3_, _int_4_;
ENDPARSE
};
ok($@,'',"failed to parse C-file");
eval {
$dump1 = $orig->sourcify;
$dump2 = $orig->sourcify;
$dump3 = $orig->sourcify;
};
ok($@,'',"failed to dump definitions");
ok( $dump1, $dump2, "dumps 1+2 differ" );
ok( $dump2, $dump3, "dumps 2+3 differ" );
ok( !/^#line/m ) for $dump1, $dump2, $dump3;
ok( !/^#define/m ) for $dump1, $dump2, $dump3;
eval {
$dump1 = $orig->sourcify( { Context => 1 } );
$dump2 = $orig->sourcify( { Context => 1 } );
$dump3 = $orig->sourcify( { Context => 1 } );
};
ok($@,'',"failed to dump definitions with context");
ok( $dump1, $dump2, "context dumps 1+2 differ" );
ok( $dump2, $dump3, "context dumps 2+3 differ" );
ok( /^#line\s+\d+\s+"[^"]+"/m ) for $dump1, $dump2, $dump3;
ok( !/^#define/m ) for $dump1, $dump2, $dump3;
eval {
$dump1 = $orig->sourcify( { Defines => 1 } );
$dump2 = $orig->sourcify( { Defines => 1 } );
$dump3 = $orig->sourcify( { Defines => 1 } );
};
ok($@,'',"failed to dump definitions with context");
ok( $dump1, $dump2, "context dumps 1+2 differ" );
ok( $dump2, $dump3, "context dumps 2+3 differ" );
ok( !/^#line/m ) for $dump1, $dump2, $dump3;
ok( /^#define\s+\w+/m ) for $dump1, $dump2, $dump3;
eval {
$dump1 = $orig->sourcify( { Context => 1, Defines => 1 } );
$dump2 = $orig->sourcify( { Context => 1, Defines => 1 } );
$dump3 = $orig->sourcify( { Context => 1, Defines => 1 } );
};
ok($@,'',"failed to dump definitions with context");
ok( $dump1, $dump2, "context dumps 1+2 differ" );
ok( $dump2, $dump3, "context dumps 2+3 differ" );
ok( /^#line\s+\d+\s+"[^"]+"/m ) for $dump1, $dump2, $dump3;
ok( /^#define\s+\w+/m ) for $dump1, $dump2, $dump3;
eval {
$clone[0]->parse( $orig->sourcify( { Context => 1, Defines => 1 } ) );
};
ok($@,'',"failed to parse clone data (0)");
eval {
$clone[1]->parse( $clone[0]->sourcify( { Context => 1, Defines => 1 } ) );
};
ok($@,'',"failed to parse clone data (1)");
for my $meth ( qw( enum compound struct union typedef macro ) ) {
my $meth_names = $meth.'_names';
my @orig_names = sort $orig->$meth_names();
print "# checking if any names exist\n";
ok( @orig_names > 0 );
for my $c ( 0 .. $#clone ) {
print "# checking counts for \$clone[$c]->$meth_names\n";
ok(scalar $orig->$_(), scalar $clone[$c]->$_(), "count mismatch in $_ ($c)")
for $meth, $meth_names;
print "# checking parsed names for \$clone[$c]->$meth_names\n";
ok(join( ',', @orig_names ),
join( ',', sort $clone[$c]->$meth_names() ),
"parsed names differ in $meth_names ($c)" );
my @failed = map {
print "# checking \$clone[$c]->$meth( \"$_\" )\n";
reccmp($orig->$meth($_), $clone[$c]->$meth($_)) ? () : $_
} @orig_names;
print "# $_\n" for @failed;
ok(scalar @failed, 0, "$meth failed cloning");
}
}
eval {
$orig->clean->parse( <<ENDC );
#pragma pack( push, 1 )
typedef struct { struct B *x; } A;
typedef struct B { A *x; } B;
#pragma pack( pop )
enum buzz { BUZZER };
struct foo {
enum { FOOBAR } bar;
enum buzz baz;
};
struct {
struct {
enum { FOO } bar;
} x;
union {
enum { ZAP } husel;
};
} x;
ENDC
};
ok($@,'',"failed to parse C code");
eval {
$clone[0]->clean->parse( $orig->sourcify );
};
ok($@,'',"failed to parse sourcified code");
eval {
$orig->clean->parse( 'typedef struct { ' . 'struct { 'x42 . 'int a;' . ' } a;'x42 . ' } rec;' );
};
ok($@,'',"failed to parse C code");
eval {
$clone[1]->clean->parse( $orig->sourcify );
};
ok($@,'',"failed to parse sourcified code");
sub reccmp
{
my($ref, $val) = @_;
unless (ref $ref) {
return 1 unless defined $ref || defined $val;
return 0 unless defined $ref && defined $val;
my $r = $ref eq $val;
print "# $ref ne $val\n" unless $r;
return $r;
}
if( ref $ref eq 'ARRAY' ) {
@$ref == @$val or return 0;
for( 0..$#$ref ) {
reccmp( $ref->[$_], $val->[$_] ) or return 0;
}
}
elsif( ref $ref eq 'HASH' ) {
@{[keys %$ref]} == @{[keys %$val]} or return 0;
for( keys %$ref ) {
reccmp( $ref->{$_}, $val->{$_} ) or return 0;
}
}
else { return 0 }
return 1;
}