diff options
Diffstat (limited to 'tools/pidl/tests')
26 files changed, 3712 insertions, 0 deletions
diff --git a/tools/pidl/tests/Util.pm b/tools/pidl/tests/Util.pm new file mode 100644 index 00000000..86b521bf --- /dev/null +++ b/tools/pidl/tests/Util.pm @@ -0,0 +1,181 @@ +# Some simple utility functions for pidl tests +# Copyright (C) 2005-2006 Jelmer Vernooij +# Published under the GNU General Public License + +package Util; + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(test_samba4_ndr test_warnings test_errors); + +use strict; + +use FindBin qw($RealBin); +use lib "$RealBin/../lib"; + +use Parse::Pidl::Samba4 qw(is_intree); + +use Parse::Pidl; +my $warnings = ""; +undef &Parse::Pidl::warning; +*Parse::Pidl::warning = sub { + my ($e, $l) = @_; + if (defined($e)) { + $warnings .= "$e->{FILE}:$e->{LINE}: $l\n"; + } else { + $warnings .= "$l\n"; + } +}; + +my $errors = ""; +undef &Parse::Pidl::error; +*Parse::Pidl::error = sub { + my ($e, $l) = @_; + if (defined($e)) { + $errors .= "$e->{FILE}:$e->{LINE}: $l\n"; + } else { + $errors .= "$l\n"; + } +}; + +use Test::More; +use Parse::Pidl::IDL; +use Parse::Pidl::NDR; +use Parse::Pidl::Samba4::NDR::Parser; +use Parse::Pidl::Samba4::Header; + +# Generate a Samba4 parser for an IDL fragment and run it with a specified +# piece of code to check whether the parser works as expected +sub test_samba4_ndr +{ + my ($name,$idl,$c,$extra) = @_; + + $extra = "" unless defined($extra); + + my $pidl = Parse::Pidl::IDL::parse_string("interface echo { $idl }; ", "<$name>"); + ok(defined($pidl), "($name) parse idl"); + + my $pndr = Parse::Pidl::NDR::Parse($pidl); + ok(defined($pndr), "($name) generate NDR tree"); + + my $header = Parse::Pidl::Samba4::Header::Parse($pndr); + ok(defined($header), "($name) generate generic header"); + + my $generator = new Parse::Pidl::Samba4::NDR::Parser(); + my ($ndrheader,$ndrparser) = $generator->Parse($pndr, undef, undef); + ok(defined($ndrparser), "($name) generate NDR parser"); + ok(defined($ndrheader), "($name) generate NDR header"); + +SKIP: { + + my $flags; + if (system("pkg-config --exists ndr") == 0 and !is_intree()) { + $flags = `pkg-config --libs --cflags ndr`; + } else { + skip "no samba environment available, skipping compilation", 3; + } + + my $main = " +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdarg.h> +#include <util/data_blob.h> + +/* header start */ +$header +/* header end */ + +/* ndrheader start */ +$ndrheader +/* ndrheader end */ + +/* extra start */ +$extra +/* extra end */ + +/* ndrparser start */ +$ndrparser +/* ndrparser end */ + +/* main start */ +int main(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx = talloc_init(NULL); + +$c + + talloc_free(mem_ctx); + + return 0; +} +/* main end */ +\n"; + + my $main_debug = "# ".join("\n# ", split("\n", $main)); + + my $test_data_prefix = $ENV{TEST_DATA_PREFIX}; + my $outfile; + if (defined($test_data_prefix)) { + $outfile = "$test_data_prefix/test-$name"; + } else { + $outfile = "./test-$name"; + } + + my $cflags = $ENV{CFLAGS}; + unless (defined($cflags)) { + $cflags = ""; + } + + my $ldflags = $ENV{LDFLAGS}; + unless (defined($ldflags)) { + $ldflags = ""; + } + + my $cc = $ENV{CC}; + unless (defined($cc)) { + $cc = "cc"; + } + + my $cmd = "$cc $cflags -x c - -o $outfile $flags $ldflags"; + $cmd =~ s/\n//g; + open CC, "|$cmd"; + print CC $main; + close CC; + + ok(-f $outfile, "($name) compile"); + + my $ret = system($outfile, ()) >> 8; + print "# code:\n#\n$main_debug\n" if ($ret != 0); + print "# cmd: $cmd\n" if ($ret != 0); + print "# return code: $ret\n" if ($ret != 0); + + ok($ret == 0, "($name) run"); + + ok(unlink($outfile), "($name) remove"); + + } +} + +sub test_warnings($$) +{ + my ($exp, $code) = @_; + + $warnings = ""; + + $code->(); + + is($warnings, $exp); +} + +sub test_errors($$) +{ + my ($exp, $code) = @_; + $errors = ""; + $code->(); + + is($errors, $exp); +} + +1; diff --git a/tools/pidl/tests/cutil.pl b/tools/pidl/tests/cutil.pl new file mode 100755 index 00000000..78c8bce4 --- /dev/null +++ b/tools/pidl/tests/cutil.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 7; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::CUtil qw(get_pointer_to get_value_of); + +is("&foo", get_pointer_to("foo")); +is("&(&foo)", get_pointer_to(get_pointer_to("foo"))); +is("*foo", get_pointer_to("**foo")); +is("foo", get_pointer_to("*foo")); + +is("foo", get_value_of("&foo")); +is("*foo", get_value_of("foo")); +is("**foo", get_value_of("*foo")); diff --git a/tools/pidl/tests/dump.pl b/tools/pidl/tests/dump.pl new file mode 100755 index 00000000..d1a56f09 --- /dev/null +++ b/tools/pidl/tests/dump.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 1; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Dump qw(DumpStruct); + +is (DumpStruct({ NAME => "foo", ELEMENTS => []}), + "struct foo {\n}"); + diff --git a/tools/pidl/tests/header.pl b/tools/pidl/tests/header.pl new file mode 100755 index 00000000..db594844 --- /dev/null +++ b/tools/pidl/tests/header.pl @@ -0,0 +1,108 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 27; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::Samba4::Header qw( + GenerateFunctionInEnv GenerateFunctionOutEnv GenerateStructEnv + EnvSubstituteValue); +use Parse::Pidl::IDL qw(parse_string); +use Parse::Pidl::NDR; + +sub parse_idl($) +{ + my $text = shift; + my $idl = Parse::Pidl::IDL::parse_string($text, "nofile"); + my $ndr = Parse::Pidl::NDR::Parse($idl); + return Parse::Pidl::Samba4::Header::Parse($ndr); +} + +like(parse_idl(""), qr/\/\* header auto-generated by pidl \*\/\n/sm, "includes work"); +like(parse_idl("interface x {}"), qr/\/\* header auto-generated by pidl \*\/\n/sm, "simple empty interface doesn't cause overhead"); +like(parse_idl("interface p { typedef struct { int y; } x; };"), + qr/.*#ifndef _HEADER_p\n#define _HEADER_p\n.+\n#endif \/\* _HEADER_p \*\/.*/ms, "ifdefs are created"); +like(parse_idl("interface p { typedef struct { int y; } x; };"), + qr/struct x.*{.*int32_t y;.*}.*;/sm, "interface member generated properly"); +like(parse_idl("interface x { void foo (void); };"), + qr/struct foo.*{\s+int _dummy_element;\s+};/sm, "void fn contains dummy element"); +like(parse_idl("interface x { void foo ([in] uint32 x); };"), + qr/struct foo.*{\s+struct\s+{\s+uint32_t x;\s+} in;\s+};/sm, "fn in arg works"); +like(parse_idl("interface x { void foo ([out] uint32 x); };"), + qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn out arg works"); +like(parse_idl("interface x { void foo ([in,out] uint32 x); };"), + qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} in;\s+struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn in,out arg works"); +like(parse_idl("interface x { void foo (uint32 x); };"), qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} in;\s+struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn with no props implies in,out"); +like(parse_idl("interface p { struct x { int y; }; };"), + qr/struct x.*{.*int32_t y;.*}.*;/sm, "interface member generated properly"); + +like(parse_idl("interface p { struct x { struct y z; }; };"), + qr/struct x.*{.*struct y z;.*}.*;/sm, "tagged type struct member"); + +like(parse_idl("interface p { struct x { union y z; }; };"), + qr/struct x.*{.*union y z;.*}.*;/sm, "tagged type union member"); + +like(parse_idl("interface p { struct x { }; };"), + qr/struct x.*{.*char _empty_;.*}.*;/sm, "empty struct"); + +like(parse_idl("interface p { struct x; };"), + qr/struct x;/sm, "struct declaration"); + +like(parse_idl("interface p { typedef struct x { int p; } x; };"), + qr/struct x.*{.*int32_t p;.*};/sm, "double struct declaration"); + +like(parse_idl("cpp_quote(\"some-foo\")"), + qr/some-foo/sm, "cpp quote"); + +# Make sure GenerateFunctionInEnv and GenerateFunctionOutEnv work +my $fn = { ELEMENTS => [ { DIRECTION => ["in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionInEnv($fn)); + +$fn = { ELEMENTS => [ { DIRECTION => ["out"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r->out.foo" }, GenerateFunctionOutEnv($fn)); + +$fn = { ELEMENTS => [ { DIRECTION => ["out", "in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionInEnv($fn)); + +$fn = { ELEMENTS => [ { DIRECTION => ["out", "in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r->out.foo" }, GenerateFunctionOutEnv($fn)); + +$fn = { ELEMENTS => [ { DIRECTION => ["in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionOutEnv($fn)); + +$fn = { ELEMENTS => [ { DIRECTION => ["out"], NAME => "foo" } ] }; +is_deeply({ }, GenerateFunctionInEnv($fn)); + +$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] }; +is_deeply({ foo => "r->foo", bar => "r->bar", this => "r" }, + GenerateStructEnv($fn, "r")); + +$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] }; +is_deeply({ foo => "some->complex.variable->foo", + bar => "some->complex.variable->bar", + this => "some->complex.variable" }, + GenerateStructEnv($fn, "some->complex.variable")); + +$fn = { ELEMENTS => [ { NAME => "foo", PROPERTIES => { value => 3 }} ] }; + +my $env = GenerateStructEnv($fn, "r"); +EnvSubstituteValue($env, $fn); +is_deeply($env, { foo => 3, this => "r" }); + +$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] }; +$env = GenerateStructEnv($fn, "r"); +EnvSubstituteValue($env, $fn); +is_deeply($env, { foo => 'r->foo', bar => 'r->bar', this => "r" }); + +$fn = { ELEMENTS => [ { NAME => "foo", PROPERTIES => { value => 0 }} ] }; + +$env = GenerateStructEnv($fn, "r"); +EnvSubstituteValue($env, $fn); +is_deeply($env, { foo => 0, this => "r" }); + + diff --git a/tools/pidl/tests/ndr.pl b/tools/pidl/tests/ndr.pl new file mode 100755 index 00000000..b6fd4899 --- /dev/null +++ b/tools/pidl/tests/ndr.pl @@ -0,0 +1,561 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 47; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::NDR qw(GetElementLevelTable ParseElement align_type mapToScalar ParseType can_contain_deferred); + +# Case 1 + +my $e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {}, + 'POINTERS' => 0, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + 'IS_DEFERRED' => 0, + 'LEVEL_INDEX' => 0, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +my $ne = ParseElement($e, "unique", 0); +is($ne->{ORIGINAL}, $e); +is($ne->{NAME}, "v"); +is($ne->{ALIGN}, 1); +is($ne->{TYPE}, "uint8"); +is_deeply($ne->{LEVELS}, [ + { + 'IS_DEFERRED' => 0, + 'LEVEL_INDEX' => 0, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 2 : pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"unique" => 1}, + 'POINTERS' => 1, + 'PARENT' => { TYPE => 'STRUCT' }, + 'TYPE' => 'uint8', + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 0, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 1, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 3 : double pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"unique" => 1}, + 'POINTERS' => 2, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 0, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 2, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 3 : ref pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 1, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 1, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 3 : ref pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 3 : ref pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "ref", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 4 : top-level ref pointers +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 1, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'FUNCTION' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'TOP' + }, + { + 'IS_DEFERRED' => 0, + 'LEVEL_INDEX' => 1, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 4 : top-level ref pointers, triple with pointer_default("unique") +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'FUNCTION' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'TOP' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 4 : top-level unique pointers, triple with pointer_default("unique") +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"unique" => 1, "in" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'FUNCTION' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "unique", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 0, + LEVEL => 'TOP' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 4 : top-level unique pointers, triple with pointer_default("ref") +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"unique" => 1, "in" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'FUNCTION' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "ref", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "unique", + POINTER_INDEX => 0, + LEVEL => 'TOP' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# Case 4 : top-level ref pointers, triple with pointer_default("ref") +# +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"ref" => 1}, + 'POINTERS' => 3, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'FUNCTION' }, + 'LINE' => 42 }; + +is_deeply(GetElementLevelTable($e, "ref", 0), [ + { + LEVEL_INDEX => 0, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 0, + LEVEL => 'TOP' + }, + { + LEVEL_INDEX => 1, + IS_DEFERRED => 0, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 1, + LEVEL => 'EMBEDDED' + }, + { + LEVEL_INDEX => 2, + IS_DEFERRED => 1, + TYPE => 'POINTER', + POINTER_TYPE => "ref", + POINTER_INDEX => 2, + LEVEL => 'EMBEDDED' + }, + { + 'IS_DEFERRED' => 1, + 'LEVEL_INDEX' => 3, + 'DATA_TYPE' => 'uint8', + 'CONTAINS_DEFERRED' => 0, + 'TYPE' => 'DATA', + 'IS_SURROUNDING' => 0, + } +]); + +# representation_type +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => { represent_as => "bar" }, + 'POINTERS' => 0, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +$ne = ParseElement($e, undef, 0); +is($ne->{REPRESENTATION_TYPE}, "bar"); + +# representation_type +$e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => { }, + 'POINTERS' => 0, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +$ne = ParseElement($e, undef, 0); +is($ne->{REPRESENTATION_TYPE}, "uint8"); + +is(align_type("hyper"), 8); +is(align_type("double"), 8); +is(align_type("uint32"), 4); +is(align_type("uint16"), 2); +is(align_type("uint8"), 1); +is(align_type({ TYPE => "STRUCT", "NAME" => "bla", + ELEMENTS => [ { TYPE => "uint16" } ] }), 4); +is(align_type({ TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "hyper" } ] }), 8); +is(align_type({ TYPE => "TYPEDEF", DATA => { + TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "hyper" } ] }}), 8); +# typedef of struct without body +is(align_type({ TYPE => "TYPEDEF", DATA => { + TYPE => "STRUCT", ELEMENTS => undef }}), 4); +# struct without body +is(align_type({ TYPE => "STRUCT", ELEMENTS => undef }), 4); +# empty struct +is(align_type({ TYPE => "STRUCT", ELEMENTS => [] }), 1); +is(align_type({ TYPE => "STRUCT", "NAME" => "bla", + ELEMENTS => [ { TYPE => "uint8" } ] }), 4); + +is(mapToScalar("someverymuchnotexistingtype"), undef); +is(mapToScalar("uint32"), "uint32"); +is(mapToScalar({TYPE => "ENUM", PARENT => { PROPERTIES => { enum8bit => 1 } } }), "uint8"); +is(mapToScalar({TYPE => "BITMAP", PROPERTIES => { bitmap64bit => 1 } }), + "hyper"); +is(mapToScalar({TYPE => "TYPEDEF", DATA => {TYPE => "ENUM", PARENT => { PROPERTIES => { enum8bit => 1 } } }}), "uint8"); + +my $t; +$t = { + TYPE => "STRUCT", + NAME => "foo", + SURROUNDING_ELEMENT => undef, + ELEMENTS => undef, + PROPERTIES => undef, + ORIGINAL => { + TYPE => "STRUCT", + NAME => "foo" + }, + ALIGN => undef +}; +is_deeply(ParseType($t->{ORIGINAL}, "ref", 0), $t); + +$t = { + TYPE => "UNION", + NAME => "foo", + SWITCH_TYPE => "uint32", + ELEMENTS => undef, + PROPERTIES => undef, + HAS_DEFAULT => 0, + IS_MS_UNION => 0, + ORIGINAL => { + TYPE => "UNION", + NAME => "foo" + }, + ALIGN => undef +}; +is_deeply(ParseType($t->{ORIGINAL}, "ref", 0), $t); + +ok(not can_contain_deferred("uint32")); +ok(can_contain_deferred("some_unknown_type")); +ok(can_contain_deferred({ TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "uint32", POINTERS => 40 } ]})); +ok(can_contain_deferred({ TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "uint32", POINTERS => 40 } ]}})); +ok(not can_contain_deferred({ TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "uint32" } ]})); +ok(not can_contain_deferred({ TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "uint32" } ]}})); +ok(can_contain_deferred({ TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "someunknowntype" } ]})); +# Make sure the elements for a enum without body aren't filled in +ok(not defined(ParseType({TYPE => "ENUM", NAME => "foo" }, "ref", 0)->{ELEMENTS})); +# Make sure the elements for a bitmap without body aren't filled in +ok(not defined(ParseType({TYPE => "BITMAP", NAME => "foo" }, "ref", 0)->{ELEMENTS})); +# Make sure the elements for a union without body aren't filled in +ok(not defined(ParseType({TYPE => "UNION", NAME => "foo" }, "ref", 0)->{ELEMENTS})); diff --git a/tools/pidl/tests/ndr_align.pl b/tools/pidl/tests/ndr_align.pl new file mode 100755 index 00000000..cc089eaa --- /dev/null +++ b/tools/pidl/tests/ndr_align.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl +# NDR alignment tests +# (C) 2005 Jelmer Vernooij. Published under the GNU GPL +use strict; + +use Test::More tests => 5 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr('align-uint8-uint16', +' + typedef [public] struct { + uint8 x; + uint16 y; + } bla; +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct bla r; + uint8_t expected[] = { 0x0D, 0x00, 0xef, 0xbe }; + DATA_BLOB expected_blob = { expected, 4 }; + DATA_BLOB result_blob; + r.x = 13; + r.y = 0xbeef; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + +test_samba4_ndr('align-uint8-uint32', +' + typedef [public] struct { + uint8 x; + uint32 y; + } bla; +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct bla r; + uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xef, 0xbe }; + DATA_BLOB expected_blob = { expected, 8 }; + DATA_BLOB result_blob; + r.x = 13; + r.y = 0xbeefbeef; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + + +test_samba4_ndr('align-uint8-hyper', +' + typedef [public] struct { + uint8 x; + hyper y; + } bla; +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct bla r; + uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe }; + DATA_BLOB expected_blob = { expected, 16 }; + DATA_BLOB result_blob; + r.x = 13; + r.y = 0xbeefbeefbeefbeefLLU; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + +test_samba4_ndr('noalignflag-uint8-uint16', +' + typedef [public] struct { + uint8 x; + uint16 y; + } bla; +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct bla r; + uint8_t expected[] = { 0x0D, 0xef, 0xbe }; + DATA_BLOB expected_blob = { expected, 3 }; + DATA_BLOB result_blob; + ndr->flags |= LIBNDR_FLAG_NOALIGN; + + r.x = 13; + r.y = 0xbeef; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + +test_samba4_ndr('align-blob-align2', +' + typedef [public] struct { + uint8 x; + [flag(LIBNDR_FLAG_ALIGN2)] DATA_BLOB data; + uint8 y; + } blie; +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct blie r; + uint8_t data[] = { 0x01, 0x02 }; + uint8_t expected[] = { 0x0D, 0x00, 0x0E }; + DATA_BLOB expected_blob = { expected, 3 }; + DATA_BLOB result_blob; + + r.x = 13; + r.y = 14; + r.data.data = data; + r.data.length = 2; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_blie(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); diff --git a/tools/pidl/tests/ndr_alloc.pl b/tools/pidl/tests/ndr_alloc.pl new file mode 100755 index 00000000..399fbd21 --- /dev/null +++ b/tools/pidl/tests/ndr_alloc.pl @@ -0,0 +1,118 @@ +#!/usr/bin/perl +# NDR allocation tests +# (C) 2005 Jelmer Vernooij. Published under the GNU GPL +use strict; + +use Test::More tests => 5 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +# Check that an outgoing scalar pointer is allocated correctly + +test_samba4_ndr("alloc-scalar", +' + typedef struct { + uint8 *x; + } bla; + + [public] void TestAlloc([in] bla foo); +',' + uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 }; + DATA_BLOB b = { data, 5 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct TestAlloc r; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r))) + return 1; + + if (r.in.foo.x == NULL) + return 2; + + if (*r.in.foo.x != 0x03) + return 3; +' +); + +# Check that an outgoing buffer pointer is allocated correctly +test_samba4_ndr("alloc-buffer", +' + typedef struct { uint8 data; } blie; + typedef struct { blie *x; } bla; + + [public] void TestAlloc([in] bla foo); +',' + uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 }; + DATA_BLOB b = { data, 5 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct TestAlloc r; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r))) + return 1; + + if (r.in.foo.x == NULL) + return 2; + + if (r.in.foo.x->data != 0x03) + return 3; +' +); + +# Check that ref pointers aren't allocated by default +test_samba4_ndr("ref-noalloc-null", +' + [public] void TestAlloc([in,ref] uint8 *t); +',' + uint8_t data[] = { 0x03 }; + DATA_BLOB b = { data, 1 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct TestAlloc r; + r.in.t = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r))) + return 1; +' +); + +# Check that ref pointers aren't allocated by default +test_samba4_ndr("ref-noalloc", +' + [public] void TestAlloc([in,ref] uint8 *t); +',' + uint8_t data[] = { 0x03 }; + DATA_BLOB b = { data, 1 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct TestAlloc r; + uint8_t x; + r.in.t = &x; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r))) + return 1; + + if (*r.in.t != 0x03) + return 2; +' +); + +# Check that an outgoing ref pointer is allocated correctly +test_samba4_ndr("ref-alloc", +' + [public] void TestAlloc([in,ref] uint8 *t); +',' + uint8_t data[] = { 0x03 }; + DATA_BLOB b = { data, 1 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct TestAlloc r; + ndr->flags |= LIBNDR_FLAG_REF_ALLOC; + r.in.t = NULL; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r))) + return 1; + + if (r.in.t == NULL) + return 2; + + if (*r.in.t != 0x03) + return 3; +' +); diff --git a/tools/pidl/tests/ndr_array.pl b/tools/pidl/tests/ndr_array.pl new file mode 100755 index 00000000..2a6b5bbd --- /dev/null +++ b/tools/pidl/tests/ndr_array.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +# Array testing +# (C) 2005 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr( + 'Fixed-Array', + + '[public] void Test([in] uint8 x[10]);', + + ' + uint8_t data[] = {1,2,3,4,5,6,7,8,9,10}; + int i; + DATA_BLOB b; + struct ndr_pull *ndr; + struct Test r; + + b.data = data; + b.length = 10; + ndr = ndr_pull_init_blob(&b, mem_ctx, NULL); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_Test(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 10) + return 2; + + for (i = 0; i < 10; i++) { + if (r.in.x[i] != i+1) return 3; + } +'); diff --git a/tools/pidl/tests/ndr_compat.pl b/tools/pidl/tests/ndr_compat.pl new file mode 100755 index 00000000..355e7f67 --- /dev/null +++ b/tools/pidl/tests/ndr_compat.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 2; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl; +use Parse::Pidl::IDL; + +sub parse_idl($) +{ + my $idl = shift; + my $pidl = Parse::Pidl::IDL::parse_string("interface echo { $idl }; ", "nofile"); + Parse::Pidl::NDR::Parse($pidl); +} + +test_warnings("", sub {parse_idl("void x();"); }); +test_warnings("nofile:0: top-level [out] pointer `x' is not a [ref] pointer\n", sub {parse_idl("void x([out,unique] int *x);"); }); diff --git a/tools/pidl/tests/ndr_deprecations.pl b/tools/pidl/tests/ndr_deprecations.pl new file mode 100755 index 00000000..86828e59 --- /dev/null +++ b/tools/pidl/tests/ndr_deprecations.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 1; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::NDR qw(ValidElement); + +# Case 1 + +my $e = { + 'FILE' => 'foo.idl', + 'NAME' => 'v', + 'PROPERTIES' => {"subcontext" => 1}, + 'POINTERS' => 0, + 'TYPE' => 'uint8', + 'PARENT' => { TYPE => 'STRUCT' }, + 'LINE' => 42 }; + +test_warnings("foo.idl:42: subcontext() is deprecated. Use represent_as() or transmit_as() instead\n", + sub { ValidElement($e); }); diff --git a/tools/pidl/tests/ndr_fullptr.pl b/tools/pidl/tests/ndr_fullptr.pl new file mode 100755 index 00000000..cc6fca7a --- /dev/null +++ b/tools/pidl/tests/ndr_fullptr.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# Simple tests for unique pointers +# (C) 2006 Jelmer Vernooij <jelmer@samba.org>. +# Published under the GNU General Public License. +use strict; + +use Test::More tests => 1 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +SKIP: { + skip "full pointers not supported yet", 8; + +test_samba4_ndr("fullptr-push-dup", +' + [public] uint16 echo_TestFull([in,ptr] uint32 *x, [in,ptr] uint32 *y); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + uint32_t v = 13; + struct echo_TestFull r; + r.in.x = &v; + r.in.y = &v; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestFull(ndr, NDR_IN, &r))) { + fprintf(stderr, "push failed\n"); + return 1; + } + + if (ndr->offset != 12) { + fprintf(stderr, "Offset(%d) != 12\n", ndr->offset); + return 2; + } + + if (ndr->data[0] != ndr->data[8] || + ndr->data[1] != ndr->data[9] || + ndr->data[2] != ndr->data[10] || + ndr->data[3] != ndr->data[11]) { + fprintf(stderr, "Data incorrect\n"); + return 3; + } +'); +} diff --git a/tools/pidl/tests/ndr_refptr.pl b/tools/pidl/tests/ndr_refptr.pl new file mode 100755 index 00000000..d5dd8395 --- /dev/null +++ b/tools/pidl/tests/ndr_refptr.pl @@ -0,0 +1,526 @@ +#!/usr/bin/perl +# Simple tests for pidl's handling of ref pointers, based +# on tridge's ref_notes.txt +# (C) 2005 Jelmer Vernooij <jelmer@samba.org>. +# Published under the GNU General Public License. +use strict; + +use Test::More tests => 22 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr("noptr-push", +' typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + uint16_t v = 13; + struct echo_TestRef r; + r.in.foo.x = v; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) { + fprintf(stderr, "push failed\n"); + return 1; + } + + if (ndr->offset != 2) { + fprintf(stderr, "Offset(%d) != 2\n", ndr->offset); + return 2; + } + + if (ndr->data[0] != 13 || ndr->data[1] != 0) { + fprintf(stderr, "Data incorrect\n"); + return 3; + } +'); + +test_samba4_ndr("ptr-embedded-push", +' typedef struct { + uint16 *x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct foo); +', +' + uint16_t v = 13; + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo.x = &v; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 6) + return 2; + + if (ndr->data[0] == 0 && ndr->data[1] == 0 && + ndr->data[2] == 0 && ndr->data[3] == 0) + return 3; + + if (ndr->data[4] != 13 || ndr->data[5] != 0) + return 4; +'); + +test_samba4_ndr("ptr-embedded-push-null", +' typedef struct { + uint16 *x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo.x = NULL; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 4) + return 2; + + if (ndr->data[0] != 0 || ndr->data[1] != 0 || + ndr->data[2] != 0 || ndr->data[3] != 0) + return 3; +'); + +test_samba4_ndr("refptr-embedded-push", +' + typedef struct { + [ref] uint16 *x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct foo); +', +' + uint16_t v = 13; + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo.x = &v; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 6) + return 2; + + if (ndr->data[0] == 0 && ndr->data[1] == 0 && + ndr->data[2] == 0 && ndr->data[3] == 0) + return 3; + + if (ndr->data[4] != 13 || ndr->data[5] != 0) + return 4; +'); + +test_samba4_ndr("refptr-embedded-push-null", +' + typedef struct { + [ref] uint16 *x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo.x = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + /* Windows gives [client runtime error 0x6f4] */ +'); + +test_samba4_ndr("ptr-top-push", +' + typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + struct xstruct s; + s.x = 13; + r.in.foo = &s; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 2) + return 2; + + if (ndr->data[0] != 13 || ndr->data[1] != 0) + return 3; +'); + +test_samba4_ndr("ptr-top-push-null", +' + typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ +'); + + +test_samba4_ndr("refptr-top-push", +' + typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in,ref] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + struct xstruct s; + s.x = 13; + r.in.foo = &s; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 2) + return 2; + + if (ndr->data[0] != 13 || ndr->data[1] != 0) + return 3; +'); + +test_samba4_ndr("refptr-top-push-null", +' + typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in,ref] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ +'); + + +test_samba4_ndr("uniqueptr-top-push", +' typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in,unique] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + struct xstruct s; + s.x = 13; + r.in.foo = &s; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 6) + return 2; + + if (ndr->data[0] == 0 && ndr->data[1] == 0 && + ndr->data[2] == 0 && ndr->data[3] == 0) + return 3; + + if (ndr->data[4] != 13 || ndr->data[5] != 0) + return 4; +'); + +test_samba4_ndr("uniqueptr-top-push-null", +' typedef struct { + uint16 x; + } xstruct; + + [public] uint16 echo_TestRef([in,unique] xstruct *foo); +', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo = NULL; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 4) + return 2; + + if (ndr->data[0] != 0 || ndr->data[1] != 0 || + ndr->data[2] != 0 || ndr->data[3] != 0) + return 3; +'); + + +test_samba4_ndr("ptr-top-out-pull", +' + typedef struct { + uint16 x; + } xstruct; + + [public] void echo_TestRef([out] xstruct *foo); +', +' + uint8_t data[] = { 0x0D, 0x00 }; + DATA_BLOB b = { data, 2 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct xstruct s; + struct echo_TestRef r; + + r.out.foo = &s; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r))) + return 1; + + if (!r.out.foo) + return 2; + + if (r.out.foo->x != 13) + return 3; +'); + +test_samba4_ndr("ptr-top-out-pull-null", +' + typedef struct { + uint16 x; + } xstruct; + + [public] void echo_TestRef([out] xstruct *foo); +', +' + uint8_t data[] = { 0x0D, 0x00 }; + DATA_BLOB b = { data, 2 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct echo_TestRef r; + + r.out.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ +'); + + +test_samba4_ndr("refptr-top-out-pull", +' + typedef struct { + uint16 x; + } xstruct; + + [public] void echo_TestRef([out,ref] xstruct *foo); +', +' + uint8_t data[] = { 0x0D, 0x00 }; + DATA_BLOB b = { data, 2 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct xstruct s; + struct echo_TestRef r; + + r.out.foo = &s; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r))) + return 1; + + if (!r.out.foo) + return 2; + + if (r.out.foo->x != 13) + return 3; +'); + +test_samba4_ndr("refptr-top-out-pull-null", +' + typedef struct { + uint16 x; + } xstruct; + + [public] void echo_TestRef([out,ref] xstruct *foo); +', +' + uint8_t data[] = { 0x0D, 0x00 }; + DATA_BLOB b = { data, 2 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL); + struct echo_TestRef r; + + r.out.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ +'); + + +test_samba4_ndr("ptr-top-push-double", +' + [public] void echo_TestRef([in] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + uint16_t v = 13; + uint16_t *pv = &v; + r.in.foo = &pv; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 6) + return 2; + + if (ndr->data[0] == 0 && ndr->data[1] == 0 && + ndr->data[2] == 0 && ndr->data[3] == 0) + return 3; + + if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00) + return 4; +'); + +SKIP: { + skip "ptr-top-push-double-sndnull is known to fail", 8; + +test_samba4_ndr("ptr-top-push-double-sndnull", +' + [public] void echo_TestRef([in] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + uint16_t *pv = NULL; + r.in.foo = &pv; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 4) + return 2; + + if (ndr->data[0] != 0 || ndr->data[1] != 0 || + ndr->data[2] != 0 || ndr->data[3] != 0) + return 3; +'); +} + +test_samba4_ndr("ptr-top-push-double-fstnull", +' + [public] void echo_TestRef([in] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ + +'); + + +test_samba4_ndr("refptr-top-push-double", +' + [public] void echo_TestRef([in,ref] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + uint16_t v = 13; + uint16_t *pv = &v; + r.in.foo = &pv; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 6) + return 2; + + if (ndr->data[0] == 0 && ndr->data[1] == 0 && + ndr->data[2] == 0 && ndr->data[3] == 0) + return 3; + + if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00) + return 4; +'); + +SKIP: { + + skip "refptr-top-push-double-sndnull is known to fail", 8; + +test_samba4_ndr("refptr-top-push-double-sndnull", +' + [public] void echo_TestRef([in,ref] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + uint16_t *pv = NULL; + r.in.foo = &pv; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 4) + return 2; + + if (ndr->data[0] != 0 || ndr->data[1] != 0 || + ndr->data[2] != 0 || ndr->data[3] != 0) + return 3; +'); +} + +test_samba4_ndr("refptr-top-push-double-fstnull", +' + [public] void echo_TestRef([in,ref] uint16 **foo); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + r.in.foo = NULL; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + /* Windows gives [client runtime error 0x6f4] */ + +'); + +SKIP: { + skip "ignore-ptrs are not supported yet", 8; +test_samba4_ndr("ignore-ptr", +' + [public] void echo_TestRef([in,ignore] uint16 *foo, [in] uint16 *bar); +', +' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct echo_TestRef r; + uint16_t v = 10; + r.in.foo = &v; + r.in.bar = &v; + + if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) + return 1; + + if (ndr->offset != 4) + return 2; +'); +} diff --git a/tools/pidl/tests/ndr_represent.pl b/tools/pidl/tests/ndr_represent.pl new file mode 100755 index 00000000..2d65fb92 --- /dev/null +++ b/tools/pidl/tests/ndr_represent.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# NDR represent_as() / transmit_as() tests +# (C) 2006 Jelmer Vernooij. Published under the GNU GPL +use strict; + +use Test::More tests => 2 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr('represent_as-simple', +' + void bla([in,represent_as(uint32)] uint8 x); +', +' + uint8_t expected[] = { 0x0D }; + DATA_BLOB in_blob = { expected, 1 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&in_blob, NULL, NULL); + struct bla r; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + if (r.in.x != 13) + return 2; +', +' +enum ndr_err_code ndr_uint8_to_uint32(uint8_t from, uint32_t *to) +{ + *to = from; + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_uint32_to_uint8(uint32_t from, uint8_t *to) +{ + *to = from; + return NDR_ERR_SUCCESS; +} +' +); + +test_samba4_ndr('transmit_as-simple', +' + void bla([in,transmit_as(uint32)] uint8 x); +', +' + uint8_t expected[] = { 0x0D }; + DATA_BLOB in_blob = { expected, 1 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&in_blob, NULL, NULL); + struct bla r; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + if (r.in.x != 13) + return 2; +', +' +enum ndr_err_code ndr_uint8_to_uint32(uint8_t from, uint32_t *to) +{ + *to = from; + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_uint32_to_uint8(uint32_t from, uint8_t *to) +{ + *to = from; + return NDR_ERR_SUCCESS; +} +' +); diff --git a/tools/pidl/tests/ndr_simple.pl b/tools/pidl/tests/ndr_simple.pl new file mode 100755 index 00000000..15e07d56 --- /dev/null +++ b/tools/pidl/tests/ndr_simple.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +# Some simple tests for pidl +# (C) 2005 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr("simple", "void Test(); ", +" + uint8_t data[] = { 0x02 }; + uint8_t result; + DATA_BLOB b; + struct ndr_pull *ndr; + + b.data = data; + b.length = 1; + ndr = ndr_pull_init_blob(&b, mem_ctx, NULL); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_uint8(ndr, NDR_SCALARS, &result))) + return 1; + + if (result != 0x02) + return 2; +"); diff --git a/tools/pidl/tests/ndr_string.pl b/tools/pidl/tests/ndr_string.pl new file mode 100755 index 00000000..8e8b8ecb --- /dev/null +++ b/tools/pidl/tests/ndr_string.pl @@ -0,0 +1,192 @@ +#!/usr/bin/perl +# String tests for pidl +# (C) 2005 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 6 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr("string-pull-empty", +' [public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data);', +' + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00 }; + DATA_BLOB b = { data, 4 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + r.in.data = NULL; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; + + if (r.in.data == NULL) + return 2; + + if (r.in.data[0] != 0) + return 3; +'); + +test_samba4_ndr("string-ascii-pull", +' + [public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data); +', +' + uint8_t data[] = { 0x03, 0x00, 0x00, 0x00, + \'f\', \'o\', \'o\', 0 }; + DATA_BLOB b = { data, 8 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + r.in.data = NULL; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; + + if (r.in.data == NULL) + return 2; + + if (strncmp(r.in.data, "foo", 3) != 0) + return 3; + + if (r.in.data[4] != 0) + return 4; +'); + +test_samba4_ndr("string-wchar-fixed-array-01", +' + typedef struct { + uint32 l1; + [string,charset(UTF16)] uint16 str[6]; + uint32 l2; + } TestStringStruct; + + [public] void TestString([in,ref] TestStringStruct *str); +', +' + uint8_t data[] = { 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, + \'f\', 0x00, \'o\', 0x00, + \'o\', 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00 + }; + DATA_BLOB b = { data, sizeof(data) }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + struct TestStringStruct str; + r.in.str = &str; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; + + if (r.in.str == NULL) + return 2; + + if (r.in.str->l1 != 0x00000001) + return 3; + + if (strncmp(str.str, "foo", 3) != 0) + return 4; + + if (r.in.str->str[4] != 0) + return 5; + + if (r.in.str->l2 != 0x00000002) + return 6; +'); + +test_samba4_ndr("string-wchar-fixed-array-02", +' + typedef struct { + uint32 l1; + [string,charset(UTF16)] uint16 str[6]; + uint32 l2; + } TestStringStruct; + + [public] void TestString([in,ref] TestStringStruct *str); +', +' + uint8_t data[] = { 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, + \'f\', 0x00, \'o\', 0x00, + \'o\', 0x00, \'b\', 0x00, + \'a\', 0x00, \'r\', 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00 + }; + DATA_BLOB b = { data, sizeof(data) }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + struct TestStringStruct str; + r.in.str = &str; + + /* the string terminator is wrong */ + if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; +'); + +test_samba4_ndr("string-wchar-fixed-array-03", +' + typedef struct { + uint32 l1; + [string,charset(UTF16)] uint16 str[6]; + uint32 l2; + } TestStringStruct; + + [public] void TestString([in,ref] TestStringStruct *str); +', +' + uint8_t data[] = { 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, + \'f\', 0x00, \'o\', 0x00, + \'o\', 0x00, \'b\', 0x00, + \'a\', 0x00, \'r\', 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00 + }; + DATA_BLOB b = { data, sizeof(data) }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + struct TestStringStruct str; + r.in.str = &str; + + /* the length 0x07 is to large */ + if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; +'); + +SKIP: { + skip "doesn't seem to work yet", 8; + +test_samba4_ndr("string-out", +' + [public] void TestString([out,string,charset(UNIX)] uint8 **data); +', +' + uint8_t data[] = { 0x03, 0x00, 0x00, 0x00, + \'f\', \'o\', \'o\', 0 }; + DATA_BLOB b = { data, 8 }; + struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL); + struct TestString r; + char *str = NULL; + r.out.data = &str; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r))) + return 1; + + if (r.out.data == NULL) + return 2; + + if (*r.out.data == NULL) + return 3; + + if (strncmp(r.out.data, "foo", 3) != 0) + return 4; + + if (r.out.data[4] != 0) + return 5; +'); +} diff --git a/tools/pidl/tests/ndr_tagtype.pl b/tools/pidl/tests/ndr_tagtype.pl new file mode 100755 index 00000000..3f9b717b --- /dev/null +++ b/tools/pidl/tests/ndr_tagtype.pl @@ -0,0 +1,66 @@ +#!/usr/bin/perl +# Support for tagged types +# (C) 2005 Jelmer Vernooij. Published under the GNU GPL +use strict; + +use Test::More tests => 3 * 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_samba4_ndr); + +test_samba4_ndr('struct-notypedef', '[public] struct bla { uint8 x; }; ', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct bla r; + uint8_t expected[] = { 0x0D }; + DATA_BLOB expected_blob = { expected, 1 }; + DATA_BLOB result_blob; + r.x = 13; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_STRUCT_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + +test_samba4_ndr('struct-notypedef-used', '[public] struct bla { uint8 x; }; + [public] void myfn([in] struct bla r); ', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct myfn fn; + uint8_t expected[] = { 0x0D }; + DATA_BLOB expected_blob = { expected, 1 }; + DATA_BLOB result_blob; + fn.in.r.x = 13; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_myfn(ndr, NDR_IN, &fn))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); + + +test_samba4_ndr('struct-notypedef-embedded', 'struct bla { uint8 x; }; + [public] struct myst { struct bla r; }; ', +' + struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL); + struct myst st; + uint8_t expected[] = { 0x0D }; + DATA_BLOB expected_blob = { expected, 1 }; + DATA_BLOB result_blob; + st.r.x = 13; + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_STRUCT_myst(ndr, NDR_IN, &st))) + return 1; + + result_blob = ndr_push_blob(ndr); + + if (data_blob_cmp(&result_blob, &expected_blob) != 0) + return 2; +'); diff --git a/tools/pidl/tests/parse_idl.pl b/tools/pidl/tests/parse_idl.pl new file mode 100755 index 00000000..14138a37 --- /dev/null +++ b/tools/pidl/tests/parse_idl.pl @@ -0,0 +1,243 @@ +#!/usr/bin/perl +# Some simple tests for pidls parsing routines +# (C) 2005 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 65 * 2 + 7; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_errors); +use Parse::Pidl::IDL; +use Parse::Pidl::NDR; + +sub testok($$) +{ + my ($name, $data) = @_; + + test_errors("", sub { + my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>"); + ok (defined($pidl), $name); + }); +} + +sub testfail($$$) +{ + my ($name, $data, $error) = @_; + + test_errors($error, sub { + my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>"); + + ok ((not defined $pidl), $name); + }); +} + +testfail "unknowntag", "bla test {};", + "<unknowntag>:0: Syntax error near 'bla'\n"; +testok "test1", "interface test { void Test(); }; "; +testok "voidtest", "interface test { int Testx(void); }; "; +testfail "voidtest", "interface test { Test(); }; ", + "<voidtest>:0: Syntax error near '('\n"; +testok "argtest", "interface test { int Test(int a, long b, uint32 c); }; "; +testok "array1", "interface test { int Test(int a[]); };"; +testok "array2", "interface test { int Test(int a[2]); };"; +testok "array3", "interface test { int Test(int a[b]); };"; +testfail "array4", "interface test { int Test(int[] a); };", + "<array4>:0: Syntax error near '['\n"; +testok "ptr1", "interface test { int Test(int *a); };"; +testok "ptr2", "interface test { int Test(int **a); };"; +testok "ptr3", "interface test { int Test(int ***a); };"; +testfail "empty1", "interface test { };", "<empty1>:0: Syntax error near '}'\n"; +testfail "empty2", "", ""; +testok "attr1", "[uuid(\"myuuid\"),attr] interface test { int Test(int ***a); };"; +testok "attr2", "interface test { [public] int Test(); };"; +testok "attr3", "[attr1] [attr2] interface test { [public] int Test(); };"; +testok "multfn", "interface test { int test1(); int test2(); };"; +testok "multif", "interface test { int test1(); }; interface test2 { int test2(); };"; +testok "tdstruct1", "interface test { typedef struct { } foo; };"; +testok "tdstruct2", "interface test { typedef struct { int a; } foo; };"; +testok "tdstruct3", "interface test { typedef struct { int a; int b; } foo; };"; +testfail "tdstruct4", "interface test { typedef struct { int a, int b; } foo; };", + "<tdstruct4>:0: Syntax error near ','\n"; +testok "struct1", "interface test { struct x { }; };"; +testok "struct2", "interface test { struct x { int a; }; };"; +testok "struct3", "interface test { struct x { int a; int b; }; };"; +testfail "struct4", "interface test { struct x { int a, int b; }; };", + "<struct4>:0: Syntax error near ','\n"; +testfail "struct5", "interface test { struct { int a; } x; };", + "<struct5>:0: Syntax error near 'x'\n"; +testok "tdunion1", "interface test { typedef union { } a; };"; +testok "tdunion2", "interface test { typedef union { int a; } a; };"; +testok "union1", "interface test { union a { }; };"; +testok "union2", "interface test { union x { int a; }; };"; +testfail "union3", "interface test { union { int a; } x; };", + "<union3>:0: Syntax error near 'x'\n"; +testok "typedef1", "interface test { typedef int a; };"; +testfail "typedef2", "interface test { typedef x; };", + "<typedef2>:0: Syntax error near ';'\n"; +testok "tdenum1", "interface test { typedef enum { A=1, B=2, C} a; };"; +testok "enum1", "interface test { enum a { A=1, B=2, C}; };"; +testfail "enum2", "interface test { enum { A=1, B=2, C} a; };", + "<enum2>:0: Syntax error near 'a'\n"; +testok "nested1", "interface test { struct x { struct { int a; } z; }; };"; +testok "nested2", "interface test { struct x { struct y { int a; } z; }; };"; +testok "bitmap1", "interface test { bitmap x { a=1 }; };"; +testok "unsigned", "interface test { struct x { unsigned short y; }; };"; +testok "struct-property", "interface test { [public] struct x { short y; }; };"; +testok "signed", "interface test { struct x { signed short y; }; };"; +testok "declarg", "interface test { void test(struct { int x; } a); };"; +testok "structarg", "interface test { void test(struct a b); };"; +testfail "structargmissing", "interface test { void test(struct a); };", + "<structargmissing>:0: Syntax error near ')'\n"; +testok "structqual", "interface test { struct x { struct y z; }; };"; +testok "unionqual", "interface test { struct x { union y z; }; };"; +testok "enumqual", "interface test { struct x { enum y z; }; };"; +testok "bitmapqual", "interface test { struct x { bitmap y z; }; };"; +testok "emptystructdecl", "interface test { struct x; };"; +testok "emptyenumdecl", "interface test { enum x; };"; +testok "emptytdstructdecl", "interface test { typedef struct x y; };"; +testok "import", "import \"foo.idl\";"; +testok "include", "include \"foo.h\";"; +testfail "import-noquotes", "import foo.idl;", + "<import-noquotes>:0: Syntax error near 'foo'\n"; +testfail "include-noquotes", "include foo.idl;", + "<include-noquotes>:0: Syntax error near 'foo'\n"; +testok "importlib", "importlib \"foo.idl\";"; +testfail "import-nosemicolon", "import \"foo.idl\"", + "<import-nosemicolon>:0: Syntax error near 'foo.idl'\n"; +testok "import-multiple", "import \"foo.idl\", \"bar.idl\";"; +testok "include-multiple", "include \"foo.idl\", \"bar.idl\";"; +testok "empty-struct", "interface test { struct foo { }; }"; +testok "typedef-double", "interface test { typedef struct foo { } foo; }"; +testok "cpp-quote", "cpp_quote(\"bla\")"; + +my $x = Parse::Pidl::IDL::parse_string("interface foo { struct x {}; }", "<foo>"); + +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'STRUCT', + 'NAME' => 'x', + 'ELEMENTS' => [], + 'FILE' => '<foo>', + 'LINE' => 0 + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); + +$x = Parse::Pidl::IDL::parse_string("interface foo { struct x; }", "<foo>"); +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'STRUCT', + 'NAME' => 'x', + 'FILE' => '<foo>', + 'LINE' => 0 + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); + +$x = Parse::Pidl::IDL::parse_string("cpp_quote(\"foobar\")", "<quote>"); +is_deeply($x, [ { + 'TYPE' => 'CPP_QUOTE', + 'DATA' => '"foobar"', + 'FILE' => '<quote>', + 'LINE' => 0 +}]); + +# A typedef of a struct without body +$x = Parse::Pidl::IDL::parse_string("interface foo { typedef struct x y; }", "<foo>"); + +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'TYPEDEF', + 'NAME' => 'y', + 'POINTERS' => 0, + 'DATA' => { + 'TYPE' => 'STRUCT', + 'NAME' => 'x', + 'FILE' => '<foo>', + 'LINE' => 0, + }, + 'FILE' => '<foo>', + 'LINE' => 0, + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); + +# A typedef of a struct with empty body +$x = Parse::Pidl::IDL::parse_string("interface foo { typedef struct {} y; }", "<foo>"); + +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'TYPEDEF', + 'NAME' => 'y', + 'POINTERS' => 0, + 'DATA' => { + 'TYPE' => 'STRUCT', + 'ELEMENTS' => [], + 'FILE' => '<foo>', + 'LINE' => 0 + }, + 'FILE' => '<foo>', + 'LINE' => 0 + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); + +# A typedef of a bitmap with no body +$x = Parse::Pidl::IDL::parse_string("interface foo { typedef bitmap x y; }", "<foo>"); + +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'TYPEDEF', + 'NAME' => 'y', + 'POINTERS' => 0, + 'DATA' => { + 'TYPE' => 'BITMAP', + 'NAME' => 'x', + 'FILE' => '<foo>', + 'LINE' => 0 + }, + 'FILE' => '<foo>', + 'LINE' => 0 + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); + + +# A typedef of a union with no body +$x = Parse::Pidl::IDL::parse_string("interface foo { typedef union x y; }", "<foo>"); + +is_deeply($x, [ { + 'TYPE' => 'INTERFACE', + 'NAME' => 'foo', + 'DATA' => [ { + 'TYPE' => 'TYPEDEF', + 'NAME' => 'y', + 'POINTERS' => 0, + 'DATA' => { + 'TYPE' => 'UNION', + 'NAME' => 'x', + 'FILE' => '<foo>', + 'LINE' => 0 + }, + 'FILE' => '<foo>', + 'LINE' => 0 + } ], + 'FILE' => '<foo>', + 'LINE' => 0 +}]); diff --git a/tools/pidl/tests/samba-ndr.pl b/tools/pidl/tests/samba-ndr.pl new file mode 100755 index 00000000..7c53cbc7 --- /dev/null +++ b/tools/pidl/tests/samba-ndr.pl @@ -0,0 +1,300 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 31; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use strict; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::Samba4::NDR::Parser qw(check_null_pointer + NeededFunction NeededElement NeededType + NeededInterface TypeFunctionName ParseElementPrint); + +my $output; +sub print_fn($) { my $x = shift; $output.=$x; } + +# Test case 1: Simple unique pointer dereference + +$output = ""; +my $fn = check_null_pointer({ + PARENT => { + ELEMENTS => [ + { + NAME => "bla", + LEVELS => [ + { TYPE => "POINTER", + POINTER_INDEX => 0, + POINTER_TYPE => "unique" }, + { TYPE => "DATA" } + ], + }, + ] + } +}, { bla => "r->in.bla" }, \&print_fn, "return;"); + + +test_warnings("", sub { $fn->("r->in.bla"); }); + +is($output, "if (r->in.bla == NULL) return;"); + +# Test case 2: Simple ref pointer dereference + +$output = ""; +$fn = check_null_pointer({ + PARENT => { + ELEMENTS => [ + { + NAME => "bla", + LEVELS => [ + { TYPE => "POINTER", + POINTER_INDEX => 0, + POINTER_TYPE => "ref" }, + { TYPE => "DATA" } + ], + }, + ] + } +}, { bla => "r->in.bla" }, \&print_fn, undef); + +test_warnings("", sub { $fn->("r->in.bla"); }); + +is($output, ""); + +# Test case 3: Illegal dereference + +$output = ""; +$fn = check_null_pointer({ + FILE => "nofile", + LINE => 1, + PARENT => { + ELEMENTS => [ + { + NAME => "bla", + LEVELS => [ + { TYPE => "DATA" } + ], + }, + ] + } +}, { bla => "r->in.bla" }, \&print_fn, undef); + +test_warnings("nofile:1: too much dereferences for `bla'\n", + sub { $fn->("r->in.bla"); }); + +is($output, ""); + +# Test case 4: Double pointer dereference + +$output = ""; +$fn = check_null_pointer({ + PARENT => { + ELEMENTS => [ + { + NAME => "bla", + LEVELS => [ + { TYPE => "POINTER", + POINTER_INDEX => 0, + POINTER_TYPE => "unique" }, + { TYPE => "POINTER", + POINTER_INDEX => 1, + POINTER_TYPE => "unique" }, + { TYPE => "DATA" } + ], + }, + ] + } +}, { bla => "r->in.bla" }, \&print_fn, "return;"); + +test_warnings("", + sub { $fn->("*r->in.bla"); }); + +is($output, "if (*r->in.bla == NULL) return;"); + +# Test case 5: Unknown variable + +$output = ""; +$fn = check_null_pointer({ + FILE => "nofile", + LINE => 2, + PARENT => { + ELEMENTS => [ + { + NAME => "bla", + LEVELS => [ + { TYPE => "DATA" } + ], + }, + ] + } +}, { }, \&print_fn, "return;"); + +test_warnings("nofile:2: unknown dereferenced expression `r->in.bla'\n", + sub { $fn->("r->in.bla"); }); + +is($output, "if (r->in.bla == NULL) return;"); + +my $needed = {}; +NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); +is_deeply($needed, { ndr_pull_foo => 1 }); + +# old settings should be kept +$needed = { ndr_pull_foo => 0 }; +NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); +is_deeply($needed, { ndr_pull_foo => 0 }); + +# print/pull/push are independent of each other +$needed = { ndr_pull_foo => 0 }; +NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "print", $needed); +is_deeply($needed, { ndr_pull_foo => 0, ndr_print_foo => 1 }); + +$needed = { }; +NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); +is_deeply($needed, { ndr_pull_foo => 1, ndr_print_foo => 1, ndr_push_foo => 1, + ndr_pull_bar => 1, ndr_print_bar => 1, ndr_push_bar => 1}); + +# push/pull/print are always set for functions +$needed = { ndr_pull_foo => 0 }; +NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); +is_deeply($needed, { ndr_pull_foo => 1, ndr_print_foo => 1, ndr_push_foo => 1, + ndr_pull_bar => 1, ndr_push_bar => 1, ndr_print_bar => 1}); + +# public structs are always needed +$needed = {}; +NeededType({ NAME => "bla", TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", ELEMENTS => [] } }, + $needed, "pull"); +is_deeply($needed, { }); + +$needed = {}; +NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", + TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", ELEMENTS => [] } } ] }, + $needed); +is_deeply($needed, { ndr_pull_bla => 1, ndr_push_bla => 1, ndr_print_bla => 1 }); + +# make sure types for elements are set too +$needed = {}; +NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", + TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] }, + $needed); +is_deeply($needed, { ndr_pull_bla => 1, ndr_pull_bar => 1, ndr_push_bla => 1, ndr_push_bar => 1, + ndr_print_bla => 1, ndr_print_bar => 1}); + +$needed = {}; +NeededInterface({ TYPES => [ { PROPERTIES => { gensize => 1}, NAME => "bla", + TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] }, + $needed); +is_deeply($needed, { ndr_size_bla => 1 }); + +# make sure types for elements are set too +$needed = { ndr_pull_bla => 1 }; +NeededType({ NAME => "bla", + TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } }, + $needed, "pull"); +is_deeply($needed, { ndr_pull_bla => 1, ndr_pull_bar => 1 }); + +$needed = {}; +NeededInterface({ TYPES => [ { PROPERTIES => { public => 1}, + NAME => "bla", + TYPE => "TYPEDEF", + DATA => { TYPE => "STRUCT", + ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "rep" } ] } } ] }, $needed); +is_deeply($needed, { ndr_pull_bla => 1, ndr_push_bla => 1, ndr_print_bla => 1, + ndr_print_rep => 1, + ndr_pull_bar => 1, ndr_push_bar => 1, + ndr_bar_to_rep => 1, ndr_rep_to_bar => 1}); + +my $generator = new Parse::Pidl::Samba4::NDR::Parser(); +$generator->ParseStructPush({ + NAME => "mystruct", + TYPE => "STRUCT", + PROPERTIES => {}, + ALIGN => 4, + ELEMENTS => [ ]}, "ndr", "x"); +is($generator->{res}, "NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); +if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); +} +if (ndr_flags & NDR_BUFFERS) { +} +"); + +$generator = new Parse::Pidl::Samba4::NDR::Parser(); +my $e = { + NAME => "el1", + TYPE => "mytype", + REPRESENTATION_TYPE => "mytype", + PROPERTIES => {}, + LEVELS => [ + { LEVEL_INDEX => 0, TYPE => "DATA", DATA_TYPE => "mytype" } +] }; +$generator->ParseStructPush({ + NAME => "mystruct", + TYPE => "STRUCT", + PROPERTIES => {}, + ALIGN => 4, + SURROUNDING_ELEMENT => $e, + ELEMENTS => [ $e ]}, "ndr", "x"); +is($generator->{res}, "NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); +if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, ndr_string_array_size(ndr, x->el1))); + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_mytype(ndr, NDR_SCALARS, &x->el1)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); +} +if (ndr_flags & NDR_BUFFERS) { +} +"); + +is(TypeFunctionName("ndr_pull", "uint32"), "ndr_pull_uint32"); +is(TypeFunctionName("ndr_pull", {TYPE => "ENUM", NAME => "bar"}), "ndr_pull_ENUM_bar"); +is(TypeFunctionName("ndr_pull", {TYPE => "TYPEDEF", NAME => "bar", DATA => undef}), "ndr_pull_bar"); +is(TypeFunctionName("ndr_push", {TYPE => "STRUCT", NAME => "bar"}), "ndr_push_STRUCT_bar"); + +# check noprint works +$generator = new Parse::Pidl::Samba4::NDR::Parser(); +$generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", + PROPERTIES => { noprint => 1}, + LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt"} ]}, + "ndr", "var", { "x" => "r->foobar" } ); +is($generator->{res}, ""); + +$generator = new Parse::Pidl::Samba4::NDR::Parser(); +$generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", + PROPERTIES => {}, + LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt" }]}, + "ndr", "var", { "x" => "r->foobar" } ); +is($generator->{res}, "ndr_print_rt(ndr, \"x\", &var);\n"); + +# make sure that a print function for an element with value() set works +$generator = new Parse::Pidl::Samba4::NDR::Parser(); +$generator->ParseElementPrint({ NAME => "x", TYPE => "uint32", REPRESENTATION_TYPE => "uint32", + PROPERTIES => { value => "23" }, + LEVELS => [ { TYPE => "DATA", DATA_TYPE => "uint32"} ]}, + "ndr", "var", { "x" => "r->foobar" } ); +is($generator->{res}, "ndr_print_uint32(ndr, \"x\", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?23:var);\n"); + +$generator = new Parse::Pidl::Samba4::NDR::Parser(); +$generator->AuthServiceStruct("bridge", "\"rot13\",\"onetimepad\""); +is($generator->{res}, "static const char * const bridge_authservice_strings[] = { + \"rot13\", + \"onetimepad\", +}; + +static const struct ndr_interface_string_array bridge_authservices = { + .count = 2, + .names = bridge_authservice_strings +}; + +"); diff --git a/tools/pidl/tests/samba3-cli.pl b/tools/pidl/tests/samba3-cli.pl new file mode 100755 index 00000000..c758ef45 --- /dev/null +++ b/tools/pidl/tests/samba3-cli.pl @@ -0,0 +1,236 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 8; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::Samba3::ClientNDR qw(ParseFunction); +use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv); + +# Make sure GenerateFunctionInEnv and GenerateFunctionOutEnv work +my $fn = { ELEMENTS => [ { DIRECTION => ["in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r.in.foo" }, GenerateFunctionInEnv($fn, "r.")); +is_deeply({ "foo" => "r.in.foo" }, GenerateFunctionOutEnv($fn, "r.")); + +$fn = { ELEMENTS => [ { DIRECTION => ["out", "in"], NAME => "foo" } ] }; +is_deeply({ "foo" => "r.in.foo" }, GenerateFunctionInEnv($fn, "r.")); +is_deeply({ "foo" => "r.out.foo" }, GenerateFunctionOutEnv($fn, "r.")); + +$fn = { ELEMENTS => [ { DIRECTION => ["out"], NAME => "foo" } ] }; +is_deeply({ }, GenerateFunctionInEnv($fn, "r.")); +is_deeply({ "foo" => "r.out.foo" }, GenerateFunctionOutEnv($fn, "r.")); + +my $x = new Parse::Pidl::Samba3::ClientNDR(); + +$fn = { NAME => "bar", ELEMENTS => [ ] }; +$x->ParseFunction("foo", $fn); +is($x->{res}, +"struct rpccli_bar_state { + TALLOC_CTX *out_mem_ctx; +}; + +static void rpccli_bar_done(struct tevent_req *subreq); + +struct tevent_req *rpccli_bar_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli) +{ + struct tevent_req *req; + struct rpccli_bar_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct rpccli_bar_state); + if (req == NULL) { + return NULL; + } + state->out_mem_ctx = NULL; + + subreq = dcerpc_bar_send(state, + ev, + cli->binding_handle); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, rpccli_bar_done, req); + return req; +} + +static void rpccli_bar_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct rpccli_bar_state *state = tevent_req_data( + req, struct rpccli_bar_state); + NTSTATUS status; + TALLOC_CTX *mem_ctx; + + if (state->out_mem_ctx) { + mem_ctx = state->out_mem_ctx; + } else { + mem_ctx = state; + } + + status = dcerpc_bar_recv(subreq, + mem_ctx); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + tevent_req_done(req); +} + +NTSTATUS rpccli_bar_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx) +{ + struct rpccli_bar_state *state = tevent_req_data( + req, struct rpccli_bar_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + /* Steal possible out parameters to the callers context */ + talloc_steal(mem_ctx, state->out_mem_ctx); + + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS rpccli_bar(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + + status = dcerpc_bar(cli->binding_handle, + mem_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Return result */ + return NT_STATUS_OK; +} + +"); + +$x = new Parse::Pidl::Samba3::ClientNDR(); + +$fn = { NAME => "bar", ELEMENTS => [ ], RETURN_TYPE => "WERROR" }; +$x->ParseFunction("foo", $fn); +is($x->{res}, +"struct rpccli_bar_state { + TALLOC_CTX *out_mem_ctx; + WERROR result; +}; + +static void rpccli_bar_done(struct tevent_req *subreq); + +struct tevent_req *rpccli_bar_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli) +{ + struct tevent_req *req; + struct rpccli_bar_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct rpccli_bar_state); + if (req == NULL) { + return NULL; + } + state->out_mem_ctx = NULL; + + subreq = dcerpc_bar_send(state, + ev, + cli->binding_handle); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, rpccli_bar_done, req); + return req; +} + +static void rpccli_bar_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct rpccli_bar_state *state = tevent_req_data( + req, struct rpccli_bar_state); + NTSTATUS status; + TALLOC_CTX *mem_ctx; + + if (state->out_mem_ctx) { + mem_ctx = state->out_mem_ctx; + } else { + mem_ctx = state; + } + + status = dcerpc_bar_recv(subreq, + mem_ctx, + &state->result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + tevent_req_done(req); +} + +NTSTATUS rpccli_bar_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + WERROR *result) +{ + struct rpccli_bar_state *state = tevent_req_data( + req, struct rpccli_bar_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + /* Steal possible out parameters to the callers context */ + talloc_steal(mem_ctx, state->out_mem_ctx); + + /* Return result */ + *result = state->result; + + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS rpccli_bar(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + WERROR *werror) +{ + WERROR result; + NTSTATUS status; + + status = dcerpc_bar(cli->binding_handle, + mem_ctx, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Return result */ + if (werror) { + *werror = result; + } + + return werror_to_ntstatus(result); +} + +"); + diff --git a/tools/pidl/tests/samba3-srv.pl b/tools/pidl/tests/samba3-srv.pl new file mode 100755 index 00000000..d1e2bc95 --- /dev/null +++ b/tools/pidl/tests/samba3-srv.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +# (C) 2008 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 1; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper has_property); +use Parse::Pidl::Samba3::ServerNDR qw(DeclLevel); + +my $l = { TYPE => "DATA", DATA_TYPE => "uint32" }; +my $e = { FILE => "foo", LINE => 0, PROPERTIES => { }, TYPE => "uint32", + LEVELS => [ $l ] }; + +is("uint32_t", DeclLevel($e, 0)); diff --git a/tools/pidl/tests/tdr.pl b/tools/pidl/tests/tdr.pl new file mode 100755 index 00000000..d6cd7a03 --- /dev/null +++ b/tools/pidl/tests/tdr.pl @@ -0,0 +1,49 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 6; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Samba4::TDR qw(ParserType); + +my $tdr = new Parse::Pidl::Samba4::TDR(); + +$tdr->ParserType({TYPE => "STRUCT", NAME => "foo", PROPERTIES => {public => 1}}, "pull"); +is($tdr->{ret}, "NTSTATUS tdr_pull_foo (struct tdr_pull *tdr, TALLOC_CTX *mem_ctx, struct foo *v) +{ + return NT_STATUS_OK; +} + +"); +is($tdr->{ret_hdr}, "NTSTATUS tdr_pull_foo (struct tdr_pull *tdr, TALLOC_CTX *mem_ctx, struct foo *v);\n"); + + +$tdr = new Parse::Pidl::Samba4::TDR(); +$tdr->ParserType({TYPE => "UNION", NAME => "bar", PROPERTIES => {public => 1}}, "pull"); +is($tdr->{ret}, "NTSTATUS tdr_pull_bar(struct tdr_pull *tdr, TALLOC_CTX *mem_ctx, int level, union bar *v) +{ + switch (level) { + } + return NT_STATUS_OK; + +} + +"); +is($tdr->{ret_hdr}, "NTSTATUS tdr_pull_bar(struct tdr_pull *tdr, TALLOC_CTX *mem_ctx, int level, union bar *v);\n"); + +$tdr = new Parse::Pidl::Samba4::TDR(); +$tdr->ParserType({TYPE => "UNION", NAME => "bar", PROPERTIES => {}}, "pull"); +is($tdr->{ret}, "static NTSTATUS tdr_pull_bar(struct tdr_pull *tdr, TALLOC_CTX *mem_ctx, int level, union bar *v) +{ + switch (level) { + } + return NT_STATUS_OK; + +} + +"); +is($tdr->{ret_hdr}, ""); diff --git a/tools/pidl/tests/test_util.pl b/tools/pidl/tests/test_util.pl new file mode 100755 index 00000000..2d59f628 --- /dev/null +++ b/tools/pidl/tests/test_util.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; + +use Test::More tests => 6; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util qw(test_warnings test_errors); +use Parse::Pidl qw(warning error); + +test_warnings("", sub {}); + +test_warnings("x:1: msg\n", sub { warning({FILE => "x", LINE => 1}, "msg"); }); +test_warnings("", sub {}); + +test_errors("", sub {}); + +test_errors("x:1: msg\n", sub { error({FILE => "x", LINE => 1}, "msg"); }); +test_errors("", sub {}); + diff --git a/tools/pidl/tests/typelist.pl b/tools/pidl/tests/typelist.pl new file mode 100755 index 00000000..681c0eac --- /dev/null +++ b/tools/pidl/tests/typelist.pl @@ -0,0 +1,93 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 56; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Typelist qw(hasType typeHasBody getType mapTypeName expandAlias + mapScalarType addType typeIs is_scalar scalar_is_reference + enum_type_fn bitmap_type_fn mapType); + +is("foo", expandAlias("foo")); +is("uint32", expandAlias("DWORD")); +is("int32", expandAlias("int")); +is("", expandAlias("")); +is("int32", expandAlias("int32")); + +is("uint32_t", mapScalarType("uint32")); +is("void", mapScalarType("void")); +is("uint64_t", mapScalarType("hyper")); +is("double", mapScalarType("double")); + +my $x = { TYPE => "ENUM", NAME => "foo", EXTRADATA => 1 }; +addType($x); +is_deeply($x, getType("foo")); +is(undef, getType("bloebla")); +is_deeply(getType({ TYPE => "STRUCT" }), { TYPE => "STRUCT" }); +is_deeply(getType({ TYPE => "ENUM", NAME => "foo" }), $x); +is_deeply(getType("uint16"), { + NAME => "uint16", + BASEFILE => "<builtin>", + TYPE => "TYPEDEF", + DATA => { NAME => "uint16", TYPE => "SCALAR" }}); + +is_deeply(getType("double"), { + NAME => "double", + BASEFILE => "<builtin>", + TYPE => "TYPEDEF", + DATA => { NAME => "double", TYPE => "SCALAR" }}); + +is(0, typeIs("someUnknownType", "ENUM")); +is(0, typeIs("foo", "ENUM")); +addType({NAME => "mytypedef", TYPE => "TYPEDEF", DATA => { TYPE => "ENUM" }}); +is(1, typeIs("mytypedef", "ENUM")); +is(0, typeIs("mytypedef", "BITMAP")); +is(1, typeIs({ TYPE => "ENUM"}, "ENUM")); +is(0, typeIs({ TYPE => "BITMAP"}, "ENUM")); +is(1, typeIs("uint32", "SCALAR")); +is(0, typeIs("uint32", "ENUM")); + +is(1, hasType("foo")); +is(0, hasType("nonexistent")); +is(0, hasType({TYPE => "ENUM", NAME => "someUnknownType"})); +is(1, hasType({TYPE => "ENUM", NAME => "foo"})); +is(1, hasType({TYPE => "ENUM"})); +is(1, hasType({TYPE => "STRUCT"})); + +is(1, is_scalar("uint32")); +is(0, is_scalar("nonexistent")); +is(1, is_scalar({TYPE => "ENUM"})); +is(0, is_scalar({TYPE => "STRUCT"})); +is(1, is_scalar({TYPE => "TYPEDEF", DATA => {TYPE => "ENUM" }})); +is(1, is_scalar("mytypedef")); + +is(1, scalar_is_reference("string")); +is(0, scalar_is_reference("uint32")); +is(0, scalar_is_reference({TYPE => "STRUCT", NAME => "echo_foobar"})); + +is("uint8", enum_type_fn({TYPE => "ENUM", PARENT=>{PROPERTIES => {enum8bit => 1}}})); +is("uint32", enum_type_fn({TYPE => "ENUM", PARENT=>{PROPERTIES => {v1_enum => 1}}})); +is("uint1632", enum_type_fn({TYPE => "ENUM", PARENT=>{PROPERTIES => {}}})); + +is("uint8", bitmap_type_fn({TYPE => "BITMAP", PROPERTIES => {bitmap8bit => 1}})); +is("uint16", bitmap_type_fn({TYPE => "BITMAP", PROPERTIES => {bitmap16bit => 1}})); +is("hyper", bitmap_type_fn({TYPE => "BITMAP", PROPERTIES => {bitmap64bit => 1}})); +is("uint32", bitmap_type_fn({TYPE => "BITMAP", PROPERTIES => {}})); + +is("enum foo", mapType({TYPE => "ENUM"}, "foo")); +is("union foo", mapType({TYPE => "UNION"}, "foo")); +is("struct foo", mapType({TYPE => "STRUCT"}, "foo")); +is("uint8_t", mapType({TYPE => "BITMAP", PROPERTIES => {bitmap8bit => 1}}, "foo")); +is("uint8_t", mapType({TYPE => "SCALAR"}, "uint8")); +is("uint32_t", mapType({TYPE => "TYPEDEF", DATA => {TYPE => "SCALAR"}}, "uint32")); + +is("void", mapTypeName(undef)); +is("uint32_t", mapTypeName("uint32")); +is("int32_t", mapTypeName("int")); + +ok(not typeHasBody({TYPE => "TYPEDEF", DATA => { TYPE => "STRUCT" }})); +ok(typeHasBody({TYPE => "TYPEDEF", DATA => { TYPE => "STRUCT", ELEMENTS => [] }})); diff --git a/tools/pidl/tests/util.pl b/tools/pidl/tests/util.pl new file mode 100755 index 00000000..cb77f34c --- /dev/null +++ b/tools/pidl/tests/util.pl @@ -0,0 +1,115 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +use strict; +use warnings; + +use Test::More tests => 72; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl qw(error); +use Parse::Pidl::Util; + +# has_property() +is(undef, has_property({}, "foo")); +is(undef, has_property({PROPERTIES => {}}, "foo")); +is("data", has_property({PROPERTIES => {foo => "data"}}, "foo")); +is(undef, has_property({PROPERTIES => {foo => undef}}, "foo")); + +# is_constant() +ok(is_constant("2")); +ok(is_constant("256")); +ok(is_constant("0x400")); +ok(is_constant("0x4BC")); +ok(not is_constant("0x4BGC")); +ok(not is_constant("str")); +ok(not is_constant("2 * expr")); + +# make_str() +is("\"bla\"", make_str("bla")); +is("\"bla\"", make_str("\"bla\"")); +is("\"\"bla\"\"", make_str("\"\"bla\"\"")); +is("\"bla\"\"", make_str("bla\"")); +is("\"foo\"bar\"", make_str("foo\"bar")); + +is("bla", unmake_str("\"bla\"")); +is("\"bla\"", unmake_str("\"\"bla\"\"")); + +# print_uuid() +is(undef, print_uuid("invalid")); +is("{0x12345778,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xac}}", + print_uuid("12345778-1234-abcd-ef00-0123456789ac")); +is("{0x12345778,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xac}}", + print_uuid("\"12345778-1234-abcd-ef00-0123456789ac\"")); + +# property_matches() +# missing property +ok(not property_matches({PROPERTIES => {}}, "x", "data")); +# data not matching +ok(not property_matches({PROPERTIES => {x => "bar"}}, "x", "data")); +# data matching exactly +ok(property_matches({PROPERTIES => {x => "data"}}, "x", "data")); +# regex matching +ok(property_matches({PROPERTIES => {x => "data"}}, "x", "^([dat]+)\$")); + +# ParseExpr() +is(undef, ParseExpr("", {}, undef)); +is("a", ParseExpr("a", {"b" => "2"}, undef)); +is("2", ParseExpr("a", {"a" => "2"}, undef)); +is("2 * 2", ParseExpr("a*a", {"a" => "2"}, undef)); +is("r->length + r->length", + ParseExpr("length+length", {"length" => "r->length"}, undef)); +is("2 / 2 * (r->length)", + ParseExpr("constant/constant*(len)", {"constant" => "2", + "len" => "r->length"}, undef)); +is("2 + 2 - r->length", + ParseExpr("constant+constant-len", {"constant" => "2", + "len" => "r->length"}, undef)); +is("*r->length", ParseExpr("*len", { "len" => "r->length"}, undef)); +is("**r->length", ParseExpr("**len", { "len" => "r->length"}, undef)); +is("r->length & 2", ParseExpr("len&2", { "len" => "r->length"}, undef)); +is("&r->length", ParseExpr("&len", { "len" => "r->length"}, undef)); +is("calc()", ParseExpr("calc()", { "foo" => "2"}, undef)); +is("calc(2 * 2)", ParseExpr("calc(foo * 2)", { "foo" => "2"}, undef)); +is("strlen(\"data\")", ParseExpr("strlen(foo)", { "foo" => "\"data\""}, undef)); +is("strlen(\"data\", 4)", ParseExpr("strlen(foo, 4)", { "foo" => "\"data\""}, undef)); +is("foo / bar", ParseExpr("foo / bar", { "bla" => "\"data\""}, undef)); +is("r->length % 2", ParseExpr("len%2", { "len" => "r->length"}, undef)); +is("r->length == 2", ParseExpr("len==2", { "len" => "r->length"}, undef)); +is("r->length != 2", ParseExpr("len!=2", { "len" => "r->length"}, undef)); +is("pr->length", ParseExpr("pr->length", { "p" => "r"}, undef)); +is("r->length", ParseExpr("p->length", { "p" => "r"}, undef)); +is("_foo / bla32", ParseExpr("_foo / bla32", { "bla" => "\"data\""}, undef)); +is("foo.bar.blah", ParseExpr("foo.blah", { "foo" => "foo.bar"}, undef)); +is("\"bla\"", ParseExpr("\"bla\"", {}, undef)); +is("1 << 2", ParseExpr("1 << 2", {}, undef)); +is("1 >> 2", ParseExpr("1 >> 2", {}, undef)); +is("0x200", ParseExpr("0x200", {}, undef)); +is("2?3:0", ParseExpr("2?3:0", {}, undef)); +is("~0", ParseExpr("~0", {}, undef)); +is("b->a->a", ParseExpr("a->a->a", {"a" => "b"}, undef)); +is("b.a.a", ParseExpr("a.a.a", {"a" => "b"}, undef)); + +test_errors("nofile:0: Parse error in `~' near `~'\n", sub { + is(undef, ParseExpr("~", {}, {FILE => "nofile", LINE => 0})); }); + +test_errors("nofile:0: Got pointer, expected integer\n", sub { + is(undef, ParseExprExt("foo", {}, {FILE => "nofile", LINE => 0}, + undef, sub { my $x = shift; + error({FILE => "nofile", LINE => 0}, + "Got pointer, expected integer"); + return undef; }))}); + +is("b.a.a", ParseExpr("b.a.a", {"a" => "b"}, undef)); +is("((rr_type) == NBT_QTYPE_NETBIOS)", ParseExpr("((rr_type)==NBT_QTYPE_NETBIOS)", {}, undef)); +is("talloc_check_name", ParseExpr("talloc_check_name", {}, undef)); +is("talloc_check_name()", ParseExpr("talloc_check_name()", {}, undef)); +is("talloc_check_name(ndr)", ParseExpr("talloc_check_name(ndr)", {}, undef)); +is("talloc_check_name(ndr, 1)", ParseExpr("talloc_check_name(ndr,1)", {}, undef)); +is("talloc_check_name(ndr, \"struct ndr_push\")", ParseExpr("talloc_check_name(ndr,\"struct ndr_push\")", {}, undef)); +is("((rr_type) == NBT_QTYPE_NETBIOS) && talloc_check_name(ndr, \"struct ndr_push\")", ParseExpr("((rr_type)==NBT_QTYPE_NETBIOS)&&talloc_check_name(ndr,\"struct ndr_push\")", {}, undef)); +is("(rdata).data.length", ParseExpr("(rdata).data.length", {}, undef)); +is("((rdata).data.length == 2)", ParseExpr("((rdata).data.length==2)", {}, undef)); +is("((rdata).data.length == 2)?0:rr_type", ParseExpr("((rdata).data.length==2)?0:rr_type", {}, undef)); +is("((((rr_type) == NBT_QTYPE_NETBIOS) && talloc_check_name(ndr, \"struct ndr_push\") && ((rdata).data.length == 2))?0:rr_type)", ParseExpr("((((rr_type)==NBT_QTYPE_NETBIOS)&&talloc_check_name(ndr,\"struct ndr_push\")&&((rdata).data.length==2))?0:rr_type)", {}, undef)); diff --git a/tools/pidl/tests/wireshark-conf.pl b/tools/pidl/tests/wireshark-conf.pl new file mode 100755 index 00000000..fff89f6f --- /dev/null +++ b/tools/pidl/tests/wireshark-conf.pl @@ -0,0 +1,205 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +# test parsing wireshark conformance files +use strict; +use warnings; + +use Test::More tests => 49; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use Parse::Pidl::Wireshark::Conformance qw(ReadConformanceFH valid_ft_type valid_base_type); + +sub parse_conf($) +{ + my $str = shift; + open(TMP, "+>", undef) or die("unable to open temp file"); + print TMP $str; + seek(TMP, 0, 0); + my $data = {}; + ReadConformanceFH(*TMP, $data, "nofile") or return undef; + close(TMP); + return $data; +} + +ok(parse_conf("\n"), undef); +ok(parse_conf(" \n"), undef); +ok(parse_conf("CODE START\nCODE END\n")); +test_warnings("nofile:1: Expecting CODE END\n", sub { is(parse_conf("CODE START\n"), undef); }); +ok(parse_conf("#foobar\n"), undef); +test_warnings("nofile:1: Unknown command `foobar'\n", + sub { ok(parse_conf("foobar\n"), undef); }); + +test_warnings("nofile:1: incomplete HF_RENAME command\n", + sub { parse_conf("HF_RENAME\n"); }); + +is_deeply(parse_conf("HF_RENAME foo bar\n")->{hf_renames}->{foo}, + { OLDNAME => "foo", NEWNAME => "bar", POS => {FILE => "nofile", LINE => 1}, USED => 0}); + +is_deeply(parse_conf("NOEMIT\n"), { "noemit_dissector" => 1 }); +is_deeply(parse_conf("NOEMIT foo\n"), { "noemit" => { "foo" => 1 } }); + +test_warnings("nofile:1: incomplete MANUAL command\n", + sub { parse_conf("MANUAL\n"); } ); + +is_deeply(parse_conf("MANUAL foo\n"), { manual => {foo => 1}}); + +test_errors("nofile:1: incomplete INCLUDE command\n", + sub { parse_conf("INCLUDE\n"); } ); + +test_warnings("nofile:1: incomplete FIELD_DESCRIPTION command\n", + sub { parse_conf("FIELD_DESCRIPTION foo\n"); }); + +is_deeply(parse_conf("FIELD_DESCRIPTION foo \"my description\"\n"), + { fielddescription => { foo => { DESCRIPTION => "\"my description\"", POS => { FILE => "nofile", LINE => 1}, USED => 0 }}}); + +is_deeply(parse_conf("FIELD_DESCRIPTION foo my description\n"), + { fielddescription => { foo => { DESCRIPTION => "my", POS => { FILE => "nofile", LINE => 1}, USED => 0 }}}); + +is_deeply(parse_conf("CODE START\ndata\nCODE END\n"), { override => "data\n" }); +is_deeply(parse_conf("CODE START\ndata\nmore data\nCODE END\n"), { override => "data\nmore data\n" }); +test_warnings("nofile:1: CODE END outside CODE section\n", + sub { parse_conf("CODE END\n"); } ); + +is_deeply(parse_conf("TYPE winreg_String dissect_myminregstring(); FT_STRING BASE_DEC 0 0 2\n"), { types => { winreg_String => { + NAME => "winreg_String", + POS => { FILE => "nofile", LINE => 1 }, + USED => 0, + DISSECTOR_NAME => "dissect_myminregstring();", + FT_TYPE => "FT_STRING", + BASE_TYPE => "BASE_DEC", + MASK => 0, + VALSSTRING => 0, + ALIGNMENT => 2}}}); + +ok(valid_ft_type("FT_UINT32")); +ok(not valid_ft_type("BLA")); +ok(not valid_ft_type("ft_uint32")); +ok(valid_ft_type("FT_BLA")); + +ok(valid_base_type("BASE_DEC")); +ok(valid_base_type("BASE_HEX")); +ok(not valid_base_type("base_dec")); +ok(not valid_base_type("BLA")); +ok(not valid_base_type("BASEDEC")); + +test_errors("nofile:1: incomplete TYPE command\n", + sub { parse_conf("TYPE mytype dissector\n"); }); + +test_warnings("nofile:1: dissector name does not contain `dissect'\n", + sub { parse_conf("TYPE winreg_String myminregstring; FT_STRING BASE_DEC 0 0 2\n"); }); + +test_warnings("nofile:1: invalid FT_TYPE `BLA'\n", + sub { parse_conf("TYPE winreg_String dissect_myminregstring; BLA BASE_DEC 0 0 2\n"); }); + +test_warnings("nofile:1: invalid BASE_TYPE `BLOE'\n", + sub { parse_conf("TYPE winreg_String dissect_myminregstring; FT_UINT32 BLOE 0 0 2\n"); }); + +is_deeply(parse_conf("TFS hf_bla \"True string\" \"False String\"\n"), + { tfs => { hf_bla => { + TRUE_STRING => "\"True string\"", + FALSE_STRING => "\"False String\"" } } }); + +test_errors("nofile:1: incomplete TFS command\n", + sub { parse_conf("TFS hf_bla \"Trues\""); } ); + +test_errors("nofile:1: incomplete PARAM_VALUE command\n", + sub { parse_conf("PARAM_VALUE\n"); }); + +is_deeply(parse_conf("PARAM_VALUE Life 42\n"), + { dissectorparams => { + Life => { + DISSECTOR => "Life", + POS => { FILE => "nofile", LINE => 1 }, + PARAM => 42, + USED => 0 + } + } + }); + +is_deeply(parse_conf("STRIP_PREFIX bla_\n"), + { strip_prefixes => [ "bla_" ] }); + +is_deeply(parse_conf("STRIP_PREFIX bla_\nSTRIP_PREFIX bloe\n"), + { strip_prefixes => [ "bla_", "bloe" ] }); + +is_deeply(parse_conf("PROTOCOL atsvc \"Scheduling jobs on remote machines\" \"at\" \"atsvc\"\n"), + { protocols => { + atsvc => { + LONGNAME => "\"Scheduling jobs on remote machines\"", + SHORTNAME => "\"at\"", + FILTERNAME => "\"atsvc\"" + } + } + } +); + +is_deeply(parse_conf("IMPORT bla\n"), { + imports => { + bla => { + NAME => "bla", + DATA => "", + USED => 0, + POS => { FILE => "nofile", LINE => 1 } + } + } + } +); + +is_deeply(parse_conf("IMPORT bla fn1 fn2 fn3\n"), { + imports => { + bla => { + NAME => "bla", + DATA => "fn1 fn2 fn3", + USED => 0, + POS => { FILE => "nofile", LINE => 1 } + } + } + } +); + +test_errors("nofile:1: no dissectorname specified\n", + sub { parse_conf("IMPORT\n"); } ); + +test_errors("nofile:1: incomplete HF_FIELD command\n", + sub { parse_conf("HF_FIELD hf_idx\n"); }); + +test_errors("nofile:1: incomplete ETT_FIELD command\n", + sub { parse_conf("ETT_FIELD\n"); }); + +is_deeply(parse_conf("TYPE winreg_String dissect_myminregstring(); FT_STRING BASE_DEC 0 0 0 2\n"), { + types => { + winreg_String => { + NAME => "winreg_String", + POS => { FILE => "nofile", LINE => 1 }, + USED => 0, + DISSECTOR_NAME => "dissect_myminregstring();", + FT_TYPE => "FT_STRING", + BASE_TYPE => "BASE_DEC", + MASK => 0, + VALSSTRING => 0, + ALIGNMENT => 0 + } + } + } +); + + +is_deeply(parse_conf("TYPE winreg_String \"offset = dissect_myminregstring(\@HF\@);\" FT_STRING BASE_DEC 0 0 0 2\n"), { + types => { + winreg_String => { + NAME => "winreg_String", + POS => { FILE => "nofile", LINE => 1 }, + USED => 0, + DISSECTOR_NAME => "offset = dissect_myminregstring(\@HF\@);", + FT_TYPE => "FT_STRING", + BASE_TYPE => "BASE_DEC", + MASK => 0, + VALSSTRING => 0, + ALIGNMENT => 0 + } + } + } +); diff --git a/tools/pidl/tests/wireshark-ndr.pl b/tools/pidl/tests/wireshark-ndr.pl new file mode 100755 index 00000000..229315b0 --- /dev/null +++ b/tools/pidl/tests/wireshark-ndr.pl @@ -0,0 +1,274 @@ +#!/usr/bin/perl +# (C) 2007 Jelmer Vernooij <jelmer@samba.org> +# Published under the GNU General Public License +# test parsing wireshark conformance files +use strict; +use warnings; + +use Test::More tests => 40; +use FindBin qw($RealBin); +use lib "$RealBin"; +use Util; +use Parse::Pidl::Util qw(MyDumper); +use strict; +use Parse::Pidl::Wireshark::NDR qw(field2name %res PrintIdl StripPrefixes RegisterInterfaceHandoff register_hf_field ProcessImport ProcessInclude find_type DumpEttList DumpEttDeclaration DumpHfList DumpHfDeclaration DumpFunctionTable register_type register_ett); + +is("Access Mask", field2name("access_mask")); +is("AccessMask", field2name("AccessMask")); + +my $x = new Parse::Pidl::Wireshark::NDR(); +$x->PrintIdl("foo\nbar\n"); +is("/* IDL: foo */ +/* IDL: bar */ + +", $x->{res}->{code}); + +is("bla_foo", StripPrefixes("bla_foo", [])); +is("foo", StripPrefixes("bla_foo", ["bla"])); +is("foo_bla", StripPrefixes("foo_bla", ["bla"])); + +$x = new Parse::Pidl::Wireshark::NDR(); +$x->RegisterInterfaceHandoff({}); +is($x->{res}->{code}, ""); +ok(not defined($x->{hf_used}->{hf_bla_opnum})); + +$x = new Parse::Pidl::Wireshark::NDR(); +$x->{res}->{code} = ""; +$x->RegisterInterfaceHandoff({UUID => "uuid", NAME => "bla"}); +is($x->{res}->{code}, 'void proto_reg_handoff_dcerpc_bla(void) +{ + dcerpc_init_uuid(proto_dcerpc_bla, ett_dcerpc_bla, + &uuid_dcerpc_bla, ver_dcerpc_bla, + bla_dissectors, hf_bla_opnum); +} +'); +is($x->{hf_used}->{hf_bla_opnum}, 1); + +$x->{conformance} = {}; +is("hf_bla_idx", + $x->register_hf_field("hf_bla_idx", "bla", "my.filter", "FT_UINT32", "BASE_HEX", "NULL", 0xF, undef)); +is_deeply($x->{conformance}, { + header_fields => { + "hf_bla_idx" => { + INDEX => "hf_bla_idx", + NAME => "bla", + FILTER => "my.filter", + BASE_TYPE => "BASE_HEX", + FT_TYPE => "FT_UINT32", + VALSSTRING => "NULL", + BLURB => undef, + MASK => 0xF + } + }, + hf_renames => {}, + fielddescription => {} +}); + +$x->{conformance} = { fielddescription => { hf_bla_idx => { DESCRIPTION => "Some Description" }}}; +is("hf_bla_idx", + $x->register_hf_field("hf_bla_idx", "bla", "my.filter", "FT_UINT32", "BASE_HEX", "NULL", 0xF, undef)); +is_deeply($x->{conformance}, { + fielddescription => { + hf_bla_idx => { + DESCRIPTION => "Some Description", + USED => 1 + } + }, + header_fields => { + "hf_bla_idx" => { + INDEX => "hf_bla_idx", + NAME => "bla", + FILTER => "my.filter", + BASE_TYPE => "BASE_HEX", + FT_TYPE => "FT_UINT32", + VALSSTRING => "NULL", + BLURB => "Some Description", + MASK => 0xF + } + }, + hf_renames => {}, +}); + +$x->{conformance} = { fielddescription => { hf_bla_idx => { DESCRIPTION => "Some Description" }}}; +is("hf_bla_idx", + $x->register_hf_field("hf_bla_idx", "bla", "my.filter", "FT_UINT32", "BASE_HEX", "NULL", 0xF, + "Actual Description")); +is_deeply($x->{conformance}, { + fielddescription => { + hf_bla_idx => { DESCRIPTION => "Some Description" } + }, + header_fields => { + "hf_bla_idx" => { + INDEX => "hf_bla_idx", + NAME => "bla", + FILTER => "my.filter", + BASE_TYPE => "BASE_HEX", + FT_TYPE => "FT_UINT32", + VALSSTRING => "NULL", + BLURB => "Actual Description", + MASK => 0xF + } + }, + hf_renames => {}, +}); + + + +$x->{conformance} = { hf_renames => { "hf_bla_idx" => { NEWNAME => "hf_bloe_idx" } } }; +$x->register_hf_field("hf_bla_idx", "bla", "my.filter", "FT_UINT32", "BASE_HEX", "NULL", 0xF, undef); +is_deeply($x->{conformance}, { + hf_renames => { hf_bla_idx => { USED => 1, NEWNAME => "hf_bloe_idx" } } }); + +$x->{hf_used} = { hf_bla => 1 }; +test_warnings("", sub { + $x->CheckUsed({ header_fields => { foo => { INDEX => "hf_bla" }}})}); + +$x->{hf_used} = { }; +test_warnings("hf field `hf_bla' not used\n", sub { + $x->CheckUsed({ header_fields => { foo => { INDEX => "hf_bla" }}})}); + +test_warnings("hf field `hf_id' not used\n", + sub { $x->CheckUsed({ + hf_renames => { + hf_id => { + OLDNAME => "hf_id", + NEWNAME => "hf_newid", + USED => 0 + } + } +}); } ); + +test_warnings("dissector param never used\n", + sub { $x->CheckUsed({ + dissectorparams => { + dissect_foo => { + PARAM => 42, + USED => 0 + } + } +}); } ); + +test_warnings("description never used\n", + sub { $x->CheckUsed({ + fielddescription => { + hf_bla => { + USED => 0 + } + } +}); } ); + +test_warnings("import never used\n", + sub { $x->CheckUsed({ + imports => { + bla => { + USED => 0 + } + } +}); } ); + +test_warnings("nofile:1: type never used\n", + sub { $x->CheckUsed({ + types => { + bla => { + USED => 0, + POS => { FILE => "nofile", LINE => 1 } + } + } +}); } ); + +test_warnings("True/False description never used\n", + sub { $x->CheckUsed({ + tfs => { + hf_bloe => { + USED => 0 + } + } +}); } ); + +$x = new Parse::Pidl::Wireshark::NDR(); +$x->ProcessImport("security", "bla"); +is($x->{res}->{hdr}, "#include \"packet-dcerpc-bla.h\"\n\n"); + +$x = new Parse::Pidl::Wireshark::NDR(); +$x->ProcessImport("\"bla.idl\"", "\"foo.idl\""); +is($x->{res}->{hdr}, "#include \"packet-dcerpc-bla.h\"\n" . + "#include \"packet-dcerpc-foo.h\"\n\n"); + +$x = new Parse::Pidl::Wireshark::NDR(); +$x->ProcessInclude("foo.h", "bla.h", "bar.h"); +is($x->{res}->{hdr}, "#include \"foo.h\"\n" . + "#include \"bla.h\"\n" . + "#include \"bar.h\"\n\n"); + +$x->{conformance} = {types => { bla => "brainslug" } }; +is("brainslug", $x->find_type("bla")); + +is(DumpEttList(["ett_t1", "ett_bla"]), + "\tstatic gint *ett[] = {\n" . + "\t\t&ett_t1,\n" . + "\t\t&ett_bla,\n" . + "\t};\n"); + +is(DumpEttList(), "\tstatic gint *ett[] = {\n\t};\n"); +is(DumpEttList(["bla"]), "\tstatic gint *ett[] = {\n\t\t&bla,\n\t};\n"); + +is(DumpEttDeclaration(["void", "zoid"]), + "\n/* Ett declarations */\n" . + "static gint void = -1;\n" . + "static gint zoid = -1;\n" . + "\n"); + +is(DumpEttDeclaration(), "\n/* Ett declarations */\n\n"); + +$x->{conformance} = { + header_fields => { + hf_bla => { INDEX => "hf_bla", NAME => "Bla", FILTER => "bla.field", FT_TYPE => "FT_UINT32", BASE_TYPE => "BASE_DEC", VALSSTRING => "NULL", MASK => 0xFF, BLURB => "NULL" } + } +}; + +is($x->DumpHfList(), "\tstatic hf_register_info hf[] = { + { &hf_bla, + { \"Bla\", \"bla.field\", FT_UINT32, BASE_DEC, NULL, 255, \"NULL\", HFILL }}, + }; +"); + +is($x->DumpHfDeclaration(), " +/* Header field declarations */ +static gint hf_bla = -1; + +"); + +is(DumpFunctionTable({ + NAME => "someif", + FUNCTIONS => [ { NAME => "fn1", OPNUM => 3 }, { NAME => "someif_fn2", OPNUM => 2 } ] }), +'static dcerpc_sub_dissector someif_dissectors[] = { + { 3, "fn1", + someif_dissect_fn1_request, someif_dissect_fn1_response}, + { 2, "fn2", + someif_dissect_fn2_request, someif_dissect_fn2_response}, + { 0, NULL, NULL, NULL } +}; +'); + +$x->{conformance} = {}; +$x->register_type("bla_type", "dissect_bla", "FT_UINT32", "BASE_HEX", 0xFF, "NULL", 4); +is_deeply($x->{conformance}, { + types => { + bla_type => { + NAME => "bla_type", + DISSECTOR_NAME => "dissect_bla", + FT_TYPE => "FT_UINT32", + BASE_TYPE => "BASE_HEX", + MASK => 255, + VALSSTRING => "NULL", + ALIGNMENT => 4 + } + } + } +); + +$x->{ett} = []; +$x->register_ett("name"); +is_deeply($x->{ett}, ["name"]); +$x->register_ett("leela"); +is_deeply($x->{ett}, ["name", "leela"]); |