xref: /aosp_15_r20/build/soong/android/config_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage android
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
20*333d2b36SAndroid Build Coastguard Worker	"reflect"
21*333d2b36SAndroid Build Coastguard Worker	"strings"
22*333d2b36SAndroid Build Coastguard Worker	"testing"
23*333d2b36SAndroid Build Coastguard Worker)
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Workerfunc validateConfigAnnotations(configurable jsonConfigurable) (err error) {
26*333d2b36SAndroid Build Coastguard Worker	reflectType := reflect.TypeOf(configurable)
27*333d2b36SAndroid Build Coastguard Worker	reflectType = reflectType.Elem()
28*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < reflectType.NumField(); i++ {
29*333d2b36SAndroid Build Coastguard Worker		field := reflectType.Field(i)
30*333d2b36SAndroid Build Coastguard Worker		jsonTag := field.Tag.Get("json")
31*333d2b36SAndroid Build Coastguard Worker		// Check for mistakes in the json tag
32*333d2b36SAndroid Build Coastguard Worker		if jsonTag != "" && !strings.HasPrefix(jsonTag, ",") {
33*333d2b36SAndroid Build Coastguard Worker			if !strings.Contains(jsonTag, ",") {
34*333d2b36SAndroid Build Coastguard Worker				// Probably an accidental rename, most likely "omitempty" instead of ",omitempty"
35*333d2b36SAndroid Build Coastguard Worker				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
36*333d2b36SAndroid Build Coastguard Worker					"Did you mean to use an annotation of %q?\n"+
37*333d2b36SAndroid Build Coastguard Worker					"(Alternatively, to change the json name of the field, rename the field in source instead.)",
38*333d2b36SAndroid Build Coastguard Worker					reflectType.Name(), field.Name, field.Tag, jsonTag, ","+jsonTag)
39*333d2b36SAndroid Build Coastguard Worker			} else {
40*333d2b36SAndroid Build Coastguard Worker				// Although this rename was probably intentional,
41*333d2b36SAndroid Build Coastguard Worker				// a json annotation is still more confusing than renaming the source variable
42*333d2b36SAndroid Build Coastguard Worker				requestedName := strings.Split(jsonTag, ",")[0]
43*333d2b36SAndroid Build Coastguard Worker				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
44*333d2b36SAndroid Build Coastguard Worker					"To change the json name of the field, rename the field in source instead.",
45*333d2b36SAndroid Build Coastguard Worker					reflectType.Name(), field.Name, field.Tag, requestedName)
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker			}
48*333d2b36SAndroid Build Coastguard Worker		}
49*333d2b36SAndroid Build Coastguard Worker	}
50*333d2b36SAndroid Build Coastguard Worker	return nil
51*333d2b36SAndroid Build Coastguard Worker}
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Workertype configType struct {
54*333d2b36SAndroid Build Coastguard Worker	PopulateMe *bool `json:"omitempty"`
55*333d2b36SAndroid Build Coastguard Worker}
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Workerfunc (c *configType) SetDefaultConfig() {
58*333d2b36SAndroid Build Coastguard Worker}
59*333d2b36SAndroid Build Coastguard Worker
60*333d2b36SAndroid Build Coastguard Worker// tests that ValidateConfigAnnotation works
61*333d2b36SAndroid Build Coastguard Workerfunc TestValidateConfigAnnotations(t *testing.T) {
62*333d2b36SAndroid Build Coastguard Worker	config := configType{}
63*333d2b36SAndroid Build Coastguard Worker	err := validateConfigAnnotations(&config)
64*333d2b36SAndroid Build Coastguard Worker	expectedError := `Field configType.PopulateMe has tag json:"omitempty" which specifies to change its json field name to "omitempty".
65*333d2b36SAndroid Build Coastguard WorkerDid you mean to use an annotation of ",omitempty"?
66*333d2b36SAndroid Build Coastguard Worker(Alternatively, to change the json name of the field, rename the field in source instead.)`
67*333d2b36SAndroid Build Coastguard Worker	if err.Error() != expectedError {
68*333d2b36SAndroid Build Coastguard Worker		t.Errorf("Incorrect error; expected:\n"+
69*333d2b36SAndroid Build Coastguard Worker			"%s\n"+
70*333d2b36SAndroid Build Coastguard Worker			"got:\n"+
71*333d2b36SAndroid Build Coastguard Worker			"%s",
72*333d2b36SAndroid Build Coastguard Worker			expectedError, err.Error())
73*333d2b36SAndroid Build Coastguard Worker	}
74*333d2b36SAndroid Build Coastguard Worker}
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker// run validateConfigAnnotations against each type that might have json annotations
77*333d2b36SAndroid Build Coastguard Workerfunc TestProductConfigAnnotations(t *testing.T) {
78*333d2b36SAndroid Build Coastguard Worker	err := validateConfigAnnotations(&ProductVariables{})
79*333d2b36SAndroid Build Coastguard Worker	if err != nil {
80*333d2b36SAndroid Build Coastguard Worker		t.Errorf(err.Error())
81*333d2b36SAndroid Build Coastguard Worker	}
82*333d2b36SAndroid Build Coastguard Worker}
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Workerfunc TestMissingVendorConfig(t *testing.T) {
85*333d2b36SAndroid Build Coastguard Worker	c := &config{}
86*333d2b36SAndroid Build Coastguard Worker	if c.VendorConfig("test").Bool("not_set") {
87*333d2b36SAndroid Build Coastguard Worker		t.Errorf("Expected false")
88*333d2b36SAndroid Build Coastguard Worker	}
89*333d2b36SAndroid Build Coastguard Worker}
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Workerfunc verifyProductVariableMarshaling(t *testing.T, v ProductVariables) {
92*333d2b36SAndroid Build Coastguard Worker	dir := t.TempDir()
93*333d2b36SAndroid Build Coastguard Worker	path := filepath.Join(dir, "test.variables")
94*333d2b36SAndroid Build Coastguard Worker	err := saveToConfigFile(&v, path)
95*333d2b36SAndroid Build Coastguard Worker	if err != nil {
96*333d2b36SAndroid Build Coastguard Worker		t.Errorf("Couldn't save default product config: %q", err)
97*333d2b36SAndroid Build Coastguard Worker	}
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Worker	var v2 ProductVariables
100*333d2b36SAndroid Build Coastguard Worker	err = loadFromConfigFile(&v2, path)
101*333d2b36SAndroid Build Coastguard Worker	if err != nil {
102*333d2b36SAndroid Build Coastguard Worker		t.Errorf("Couldn't load default product config: %q", err)
103*333d2b36SAndroid Build Coastguard Worker	}
104*333d2b36SAndroid Build Coastguard Worker}
105*333d2b36SAndroid Build Coastguard Workerfunc TestDefaultProductVariableMarshaling(t *testing.T) {
106*333d2b36SAndroid Build Coastguard Worker	v := ProductVariables{}
107*333d2b36SAndroid Build Coastguard Worker	v.SetDefaultConfig()
108*333d2b36SAndroid Build Coastguard Worker	verifyProductVariableMarshaling(t, v)
109*333d2b36SAndroid Build Coastguard Worker}
110*333d2b36SAndroid Build Coastguard Worker
111*333d2b36SAndroid Build Coastguard Workerfunc TestBootJarsMarshaling(t *testing.T) {
112*333d2b36SAndroid Build Coastguard Worker	v := ProductVariables{}
113*333d2b36SAndroid Build Coastguard Worker	v.SetDefaultConfig()
114*333d2b36SAndroid Build Coastguard Worker	v.BootJars = ConfiguredJarList{
115*333d2b36SAndroid Build Coastguard Worker		apexes: []string{"apex"},
116*333d2b36SAndroid Build Coastguard Worker		jars:   []string{"jar"},
117*333d2b36SAndroid Build Coastguard Worker	}
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker	verifyProductVariableMarshaling(t, v)
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Workerfunc assertStringEquals(t *testing.T, expected, actual string) {
123*333d2b36SAndroid Build Coastguard Worker	if actual != expected {
124*333d2b36SAndroid Build Coastguard Worker		t.Errorf("expected %q found %q", expected, actual)
125*333d2b36SAndroid Build Coastguard Worker	}
126*333d2b36SAndroid Build Coastguard Worker}
127*333d2b36SAndroid Build Coastguard Worker
128*333d2b36SAndroid Build Coastguard Workerfunc TestReleaseAconfigExtraReleaseConfigs(t *testing.T) {
129*333d2b36SAndroid Build Coastguard Worker	testCases := []struct {
130*333d2b36SAndroid Build Coastguard Worker		name     string
131*333d2b36SAndroid Build Coastguard Worker		flag     string
132*333d2b36SAndroid Build Coastguard Worker		expected []string
133*333d2b36SAndroid Build Coastguard Worker	}{
134*333d2b36SAndroid Build Coastguard Worker		{
135*333d2b36SAndroid Build Coastguard Worker			name:     "empty",
136*333d2b36SAndroid Build Coastguard Worker			flag:     "",
137*333d2b36SAndroid Build Coastguard Worker			expected: []string{},
138*333d2b36SAndroid Build Coastguard Worker		},
139*333d2b36SAndroid Build Coastguard Worker		{
140*333d2b36SAndroid Build Coastguard Worker			name:     "specified",
141*333d2b36SAndroid Build Coastguard Worker			flag:     "bar foo",
142*333d2b36SAndroid Build Coastguard Worker			expected: []string{"bar", "foo"},
143*333d2b36SAndroid Build Coastguard Worker		},
144*333d2b36SAndroid Build Coastguard Worker		{
145*333d2b36SAndroid Build Coastguard Worker			name:     "duplicates",
146*333d2b36SAndroid Build Coastguard Worker			flag:     "foo bar foo",
147*333d2b36SAndroid Build Coastguard Worker			expected: []string{"foo", "bar"},
148*333d2b36SAndroid Build Coastguard Worker		},
149*333d2b36SAndroid Build Coastguard Worker	}
150*333d2b36SAndroid Build Coastguard Worker
151*333d2b36SAndroid Build Coastguard Worker	for _, tc := range testCases {
152*333d2b36SAndroid Build Coastguard Worker		fixture := GroupFixturePreparers(
153*333d2b36SAndroid Build Coastguard Worker			PrepareForTestWithBuildFlag("RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS", tc.flag),
154*333d2b36SAndroid Build Coastguard Worker		)
155*333d2b36SAndroid Build Coastguard Worker		actual := fixture.RunTest(t).Config.ReleaseAconfigExtraReleaseConfigs()
156*333d2b36SAndroid Build Coastguard Worker		AssertArrayString(t, tc.name, tc.expected, actual)
157*333d2b36SAndroid Build Coastguard Worker	}
158*333d2b36SAndroid Build Coastguard Worker}
159*333d2b36SAndroid Build Coastguard Worker
160*333d2b36SAndroid Build Coastguard Workerfunc TestConfiguredJarList(t *testing.T) {
161*333d2b36SAndroid Build Coastguard Worker	list1 := CreateTestConfiguredJarList([]string{"apex1:jarA"})
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Worker	t.Run("create", func(t *testing.T) {
164*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA", list1.String())
165*333d2b36SAndroid Build Coastguard Worker	})
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Worker	t.Run("create invalid - missing apex", func(t *testing.T) {
168*333d2b36SAndroid Build Coastguard Worker		defer func() {
169*333d2b36SAndroid Build Coastguard Worker			err := recover().(error)
170*333d2b36SAndroid Build Coastguard Worker			assertStringEquals(t, "malformed (apex, jar) pair: 'jarA', expected format: <apex>:<jar>", err.Error())
171*333d2b36SAndroid Build Coastguard Worker		}()
172*333d2b36SAndroid Build Coastguard Worker		CreateTestConfiguredJarList([]string{"jarA"})
173*333d2b36SAndroid Build Coastguard Worker	})
174*333d2b36SAndroid Build Coastguard Worker
175*333d2b36SAndroid Build Coastguard Worker	t.Run("create invalid - empty apex", func(t *testing.T) {
176*333d2b36SAndroid Build Coastguard Worker		defer func() {
177*333d2b36SAndroid Build Coastguard Worker			err := recover().(error)
178*333d2b36SAndroid Build Coastguard Worker			assertStringEquals(t, "invalid apex '' in <apex>:<jar> pair ':jarA', expected format: <apex>:<jar>", err.Error())
179*333d2b36SAndroid Build Coastguard Worker		}()
180*333d2b36SAndroid Build Coastguard Worker		CreateTestConfiguredJarList([]string{":jarA"})
181*333d2b36SAndroid Build Coastguard Worker	})
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Worker	list2 := list1.Append("apex2", "jarB")
184*333d2b36SAndroid Build Coastguard Worker	t.Run("append", func(t *testing.T) {
185*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
186*333d2b36SAndroid Build Coastguard Worker	})
187*333d2b36SAndroid Build Coastguard Worker
188*333d2b36SAndroid Build Coastguard Worker	t.Run("append does not modify", func(t *testing.T) {
189*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA", list1.String())
190*333d2b36SAndroid Build Coastguard Worker	})
191*333d2b36SAndroid Build Coastguard Worker
192*333d2b36SAndroid Build Coastguard Worker	// Make sure that two lists created by appending to the same list do not share storage.
193*333d2b36SAndroid Build Coastguard Worker	list3 := list1.Append("apex3", "jarC")
194*333d2b36SAndroid Build Coastguard Worker	t.Run("append does not share", func(t *testing.T) {
195*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
196*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA,apex3:jarC", list3.String())
197*333d2b36SAndroid Build Coastguard Worker	})
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Worker	list4 := list3.RemoveList(list1)
200*333d2b36SAndroid Build Coastguard Worker	t.Run("remove", func(t *testing.T) {
201*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex3:jarC", list4.String())
202*333d2b36SAndroid Build Coastguard Worker	})
203*333d2b36SAndroid Build Coastguard Worker
204*333d2b36SAndroid Build Coastguard Worker	t.Run("remove does not modify", func(t *testing.T) {
205*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA,apex3:jarC", list3.String())
206*333d2b36SAndroid Build Coastguard Worker	})
207*333d2b36SAndroid Build Coastguard Worker
208*333d2b36SAndroid Build Coastguard Worker	// Make sure that two lists created by removing from the same list do not share storage.
209*333d2b36SAndroid Build Coastguard Worker	list5 := list3.RemoveList(CreateTestConfiguredJarList([]string{"apex3:jarC"}))
210*333d2b36SAndroid Build Coastguard Worker	t.Run("remove", func(t *testing.T) {
211*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex3:jarC", list4.String())
212*333d2b36SAndroid Build Coastguard Worker		assertStringEquals(t, "apex1:jarA", list5.String())
213*333d2b36SAndroid Build Coastguard Worker	})
214*333d2b36SAndroid Build Coastguard Worker}
215*333d2b36SAndroid Build Coastguard Worker
216*333d2b36SAndroid Build Coastguard Workerfunc (p partialCompileFlags) updateEnabled(value bool) partialCompileFlags {
217*333d2b36SAndroid Build Coastguard Worker	p.enabled = value
218*333d2b36SAndroid Build Coastguard Worker	return p
219*333d2b36SAndroid Build Coastguard Worker}
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Workerfunc (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags {
222*333d2b36SAndroid Build Coastguard Worker	p.use_d8 = value
223*333d2b36SAndroid Build Coastguard Worker	return p
224*333d2b36SAndroid Build Coastguard Worker}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Workerfunc TestPartialCompile(t *testing.T) {
227*333d2b36SAndroid Build Coastguard Worker	mockConfig := func(value string) *config {
228*333d2b36SAndroid Build Coastguard Worker		c := &config{
229*333d2b36SAndroid Build Coastguard Worker			env: map[string]string{
230*333d2b36SAndroid Build Coastguard Worker				"SOONG_PARTIAL_COMPILE": value,
231*333d2b36SAndroid Build Coastguard Worker			},
232*333d2b36SAndroid Build Coastguard Worker		}
233*333d2b36SAndroid Build Coastguard Worker		return c
234*333d2b36SAndroid Build Coastguard Worker	}
235*333d2b36SAndroid Build Coastguard Worker	tests := []struct {
236*333d2b36SAndroid Build Coastguard Worker		value      string
237*333d2b36SAndroid Build Coastguard Worker		isEngBuild bool
238*333d2b36SAndroid Build Coastguard Worker		expected   partialCompileFlags
239*333d2b36SAndroid Build Coastguard Worker	}{
240*333d2b36SAndroid Build Coastguard Worker		{"", true, defaultPartialCompileFlags},
241*333d2b36SAndroid Build Coastguard Worker		{"false", true, partialCompileFlags{}},
242*333d2b36SAndroid Build Coastguard Worker		{"true", true, defaultPartialCompileFlags.updateEnabled(true)},
243*333d2b36SAndroid Build Coastguard Worker		{"true", false, partialCompileFlags{}},
244*333d2b36SAndroid Build Coastguard Worker		{"true,use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(true)},
245*333d2b36SAndroid Build Coastguard Worker		{"true,-use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(false)},
246*333d2b36SAndroid Build Coastguard Worker		{"use_d8,false", true, partialCompileFlags{}},
247*333d2b36SAndroid Build Coastguard Worker		{"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)},
248*333d2b36SAndroid Build Coastguard Worker	}
249*333d2b36SAndroid Build Coastguard Worker
250*333d2b36SAndroid Build Coastguard Worker	for _, test := range tests {
251*333d2b36SAndroid Build Coastguard Worker		t.Run(test.value, func(t *testing.T) {
252*333d2b36SAndroid Build Coastguard Worker			config := mockConfig(test.value)
253*333d2b36SAndroid Build Coastguard Worker			flags, _ := config.parsePartialCompileFlags(test.isEngBuild)
254*333d2b36SAndroid Build Coastguard Worker			if flags != test.expected {
255*333d2b36SAndroid Build Coastguard Worker				t.Errorf("expected %v found %v", test.expected, flags)
256*333d2b36SAndroid Build Coastguard Worker			}
257*333d2b36SAndroid Build Coastguard Worker		})
258*333d2b36SAndroid Build Coastguard Worker	}
259*333d2b36SAndroid Build Coastguard Worker}
260