blob: b65fa3f277d6f05b06877692564f454f44ac5176 [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
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
Colin Cross4adc8192015-06-22 13:38:45 -070019 "fmt"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "reflect"
21 "testing"
Colin Cross4adc8192015-06-22 13:38:45 -070022 "text/scanner"
23
24 "github.com/google/blueprint/parser"
25 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070026)
27
28var validUnpackTestCases = []struct {
29 input string
Colin Crosse32cc802016-06-07 12:28:16 -070030 output []interface{}
Colin Crossc3d73122016-08-05 17:19:36 -070031 empty []interface{}
Colin Cross4adc8192015-06-22 13:38:45 -070032 errs []error
Jamie Gennis1bc967e2014-05-27 16:34:41 -070033}{
Colin Crossc3d73122016-08-05 17:19:36 -070034 {
35 input: `
36 m {
37 name: "abc",
38 blank: "",
39 }
Colin Cross80117682015-10-30 15:53:55 -070040 `,
Colin Crossc3d73122016-08-05 17:19:36 -070041 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -070042 struct {
43 Name *string
44 Blank *string
45 Unset *string
46 }{
47 Name: proptools.StringPtr("abc"),
48 Blank: proptools.StringPtr(""),
49 Unset: nil,
50 },
Colin Cross80117682015-10-30 15:53:55 -070051 },
Colin Cross80117682015-10-30 15:53:55 -070052 },
53
Colin Crossc3d73122016-08-05 17:19:36 -070054 {
55 input: `
56 m {
57 name: "abc",
58 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -070059 `,
Colin Crossc3d73122016-08-05 17:19:36 -070060 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -070061 struct {
62 Name string
63 }{
64 Name: "abc",
65 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066 },
67 },
68
Colin Crossc3d73122016-08-05 17:19:36 -070069 {
70 input: `
71 m {
72 isGood: true,
73 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074 `,
Colin Crossc3d73122016-08-05 17:19:36 -070075 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -070076 struct {
77 IsGood bool
78 }{
79 IsGood: true,
80 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070081 },
82 },
83
Colin Crossc3d73122016-08-05 17:19:36 -070084 {
85 input: `
86 m {
87 isGood: true,
88 isBad: false,
89 }
Colin Cross80117682015-10-30 15:53:55 -070090 `,
Colin Crossc3d73122016-08-05 17:19:36 -070091 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -070092 struct {
93 IsGood *bool
94 IsBad *bool
95 IsUgly *bool
96 }{
97 IsGood: proptools.BoolPtr(true),
98 IsBad: proptools.BoolPtr(false),
99 IsUgly: nil,
100 },
Colin Cross80117682015-10-30 15:53:55 -0700101 },
Colin Cross80117682015-10-30 15:53:55 -0700102 },
103
Colin Crossc3d73122016-08-05 17:19:36 -0700104 {
105 input: `
106 m {
107 stuff: ["asdf", "jkl;", "qwert",
108 "uiop", "bnm,"],
109 empty: []
110 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700111 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700112 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700113 struct {
114 Stuff []string
115 Empty []string
116 Nil []string
117 }{
118 Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
119 Empty: []string{},
120 Nil: nil,
121 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122 },
123 },
124
Colin Crossc3d73122016-08-05 17:19:36 -0700125 {
126 input: `
127 m {
128 nested: {
129 name: "abc",
130 }
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 Crosse32cc802016-06-07 12:28:16 -0700134 struct {
135 Nested struct {
136 Name string
137 }
138 }{
139 Nested: struct{ Name string }{
140 Name: "abc",
141 },
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: {
150 name: "def",
151 }
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 Crosse32cc802016-06-07 12:28:16 -0700155 struct {
156 Nested interface{}
Colin Cross4adc8192015-06-22 13:38:45 -0700157 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700158 Nested: &struct{ Name string }{
159 Name: "def",
160 },
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 Crosse32cc802016-06-07 12:28:16 -0700176 struct {
177 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 Crosse32cc802016-06-07 12:28:16 -0700203 struct {
204 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
Colin Crossc3d73122016-08-05 17:19:36 -0700221 {
222 input: `
223 m {
224 nested: {
225 foo: "abc",
226 },
227 bar: false,
228 baz: ["def", "ghi"],
229 }
Colin Crosse32cc802016-06-07 12:28:16 -0700230 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700231 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700232 struct {
233 Nested struct {
234 Foo string
235 } `blueprint:"filter(allowNested:\"true\")"`
236 Bar bool
237 Baz []string
238 }{
239 Nested: struct{ Foo string }{
240 Foo: "",
241 },
242 Bar: false,
243 Baz: []string{"def", "ghi"},
244 },
Colin Cross4adc8192015-06-22 13:38:45 -0700245 },
Colin Crossc3d73122016-08-05 17:19:36 -0700246 errs: []error{
Colin Cross2c628442016-10-07 17:13:10 -0700247 &BlueprintError{
Colin Cross4adc8192015-06-22 13:38:45 -0700248 Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
Colin Crossc3d73122016-08-05 17:19:36 -0700249 Pos: mkpos(30, 4, 9),
Colin Cross4adc8192015-06-22 13:38:45 -0700250 },
251 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700252 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800253
254 // Anonymous struct
Colin Crossc3d73122016-08-05 17:19:36 -0700255 {
256 input: `
257 m {
258 name: "abc",
259 nested: {
260 name: "def",
261 },
262 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800263 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700264 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700265 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800266 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700267 Nested struct {
268 EmbeddedStruct
269 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800270 }{
271 EmbeddedStruct: EmbeddedStruct{
Colin Crosse32cc802016-06-07 12:28:16 -0700272 Name: "abc",
273 },
274 Nested: struct {
275 EmbeddedStruct
276 }{
277 EmbeddedStruct: EmbeddedStruct{
278 Name: "def",
279 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800280 },
281 },
282 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800283 },
284
285 // Anonymous interface
Colin Crossc3d73122016-08-05 17:19:36 -0700286 {
287 input: `
288 m {
289 name: "abc",
290 nested: {
291 name: "def",
292 },
293 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800294 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700295 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700296 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800297 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700298 Nested struct {
299 EmbeddedInterface
300 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800301 }{
302 EmbeddedInterface: &struct{ Name string }{
Colin Crosse32cc802016-06-07 12:28:16 -0700303 Name: "abc",
304 },
305 Nested: struct {
306 EmbeddedInterface
307 }{
308 EmbeddedInterface: &struct{ Name string }{
309 Name: "def",
310 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800311 },
312 },
313 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800314 },
315
316 // Anonymous struct with name collision
Colin Crossc3d73122016-08-05 17:19:36 -0700317 {
318 input: `
319 m {
320 name: "abc",
321 nested: {
322 name: "def",
323 },
324 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800325 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700326 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700327 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800328 Name string
329 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700330 Nested struct {
331 Name string
332 EmbeddedStruct
333 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800334 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700335 Name: "abc",
Colin Cross9d1469d2015-11-20 17:03:25 -0800336 EmbeddedStruct: EmbeddedStruct{
Colin Crosse32cc802016-06-07 12:28:16 -0700337 Name: "abc",
338 },
339 Nested: struct {
340 Name string
341 EmbeddedStruct
342 }{
Colin Cross9d1469d2015-11-20 17:03:25 -0800343 Name: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700344 EmbeddedStruct: EmbeddedStruct{
345 Name: "def",
346 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800347 },
348 },
349 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800350 },
351
352 // Anonymous interface with name collision
Colin Crossc3d73122016-08-05 17:19:36 -0700353 {
354 input: `
355 m {
356 name: "abc",
357 nested: {
358 name: "def",
359 },
360 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800361 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700362 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700363 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800364 Name string
365 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700366 Nested struct {
367 Name string
368 EmbeddedInterface
369 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800370 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700371 Name: "abc",
Colin Cross9d1469d2015-11-20 17:03:25 -0800372 EmbeddedInterface: &struct{ Name string }{
Colin Crosse32cc802016-06-07 12:28:16 -0700373 Name: "abc",
374 },
375 Nested: struct {
376 Name string
377 EmbeddedInterface
378 }{
Colin Cross9d1469d2015-11-20 17:03:25 -0800379 Name: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700380 EmbeddedInterface: &struct{ Name string }{
381 Name: "def",
382 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800383 },
384 },
385 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800386 },
Colin Crosse32cc802016-06-07 12:28:16 -0700387
388 // Variables
Colin Crossc3d73122016-08-05 17:19:36 -0700389 {
390 input: `
391 list = ["abc"]
392 string = "def"
393 list_with_variable = [string]
394 m {
395 name: string,
396 list: list,
397 list2: list_with_variable,
398 }
Colin Crosse32cc802016-06-07 12:28:16 -0700399 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700400 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700401 struct {
402 Name string
403 List []string
404 List2 []string
405 }{
406 Name: "def",
407 List: []string{"abc"},
408 List2: []string{"def"},
409 },
410 },
Colin Crosse32cc802016-06-07 12:28:16 -0700411 },
412
413 // Multiple property structs
Colin Crossc3d73122016-08-05 17:19:36 -0700414 {
415 input: `
416 m {
417 nested: {
418 name: "abc",
419 }
Colin Crosse32cc802016-06-07 12:28:16 -0700420 }
Colin Crosse32cc802016-06-07 12:28:16 -0700421 `,
Colin Crossc3d73122016-08-05 17:19:36 -0700422 output: []interface{}{
Colin Crosse32cc802016-06-07 12:28:16 -0700423 struct {
424 Nested struct {
425 Name string
426 }
427 }{
428 Nested: struct{ Name string }{
429 Name: "abc",
430 },
431 },
432 struct {
433 Nested struct {
434 Name string
435 }
436 }{
437 Nested: struct{ Name string }{
438 Name: "abc",
439 },
440 },
441 struct {
442 }{},
443 },
Colin Crossc3d73122016-08-05 17:19:36 -0700444 },
445
446 // Nil pointer to struct
447 {
448 input: `
449 m {
450 nested: {
451 name: "abc",
452 }
453 }
454 `,
455 output: []interface{}{
456 struct {
457 Nested *struct {
458 Name string
459 }
460 }{
461 Nested: &struct{ Name string }{
462 Name: "abc",
463 },
464 },
465 },
466 empty: []interface{}{
467 &struct {
468 Nested *struct {
469 Name string
470 }
471 }{},
472 },
473 },
474
475 // Interface containing nil pointer to struct
476 {
477 input: `
478 m {
479 nested: {
480 name: "abc",
481 }
482 }
483 `,
484 output: []interface{}{
485 struct {
486 Nested interface{}
487 }{
488 Nested: &EmbeddedStruct{
489 Name: "abc",
490 },
491 },
492 },
493 empty: []interface{}{
494 &struct {
495 Nested interface{}
496 }{
497 Nested: (*EmbeddedStruct)(nil),
498 },
499 },
Colin Crosse32cc802016-06-07 12:28:16 -0700500 },
Colin Cross05b36072017-07-28 17:51:37 -0700501
502 // Factory set properties
503 {
504 input: `
505 m {
506 string: "abc",
507 string_ptr: "abc",
508 bool: false,
509 bool_ptr: false,
510 list: ["a", "b", "c"],
511 }
512 `,
513 output: []interface{}{
514 struct {
515 String string
516 String_ptr *string
517 Bool bool
518 Bool_ptr *bool
519 List []string
520 }{
521 String: "012abc",
522 String_ptr: proptools.StringPtr("abc"),
523 Bool: true,
524 Bool_ptr: proptools.BoolPtr(false),
525 List: []string{"0", "1", "2", "a", "b", "c"},
526 },
527 },
528 empty: []interface{}{
529 &struct {
530 String string
531 String_ptr *string
532 Bool bool
533 Bool_ptr *bool
534 List []string
535 }{
536 String: "012",
537 String_ptr: proptools.StringPtr("012"),
538 Bool: true,
539 Bool_ptr: proptools.BoolPtr(true),
540 List: []string{"0", "1", "2"},
541 },
542 },
543 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700544}
545
Colin Cross9d1469d2015-11-20 17:03:25 -0800546type EmbeddedStruct struct{ Name string }
547type EmbeddedInterface interface{}
548
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700549func TestUnpackProperties(t *testing.T) {
550 for _, testCase := range validUnpackTestCases {
551 r := bytes.NewBufferString(testCase.input)
Colin Crosse32cc802016-06-07 12:28:16 -0700552 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700553 if len(errs) != 0 {
554 t.Errorf("test case: %s", testCase.input)
555 t.Errorf("unexpected parse errors:")
556 for _, err := range errs {
557 t.Errorf(" %s", err)
558 }
559 t.FailNow()
560 }
561
Colin Crosse32cc802016-06-07 12:28:16 -0700562 for _, def := range file.Defs {
563 module, ok := def.(*parser.Module)
564 if !ok {
565 continue
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700566 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700567
Colin Crossc3d73122016-08-05 17:19:36 -0700568 var output []interface{}
569 if len(testCase.empty) > 0 {
570 output = testCase.empty
571 } else {
572 for _, p := range testCase.output {
573 output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
574 }
Colin Crosse32cc802016-06-07 12:28:16 -0700575 }
576 _, errs = unpackProperties(module.Properties, output...)
577 if len(errs) != 0 && len(testCase.errs) == 0 {
578 t.Errorf("test case: %s", testCase.input)
579 t.Errorf("unexpected unpack errors:")
580 for _, err := range errs {
581 t.Errorf(" %s", err)
582 }
583 t.FailNow()
584 } else if !reflect.DeepEqual(errs, testCase.errs) {
585 t.Errorf("test case: %s", testCase.input)
586 t.Errorf("incorrect errors:")
587 t.Errorf(" expected: %+v", testCase.errs)
588 t.Errorf(" got: %+v", errs)
589 }
590
591 if len(output) != len(testCase.output) {
592 t.Fatalf("incorrect number of property structs, expected %d got %d",
593 len(testCase.output), len(output))
594 }
595
596 for i := range output {
597 got := reflect.ValueOf(output[i]).Elem().Interface()
598 if !reflect.DeepEqual(got, testCase.output[i]) {
599 t.Errorf("test case: %s", testCase.input)
600 t.Errorf("incorrect output:")
601 t.Errorf(" expected: %+v", testCase.output[i])
602 t.Errorf(" got: %+v", got)
603 }
604 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700605 }
606 }
607}
Colin Cross017ed2e2016-05-31 15:53:32 -0700608
609func mkpos(offset, line, column int) scanner.Position {
610 return scanner.Position{
611 Offset: offset,
612 Line: line,
613 Column: column,
614 }
615}