blob: b33ae7905679ccd1773d7625215c59399032694b [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
30 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 `,
39 struct {
40 Name *string
41 Blank *string
42 Unset *string
43 }{
44 Name: proptools.StringPtr("abc"),
45 Blank: proptools.StringPtr(""),
46 Unset: nil,
47 },
48 nil,
49 },
50
51 {`
52 m {
53 name: "abc",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070054 }
55 `,
56 struct {
57 Name string
58 }{
59 Name: "abc",
60 },
Colin Cross4adc8192015-06-22 13:38:45 -070061 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -070062 },
63
64 {`
65 m {
66 isGood: true,
67 }
68 `,
69 struct {
70 IsGood bool
71 }{
72 IsGood: true,
73 },
Colin Cross4adc8192015-06-22 13:38:45 -070074 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -070075 },
76
77 {`
78 m {
Colin Cross80117682015-10-30 15:53:55 -070079 isGood: true,
80 isBad: false,
81 }
82 `,
83 struct {
84 IsGood *bool
85 IsBad *bool
86 IsUgly *bool
87 }{
88 IsGood: proptools.BoolPtr(true),
89 IsBad: proptools.BoolPtr(false),
90 IsUgly: nil,
91 },
92 nil,
93 },
94
95 {`
96 m {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097 stuff: ["asdf", "jkl;", "qwert",
Colin Crossecca05e2015-10-31 21:32:08 -070098 "uiop", "bnm,"],
99 empty: []
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100 }
101 `,
102 struct {
103 Stuff []string
Colin Crossecca05e2015-10-31 21:32:08 -0700104 Empty []string
105 Nil []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700106 }{
107 Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
Colin Crossecca05e2015-10-31 21:32:08 -0700108 Empty: []string{},
109 Nil: nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700110 },
Colin Cross4adc8192015-06-22 13:38:45 -0700111 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700112 },
113
114 {`
115 m {
Jamie Gennis87622922014-09-30 11:38:25 -0700116 nested: {
117 name: "abc",
118 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119 }
120 `,
121 struct {
122 Nested struct {
123 Name string
124 }
125 }{
126 Nested: struct{ Name string }{
127 Name: "abc",
128 },
129 },
Colin Cross4adc8192015-06-22 13:38:45 -0700130 nil,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700131 },
132
133 {`
134 m {
Jamie Gennis87622922014-09-30 11:38:25 -0700135 nested: {
136 name: "def",
137 }
138 }
139 `,
140 struct {
141 Nested interface{}
142 }{
143 Nested: &struct{ Name string }{
144 Name: "def",
145 },
146 },
Colin Cross4adc8192015-06-22 13:38:45 -0700147 nil,
Jamie Gennis87622922014-09-30 11:38:25 -0700148 },
149
150 {`
151 m {
152 nested: {
153 foo: "abc",
154 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700155 bar: false,
156 baz: ["def", "ghi"],
157 }
158 `,
159 struct {
160 Nested struct {
161 Foo string
162 }
163 Bar bool
164 Baz []string
165 }{
166 Nested: struct{ Foo string }{
167 Foo: "abc",
168 },
169 Bar: false,
170 Baz: []string{"def", "ghi"},
171 },
Colin Cross4adc8192015-06-22 13:38:45 -0700172 nil,
173 },
174
175 {`
176 m {
177 nested: {
178 foo: "abc",
179 },
180 bar: false,
181 baz: ["def", "ghi"],
182 }
183 `,
184 struct {
185 Nested struct {
186 Foo string `allowNested:"true"`
187 } `blueprint:"filter(allowNested:\"true\")"`
188 Bar bool
189 Baz []string
190 }{
191 Nested: struct {
192 Foo string `allowNested:"true"`
193 }{
194 Foo: "abc",
195 },
196 Bar: false,
197 Baz: []string{"def", "ghi"},
198 },
199 nil,
200 },
201
202 {`
203 m {
204 nested: {
205 foo: "abc",
206 },
207 bar: false,
208 baz: ["def", "ghi"],
209 }
210 `,
211 struct {
212 Nested struct {
213 Foo string
214 } `blueprint:"filter(allowNested:\"true\")"`
215 Bar bool
216 Baz []string
217 }{
218 Nested: struct{ Foo string }{
219 Foo: "",
220 },
221 Bar: false,
222 Baz: []string{"def", "ghi"},
223 },
224 []error{
225 &Error{
226 Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
227 Pos: scanner.Position{"", 27, 4, 8},
228 },
229 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700230 },
Colin Cross9d1469d2015-11-20 17:03:25 -0800231
232 // Anonymous struct
233 {`
234 m {
235 name: "abc",
236 nested: {
237 name: "def",
238 },
239 }
240 `,
241 struct {
242 EmbeddedStruct
243 Nested struct {
244 EmbeddedStruct
245 }
246 }{
247 EmbeddedStruct: EmbeddedStruct{
248 Name: "abc",
249 },
250 Nested: struct {
251 EmbeddedStruct
252 }{
253 EmbeddedStruct: EmbeddedStruct{
254 Name: "def",
255 },
256 },
257 },
258 nil,
259 },
260
261 // Anonymous interface
262 {`
263 m {
264 name: "abc",
265 nested: {
266 name: "def",
267 },
268 }
269 `,
270 struct {
271 EmbeddedInterface
272 Nested struct {
273 EmbeddedInterface
274 }
275 }{
276 EmbeddedInterface: &struct{ Name string }{
277 Name: "abc",
278 },
279 Nested: struct {
280 EmbeddedInterface
281 }{
282 EmbeddedInterface: &struct{ Name string }{
283 Name: "def",
284 },
285 },
286 },
287 nil,
288 },
289
290 // Anonymous struct with name collision
291 {`
292 m {
293 name: "abc",
294 nested: {
295 name: "def",
296 },
297 }
298 `,
299 struct {
300 Name string
301 EmbeddedStruct
302 Nested struct {
303 Name string
304 EmbeddedStruct
305 }
306 }{
307 Name: "abc",
308 EmbeddedStruct: EmbeddedStruct{
309 Name: "abc",
310 },
311 Nested: struct {
312 Name string
313 EmbeddedStruct
314 }{
315 Name: "def",
316 EmbeddedStruct: EmbeddedStruct{
317 Name: "def",
318 },
319 },
320 },
321 nil,
322 },
323
324 // Anonymous interface with name collision
325 {`
326 m {
327 name: "abc",
328 nested: {
329 name: "def",
330 },
331 }
332 `,
333 struct {
334 Name string
335 EmbeddedInterface
336 Nested struct {
337 Name string
338 EmbeddedInterface
339 }
340 }{
341 Name: "abc",
342 EmbeddedInterface: &struct{ Name string }{
343 Name: "abc",
344 },
345 Nested: struct {
346 Name string
347 EmbeddedInterface
348 }{
349 Name: "def",
350 EmbeddedInterface: &struct{ Name string }{
351 Name: "def",
352 },
353 },
354 },
355 nil,
356 },
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700357}
358
Colin Cross9d1469d2015-11-20 17:03:25 -0800359type EmbeddedStruct struct{ Name string }
360type EmbeddedInterface interface{}
361
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700362func TestUnpackProperties(t *testing.T) {
363 for _, testCase := range validUnpackTestCases {
364 r := bytes.NewBufferString(testCase.input)
Colin Crossd1facc12015-01-08 14:56:03 -0800365 file, errs := parser.Parse("", r, nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700366 if len(errs) != 0 {
367 t.Errorf("test case: %s", testCase.input)
368 t.Errorf("unexpected parse errors:")
369 for _, err := range errs {
370 t.Errorf(" %s", err)
371 }
372 t.FailNow()
373 }
374
Colin Crossd1facc12015-01-08 14:56:03 -0800375 module := file.Defs[0].(*parser.Module)
Jamie Gennis87622922014-09-30 11:38:25 -0700376 properties := proptools.CloneProperties(reflect.ValueOf(testCase.output))
377 proptools.ZeroProperties(properties.Elem())
378 _, errs = unpackProperties(module.Properties, properties.Interface())
Colin Cross4adc8192015-06-22 13:38:45 -0700379 if len(errs) != 0 && len(testCase.errs) == 0 {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700380 t.Errorf("test case: %s", testCase.input)
381 t.Errorf("unexpected unpack errors:")
382 for _, err := range errs {
383 t.Errorf(" %s", err)
384 }
385 t.FailNow()
Colin Cross4adc8192015-06-22 13:38:45 -0700386 } else if !reflect.DeepEqual(errs, testCase.errs) {
387 t.Errorf("test case: %s", testCase.input)
388 t.Errorf("incorrect errors:")
389 t.Errorf(" expected: %+v", testCase.errs)
390 t.Errorf(" got: %+v", errs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700391 }
392
393 output := properties.Elem().Interface()
394 if !reflect.DeepEqual(output, testCase.output) {
395 t.Errorf("test case: %s", testCase.input)
396 t.Errorf("incorrect output:")
397 t.Errorf(" expected: %+v", testCase.output)
398 t.Errorf(" got: %+v", output)
399 }
400 }
401}