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