123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- // Copyright 2021 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package android
- import (
- "android/soong/bazel"
- "testing"
- )
- func TestExpandVars(t *testing.T) {
- android_arm64_config := TestConfig("out", nil, "", nil)
- android_arm64_config.BuildOS = Android
- android_arm64_config.BuildArch = Arm64
- testCases := []struct {
- description string
- config Config
- stringScope ExportedStringVariables
- stringListScope ExportedStringListVariables
- configVars ExportedConfigDependingVariables
- toExpand string
- expectedValues []string
- }{
- {
- description: "no expansion for non-interpolated value",
- toExpand: "foo",
- expectedValues: []string{"foo"},
- },
- {
- description: "single level expansion for string var",
- stringScope: ExportedStringVariables{
- "foo": "bar",
- },
- toExpand: "${foo}",
- expectedValues: []string{"bar"},
- },
- {
- description: "single level expansion with short-name for string var",
- stringScope: ExportedStringVariables{
- "foo": "bar",
- },
- toExpand: "${config.foo}",
- expectedValues: []string{"bar"},
- },
- {
- description: "single level expansion string list var",
- stringListScope: ExportedStringListVariables{
- "foo": []string{"bar"},
- },
- toExpand: "${foo}",
- expectedValues: []string{"bar"},
- },
- {
- description: "mixed level expansion for string list var",
- stringScope: ExportedStringVariables{
- "foo": "${bar}",
- "qux": "hello",
- },
- stringListScope: ExportedStringListVariables{
- "bar": []string{"baz", "${qux}"},
- },
- toExpand: "${foo}",
- expectedValues: []string{"baz hello"},
- },
- {
- description: "double level expansion",
- stringListScope: ExportedStringListVariables{
- "foo": []string{"${bar}"},
- "bar": []string{"baz"},
- },
- toExpand: "${foo}",
- expectedValues: []string{"baz"},
- },
- {
- description: "double level expansion with a literal",
- stringListScope: ExportedStringListVariables{
- "a": []string{"${b}", "c"},
- "b": []string{"d"},
- },
- toExpand: "${a}",
- expectedValues: []string{"d c"},
- },
- {
- description: "double level expansion, with two variables in a string",
- stringListScope: ExportedStringListVariables{
- "a": []string{"${b} ${c}"},
- "b": []string{"d"},
- "c": []string{"e"},
- },
- toExpand: "${a}",
- expectedValues: []string{"d e"},
- },
- {
- description: "triple level expansion with two variables in a string",
- stringListScope: ExportedStringListVariables{
- "a": []string{"${b} ${c}"},
- "b": []string{"${c}", "${d}"},
- "c": []string{"${d}"},
- "d": []string{"foo"},
- },
- toExpand: "${a}",
- expectedValues: []string{"foo foo foo"},
- },
- {
- description: "expansion with config depending vars",
- configVars: ExportedConfigDependingVariables{
- "a": func(c Config) string { return c.BuildOS.String() },
- "b": func(c Config) string { return c.BuildArch.String() },
- },
- config: android_arm64_config,
- toExpand: "${a}-${b}",
- expectedValues: []string{"android-arm64"},
- },
- {
- description: "double level multi type expansion",
- stringListScope: ExportedStringListVariables{
- "platform": []string{"${os}-${arch}"},
- "const": []string{"const"},
- },
- configVars: ExportedConfigDependingVariables{
- "os": func(c Config) string { return c.BuildOS.String() },
- "arch": func(c Config) string { return c.BuildArch.String() },
- "foo": func(c Config) string { return "foo" },
- },
- config: android_arm64_config,
- toExpand: "${const}/${platform}/${foo}",
- expectedValues: []string{"const/android-arm64/foo"},
- },
- }
- for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
- output, _ := expandVar(testCase.config, testCase.toExpand, testCase.stringScope, testCase.stringListScope, testCase.configVars)
- if len(output) != len(testCase.expectedValues) {
- t.Errorf("Expected %d values, got %d", len(testCase.expectedValues), len(output))
- }
- for i, actual := range output {
- expectedValue := testCase.expectedValues[i]
- if actual != expectedValue {
- t.Errorf("Actual value '%s' doesn't match expected value '%s'", actual, expectedValue)
- }
- }
- })
- }
- }
- func TestBazelToolchainVars(t *testing.T) {
- testCases := []struct {
- name string
- config Config
- vars ExportedVariables
- expectedOut string
- }{
- {
- name: "exports strings",
- vars: ExportedVariables{
- exportedStringVars: ExportedStringVariables{
- "a": "b",
- "c": "d",
- },
- },
- expectedOut: bazel.GeneratedBazelFileWarning + `
- _a = "b"
- _c = "d"
- constants = struct(
- a = _a,
- c = _c,
- )`,
- },
- {
- name: "exports string lists",
- vars: ExportedVariables{
- exportedStringListVars: ExportedStringListVariables{
- "a": []string{"b1", "b2"},
- "c": []string{"d1", "d2"},
- },
- },
- expectedOut: bazel.GeneratedBazelFileWarning + `
- _a = [
- "b1",
- "b2",
- ]
- _c = [
- "d1",
- "d2",
- ]
- constants = struct(
- a = _a,
- c = _c,
- )`,
- },
- {
- name: "exports string lists dicts",
- vars: ExportedVariables{
- exportedStringListDictVars: ExportedStringListDictVariables{
- "a": map[string][]string{"b1": {"b2"}},
- "c": map[string][]string{"d1": {"d2"}},
- },
- },
- expectedOut: bazel.GeneratedBazelFileWarning + `
- _a = {
- "b1": ["b2"],
- }
- _c = {
- "d1": ["d2"],
- }
- constants = struct(
- a = _a,
- c = _c,
- )`,
- },
- {
- name: "exports dict with var refs",
- vars: ExportedVariables{
- exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
- "a": map[string]string{"b1": "${b2}"},
- "c": map[string]string{"d1": "${config.d2}"},
- },
- },
- expectedOut: bazel.GeneratedBazelFileWarning + `
- _a = {
- "b1": _b2,
- }
- _c = {
- "d1": _d2,
- }
- constants = struct(
- a = _a,
- c = _c,
- )`,
- },
- {
- name: "sorts across types with variable references last",
- vars: ExportedVariables{
- exportedStringVars: ExportedStringVariables{
- "b": "b-val",
- "d": "d-val",
- },
- exportedStringListVars: ExportedStringListVariables{
- "c": []string{"c-val"},
- "e": []string{"e-val"},
- },
- exportedStringListDictVars: ExportedStringListDictVariables{
- "a": map[string][]string{"a1": {"a2"}},
- "f": map[string][]string{"f1": {"f2"}},
- },
- exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
- "aa": map[string]string{"b1": "${b}"},
- "cc": map[string]string{"d1": "${config.d}"},
- },
- },
- expectedOut: bazel.GeneratedBazelFileWarning + `
- _a = {
- "a1": ["a2"],
- }
- _b = "b-val"
- _c = ["c-val"]
- _d = "d-val"
- _e = ["e-val"]
- _f = {
- "f1": ["f2"],
- }
- _aa = {
- "b1": _b,
- }
- _cc = {
- "d1": _d,
- }
- constants = struct(
- a = _a,
- b = _b,
- c = _c,
- d = _d,
- e = _e,
- f = _f,
- aa = _aa,
- cc = _cc,
- )`,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- out := BazelToolchainVars(tc.config, tc.vars)
- if out != tc.expectedOut {
- t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out)
- }
- })
- }
- }
- func TestSplitStringKeepingQuotedSubstring(t *testing.T) {
- testCases := []struct {
- description string
- s string
- delimiter byte
- split []string
- }{
- {
- description: "empty string returns single empty string",
- s: "",
- delimiter: ' ',
- split: []string{
- "",
- },
- },
- {
- description: "string with single space returns two empty strings",
- s: " ",
- delimiter: ' ',
- split: []string{
- "",
- "",
- },
- },
- {
- description: "string with two spaces returns three empty strings",
- s: " ",
- delimiter: ' ',
- split: []string{
- "",
- "",
- "",
- },
- },
- {
- description: "string with four words returns four word string",
- s: "hello world with words",
- delimiter: ' ',
- split: []string{
- "hello",
- "world",
- "with",
- "words",
- },
- },
- {
- description: "string with words and nested quote returns word strings and quote string",
- s: `hello "world with" words`,
- delimiter: ' ',
- split: []string{
- "hello",
- `"world with"`,
- "words",
- },
- },
- {
- description: "string with escaped quote inside real quotes",
- s: `hello \"world "with\" words"`,
- delimiter: ' ',
- split: []string{
- "hello",
- `"world`,
- `"with" words"`,
- },
- },
- {
- description: "string with words and escaped quotes returns word strings",
- s: `hello \"world with\" words`,
- delimiter: ' ',
- split: []string{
- "hello",
- `"world`,
- `with"`,
- "words",
- },
- },
- {
- description: "string which is single quoted substring returns only substring",
- s: `"hello world with words"`,
- delimiter: ' ',
- split: []string{
- `"hello world with words"`,
- },
- },
- {
- description: "string starting with quote returns quoted string",
- s: `"hello world with" words`,
- delimiter: ' ',
- split: []string{
- `"hello world with"`,
- "words",
- },
- },
- {
- description: "string with starting quote and no ending quote returns quote to end of string",
- s: `hello "world with words`,
- delimiter: ' ',
- split: []string{
- "hello",
- `"world with words`,
- },
- },
- {
- description: "quoted string is treated as a single \"word\" unless separated by delimiter",
- s: `hello "world"with words`,
- delimiter: ' ',
- split: []string{
- "hello",
- `"world"with`,
- "words",
- },
- },
- }
- for _, tc := range testCases {
- t.Run(tc.description, func(t *testing.T) {
- split := splitStringKeepingQuotedSubstring(tc.s, tc.delimiter)
- if len(split) != len(tc.split) {
- t.Fatalf("number of split string elements (%d) differs from expected (%d): split string (%v), expected (%v)",
- len(split), len(tc.split), split, tc.split,
- )
- }
- for i := range split {
- if split[i] != tc.split[i] {
- t.Errorf("split string element (%d), %v, differs from expected, %v", i, split[i], tc.split[i])
- }
- }
- })
- }
- }
|