blob: 7b314ddc7164d960c056d1d58ac1089d2584158a [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 Cross4adc8192015-06-22 13:38:45 -070031 errs []error
Jamie Gennis1bc967e2014-05-27 16:34:41 -070032}{
33 {`
34 m {
35 name: "abc",
Colin Cross80117682015-10-30 15:53:55 -070036 blank: "",
37 }
38 `,
Colin Crosse32cc802016-06-07 12:28:16 -070039 []interface{}{
40 struct {
41 Name *string
42 Blank *string
43 Unset *string
44 }{
45 Name: proptools.StringPtr("abc"),
46 Blank: proptools.StringPtr(""),
47 Unset: nil,
48 },
Colin Cross80117682015-10-30 15:53:55 -070049 },
50 nil,
51 },
52
53 {`
54 m {
55 name: "abc",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070056 }
57 `,
Colin Crosse32cc802016-06-07 12:28:16 -070058 []interface{}{
59 struct {
60 Name string
61 }{
62 Name: "abc",
63 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064 },
Colin Cross4adc8192015-06-22 13:38:45 -070065 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066 },
67
68 {`
69 m {
70 isGood: true,
71 }
72 `,
Colin Crosse32cc802016-06-07 12:28:16 -070073 []interface{}{
74 struct {
75 IsGood bool
76 }{
77 IsGood: true,
78 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -070079 },
Colin Cross4adc8192015-06-22 13:38:45 -070080 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -070081 },
82
83 {`
84 m {
Colin Cross80117682015-10-30 15:53:55 -070085 isGood: true,
86 isBad: false,
87 }
88 `,
Colin Crosse32cc802016-06-07 12:28:16 -070089 []interface{}{
90 struct {
91 IsGood *bool
92 IsBad *bool
93 IsUgly *bool
94 }{
95 IsGood: proptools.BoolPtr(true),
96 IsBad: proptools.BoolPtr(false),
97 IsUgly: nil,
98 },
Colin Cross80117682015-10-30 15:53:55 -070099 },
100 nil,
101 },
102
103 {`
104 m {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105 stuff: ["asdf", "jkl;", "qwert",
Colin Crossecca05e2015-10-31 21:32:08 -0700106 "uiop", "bnm,"],
107 empty: []
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700108 }
109 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700110 []interface{}{
111 struct {
112 Stuff []string
113 Empty []string
114 Nil []string
115 }{
116 Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
117 Empty: []string{},
118 Nil: nil,
119 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700120 },
Colin Cross4adc8192015-06-22 13:38:45 -0700121 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122 },
123
124 {`
125 m {
Jamie Gennis87622922014-09-30 11:38:25 -0700126 nested: {
127 name: "abc",
128 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700129 }
130 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700131 []interface{}{
132 struct {
133 Nested struct {
134 Name string
135 }
136 }{
137 Nested: struct{ Name string }{
138 Name: "abc",
139 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700140 },
141 },
Colin Cross4adc8192015-06-22 13:38:45 -0700142 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700143 },
144
145 {`
146 m {
Jamie Gennis87622922014-09-30 11:38:25 -0700147 nested: {
148 name: "def",
149 }
150 }
151 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700152 []interface{}{
153 struct {
154 Nested interface{}
Colin Cross4adc8192015-06-22 13:38:45 -0700155 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700156 Nested: &struct{ Name string }{
157 Name: "def",
158 },
Colin Cross4adc8192015-06-22 13:38:45 -0700159 },
Colin Cross4adc8192015-06-22 13:38:45 -0700160 },
161 nil,
162 },
163
164 {`
165 m {
166 nested: {
167 foo: "abc",
168 },
169 bar: false,
170 baz: ["def", "ghi"],
171 }
172 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700173 []interface{}{
174 struct {
175 Nested struct {
176 Foo string
177 }
178 Bar bool
179 Baz []string
180 }{
181 Nested: struct{ Foo string }{
182 Foo: "abc",
183 },
184 Bar: false,
185 Baz: []string{"def", "ghi"},
Colin Cross4adc8192015-06-22 13:38:45 -0700186 },
Colin Crosse32cc802016-06-07 12:28:16 -0700187 },
188 nil,
189 },
190
191 {`
192 m {
193 nested: {
194 foo: "abc",
195 },
196 bar: false,
197 baz: ["def", "ghi"],
198 }
199 `,
200 []interface{}{
201 struct {
202 Nested struct {
203 Foo string `allowNested:"true"`
204 } `blueprint:"filter(allowNested:\"true\")"`
205 Bar bool
206 Baz []string
207 }{
208 Nested: struct {
209 Foo string `allowNested:"true"`
210 }{
211 Foo: "abc",
212 },
213 Bar: false,
214 Baz: []string{"def", "ghi"},
215 },
216 },
217 nil,
218 },
219
220 {`
221 m {
222 nested: {
223 foo: "abc",
224 },
225 bar: false,
226 baz: ["def", "ghi"],
227 }
228 `,
229 []interface{}{
230 struct {
231 Nested struct {
232 Foo string
233 } `blueprint:"filter(allowNested:\"true\")"`
234 Bar bool
235 Baz []string
236 }{
237 Nested: struct{ Foo string }{
238 Foo: "",
239 },
240 Bar: false,
241 Baz: []string{"def", "ghi"},
242 },
Colin Cross4adc8192015-06-22 13:38:45 -0700243 },
244 []error{
245 &Error{
246 Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
Colin Cross017ed2e2016-05-31 15:53:32 -0700247 Pos: mkpos(27, 4, 8),
Colin Cross4adc8192015-06-22 13:38:45 -0700248 },
249 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700250 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800251
252 // Anonymous struct
253 {`
254 m {
255 name: "abc",
256 nested: {
257 name: "def",
258 },
259 }
260 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700261 []interface{}{
262 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800263 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700264 Nested struct {
265 EmbeddedStruct
266 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800267 }{
268 EmbeddedStruct: EmbeddedStruct{
Colin Crosse32cc802016-06-07 12:28:16 -0700269 Name: "abc",
270 },
271 Nested: struct {
272 EmbeddedStruct
273 }{
274 EmbeddedStruct: EmbeddedStruct{
275 Name: "def",
276 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800277 },
278 },
279 },
280 nil,
281 },
282
283 // Anonymous interface
284 {`
285 m {
286 name: "abc",
287 nested: {
288 name: "def",
289 },
290 }
291 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700292 []interface{}{
293 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800294 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700295 Nested struct {
296 EmbeddedInterface
297 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800298 }{
299 EmbeddedInterface: &struct{ Name string }{
Colin Crosse32cc802016-06-07 12:28:16 -0700300 Name: "abc",
301 },
302 Nested: struct {
303 EmbeddedInterface
304 }{
305 EmbeddedInterface: &struct{ Name string }{
306 Name: "def",
307 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800308 },
309 },
310 },
311 nil,
312 },
313
314 // Anonymous struct with name collision
315 {`
316 m {
317 name: "abc",
318 nested: {
319 name: "def",
320 },
321 }
322 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700323 []interface{}{
324 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800325 Name string
326 EmbeddedStruct
Colin Crosse32cc802016-06-07 12:28:16 -0700327 Nested struct {
328 Name string
329 EmbeddedStruct
330 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800331 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700332 Name: "abc",
Colin Cross9d1469d2015-11-20 17:03:25 -0800333 EmbeddedStruct: EmbeddedStruct{
Colin Crosse32cc802016-06-07 12:28:16 -0700334 Name: "abc",
335 },
336 Nested: struct {
337 Name string
338 EmbeddedStruct
339 }{
Colin Cross9d1469d2015-11-20 17:03:25 -0800340 Name: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700341 EmbeddedStruct: EmbeddedStruct{
342 Name: "def",
343 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800344 },
345 },
346 },
347 nil,
348 },
349
350 // Anonymous interface with name collision
351 {`
352 m {
353 name: "abc",
354 nested: {
355 name: "def",
356 },
357 }
358 `,
Colin Crosse32cc802016-06-07 12:28:16 -0700359 []interface{}{
360 struct {
Colin Cross9d1469d2015-11-20 17:03:25 -0800361 Name string
362 EmbeddedInterface
Colin Crosse32cc802016-06-07 12:28:16 -0700363 Nested struct {
364 Name string
365 EmbeddedInterface
366 }
Colin Cross9d1469d2015-11-20 17:03:25 -0800367 }{
Colin Crosse32cc802016-06-07 12:28:16 -0700368 Name: "abc",
Colin Cross9d1469d2015-11-20 17:03:25 -0800369 EmbeddedInterface: &struct{ Name string }{
Colin Crosse32cc802016-06-07 12:28:16 -0700370 Name: "abc",
371 },
372 Nested: struct {
373 Name string
374 EmbeddedInterface
375 }{
Colin Cross9d1469d2015-11-20 17:03:25 -0800376 Name: "def",
Colin Crosse32cc802016-06-07 12:28:16 -0700377 EmbeddedInterface: &struct{ Name string }{
378 Name: "def",
379 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800380 },
381 },
382 },
383 nil,
384 },
Colin Crosse32cc802016-06-07 12:28:16 -0700385
386 // Variables
387 {`
388 list = ["abc"]
389 string = "def"
390 list_with_variable = [string]
391 m {
392 name: string,
393 list: list,
394 list2: list_with_variable,
395 }
396 `,
397 []interface{}{
398 struct {
399 Name string
400 List []string
401 List2 []string
402 }{
403 Name: "def",
404 List: []string{"abc"},
405 List2: []string{"def"},
406 },
407 },
408 nil,
409 },
410
411 // Multiple property structs
412 {`
413 m {
414 nested: {
415 name: "abc",
416 }
417 }
418 `,
419 []interface{}{
420 struct {
421 Nested struct {
422 Name string
423 }
424 }{
425 Nested: struct{ Name string }{
426 Name: "abc",
427 },
428 },
429 struct {
430 Nested struct {
431 Name string
432 }
433 }{
434 Nested: struct{ Name string }{
435 Name: "abc",
436 },
437 },
438 struct {
439 }{},
440 },
441 nil,
442 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700443}
444
Colin Cross9d1469d2015-11-20 17:03:25 -0800445type EmbeddedStruct struct{ Name string }
446type EmbeddedInterface interface{}
447
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700448func TestUnpackProperties(t *testing.T) {
449 for _, testCase := range validUnpackTestCases {
450 r := bytes.NewBufferString(testCase.input)
Colin Crosse32cc802016-06-07 12:28:16 -0700451 file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700452 if len(errs) != 0 {
453 t.Errorf("test case: %s", testCase.input)
454 t.Errorf("unexpected parse errors:")
455 for _, err := range errs {
456 t.Errorf(" %s", err)
457 }
458 t.FailNow()
459 }
460
Colin Crosse32cc802016-06-07 12:28:16 -0700461 for _, def := range file.Defs {
462 module, ok := def.(*parser.Module)
463 if !ok {
464 continue
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700465 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700466
Colin Crosse32cc802016-06-07 12:28:16 -0700467 output := []interface{}{}
468 for _, p := range testCase.output {
469 output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
470 }
471 _, errs = unpackProperties(module.Properties, output...)
472 if len(errs) != 0 && len(testCase.errs) == 0 {
473 t.Errorf("test case: %s", testCase.input)
474 t.Errorf("unexpected unpack errors:")
475 for _, err := range errs {
476 t.Errorf(" %s", err)
477 }
478 t.FailNow()
479 } else if !reflect.DeepEqual(errs, testCase.errs) {
480 t.Errorf("test case: %s", testCase.input)
481 t.Errorf("incorrect errors:")
482 t.Errorf(" expected: %+v", testCase.errs)
483 t.Errorf(" got: %+v", errs)
484 }
485
486 if len(output) != len(testCase.output) {
487 t.Fatalf("incorrect number of property structs, expected %d got %d",
488 len(testCase.output), len(output))
489 }
490
491 for i := range output {
492 got := reflect.ValueOf(output[i]).Elem().Interface()
493 if !reflect.DeepEqual(got, testCase.output[i]) {
494 t.Errorf("test case: %s", testCase.input)
495 t.Errorf("incorrect output:")
496 t.Errorf(" expected: %+v", testCase.output[i])
497 t.Errorf(" got: %+v", got)
498 }
499 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700500 }
501 }
502}
Colin Cross017ed2e2016-05-31 15:53:32 -0700503
504func mkpos(offset, line, column int) scanner.Position {
505 return scanner.Position{
506 Offset: offset,
507 Line: line,
508 Column: column,
509 }
510}