blob: 1a0ba7b93a22fd516fece68140fdc9e5c02d0b30 [file] [log] [blame]
Jingwen Chenbf61afb2021-05-06 13:31:18 +00001// Copyright 2021 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
Sam Delmerico7f889562022-03-25 14:55:40 +000015package android
Jingwen Chenbf61afb2021-05-06 13:31:18 +000016
17import (
Sam Delmerico7f889562022-03-25 14:55:40 +000018 "android/soong/bazel"
Jingwen Chenbf61afb2021-05-06 13:31:18 +000019 "testing"
20)
21
22func TestExpandVars(t *testing.T) {
Sam Delmerico7f889562022-03-25 14:55:40 +000023 android_arm64_config := TestConfig("out", nil, "", nil)
24 android_arm64_config.BuildOS = Android
25 android_arm64_config.BuildArch = Arm64
Chris Parsons3b1f83d2021-10-14 14:08:38 -040026
Jingwen Chenbf61afb2021-05-06 13:31:18 +000027 testCases := []struct {
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000028 description string
Sam Delmerico7f889562022-03-25 14:55:40 +000029 config Config
30 stringScope ExportedStringVariables
31 stringListScope ExportedStringListVariables
32 configVars ExportedConfigDependingVariables
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000033 toExpand string
34 expectedValues []string
Jingwen Chenbf61afb2021-05-06 13:31:18 +000035 }{
36 {
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000037 description: "no expansion for non-interpolated value",
38 toExpand: "foo",
39 expectedValues: []string{"foo"},
40 },
41 {
42 description: "single level expansion for string var",
Sam Delmerico7f889562022-03-25 14:55:40 +000043 stringScope: ExportedStringVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000044 "foo": "bar",
Jingwen Chenbf61afb2021-05-06 13:31:18 +000045 },
46 toExpand: "${foo}",
47 expectedValues: []string{"bar"},
48 },
49 {
Liz Kammere8303bd2022-02-16 09:02:48 -050050 description: "single level expansion with short-name for string var",
Sam Delmerico7f889562022-03-25 14:55:40 +000051 stringScope: ExportedStringVariables{
Liz Kammere8303bd2022-02-16 09:02:48 -050052 "foo": "bar",
53 },
54 toExpand: "${config.foo}",
55 expectedValues: []string{"bar"},
56 },
57 {
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000058 description: "single level expansion string list var",
Sam Delmerico7f889562022-03-25 14:55:40 +000059 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000060 "foo": []string{"bar"},
61 },
62 toExpand: "${foo}",
63 expectedValues: []string{"bar"},
64 },
65 {
66 description: "mixed level expansion for string list var",
Sam Delmerico7f889562022-03-25 14:55:40 +000067 stringScope: ExportedStringVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000068 "foo": "${bar}",
69 "qux": "hello",
70 },
Sam Delmerico7f889562022-03-25 14:55:40 +000071 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000072 "bar": []string{"baz", "${qux}"},
73 },
74 toExpand: "${foo}",
Chris Parsons3b1f83d2021-10-14 14:08:38 -040075 expectedValues: []string{"baz hello"},
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000076 },
77 {
Jingwen Chenbf61afb2021-05-06 13:31:18 +000078 description: "double level expansion",
Sam Delmerico7f889562022-03-25 14:55:40 +000079 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000080 "foo": []string{"${bar}"},
81 "bar": []string{"baz"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +000082 },
83 toExpand: "${foo}",
84 expectedValues: []string{"baz"},
85 },
86 {
87 description: "double level expansion with a literal",
Sam Delmerico7f889562022-03-25 14:55:40 +000088 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000089 "a": []string{"${b}", "c"},
90 "b": []string{"d"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +000091 },
92 toExpand: "${a}",
Chris Parsons3b1f83d2021-10-14 14:08:38 -040093 expectedValues: []string{"d c"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +000094 },
95 {
96 description: "double level expansion, with two variables in a string",
Sam Delmerico7f889562022-03-25 14:55:40 +000097 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +000098 "a": []string{"${b} ${c}"},
99 "b": []string{"d"},
100 "c": []string{"e"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000101 },
102 toExpand: "${a}",
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400103 expectedValues: []string{"d e"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000104 },
105 {
106 description: "triple level expansion with two variables in a string",
Sam Delmerico7f889562022-03-25 14:55:40 +0000107 stringListScope: ExportedStringListVariables{
Jingwen Chen51a1e1c2021-05-20 13:40:14 +0000108 "a": []string{"${b} ${c}"},
109 "b": []string{"${c}", "${d}"},
110 "c": []string{"${d}"},
111 "d": []string{"foo"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000112 },
113 toExpand: "${a}",
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400114 expectedValues: []string{"foo foo foo"},
115 },
116 {
117 description: "expansion with config depending vars",
Sam Delmerico7f889562022-03-25 14:55:40 +0000118 configVars: ExportedConfigDependingVariables{
119 "a": func(c Config) string { return c.BuildOS.String() },
120 "b": func(c Config) string { return c.BuildArch.String() },
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400121 },
122 config: android_arm64_config,
123 toExpand: "${a}-${b}",
124 expectedValues: []string{"android-arm64"},
125 },
126 {
127 description: "double level multi type expansion",
Sam Delmerico7f889562022-03-25 14:55:40 +0000128 stringListScope: ExportedStringListVariables{
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400129 "platform": []string{"${os}-${arch}"},
130 "const": []string{"const"},
131 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000132 configVars: ExportedConfigDependingVariables{
133 "os": func(c Config) string { return c.BuildOS.String() },
134 "arch": func(c Config) string { return c.BuildArch.String() },
135 "foo": func(c Config) string { return "foo" },
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400136 },
137 config: android_arm64_config,
138 toExpand: "${const}/${platform}/${foo}",
139 expectedValues: []string{"const/android-arm64/foo"},
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000140 },
141 }
142
143 for _, testCase := range testCases {
144 t.Run(testCase.description, func(t *testing.T) {
Chris Parsons3b1f83d2021-10-14 14:08:38 -0400145 output, _ := expandVar(testCase.config, testCase.toExpand, testCase.stringScope, testCase.stringListScope, testCase.configVars)
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000146 if len(output) != len(testCase.expectedValues) {
147 t.Errorf("Expected %d values, got %d", len(testCase.expectedValues), len(output))
148 }
149 for i, actual := range output {
150 expectedValue := testCase.expectedValues[i]
151 if actual != expectedValue {
152 t.Errorf("Actual value '%s' doesn't match expected value '%s'", actual, expectedValue)
153 }
154 }
155 })
156 }
157}
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400158
159func TestBazelToolchainVars(t *testing.T) {
160 testCases := []struct {
161 name string
Sam Delmerico7f889562022-03-25 14:55:40 +0000162 config Config
163 vars ExportedVariables
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400164 expectedOut string
165 }{
166 {
167 name: "exports strings",
Sam Delmerico7f889562022-03-25 14:55:40 +0000168 vars: ExportedVariables{
169 exportedStringVars: ExportedStringVariables{
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400170 "a": "b",
171 "c": "d",
172 },
173 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000174 expectedOut: bazel.GeneratedBazelFileWarning + `
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400175
176_a = "b"
177
178_c = "d"
179
180constants = struct(
181 a = _a,
182 c = _c,
183)`,
184 },
185 {
186 name: "exports string lists",
Sam Delmerico7f889562022-03-25 14:55:40 +0000187 vars: ExportedVariables{
188 exportedStringListVars: ExportedStringListVariables{
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400189 "a": []string{"b1", "b2"},
190 "c": []string{"d1", "d2"},
191 },
192 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000193 expectedOut: bazel.GeneratedBazelFileWarning + `
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400194
195_a = [
196 "b1",
197 "b2",
198]
199
200_c = [
201 "d1",
202 "d2",
203]
204
205constants = struct(
206 a = _a,
207 c = _c,
208)`,
209 },
210 {
211 name: "exports string lists dicts",
Sam Delmerico7f889562022-03-25 14:55:40 +0000212 vars: ExportedVariables{
213 exportedStringListDictVars: ExportedStringListDictVariables{
214 "a": map[string][]string{"b1": {"b2"}},
215 "c": map[string][]string{"d1": {"d2"}},
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400216 },
217 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000218 expectedOut: bazel.GeneratedBazelFileWarning + `
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400219
220_a = {
Liz Kammer72beb342022-02-03 08:42:10 -0500221 "b1": ["b2"],
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400222}
223
224_c = {
Liz Kammer72beb342022-02-03 08:42:10 -0500225 "d1": ["d2"],
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400226}
227
228constants = struct(
229 a = _a,
230 c = _c,
231)`,
232 },
233 {
Liz Kammere8303bd2022-02-16 09:02:48 -0500234 name: "exports dict with var refs",
Sam Delmerico7f889562022-03-25 14:55:40 +0000235 vars: ExportedVariables{
236 exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
Liz Kammere8303bd2022-02-16 09:02:48 -0500237 "a": map[string]string{"b1": "${b2}"},
238 "c": map[string]string{"d1": "${config.d2}"},
239 },
240 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000241 expectedOut: bazel.GeneratedBazelFileWarning + `
Liz Kammere8303bd2022-02-16 09:02:48 -0500242
243_a = {
244 "b1": _b2,
245}
246
247_c = {
248 "d1": _d2,
249}
250
251constants = struct(
252 a = _a,
253 c = _c,
254)`,
255 },
256 {
257 name: "sorts across types with variable references last",
Sam Delmerico7f889562022-03-25 14:55:40 +0000258 vars: ExportedVariables{
259 exportedStringVars: ExportedStringVariables{
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400260 "b": "b-val",
261 "d": "d-val",
262 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000263 exportedStringListVars: ExportedStringListVariables{
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400264 "c": []string{"c-val"},
265 "e": []string{"e-val"},
266 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000267 exportedStringListDictVars: ExportedStringListDictVariables{
268 "a": map[string][]string{"a1": {"a2"}},
269 "f": map[string][]string{"f1": {"f2"}},
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400270 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000271 exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
Liz Kammere8303bd2022-02-16 09:02:48 -0500272 "aa": map[string]string{"b1": "${b}"},
273 "cc": map[string]string{"d1": "${config.d}"},
274 },
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400275 },
Sam Delmerico7f889562022-03-25 14:55:40 +0000276 expectedOut: bazel.GeneratedBazelFileWarning + `
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400277
278_a = {
Liz Kammer72beb342022-02-03 08:42:10 -0500279 "a1": ["a2"],
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400280}
281
282_b = "b-val"
283
Liz Kammer72beb342022-02-03 08:42:10 -0500284_c = ["c-val"]
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400285
286_d = "d-val"
287
Liz Kammer72beb342022-02-03 08:42:10 -0500288_e = ["e-val"]
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400289
290_f = {
Liz Kammer72beb342022-02-03 08:42:10 -0500291 "f1": ["f2"],
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400292}
293
Liz Kammere8303bd2022-02-16 09:02:48 -0500294_aa = {
295 "b1": _b,
296}
297
298_cc = {
299 "d1": _d,
300}
301
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400302constants = struct(
303 a = _a,
304 b = _b,
305 c = _c,
306 d = _d,
307 e = _e,
308 f = _f,
Liz Kammere8303bd2022-02-16 09:02:48 -0500309 aa = _aa,
310 cc = _cc,
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400311)`,
312 },
313 }
314
315 for _, tc := range testCases {
316 t.Run(tc.name, func(t *testing.T) {
Sam Delmerico7f889562022-03-25 14:55:40 +0000317 out := BazelToolchainVars(tc.config, tc.vars)
Liz Kammer82ad8cc2021-08-02 10:41:48 -0400318 if out != tc.expectedOut {
319 t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out)
320 }
321 })
322 }
323}
Sam Delmerico932c01c2022-03-25 16:33:26 +0000324
325func TestSplitStringKeepingQuotedSubstring(t *testing.T) {
326 testCases := []struct {
327 description string
328 s string
329 delimiter byte
330 split []string
331 }{
332 {
333 description: "empty string returns single empty string",
334 s: "",
335 delimiter: ' ',
336 split: []string{
337 "",
338 },
339 },
340 {
341 description: "string with single space returns two empty strings",
342 s: " ",
343 delimiter: ' ',
344 split: []string{
345 "",
346 "",
347 },
348 },
349 {
350 description: "string with two spaces returns three empty strings",
351 s: " ",
352 delimiter: ' ',
353 split: []string{
354 "",
355 "",
356 "",
357 },
358 },
359 {
360 description: "string with four words returns four word string",
361 s: "hello world with words",
362 delimiter: ' ',
363 split: []string{
364 "hello",
365 "world",
366 "with",
367 "words",
368 },
369 },
370 {
371 description: "string with words and nested quote returns word strings and quote string",
372 s: `hello "world with" words`,
373 delimiter: ' ',
374 split: []string{
375 "hello",
376 `"world with"`,
377 "words",
378 },
379 },
380 {
381 description: "string with escaped quote inside real quotes",
382 s: `hello \"world "with\" words"`,
383 delimiter: ' ',
384 split: []string{
385 "hello",
386 `"world`,
387 `"with" words"`,
388 },
389 },
390 {
391 description: "string with words and escaped quotes returns word strings",
392 s: `hello \"world with\" words`,
393 delimiter: ' ',
394 split: []string{
395 "hello",
396 `"world`,
397 `with"`,
398 "words",
399 },
400 },
401 {
402 description: "string which is single quoted substring returns only substring",
403 s: `"hello world with words"`,
404 delimiter: ' ',
405 split: []string{
406 `"hello world with words"`,
407 },
408 },
409 {
410 description: "string starting with quote returns quoted string",
411 s: `"hello world with" words`,
412 delimiter: ' ',
413 split: []string{
414 `"hello world with"`,
415 "words",
416 },
417 },
418 {
419 description: "string with starting quote and no ending quote returns quote to end of string",
420 s: `hello "world with words`,
421 delimiter: ' ',
422 split: []string{
423 "hello",
424 `"world with words`,
425 },
426 },
427 {
428 description: "quoted string is treated as a single \"word\" unless separated by delimiter",
429 s: `hello "world"with words`,
430 delimiter: ' ',
431 split: []string{
432 "hello",
433 `"world"with`,
434 "words",
435 },
436 },
437 }
438
439 for _, tc := range testCases {
440 t.Run(tc.description, func(t *testing.T) {
441 split := splitStringKeepingQuotedSubstring(tc.s, tc.delimiter)
442 if len(split) != len(tc.split) {
443 t.Fatalf("number of split string elements (%d) differs from expected (%d): split string (%v), expected (%v)",
444 len(split), len(tc.split), split, tc.split,
445 )
446 }
447 for i := range split {
448 if split[i] != tc.split[i] {
449 t.Errorf("split string element (%d), %v, differs from expected, %v", i, split[i], tc.split[i])
450 }
451 }
452 })
453 }
454}