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