summaryrefslogtreecommitdiff
path: root/pidl/tests
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2008-09-17 17:12:27 +0200
committerJelmer Vernooij <jelmer@samba.org>2008-09-17 17:12:27 +0200
commit79190992b3820cd028c961c48bdea9b35baf13c9 (patch)
tree0de851669d98f04e947d20349d96723462cd1eb0 /pidl/tests
parent3b5330e9094ecf0be94d3dbea744de140ec55e19 (diff)
downloadsamba-79190992b3820cd028c961c48bdea9b35baf13c9.tar.gz
samba-79190992b3820cd028c961c48bdea9b35baf13c9.tar.bz2
samba-79190992b3820cd028c961c48bdea9b35baf13c9.zip
Move pidl to top-level directory.
Diffstat (limited to 'pidl/tests')
-rw-r--r--pidl/tests/Util.pm179
-rwxr-xr-xpidl/tests/cutil.pl21
-rwxr-xr-xpidl/tests/dump.pl15
-rwxr-xr-xpidl/tests/header.pl108
-rwxr-xr-xpidl/tests/ndr.pl558
-rwxr-xr-xpidl/tests/ndr_align.pl143
-rwxr-xr-xpidl/tests/ndr_alloc.pl118
-rwxr-xr-xpidl/tests/ndr_array.pl37
-rwxr-xr-xpidl/tests/ndr_compat.pl21
-rwxr-xr-xpidl/tests/ndr_deprecations.pl26
-rwxr-xr-xpidl/tests/ndr_fullptr.pl44
-rwxr-xr-xpidl/tests/ndr_refptr.pl526
-rwxr-xr-xpidl/tests/ndr_represent.pl71
-rwxr-xr-xpidl/tests/ndr_simple.pl28
-rwxr-xr-xpidl/tests/ndr_string.pl90
-rwxr-xr-xpidl/tests/ndr_tagtype.pl66
-rwxr-xr-xpidl/tests/parse_idl.pl164
-rwxr-xr-xpidl/tests/samba-ejs.pl37
-rwxr-xr-xpidl/tests/samba-ndr.pl296
-rwxr-xr-xpidl/tests/samba3-cli.pl126
-rw-r--r--pidl/tests/samba3-srv.pl18
-rwxr-xr-xpidl/tests/tdr.pl49
-rwxr-xr-xpidl/tests/test_util.pl21
-rwxr-xr-xpidl/tests/typelist.pl85
-rwxr-xr-xpidl/tests/util.pl115
-rwxr-xr-xpidl/tests/wireshark-conf.pl205
-rwxr-xr-xpidl/tests/wireshark-ndr.pl274
27 files changed, 3441 insertions, 0 deletions
diff --git a/pidl/tests/Util.pm b/pidl/tests/Util.pm
new file mode 100644
index 0000000000..4ad216a6a1
--- /dev/null
+++ b/pidl/tests/Util.pm
@@ -0,0 +1,179 @@
+# 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;
+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: {
+
+ skip "no samba environment available, skipping compilation", 3
+ if (system("pkg-config --exists ndr") != 0);
+
+ my $main = "
+#define uint_t unsigned int
+#define _GNU_SOURCE
+#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 $flags = `pkg-config --libs --cflags ndr`;
+
+ 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/pidl/tests/cutil.pl b/pidl/tests/cutil.pl
new file mode 100755
index 0000000000..78c8bce45e
--- /dev/null
+++ b/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/pidl/tests/dump.pl b/pidl/tests/dump.pl
new file mode 100755
index 0000000000..d1a56f0973
--- /dev/null
+++ b/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/pidl/tests/header.pl b/pidl/tests/header.pl
new file mode 100755
index 0000000000..db59484444
--- /dev/null
+++ b/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/pidl/tests/ndr.pl b/pidl/tests/ndr.pl
new file mode 100755
index 0000000000..504b7ec8de
--- /dev/null
+++ b/pidl/tests/ndr.pl
@@ -0,0 +1,558 @@
+#!/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 => 46;
+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"), [
+ {
+ 'IS_DEFERRED' => 0,
+ 'LEVEL_INDEX' => 0,
+ 'DATA_TYPE' => 'uint8',
+ 'CONTAINS_DEFERRED' => 0,
+ 'TYPE' => 'DATA',
+ 'IS_SURROUNDING' => 0,
+ }
+]);
+
+my $ne = ParseElement($e, "unique");
+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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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"), [
+ {
+ 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);
+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);
+is($ne->{REPRESENTATION_TYPE}, "uint8");
+
+is(align_type("hyper"), 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"), $t);
+
+$t = {
+ TYPE => "UNION",
+ NAME => "foo",
+ SWITCH_TYPE => "uint32",
+ ELEMENTS => undef,
+ PROPERTIES => undef,
+ HAS_DEFAULT => 0,
+ ORIGINAL => {
+ TYPE => "UNION",
+ NAME => "foo"
+ }
+};
+is_deeply(ParseType($t->{ORIGINAL}, "ref"), $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")->{ELEMENTS}));
+# Make sure the elements for a bitmap without body aren't filled in
+ok(not defined(ParseType({TYPE => "BITMAP", NAME => "foo" }, "ref")->{ELEMENTS}));
+# Make sure the elements for a union without body aren't filled in
+ok(not defined(ParseType({TYPE => "UNION", NAME => "foo" }, "ref")->{ELEMENTS}));
diff --git a/pidl/tests/ndr_align.pl b/pidl/tests/ndr_align.pl
new file mode 100755
index 0000000000..cc089eaa1f
--- /dev/null
+++ b/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/pidl/tests/ndr_alloc.pl b/pidl/tests/ndr_alloc.pl
new file mode 100755
index 0000000000..399fbd21d6
--- /dev/null
+++ b/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/pidl/tests/ndr_array.pl b/pidl/tests/ndr_array.pl
new file mode 100755
index 0000000000..2a6b5bbd57
--- /dev/null
+++ b/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/pidl/tests/ndr_compat.pl b/pidl/tests/ndr_compat.pl
new file mode 100755
index 0000000000..355e7f6732
--- /dev/null
+++ b/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/pidl/tests/ndr_deprecations.pl b/pidl/tests/ndr_deprecations.pl
new file mode 100755
index 0000000000..86828e5982
--- /dev/null
+++ b/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/pidl/tests/ndr_fullptr.pl b/pidl/tests/ndr_fullptr.pl
new file mode 100755
index 0000000000..cc6fca7ab3
--- /dev/null
+++ b/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/pidl/tests/ndr_refptr.pl b/pidl/tests/ndr_refptr.pl
new file mode 100755
index 0000000000..d5dd83957a
--- /dev/null
+++ b/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/pidl/tests/ndr_represent.pl b/pidl/tests/ndr_represent.pl
new file mode 100755
index 0000000000..2d65fb92b0
--- /dev/null
+++ b/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/pidl/tests/ndr_simple.pl b/pidl/tests/ndr_simple.pl
new file mode 100755
index 0000000000..15e07d5693
--- /dev/null
+++ b/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/pidl/tests/ndr_string.pl b/pidl/tests/ndr_string.pl
new file mode 100755
index 0000000000..2f2d941665
--- /dev/null
+++ b/pidl/tests/ndr_string.pl
@@ -0,0 +1,90 @@
+#!/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 => 3 * 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,
+ smb_iconv_convenience_init(NULL, "ASCII", "UTF8", true));
+ 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,
+ smb_iconv_convenience_init(NULL, "ASCII", "UTF8", true));
+ 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;
+');
+
+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,
+ smb_iconv_convenience_init(NULL, "ASCII", "UTF8", true));
+ 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/pidl/tests/ndr_tagtype.pl b/pidl/tests/ndr_tagtype.pl
new file mode 100755
index 0000000000..3f9b717bfe
--- /dev/null
+++ b/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/pidl/tests/parse_idl.pl b/pidl/tests/parse_idl.pl
new file mode 100755
index 0000000000..9d43ddccc7
--- /dev/null
+++ b/pidl/tests/parse_idl.pl
@@ -0,0 +1,164 @@
+#!/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,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'NAME' => 'x', 'TYPE' => 'STRUCT', ELEMENTS => [] } ],
+ 'TYPE' => 'INTERFACE', 'LINE' => 0 } ]);
+
+$x = Parse::Pidl::IDL::parse_string("interface foo { struct x; }", "<foo>");
+is_deeply($x,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'NAME' => 'x', 'TYPE' => 'STRUCT' } ],
+ 'TYPE' => 'INTERFACE', 'LINE' => 0 } ]);
+
+$x = Parse::Pidl::IDL::parse_string("cpp_quote(\"foobar\")", "<quote>");
+is_deeply($x,
+ [ { 'FILE' => '<quote>', 'DATA' => '"foobar"',
+ 'TYPE' => 'CPP_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,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'FILE' => '<foo>', 'LINE' => 0, 'NAME' => 'y', 'TYPE' => 'TYPEDEF', DATA => {
+ TYPE => 'STRUCT', NAME => 'x' } } ],
+ 'TYPE' => 'INTERFACE', '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,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'FILE' => '<foo>', 'LINE' => 0, 'NAME' => 'y', 'TYPE' => 'TYPEDEF', DATA => { TYPE => 'STRUCT', ELEMENTS => [] } } ],
+ 'TYPE' => 'INTERFACE', '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,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'FILE' => '<foo>', 'LINE' => 0, 'NAME' => 'y', 'TYPE' => 'TYPEDEF', DATA => { TYPE => 'BITMAP', NAME => 'x' } } ],
+ 'TYPE' => 'INTERFACE', '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,
+ [ { 'FILE' => '<foo>', 'NAME' => 'foo', 'DATA' => [
+ { 'FILE' => '<foo>', 'LINE' => 0, 'NAME' => 'y', 'TYPE' => 'TYPEDEF', DATA => { TYPE => 'UNION', NAME => 'x' } } ],
+ 'TYPE' => 'INTERFACE', 'LINE' => 0 } ]);
diff --git a/pidl/tests/samba-ejs.pl b/pidl/tests/samba-ejs.pl
new file mode 100755
index 0000000000..094d37a103
--- /dev/null
+++ b/pidl/tests/samba-ejs.pl
@@ -0,0 +1,37 @@
+#!/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 => 10;
+use FindBin qw($RealBin);
+use lib "$RealBin";
+use Util;
+use Parse::Pidl::Util qw(MyDumper);
+use Parse::Pidl::Samba4::EJS qw(check_null_pointer
+ fn_declare TypeFunctionName);
+
+my $ejs = new Parse::Pidl::Samba4::EJS();
+
+$ejs->check_null_pointer("bla");
+is($ejs->{res}, "");
+
+$ejs = new Parse::Pidl::Samba4::EJS();
+$ejs->check_null_pointer("*bla");
+is($ejs->{res}, "if (bla == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;\n");
+
+$ejs = new Parse::Pidl::Samba4::EJS();
+$ejs->fn_declare({ PROPERTIES => { public => 1 } }, "myproto(int x)");
+is($ejs->{res}, "_PUBLIC_ myproto(int x)\n");
+is($ejs->{res_hdr}, "myproto(int x);\n");
+
+$ejs = new Parse::Pidl::Samba4::EJS();
+$ejs->fn_declare({ PROPERTIES => {} }, "mybla(int foo)");
+is($ejs->{res}, "static mybla(int foo)\n");
+is($ejs->{res_hdr}, "");
+
+is(TypeFunctionName("ejs_pull", "uint32"), "ejs_pull_uint32");
+is(TypeFunctionName("ejs_pull", {TYPE => "ENUM", NAME => "bar"}), "ejs_pull_ENUM_bar");
+is(TypeFunctionName("ejs_pull", {TYPE => "TYPEDEF", NAME => "bar", DATA => undef}), "ejs_pull_bar");
+is(TypeFunctionName("ejs_push", {TYPE => "STRUCT", NAME => "bar"}), "ejs_push_STRUCT_bar");
diff --git a/pidl/tests/samba-ndr.pl b/pidl/tests/samba-ndr.pl
new file mode 100755
index 0000000000..cdfe0514f1
--- /dev/null
+++ b/pidl/tests/samba-ndr.pl
@@ -0,0 +1,296 @@
+#!/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}, "if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_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}, "if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_uint32(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));
+}
+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/pidl/tests/samba3-cli.pl b/pidl/tests/samba3-cli.pl
new file mode 100755
index 0000000000..d762954159
--- /dev/null
+++ b/pidl/tests/samba3-cli.pl
@@ -0,0 +1,126 @@
+#!/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 => 9;
+use FindBin qw($RealBin);
+use lib "$RealBin";
+use Util;
+use Parse::Pidl::Util qw(MyDumper);
+use Parse::Pidl::Samba3::ClientNDR qw(ParseFunction ParseOutputArgument);
+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},
+"NTSTATUS rpccli_bar(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx)
+{
+\tstruct bar r;
+\tNTSTATUS status;
+
+\t/* In parameters */
+
+\tif (DEBUGLEVEL >= 10) {
+\t\tNDR_PRINT_IN_DEBUG(bar, &r);
+\t}
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_foo,
+ NDR_BAR,
+ &r);
+
+\tif (!NT_STATUS_IS_OK(status)) {
+\t\treturn status;
+\t}
+
+\tif (DEBUGLEVEL >= 10) {
+\t\tNDR_PRINT_OUT_DEBUG(bar, &r);
+\t}
+
+\tif (NT_STATUS_IS_ERR(status)) {
+\t\treturn status;
+\t}
+
+\t/* Return variables */
+
+\t/* Return result */
+\treturn NT_STATUS_OK;
+}
+
+");
+
+$x = new Parse::Pidl::Samba3::ClientNDR();
+
+$fn = { NAME => "bar", ELEMENTS => [ ], RETURN_TYPE => "WERROR" };
+$x->ParseFunction("foo", $fn);
+is($x->{res},
+"NTSTATUS rpccli_bar(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ WERROR *werror)
+{
+\tstruct bar r;
+\tNTSTATUS status;
+
+\t/* In parameters */
+
+\tif (DEBUGLEVEL >= 10) {
+\t\tNDR_PRINT_IN_DEBUG(bar, &r);
+\t}
+
+ status = cli_do_rpc_ndr(cli,
+ mem_ctx,
+ &ndr_table_foo,
+ NDR_BAR,
+ &r);
+
+\tif (!NT_STATUS_IS_OK(status)) {
+\t\treturn status;
+\t}
+
+\tif (DEBUGLEVEL >= 10) {
+\t\tNDR_PRINT_OUT_DEBUG(bar, &r);
+\t}
+
+\tif (NT_STATUS_IS_ERR(status)) {
+\t\treturn status;
+\t}
+
+\t/* Return variables */
+
+\t/* Return result */
+\tif (werror) {
+\t\t*werror = r.out.result;
+\t}
+
+\treturn werror_to_ntstatus(r.out.result);
+}
+
+");
+
+$x = new Parse::Pidl::Samba3::ClientNDR();
+
+$fn = { NAME => "bar", ELEMENTS => [ ], RETURN_TYPE => "WERROR" };
+my $e = { NAME => "foo", ORIGINAL => { FILE => "f", LINE => -1 },
+ LEVELS => [ { TYPE => "ARRAY", SIZE_IS => "mysize" }, { TYPE => "DATA", DATA_TYPE => "int" } ]};
+
+$x->ParseOutputArgument($fn, $e);
+is($x->{res}, "memcpy(foo, r.out.foo, mysize * sizeof(*foo));\n");
diff --git a/pidl/tests/samba3-srv.pl b/pidl/tests/samba3-srv.pl
new file mode 100644
index 0000000000..d1e2bc9545
--- /dev/null
+++ b/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/pidl/tests/tdr.pl b/pidl/tests/tdr.pl
new file mode 100755
index 0000000000..d6cd7a03d4
--- /dev/null
+++ b/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/pidl/tests/test_util.pl b/pidl/tests/test_util.pl
new file mode 100755
index 0000000000..2d59f6283b
--- /dev/null
+++ b/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/pidl/tests/typelist.pl b/pidl/tests/typelist.pl
new file mode 100755
index 0000000000..54f4d34586
--- /dev/null
+++ b/pidl/tests/typelist.pl
@@ -0,0 +1,85 @@
+#!/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 => 54;
+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"));
+
+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",
+ TYPE => "TYPEDEF",
+ DATA => { NAME => "uint16", 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("nonexistant"));
+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("nonexistant"));
+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("uint16", 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/pidl/tests/util.pl b/pidl/tests/util.pl
new file mode 100755
index 0000000000..cb77f34c51
--- /dev/null
+++ b/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/pidl/tests/wireshark-conf.pl b/pidl/tests/wireshark-conf.pl
new file mode 100755
index 0000000000..9da5c7d1ed
--- /dev/null
+++ b/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: Unknown command `CODE'\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/pidl/tests/wireshark-ndr.pl b/pidl/tests/wireshark-ndr.pl
new file mode 100755
index 0000000000..8c2cd47584
--- /dev/null
+++ b/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"]);