1#!/usr/bin/perl 2# (C) 2007 Jelmer Vernooij <jelmer@samba.org> 3# Published under the GNU General Public License 4use strict; 5use warnings; 6 7use Test::More tests => 31; 8use FindBin qw($RealBin); 9use lib "$RealBin"; 10use Util; 11use strict; 12use Parse::Pidl::Util qw(MyDumper); 13use Parse::Pidl::Samba4::NDR::Parser qw(check_null_pointer 14 NeededFunction NeededElement NeededType 15 NeededInterface TypeFunctionName ParseElementPrint); 16 17my $output; 18sub print_fn($) { my $x = shift; $output.=$x; } 19 20# Test case 1: Simple unique pointer dereference 21 22$output = ""; 23my $fn = check_null_pointer({ 24 PARENT => { 25 ELEMENTS => [ 26 { 27 NAME => "bla", 28 LEVELS => [ 29 { TYPE => "POINTER", 30 POINTER_INDEX => 0, 31 POINTER_TYPE => "unique" }, 32 { TYPE => "DATA" } 33 ], 34 }, 35 ] 36 } 37}, { bla => "r->in.bla" }, \&print_fn, "return;"); 38 39 40test_warnings("", sub { $fn->("r->in.bla"); }); 41 42is($output, "if (r->in.bla == NULL) return;"); 43 44# Test case 2: Simple ref pointer dereference 45 46$output = ""; 47$fn = check_null_pointer({ 48 PARENT => { 49 ELEMENTS => [ 50 { 51 NAME => "bla", 52 LEVELS => [ 53 { TYPE => "POINTER", 54 POINTER_INDEX => 0, 55 POINTER_TYPE => "ref" }, 56 { TYPE => "DATA" } 57 ], 58 }, 59 ] 60 } 61}, { bla => "r->in.bla" }, \&print_fn, undef); 62 63test_warnings("", sub { $fn->("r->in.bla"); }); 64 65is($output, ""); 66 67# Test case 3: Illegal dereference 68 69$output = ""; 70$fn = check_null_pointer({ 71 FILE => "nofile", 72 LINE => 1, 73 PARENT => { 74 ELEMENTS => [ 75 { 76 NAME => "bla", 77 LEVELS => [ 78 { TYPE => "DATA" } 79 ], 80 }, 81 ] 82 } 83}, { bla => "r->in.bla" }, \&print_fn, undef); 84 85test_warnings("nofile:1: too much dereferences for `bla'\n", 86 sub { $fn->("r->in.bla"); }); 87 88is($output, ""); 89 90# Test case 4: Double pointer dereference 91 92$output = ""; 93$fn = check_null_pointer({ 94 PARENT => { 95 ELEMENTS => [ 96 { 97 NAME => "bla", 98 LEVELS => [ 99 { TYPE => "POINTER", 100 POINTER_INDEX => 0, 101 POINTER_TYPE => "unique" }, 102 { TYPE => "POINTER", 103 POINTER_INDEX => 1, 104 POINTER_TYPE => "unique" }, 105 { TYPE => "DATA" } 106 ], 107 }, 108 ] 109 } 110}, { bla => "r->in.bla" }, \&print_fn, "return;"); 111 112test_warnings("", 113 sub { $fn->("*r->in.bla"); }); 114 115is($output, "if (*r->in.bla == NULL) return;"); 116 117# Test case 5: Unknown variable 118 119$output = ""; 120$fn = check_null_pointer({ 121 FILE => "nofile", 122 LINE => 2, 123 PARENT => { 124 ELEMENTS => [ 125 { 126 NAME => "bla", 127 LEVELS => [ 128 { TYPE => "DATA" } 129 ], 130 }, 131 ] 132 } 133}, { }, \&print_fn, "return;"); 134 135test_warnings("nofile:2: unknown dereferenced expression `r->in.bla'\n", 136 sub { $fn->("r->in.bla"); }); 137 138is($output, "if (r->in.bla == NULL) return;"); 139 140my $needed = {}; 141NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); 142is_deeply($needed, { ndr_pull_foo => 1 }); 143 144# old settings should be kept 145$needed = { ndr_pull_foo => 0 }; 146NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); 147is_deeply($needed, { ndr_pull_foo => 0 }); 148 149# print/pull/push are independent of each other 150$needed = { ndr_pull_foo => 0 }; 151NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "print", $needed); 152is_deeply($needed, { ndr_pull_foo => 0, ndr_print_foo => 1 }); 153 154$needed = { }; 155NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); 156is_deeply($needed, { ndr_pull_foo => 1, ndr_print_foo => 1, ndr_push_foo => 1, 157 ndr_pull_bar => 1, ndr_print_bar => 1, ndr_push_bar => 1}); 158 159# push/pull/print are always set for functions 160$needed = { ndr_pull_foo => 0 }; 161NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); 162is_deeply($needed, { ndr_pull_foo => 1, ndr_print_foo => 1, ndr_push_foo => 1, 163 ndr_pull_bar => 1, ndr_push_bar => 1, ndr_print_bar => 1}); 164 165# public structs are always needed 166$needed = {}; 167NeededType({ NAME => "bla", TYPE => "TYPEDEF", 168 DATA => { TYPE => "STRUCT", ELEMENTS => [] } }, 169 $needed, "pull"); 170is_deeply($needed, { }); 171 172$needed = {}; 173NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", 174 TYPE => "TYPEDEF", 175 DATA => { TYPE => "STRUCT", ELEMENTS => [] } } ] }, 176 $needed); 177is_deeply($needed, { ndr_pull_bla => 1, ndr_push_bla => 1, ndr_print_bla => 1 }); 178 179# make sure types for elements are set too 180$needed = {}; 181NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", 182 TYPE => "TYPEDEF", 183 DATA => { TYPE => "STRUCT", 184 ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] }, 185 $needed); 186is_deeply($needed, { ndr_pull_bla => 1, ndr_pull_bar => 1, ndr_push_bla => 1, ndr_push_bar => 1, 187 ndr_print_bla => 1, ndr_print_bar => 1}); 188 189$needed = {}; 190NeededInterface({ TYPES => [ { PROPERTIES => { gensize => 1}, NAME => "bla", 191 TYPE => "TYPEDEF", 192 DATA => { TYPE => "STRUCT", 193 ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] }, 194 $needed); 195is_deeply($needed, { ndr_size_bla => 1 }); 196 197# make sure types for elements are set too 198$needed = { ndr_pull_bla => 1 }; 199NeededType({ NAME => "bla", 200 TYPE => "TYPEDEF", 201 DATA => { TYPE => "STRUCT", 202 ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } }, 203 $needed, "pull"); 204is_deeply($needed, { ndr_pull_bla => 1, ndr_pull_bar => 1 }); 205 206$needed = {}; 207NeededInterface({ TYPES => [ { PROPERTIES => { public => 1}, 208 NAME => "bla", 209 TYPE => "TYPEDEF", 210 DATA => { TYPE => "STRUCT", 211 ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "rep" } ] } } ] }, $needed); 212is_deeply($needed, { ndr_pull_bla => 1, ndr_push_bla => 1, ndr_print_bla => 1, 213 ndr_print_rep => 1, 214 ndr_pull_bar => 1, ndr_push_bar => 1, 215 ndr_bar_to_rep => 1, ndr_rep_to_bar => 1}); 216 217my $generator = new Parse::Pidl::Samba4::NDR::Parser(); 218$generator->ParseStructPush({ 219 NAME => "mystruct", 220 TYPE => "STRUCT", 221 PROPERTIES => {}, 222 ALIGN => 4, 223 ELEMENTS => [ ]}, "ndr", "x"); 224is($generator->{res}, "NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); 225if (ndr_flags & NDR_SCALARS) { 226 NDR_CHECK(ndr_push_align(ndr, 4)); 227 NDR_CHECK(ndr_push_trailer_align(ndr, 4)); 228} 229if (ndr_flags & NDR_BUFFERS) { 230} 231"); 232 233$generator = new Parse::Pidl::Samba4::NDR::Parser(); 234my $e = { 235 NAME => "el1", 236 TYPE => "mytype", 237 REPRESENTATION_TYPE => "mytype", 238 PROPERTIES => {}, 239 LEVELS => [ 240 { LEVEL_INDEX => 0, TYPE => "DATA", DATA_TYPE => "mytype" } 241] }; 242$generator->ParseStructPush({ 243 NAME => "mystruct", 244 TYPE => "STRUCT", 245 PROPERTIES => {}, 246 ALIGN => 4, 247 SURROUNDING_ELEMENT => $e, 248 ELEMENTS => [ $e ]}, "ndr", "x"); 249is($generator->{res}, "NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); 250if (ndr_flags & NDR_SCALARS) { 251 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, ndr_string_array_size(ndr, x->el1))); 252 NDR_CHECK(ndr_push_align(ndr, 4)); 253 NDR_CHECK(ndr_push_mytype(ndr, NDR_SCALARS, &x->el1)); 254 NDR_CHECK(ndr_push_trailer_align(ndr, 4)); 255} 256if (ndr_flags & NDR_BUFFERS) { 257} 258"); 259 260is(TypeFunctionName("ndr_pull", "uint32"), "ndr_pull_uint32"); 261is(TypeFunctionName("ndr_pull", {TYPE => "ENUM", NAME => "bar"}), "ndr_pull_ENUM_bar"); 262is(TypeFunctionName("ndr_pull", {TYPE => "TYPEDEF", NAME => "bar", DATA => undef}), "ndr_pull_bar"); 263is(TypeFunctionName("ndr_push", {TYPE => "STRUCT", NAME => "bar"}), "ndr_push_STRUCT_bar"); 264 265# check noprint works 266$generator = new Parse::Pidl::Samba4::NDR::Parser(); 267$generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", 268 PROPERTIES => { noprint => 1}, 269 LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt"} ]}, 270 "ndr", "var", { "x" => "r->foobar" } ); 271is($generator->{res}, ""); 272 273$generator = new Parse::Pidl::Samba4::NDR::Parser(); 274$generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", 275 PROPERTIES => {}, 276 LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt" }]}, 277 "ndr", "var", { "x" => "r->foobar" } ); 278is($generator->{res}, "ndr_print_rt(ndr, \"x\", &var);\n"); 279 280# make sure that a print function for an element with value() set works 281$generator = new Parse::Pidl::Samba4::NDR::Parser(); 282$generator->ParseElementPrint({ NAME => "x", TYPE => "uint32", REPRESENTATION_TYPE => "uint32", 283 PROPERTIES => { value => "23" }, 284 LEVELS => [ { TYPE => "DATA", DATA_TYPE => "uint32"} ]}, 285 "ndr", "var", { "x" => "r->foobar" } ); 286is($generator->{res}, "ndr_print_uint32(ndr, \"x\", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?23:var);\n"); 287 288$generator = new Parse::Pidl::Samba4::NDR::Parser(); 289$generator->AuthServiceStruct("bridge", "\"rot13\",\"onetimepad\""); 290is($generator->{res}, "static const char * const bridge_authservice_strings[] = { 291 \"rot13\", 292 \"onetimepad\", 293}; 294 295static const struct ndr_interface_string_array bridge_authservices = { 296 .count = 2, 297 .names = bridge_authservice_strings 298}; 299 300"); 301