blob: 6a4d7b40fc96fc5a564e9cd05e33465f1416bb47 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Colin Crossf27c5e42020-01-02 09:37:49 -080015package proptools
Jamie Gennis1bc967e2014-05-27 16:34:41 -070016
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "reflect"
Sasha Smundak29fdcad2020-02-11 22:39:47 -080020
Jamie Gennis1bc967e2014-05-27 16:34:41 -070021 "testing"
Colin Cross4adc8192015-06-22 13:38:45 -070022
23 "github.com/google/blueprint/parser"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070024)
25
26var validUnpackTestCases = []struct {
27 input string
Colin Crosse32cc802016-06-07 12:28:16 -070028 output []interface{}
Colin Crossc3d73122016-08-05 17:19:36 -070029 empty []interface{}
Colin Cross4adc8192015-06-22 13:38:45 -070030 errs []error
Jamie Gennis1bc967e2014-05-27 16:34:41 -070031}{
Colin Crossc3d73122016-08-05 17:19:36 -070032 {
33 input: `
34 m {
Colin Crossf27c5e42020-01-02 09:37:49 -080035 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -070036 blank: "",
37 }
Colin Cross80117682015-10-30 15:53:55 -070038 `,
Colin Crossc3d73122016-08-05 17:19:36 -070039 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -080040 &struct {
Colin Crossf27c5e42020-01-02 09:37:49 -080041 S *string
Colin Crosse32cc802016-06-07 12:28:16 -070042 Blank *string
43 Unset *string
44 }{
Colin Crossf27c5e42020-01-02 09:37:49 -080045 S: StringPtr("abc"),
46 Blank: StringPtr(""),
Colin Crosse32cc802016-06-07 12:28:16 -070047 Unset: nil,
48 },
Colin Cross80117682015-10-30 15:53:55 -070049 },
Colin Cross80117682015-10-30 15:53:55 -070050 },
51
Colin Crossc3d73122016-08-05 17:19:36 -070052 {
53 input: `
54 m {
Colin Crossf27c5e42020-01-02 09:37:49 -080055 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -070056 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -070057 `,
Colin Crossc3d73122016-08-05 17:19:36 -070058 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -080059 &struct {
Colin Crossf27c5e42020-01-02 09:37:49 -080060 S string
Colin Crosse32cc802016-06-07 12:28:16 -070061 }{
Colin Crossf27c5e42020-01-02 09:37:49 -080062 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -070063 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064 },
65 },
66
Colin Crossc3d73122016-08-05 17:19:36 -070067 {
68 input: `
69 m {
70 isGood: true,
71 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -070072 `,
Colin Crossc3d73122016-08-05 17:19:36 -070073 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -080074 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -070075 IsGood bool
76 }{
77 IsGood: true,
78 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070079 },
80 },
81
Colin Crossc3d73122016-08-05 17:19:36 -070082 {
83 input: `
84 m {
85 isGood: true,
86 isBad: false,
87 }
Colin Cross80117682015-10-30 15:53:55 -070088 `,
Colin Crossc3d73122016-08-05 17:19:36 -070089 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -080090 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -070091 IsGood *bool
92 IsBad *bool
93 IsUgly *bool
94 }{
Colin Crossf27c5e42020-01-02 09:37:49 -080095 IsGood: BoolPtr(true),
96 IsBad: BoolPtr(false),
Colin Crosse32cc802016-06-07 12:28:16 -070097 IsUgly: nil,
98 },
Colin Cross80117682015-10-30 15:53:55 -070099 },
Colin Cross80117682015-10-30 15:53:55 -0700100 },
101
Colin Crossc3d73122016-08-05 17:19:36 -0700102 {
103 input: `
104 m {
105 stuff: ["asdf", "jkl;", "qwert",
106 "uiop", "bnm,"],
107 empty: []
108 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700110 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800111 &struct {
Colin Cross12392ca2018-10-02 21:57:47 -0700112 Stuff []string
113 Empty []string
114 Nil []string
115 NonString []struct{ S string } `blueprint:"mutated"`
Colin Crosse32cc802016-06-07 12:28:16 -0700116 }{
Colin Cross12392ca2018-10-02 21:57:47 -0700117 Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
118 Empty: []string{},
119 Nil: nil,
120 NonString: nil,
Colin Crosse32cc802016-06-07 12:28:16 -0700121 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122 },
123 },
124
Colin Crossc3d73122016-08-05 17:19:36 -0700125 {
126 input: `
127 m {
128 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800129 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700130 }
Jamie Gennis87622922014-09-30 11:38:25 -0700131 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700132 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700133 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800134 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700135 Nested struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800136 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700137 }
138 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800139 Nested: struct{ S string }{
140 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700141 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700142 },
143 },
144 },
145
Colin Crossc3d73122016-08-05 17:19:36 -0700146 {
147 input: `
148 m {
149 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800150 s: "def",
Colin Crossc3d73122016-08-05 17:19:36 -0700151 }
Jamie Gennis87622922014-09-30 11:38:25 -0700152 }
Jamie Gennis87622922014-09-30 11:38:25 -0700153 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700154 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800155 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700156 Nested interface{}
Colin Cross4adc8192015-06-22 13:38:45 -0700157 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800158 Nested: &struct{ S string }{
159 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700160 },
Colin Cross4adc8192015-06-22 13:38:45 -0700161 },
Colin Cross4adc8192015-06-22 13:38:45 -0700162 },
Colin Cross4adc8192015-06-22 13:38:45 -0700163 },
164
Colin Crossc3d73122016-08-05 17:19:36 -0700165 {
166 input: `
167 m {
168 nested: {
169 foo: "abc",
170 },
171 bar: false,
172 baz: ["def", "ghi"],
173 }
Colin Cross4adc8192015-06-22 13:38:45 -0700174 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700175 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800176 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700177 Nested struct {
178 Foo string
179 }
180 Bar bool
181 Baz []string
182 }{
183 Nested: struct{ Foo string }{
184 Foo: "abc",
185 },
186 Bar: false,
187 Baz: []string{"def", "ghi"},
Colin Cross4adc8192015-06-22 13:38:45 -0700188 },
Colin Crosse32cc802016-06-07 12:28:16 -0700189 },
Colin Crosse32cc802016-06-07 12:28:16 -0700190 },
191
Colin Crossc3d73122016-08-05 17:19:36 -0700192 {
193 input: `
194 m {
195 nested: {
196 foo: "abc",
197 },
198 bar: false,
199 baz: ["def", "ghi"],
200 }
Colin Crosse32cc802016-06-07 12:28:16 -0700201 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700202 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800203 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700204 Nested struct {
205 Foo string `allowNested:"true"`
206 } `blueprint:"filter(allowNested:\"true\")"`
207 Bar bool
208 Baz []string
209 }{
210 Nested: struct {
211 Foo string `allowNested:"true"`
212 }{
213 Foo: "abc",
214 },
215 Bar: false,
216 Baz: []string{"def", "ghi"},
217 },
218 },
Colin Crosse32cc802016-06-07 12:28:16 -0700219 },
220
Sasha Smundak29fdcad2020-02-11 22:39:47 -0800221 // List of maps
222 {
223 input: `
224 m {
225 mapslist: [
226 {
227 foo: "abc",
228 bar: true,
229 },
230 {
231 foo: "def",
232 bar: false,
233 }
234 ],
235 }
236 `,
237 output: []interface{}{
238 &struct {
239 Mapslist []struct {
240 Foo string
241 Bar bool
242 }
243 }{
244 Mapslist: []struct {
245 Foo string
246 Bar bool
247 }{
248 {Foo: "abc", Bar: true},
249 {Foo: "def", Bar: false},
250 },
251 },
252 },
253 },
254
255 // List of pointers to structs
256 {
257 input: `
258 m {
259 mapslist: [
260 {
261 foo: "abc",
262 bar: true,
263 },
264 {
265 foo: "def",
266 bar: false,
267 }
268 ],
269 }
270 `,
271 output: []interface{}{
272 &struct {
273 Mapslist []*struct {
274 Foo string
275 Bar bool
276 }
277 }{
278 Mapslist: []*struct {
279 Foo string
280 Bar bool
281 }{
282 {Foo: "abc", Bar: true},
283 {Foo: "def", Bar: false},
284 },
285 },
286 },
287 },
288
289 // List of lists
290 {
291 input: `
292 m {
293 listoflists: [
294 ["abc",],
295 ["def",],
296 ],
297 }
298 `,
299 output: []interface{}{
300 &struct {
301 Listoflists [][]string
302 }{
303 Listoflists: [][]string{
304 []string{"abc"},
305 []string{"def"},
306 },
307 },
308 },
309 },
310
311 // Multilevel
312 {
313 input: `
314 m {
315 name: "mymodule",
316 flag: true,
317 settings: ["foo1", "foo2", "foo3",],
318 perarch: {
319 arm: "32",
320 arm64: "64",
321 },
322 configvars: [
323 { var: "var1", values: ["1.1", "1.2", ], },
324 { var: "var2", values: ["2.1", ], },
325 ],
326 }
327 `,
328 output: []interface{}{
329 &struct {
330 Name string
331 Flag bool
332 Settings []string
333 Perarch *struct {
334 Arm string
335 Arm64 string
336 }
337 Configvars []struct {
338 Var string
339 Values []string
340 }
341 }{
342 Name: "mymodule",
343 Flag: true,
344 Settings: []string{"foo1", "foo2", "foo3"},
345 Perarch: &struct {
346 Arm string
347 Arm64 string
348 }{Arm: "32", Arm64: "64"},
349 Configvars: []struct {
350 Var string
351 Values []string
352 }{
353 {Var: "var1", Values: []string{"1.1", "1.2"}},
354 {Var: "var2", Values: []string{"2.1"}},
355 },
356 },
357 },
358 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800359 // Anonymous struct
Colin Crossc3d73122016-08-05 17:19:36 -0700360 {
361 input: `
362 m {
Colin Crossf27c5e42020-01-02 09:37:49 -0800363 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700364 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800365 s: "def",
Colin Crossc3d73122016-08-05 17:19:36 -0700366 },
367 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800368 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700369 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800370 &struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800371 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700372 Nested struct {
373 EmbeddedStruct
374 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800375 }{
376 EmbeddedStruct: EmbeddedStruct{
Colin Crossf27c5e42020-01-02 09:37:49 -0800377 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700378 },
379 Nested: struct {
380 EmbeddedStruct
381 }{
382 EmbeddedStruct: EmbeddedStruct{
Colin Crossf27c5e42020-01-02 09:37:49 -0800383 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700384 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800385 },
386 },
387 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800388 },
389
390 // Anonymous interface
Colin Crossc3d73122016-08-05 17:19:36 -0700391 {
392 input: `
393 m {
Colin Crossf27c5e42020-01-02 09:37:49 -0800394 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700395 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800396 s: "def",
Colin Crossc3d73122016-08-05 17:19:36 -0700397 },
398 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800399 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700400 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800401 &struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800402 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700403 Nested struct {
404 EmbeddedInterface
405 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800406 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800407 EmbeddedInterface: &struct{ S string }{
408 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700409 },
410 Nested: struct {
411 EmbeddedInterface
412 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800413 EmbeddedInterface: &struct{ S string }{
414 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700415 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800416 },
417 },
418 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800419 },
420
421 // Anonymous struct with name collision
Colin Crossc3d73122016-08-05 17:19:36 -0700422 {
423 input: `
424 m {
Colin Crossf27c5e42020-01-02 09:37:49 -0800425 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700426 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800427 s: "def",
Colin Crossc3d73122016-08-05 17:19:36 -0700428 },
429 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800430 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700431 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800432 &struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800433 S string
Colin Cross9d1469d2015-11-20 17:03:25 -0800434 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700435 Nested struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800436 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700437 EmbeddedStruct
438 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800439 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800440 S: "abc",
Colin Cross9d1469d2015-11-20 17:03:25 -0800441 EmbeddedStruct: EmbeddedStruct{
Colin Crossf27c5e42020-01-02 09:37:49 -0800442 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700443 },
444 Nested: struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800445 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700446 EmbeddedStruct
447 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800448 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700449 EmbeddedStruct: EmbeddedStruct{
Colin Crossf27c5e42020-01-02 09:37:49 -0800450 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700451 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800452 },
453 },
454 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800455 },
456
457 // Anonymous interface with name collision
Colin Crossc3d73122016-08-05 17:19:36 -0700458 {
459 input: `
460 m {
Colin Crossf27c5e42020-01-02 09:37:49 -0800461 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700462 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800463 s: "def",
Colin Crossc3d73122016-08-05 17:19:36 -0700464 },
465 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800466 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700467 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800468 &struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800469 S string
Colin Cross9d1469d2015-11-20 17:03:25 -0800470 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700471 Nested struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800472 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700473 EmbeddedInterface
474 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800475 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800476 S: "abc",
477 EmbeddedInterface: &struct{ S string }{
478 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700479 },
480 Nested: struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800481 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700482 EmbeddedInterface
483 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800484 S: "def",
485 EmbeddedInterface: &struct{ S string }{
486 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700487 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800488 },
489 },
490 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800491 },
Colin Crosse32cc802016-06-07 12:28:16 -0700492
493 // Variables
Colin Crossc3d73122016-08-05 17:19:36 -0700494 {
495 input: `
496 list = ["abc"]
497 string = "def"
498 list_with_variable = [string]
Sasha Smundakde4d9f92020-03-03 17:36:00 -0800499 struct_value = { name: "foo" }
Colin Crossc3d73122016-08-05 17:19:36 -0700500 m {
Colin Crossf27c5e42020-01-02 09:37:49 -0800501 s: string,
Colin Crossc3d73122016-08-05 17:19:36 -0700502 list: list,
503 list2: list_with_variable,
Sasha Smundakde4d9f92020-03-03 17:36:00 -0800504 structattr: struct_value,
Colin Crossc3d73122016-08-05 17:19:36 -0700505 }
Colin Crosse32cc802016-06-07 12:28:16 -0700506 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700507 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800508 &struct {
Sasha Smundakde4d9f92020-03-03 17:36:00 -0800509 S string
510 List []string
511 List2 []string
512 Structattr struct {
513 Name string
514 }
Colin Crosse32cc802016-06-07 12:28:16 -0700515 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800516 S: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700517 List: []string{"abc"},
518 List2: []string{"def"},
Sasha Smundakde4d9f92020-03-03 17:36:00 -0800519 Structattr: struct {
520 Name string
521 }{
522 Name: "foo",
523 },
Colin Crosse32cc802016-06-07 12:28:16 -0700524 },
525 },
Colin Crosse32cc802016-06-07 12:28:16 -0700526 },
527
528 // Multiple property structs
Colin Crossc3d73122016-08-05 17:19:36 -0700529 {
530 input: `
531 m {
532 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800533 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700534 }
Colin Crosse32cc802016-06-07 12:28:16 -0700535 }
Colin Crosse32cc802016-06-07 12:28:16 -0700536 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700537 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800538 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700539 Nested struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800540 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700541 }
542 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800543 Nested: struct{ S string }{
544 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700545 },
546 },
Colin Cross5d57b2d2020-01-27 16:14:31 -0800547 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700548 Nested struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800549 S string
Colin Crosse32cc802016-06-07 12:28:16 -0700550 }
551 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800552 Nested: struct{ S string }{
553 S: "abc",
Colin Crosse32cc802016-06-07 12:28:16 -0700554 },
555 },
Colin Cross5d57b2d2020-01-27 16:14:31 -0800556 &struct {
Colin Crosse32cc802016-06-07 12:28:16 -0700557 }{},
558 },
Colin Crossc3d73122016-08-05 17:19:36 -0700559 },
560
561 // Nil pointer to struct
562 {
563 input: `
564 m {
565 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800566 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700567 }
568 }
569 `,
570 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800571 &struct {
Colin Crossc3d73122016-08-05 17:19:36 -0700572 Nested *struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800573 S string
Colin Crossc3d73122016-08-05 17:19:36 -0700574 }
575 }{
Colin Crossf27c5e42020-01-02 09:37:49 -0800576 Nested: &struct{ S string }{
577 S: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700578 },
579 },
580 },
581 empty: []interface{}{
582 &struct {
583 Nested *struct {
Colin Crossf27c5e42020-01-02 09:37:49 -0800584 S string
Colin Crossc3d73122016-08-05 17:19:36 -0700585 }
586 }{},
587 },
588 },
589
590 // Interface containing nil pointer to struct
591 {
592 input: `
593 m {
594 nested: {
Colin Crossf27c5e42020-01-02 09:37:49 -0800595 s: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700596 }
597 }
598 `,
599 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800600 &struct {
Colin Crossc3d73122016-08-05 17:19:36 -0700601 Nested interface{}
602 }{
603 Nested: &EmbeddedStruct{
Colin Crossf27c5e42020-01-02 09:37:49 -0800604 S: "abc",
Colin Crossc3d73122016-08-05 17:19:36 -0700605 },
606 },
607 },
608 empty: []interface{}{
609 &struct {
610 Nested interface{}
611 }{
612 Nested: (*EmbeddedStruct)(nil),
613 },
614 },
Colin Crosse32cc802016-06-07 12:28:16 -0700615 },
Colin Cross05b36072017-07-28 17:51:37 -0700616
617 // Factory set properties
618 {
619 input: `
620 m {
621 string: "abc",
622 string_ptr: "abc",
623 bool: false,
624 bool_ptr: false,
625 list: ["a", "b", "c"],
626 }
627 `,
628 output: []interface{}{
Colin Cross5d57b2d2020-01-27 16:14:31 -0800629 &struct {
Colin Cross05b36072017-07-28 17:51:37 -0700630 String string
631 String_ptr *string
632 Bool bool
633 Bool_ptr *bool
634 List []string
635 }{
636 String: "012abc",
Colin Crossf27c5e42020-01-02 09:37:49 -0800637 String_ptr: StringPtr("abc"),
Colin Cross05b36072017-07-28 17:51:37 -0700638 Bool: true,
Colin Crossf27c5e42020-01-02 09:37:49 -0800639 Bool_ptr: BoolPtr(false),
Colin Cross05b36072017-07-28 17:51:37 -0700640 List: []string{"0", "1", "2", "a", "b", "c"},
641 },
642 },
643 empty: []interface{}{
644 &struct {
645 String string
646 String_ptr *string
647 Bool bool
648 Bool_ptr *bool
649 List []string
650 }{
651 String: "012",
Colin Crossf27c5e42020-01-02 09:37:49 -0800652 String_ptr: StringPtr("012"),
Colin Cross05b36072017-07-28 17:51:37 -0700653 Bool: true,
Colin Crossf27c5e42020-01-02 09:37:49 -0800654 Bool_ptr: BoolPtr(true),
Colin Cross05b36072017-07-28 17:51:37 -0700655 List: []string{"0", "1", "2"},
656 },
657 },
658 },
Colin Cross3bbbdf32020-02-05 13:45:11 -0800659 // Captitalized property
660 {
661 input: `
662 m {
663 CAPITALIZED: "foo",
664 }
665 `,
666 output: []interface{}{
667 &struct {
668 CAPITALIZED string
669 }{
670 CAPITALIZED: "foo",
671 },
672 },
673 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700674}
675
676func TestUnpackProperties(t *testing.T) {
677 for _, testCase := range validUnpackTestCases {
678 r := bytes.NewBufferString(testCase.input)
Colin Crosse32cc802016-06-07 12:28:16 -0700679 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700680 if len(errs) != 0 {
681 t.Errorf("test case: %s", testCase.input)
682 t.Errorf("unexpected parse errors:")
683 for _, err := range errs {
684 t.Errorf(" %s", err)
685 }
686 t.FailNow()
687 }
688
Colin Crosse32cc802016-06-07 12:28:16 -0700689 for _, def := range file.Defs {
690 module, ok := def.(*parser.Module)
691 if !ok {
692 continue
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700693 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700694
Colin Crossc3d73122016-08-05 17:19:36 -0700695 var output []interface{}
696 if len(testCase.empty) > 0 {
697 output = testCase.empty
698 } else {
699 for _, p := range testCase.output {
Colin Crossf27c5e42020-01-02 09:37:49 -0800700 output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface())
Colin Crossc3d73122016-08-05 17:19:36 -0700701 }
Colin Crosse32cc802016-06-07 12:28:16 -0700702 }
Colin Crossf27c5e42020-01-02 09:37:49 -0800703 _, errs = UnpackProperties(module.Properties, output...)
Colin Crosse32cc802016-06-07 12:28:16 -0700704 if len(errs) != 0 && len(testCase.errs) == 0 {
705 t.Errorf("test case: %s", testCase.input)
706 t.Errorf("unexpected unpack errors:")
707 for _, err := range errs {
708 t.Errorf(" %s", err)
709 }
710 t.FailNow()
711 } else if !reflect.DeepEqual(errs, testCase.errs) {
712 t.Errorf("test case: %s", testCase.input)
713 t.Errorf("incorrect errors:")
714 t.Errorf(" expected: %+v", testCase.errs)
715 t.Errorf(" got: %+v", errs)
716 }
717
718 if len(output) != len(testCase.output) {
719 t.Fatalf("incorrect number of property structs, expected %d got %d",
720 len(testCase.output), len(output))
721 }
722
723 for i := range output {
Colin Cross5d57b2d2020-01-27 16:14:31 -0800724 got := reflect.ValueOf(output[i]).Interface()
Colin Crosse32cc802016-06-07 12:28:16 -0700725 if !reflect.DeepEqual(got, testCase.output[i]) {
726 t.Errorf("test case: %s", testCase.input)
727 t.Errorf("incorrect output:")
728 t.Errorf(" expected: %+v", testCase.output[i])
729 t.Errorf(" got: %+v", got)
730 }
731 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700732 }
733 }
734}
Colin Cross017ed2e2016-05-31 15:53:32 -0700735
Sasha Smundak29fdcad2020-02-11 22:39:47 -0800736func BenchmarkUnpackProperties(b *testing.B) {
737 run := func(b *testing.B, props []interface{}, input string) {
738 b.ReportAllocs()
739 b.StopTimer()
740 r := bytes.NewBufferString(input)
741 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
742 if len(errs) != 0 {
743 b.Errorf("test case: %s", input)
744 b.Errorf("unexpected parse errors:")
745 for _, err := range errs {
746 b.Errorf(" %s", err)
747 }
748 b.FailNow()
749 }
750
751 for i := 0; i < b.N; i++ {
752 for _, def := range file.Defs {
753 module, ok := def.(*parser.Module)
754 if !ok {
755 continue
756 }
757
758 var output []interface{}
759 for _, p := range props {
760 output = append(output, CloneProperties(reflect.ValueOf(p)).Interface())
761 }
762
763 b.StartTimer()
764 _, errs = UnpackProperties(module.Properties, output...)
765 b.StopTimer()
766 if len(errs) > 0 {
767 b.Errorf("unexpected unpack errors:")
768 for _, err := range errs {
769 b.Errorf(" %s", err)
770 }
771 }
772 }
773 }
Colin Cross017ed2e2016-05-31 15:53:32 -0700774 }
Sasha Smundak29fdcad2020-02-11 22:39:47 -0800775
776 b.Run("basic", func(b *testing.B) {
777 props := []interface{}{
778 &struct {
779 Nested struct {
780 S string
781 }
782 }{},
783 }
784 bp := `
785 m {
786 nested: {
787 s: "abc",
788 },
789 }
790 `
791 run(b, props, bp)
792 })
793
794 b.Run("interface", func(b *testing.B) {
795 props := []interface{}{
796 &struct {
797 Nested interface{}
798 }{
799 Nested: (*struct {
800 S string
801 })(nil),
802 },
803 }
804 bp := `
805 m {
806 nested: {
807 s: "abc",
808 },
809 }
810 `
811 run(b, props, bp)
812 })
813
814 b.Run("many", func(b *testing.B) {
815 props := []interface{}{
816 &struct {
817 A *string
818 B *string
819 C *string
820 D *string
821 E *string
822 F *string
823 G *string
824 H *string
825 I *string
826 J *string
827 }{},
828 }
829 bp := `
830 m {
831 a: "a",
832 b: "b",
833 c: "c",
834 d: "d",
835 e: "e",
836 f: "f",
837 g: "g",
838 h: "h",
839 i: "i",
840 j: "j",
841 }
842 `
843 run(b, props, bp)
844 })
845
846 b.Run("deep", func(b *testing.B) {
847 props := []interface{}{
848 &struct {
849 Nested struct {
850 Nested struct {
851 Nested struct {
852 Nested struct {
853 Nested struct {
854 Nested struct {
855 Nested struct {
856 Nested struct {
857 Nested struct {
858 Nested struct {
859 S string
860 }
861 }
862 }
863 }
864 }
865 }
866 }
867 }
868 }
869 }
870 }{},
871 }
872 bp := `
873 m {
874 nested: { nested: { nested: { nested: { nested: {
875 nested: { nested: { nested: { nested: { nested: {
876 s: "abc",
877 }, }, }, }, },
878 }, }, }, }, },
879 }
880 `
881 run(b, props, bp)
882 })
883
884 b.Run("mix", func(b *testing.B) {
885 props := []interface{}{
886 &struct {
887 Name string
888 Flag bool
889 Settings []string
890 Perarch *struct {
891 Arm string
892 Arm64 string
893 }
894 Configvars []struct {
895 Name string
896 Values []string
897 }
898 }{},
899 }
900 bp := `
901 m {
902 name: "mymodule",
903 flag: true,
904 settings: ["foo1", "foo2", "foo3",],
905 perarch: {
906 arm: "32",
907 arm64: "64",
908 },
909 configvars: [
910 { name: "var1", values: ["var1:1", "var1:2", ], },
911 { name: "var2", values: ["var2:1", "var2:2", ], },
912 ],
913 }
914 `
915 run(b, props, bp)
916 })
Colin Cross017ed2e2016-05-31 15:53:32 -0700917}