a14111961f58024bd731e0cccd8da3b13c3e2b9f
[jelmer/samba4-debian.git] / source / pidl / tests / samba-ndr.pl
1 #!/usr/bin/perl
2 # (C) 2007 Jelmer Vernooij <jelmer@samba.org>
3 # Published under the GNU General Public License
4 use strict;
5 use warnings;
6
7 use Test::More tests => 30;
8 use FindBin qw($RealBin);
9 use lib "$RealBin";
10 use Util;
11 use strict;
12 use Parse::Pidl::Util qw(MyDumper);
13 use Parse::Pidl::Samba4::NDR::Parser qw(check_null_pointer 
14         NeededFunction NeededElement NeededType
15         NeededInterface TypeFunctionName ParseElementPrint); 
16
17 my $output;
18 sub print_fn($) { my $x = shift; $output.=$x; }
19
20 # Test case 1: Simple unique pointer dereference
21
22 $output = "";
23 my $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
40 test_warnings("", sub { $fn->("r->in.bla"); });
41
42 is($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
63 test_warnings("", sub { $fn->("r->in.bla"); });
64
65 is($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
85 test_warnings("nofile:1: too much dereferences for `bla'\n", 
86                   sub { $fn->("r->in.bla"); });
87
88 is($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
112 test_warnings("",
113                   sub { $fn->("*r->in.bla"); });
114
115 is($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
135 test_warnings("nofile:2: unknown dereferenced expression `r->in.bla'\n",
136                   sub { $fn->("r->in.bla"); });
137
138 is($output, "if (r->in.bla == NULL) return;");
139
140 my $needed = {};
141 NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); 
142 is_deeply($needed, { ndr_pull_foo => 1 });
143
144 # old settings should be kept
145 $needed = { ndr_pull_foo => 0 };
146 NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "pull", $needed); 
147 is_deeply($needed, { ndr_pull_foo => 0 });
148
149 # print/pull/push are independent of each other
150 $needed = { ndr_pull_foo => 0 };
151 NeededElement({ TYPE => "foo", REPRESENTATION_TYPE => "foo" }, "print", $needed); 
152 is_deeply($needed, { ndr_pull_foo => 0, ndr_print_foo => 1 });
153
154 $needed = { };
155 NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); 
156 is_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 };
161 NeededFunction({ NAME => "foo", ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] }, $needed); 
162 is_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 = {};
167 NeededType({ NAME => "bla", TYPE => "TYPEDEF",
168                 DATA => { TYPE => "STRUCT", ELEMENTS => [] } },
169                           $needed, "pull");
170 is_deeply($needed, { });
171
172 $needed = {};
173 NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", 
174                                 TYPE => "TYPEDEF",
175                     DATA => { TYPE => "STRUCT", ELEMENTS => [] } } ] },
176                           $needed);
177 is_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 = {};
181 NeededInterface({ TYPES => [ { PROPERTIES => { public => 1 }, NAME => "bla", 
182                                 TYPE => "TYPEDEF",
183                     DATA => { TYPE => "STRUCT", 
184                                                   ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] },
185                           $needed);
186 is_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 = {};
190 NeededInterface({ TYPES => [ { PROPERTIES => { gensize => 1}, NAME => "bla", 
191                                 TYPE => "TYPEDEF",
192                     DATA => { TYPE => "STRUCT", 
193                                                   ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } } ] },
194                           $needed);
195 is_deeply($needed, { ndr_size_bla => 1 });
196                          
197 # make sure types for elements are set too
198 $needed = { ndr_pull_bla => 1 };
199 NeededType({ NAME => "bla", 
200                                 TYPE => "TYPEDEF",
201                     DATA => { TYPE => "STRUCT", 
202                                                   ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "bar" } ] } },
203                           $needed, "pull");
204 is_deeply($needed, { ndr_pull_bla => 1, ndr_pull_bar => 1 });
205
206 $needed = {};
207 NeededInterface({ TYPES => [ { PROPERTIES => { public => 1}, 
208                                 NAME => "bla", 
209                                 TYPE => "TYPEDEF",
210                     DATA => { TYPE => "STRUCT", 
211                                                   ELEMENTS => [ { TYPE => "bar", REPRESENTATION_TYPE => "rep" } ] } } ] }, $needed);
212 is_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         
217 my $generator = new Parse::Pidl::Samba4::NDR::Parser();
218 $generator->ParseStructPush({
219                         NAME => "mystruct",
220                         TYPE => "STRUCT",
221                         PROPERTIES => {},
222                         ALIGN => 4,
223                         ELEMENTS => [ ]}, "x");
224 is($generator->{res}, "if (ndr_flags & NDR_SCALARS) {
225         NDR_CHECK(ndr_push_align(ndr, 4));
226 }
227 if (ndr_flags & NDR_BUFFERS) {
228 }
229 ");
230
231 $generator = new Parse::Pidl::Samba4::NDR::Parser();
232 my $e = { 
233         NAME => "el1", 
234         TYPE => "mytype",
235         REPRESENTATION_TYPE => "mytype",
236         PROPERTIES => {},
237         LEVELS => [ 
238                 { LEVEL_INDEX => 0, TYPE => "DATA", DATA_TYPE => "mytype" } 
239 ] };
240 $generator->ParseStructPush({
241                         NAME => "mystruct",
242                         TYPE => "STRUCT",
243                         PROPERTIES => {},
244                         ALIGN => 4,
245                         SURROUNDING_ELEMENT => $e,
246                         ELEMENTS => [ $e ]}, "x");
247 is($generator->{res}, "if (ndr_flags & NDR_SCALARS) {
248         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_string_array_size(ndr, x->el1)));
249         NDR_CHECK(ndr_push_align(ndr, 4));
250         NDR_CHECK(ndr_push_mytype(ndr, NDR_SCALARS, &x->el1));
251 }
252 if (ndr_flags & NDR_BUFFERS) {
253 }
254 ");
255
256 is(TypeFunctionName("ndr_pull", "uint32"), "ndr_pull_uint32");
257 is(TypeFunctionName("ndr_pull", {TYPE => "ENUM", NAME => "bar"}), "ndr_pull_ENUM_bar");
258 is(TypeFunctionName("ndr_pull", {TYPE => "TYPEDEF", NAME => "bar", DATA => undef}), "ndr_pull_bar");
259 is(TypeFunctionName("ndr_push", {TYPE => "STRUCT", NAME => "bar"}), "ndr_push_STRUCT_bar");
260
261 # check noprint works
262 $generator = new Parse::Pidl::Samba4::NDR::Parser();
263 $generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", 
264                                     PROPERTIES => { noprint => 1},
265                                     LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt"} ]}, "var", { "x" => "r->foobar" } );
266 is($generator->{res}, "");
267
268 $generator = new Parse::Pidl::Samba4::NDR::Parser();
269 $generator->ParseElementPrint({ NAME => "x", TYPE => "rt", REPRESENTATION_TYPE => "rt", 
270                                     PROPERTIES => {},
271                                     LEVELS => [ { TYPE => "DATA", DATA_TYPE => "rt" }]}, "var", { "x" => "r->foobar" } );
272 is($generator->{res}, "ndr_print_rt(ndr, \"x\", &var);\n");
273
274 # make sure that a print function for an element with value() set works
275 $generator = new Parse::Pidl::Samba4::NDR::Parser();
276 $generator->ParseElementPrint({ NAME => "x", TYPE => "uint32", REPRESENTATION_TYPE => "uint32", 
277                                     PROPERTIES => { value => "23" },
278                                     LEVELS => [ { TYPE => "DATA", DATA_TYPE => "uint32"} ]}, "var", { "x" => "r->foobar" } );
279 is($generator->{res}, "ndr_print_uint32(ndr, \"x\", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?23:var);\n");