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