1*333d2b36SAndroid Build Coastguard Worker// Copyright 2022 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 cc 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "strings" 20*333d2b36SAndroid Build Coastguard Worker "testing" 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 23*333d2b36SAndroid Build Coastguard Worker) 24*333d2b36SAndroid Build Coastguard Worker 25*333d2b36SAndroid Build Coastguard Workerfunc TestTidyFlagsWarningsAsErrors(t *testing.T) { 26*333d2b36SAndroid Build Coastguard Worker // The "tidy_flags" property should not contain -warnings-as-errors. 27*333d2b36SAndroid Build Coastguard Worker type testCase struct { 28*333d2b36SAndroid Build Coastguard Worker libName, bp string 29*333d2b36SAndroid Build Coastguard Worker errorMsg string // a negative test; must have error message 30*333d2b36SAndroid Build Coastguard Worker flags []string // must have substrings in tidyFlags 31*333d2b36SAndroid Build Coastguard Worker noFlags []string // must not have substrings in tidyFlags 32*333d2b36SAndroid Build Coastguard Worker } 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Worker testCases := []testCase{ 35*333d2b36SAndroid Build Coastguard Worker { 36*333d2b36SAndroid Build Coastguard Worker "libfoo1", 37*333d2b36SAndroid Build Coastguard Worker `cc_library_shared { // no warnings-as-errors, good tidy_flags 38*333d2b36SAndroid Build Coastguard Worker name: "libfoo1", 39*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 40*333d2b36SAndroid Build Coastguard Worker tidy_flags: ["-header-filter=dir1/"], 41*333d2b36SAndroid Build Coastguard Worker }`, 42*333d2b36SAndroid Build Coastguard Worker "", 43*333d2b36SAndroid Build Coastguard Worker []string{"-header-filter=dir1/"}, 44*333d2b36SAndroid Build Coastguard Worker []string{"-warnings-as-errors"}, 45*333d2b36SAndroid Build Coastguard Worker }, 46*333d2b36SAndroid Build Coastguard Worker { 47*333d2b36SAndroid Build Coastguard Worker "libfoo2", 48*333d2b36SAndroid Build Coastguard Worker `cc_library_shared { // good use of tidy_checks_as_errors 49*333d2b36SAndroid Build Coastguard Worker name: "libfoo2", 50*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 51*333d2b36SAndroid Build Coastguard Worker tidy_checks_as_errors: ["xyz-*", "abc"], 52*333d2b36SAndroid Build Coastguard Worker }`, 53*333d2b36SAndroid Build Coastguard Worker "", 54*333d2b36SAndroid Build Coastguard Worker []string{ 55*333d2b36SAndroid Build Coastguard Worker "-header-filter=^", // there is a default header filter 56*333d2b36SAndroid Build Coastguard Worker "-warnings-as-errors='xyz-*',abc,${config.TidyGlobalNoErrorChecks}", 57*333d2b36SAndroid Build Coastguard Worker }, 58*333d2b36SAndroid Build Coastguard Worker []string{}, 59*333d2b36SAndroid Build Coastguard Worker }, 60*333d2b36SAndroid Build Coastguard Worker } 61*333d2b36SAndroid Build Coastguard Worker if NoWarningsAsErrorsInTidyFlags { 62*333d2b36SAndroid Build Coastguard Worker testCases = append(testCases, testCase{ 63*333d2b36SAndroid Build Coastguard Worker "libfoo3", 64*333d2b36SAndroid Build Coastguard Worker `cc_library_shared { // bad use of -warnings-as-errors in tidy_flags 65*333d2b36SAndroid Build Coastguard Worker name: "libfoo3", 66*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 67*333d2b36SAndroid Build Coastguard Worker tidy_flags: [ 68*333d2b36SAndroid Build Coastguard Worker "-header-filters=.*", 69*333d2b36SAndroid Build Coastguard Worker "-warnings-as-errors=xyz-*", 70*333d2b36SAndroid Build Coastguard Worker ], 71*333d2b36SAndroid Build Coastguard Worker }`, 72*333d2b36SAndroid Build Coastguard Worker `module "libfoo3" .*: tidy_flags: should not contain .*;` + 73*333d2b36SAndroid Build Coastguard Worker ` use tidy_checks_as_errors instead`, 74*333d2b36SAndroid Build Coastguard Worker []string{}, 75*333d2b36SAndroid Build Coastguard Worker []string{}, 76*333d2b36SAndroid Build Coastguard Worker }) 77*333d2b36SAndroid Build Coastguard Worker } 78*333d2b36SAndroid Build Coastguard Worker for _, test := range testCases { 79*333d2b36SAndroid Build Coastguard Worker if test.errorMsg != "" { 80*333d2b36SAndroid Build Coastguard Worker testCcError(t, test.errorMsg, test.bp) 81*333d2b36SAndroid Build Coastguard Worker continue 82*333d2b36SAndroid Build Coastguard Worker } 83*333d2b36SAndroid Build Coastguard Worker variant := "android_arm64_armv8-a_shared" 84*333d2b36SAndroid Build Coastguard Worker ctx := testCc(t, test.bp) 85*333d2b36SAndroid Build Coastguard Worker t.Run("caseTidyFlags", func(t *testing.T) { 86*333d2b36SAndroid Build Coastguard Worker flags := ctx.ModuleForTests(test.libName, variant).Rule("clangTidy").Args["tidyFlags"] 87*333d2b36SAndroid Build Coastguard Worker for _, flag := range test.flags { 88*333d2b36SAndroid Build Coastguard Worker if !strings.Contains(flags, flag) { 89*333d2b36SAndroid Build Coastguard Worker t.Errorf("tidyFlags %v for %s does not contain %s.", flags, test.libName, flag) 90*333d2b36SAndroid Build Coastguard Worker } 91*333d2b36SAndroid Build Coastguard Worker } 92*333d2b36SAndroid Build Coastguard Worker for _, flag := range test.noFlags { 93*333d2b36SAndroid Build Coastguard Worker if strings.Contains(flags, flag) { 94*333d2b36SAndroid Build Coastguard Worker t.Errorf("tidyFlags %v for %s should not contain %s.", flags, test.libName, flag) 95*333d2b36SAndroid Build Coastguard Worker } 96*333d2b36SAndroid Build Coastguard Worker } 97*333d2b36SAndroid Build Coastguard Worker }) 98*333d2b36SAndroid Build Coastguard Worker } 99*333d2b36SAndroid Build Coastguard Worker} 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Workerfunc TestTidyChecks(t *testing.T) { 102*333d2b36SAndroid Build Coastguard Worker // The "tidy_checks" property defines additional checks appended 103*333d2b36SAndroid Build Coastguard Worker // to global default. But there are some checks disabled after 104*333d2b36SAndroid Build Coastguard Worker // the local tidy_checks. 105*333d2b36SAndroid Build Coastguard Worker bp := ` 106*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // has global checks + extraGlobalChecks 107*333d2b36SAndroid Build Coastguard Worker name: "libfoo_1", 108*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 109*333d2b36SAndroid Build Coastguard Worker } 110*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // has only local checks + extraGlobalChecks 111*333d2b36SAndroid Build Coastguard Worker name: "libfoo_2", 112*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 113*333d2b36SAndroid Build Coastguard Worker tidy_checks: ["-*", "xyz-*"], 114*333d2b36SAndroid Build Coastguard Worker } 115*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // has global checks + local checks + extraGlobalChecks 116*333d2b36SAndroid Build Coastguard Worker name: "libfoo_3", 117*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 118*333d2b36SAndroid Build Coastguard Worker tidy_checks: ["-abc*", "xyz-*", "mycheck"], 119*333d2b36SAndroid Build Coastguard Worker } 120*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // has only local checks after "-*" + extraGlobalChecks 121*333d2b36SAndroid Build Coastguard Worker name: "libfoo_4", 122*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 123*333d2b36SAndroid Build Coastguard Worker tidy_checks: ["-abc*", "xyz-*", "mycheck", "-*", "xyz-*"], 124*333d2b36SAndroid Build Coastguard Worker }` 125*333d2b36SAndroid Build Coastguard Worker ctx := testCc(t, bp) 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker globalChecks := "-checks=${config.TidyDefaultGlobalChecks}," 128*333d2b36SAndroid Build Coastguard Worker firstXyzChecks := "-checks='-*','xyz-*'," 129*333d2b36SAndroid Build Coastguard Worker localXyzChecks := "'-*','xyz-*'" 130*333d2b36SAndroid Build Coastguard Worker localAbcChecks := "'-abc*','xyz-*',mycheck" 131*333d2b36SAndroid Build Coastguard Worker extraGlobalChecks := ",${config.TidyGlobalNoChecks}" 132*333d2b36SAndroid Build Coastguard Worker testCases := []struct { 133*333d2b36SAndroid Build Coastguard Worker libNumber int // 1,2,3,... 134*333d2b36SAndroid Build Coastguard Worker checks []string // must have substrings in -checks 135*333d2b36SAndroid Build Coastguard Worker noChecks []string // must not have substrings in -checks 136*333d2b36SAndroid Build Coastguard Worker }{ 137*333d2b36SAndroid Build Coastguard Worker {1, []string{globalChecks, extraGlobalChecks}, []string{localXyzChecks, localAbcChecks}}, 138*333d2b36SAndroid Build Coastguard Worker {2, []string{firstXyzChecks, extraGlobalChecks}, []string{globalChecks, localAbcChecks}}, 139*333d2b36SAndroid Build Coastguard Worker {3, []string{globalChecks, localAbcChecks, extraGlobalChecks}, []string{localXyzChecks}}, 140*333d2b36SAndroid Build Coastguard Worker {4, []string{firstXyzChecks, extraGlobalChecks}, []string{globalChecks, localAbcChecks}}, 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker t.Run("caseTidyChecks", func(t *testing.T) { 143*333d2b36SAndroid Build Coastguard Worker variant := "android_arm64_armv8-a_shared" 144*333d2b36SAndroid Build Coastguard Worker for _, test := range testCases { 145*333d2b36SAndroid Build Coastguard Worker libName := fmt.Sprintf("libfoo_%d", test.libNumber) 146*333d2b36SAndroid Build Coastguard Worker flags := ctx.ModuleForTests(libName, variant).Rule("clangTidy").Args["tidyFlags"] 147*333d2b36SAndroid Build Coastguard Worker splitFlags := strings.Split(flags, " ") 148*333d2b36SAndroid Build Coastguard Worker foundCheckFlag := false 149*333d2b36SAndroid Build Coastguard Worker for _, flag := range splitFlags { 150*333d2b36SAndroid Build Coastguard Worker if strings.HasPrefix(flag, "-checks=") { 151*333d2b36SAndroid Build Coastguard Worker foundCheckFlag = true 152*333d2b36SAndroid Build Coastguard Worker for _, check := range test.checks { 153*333d2b36SAndroid Build Coastguard Worker if !strings.Contains(flag, check) { 154*333d2b36SAndroid Build Coastguard Worker t.Errorf("tidyFlags for %s does not contain %s.", libName, check) 155*333d2b36SAndroid Build Coastguard Worker } 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker for _, check := range test.noChecks { 158*333d2b36SAndroid Build Coastguard Worker if strings.Contains(flag, check) { 159*333d2b36SAndroid Build Coastguard Worker t.Errorf("tidyFlags for %s should not contain %s.", libName, check) 160*333d2b36SAndroid Build Coastguard Worker } 161*333d2b36SAndroid Build Coastguard Worker } 162*333d2b36SAndroid Build Coastguard Worker break 163*333d2b36SAndroid Build Coastguard Worker } 164*333d2b36SAndroid Build Coastguard Worker } 165*333d2b36SAndroid Build Coastguard Worker if !foundCheckFlag { 166*333d2b36SAndroid Build Coastguard Worker t.Errorf("tidyFlags for %s does not contain -checks=.", libName) 167*333d2b36SAndroid Build Coastguard Worker } 168*333d2b36SAndroid Build Coastguard Worker } 169*333d2b36SAndroid Build Coastguard Worker }) 170*333d2b36SAndroid Build Coastguard Worker} 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Workerfunc TestWithTidy(t *testing.T) { 173*333d2b36SAndroid Build Coastguard Worker // When WITH_TIDY=1 or (ALLOW_LOCAL_TIDY_TRUE=1 and local tidy:true) 174*333d2b36SAndroid Build Coastguard Worker // a C++ library should depend on .tidy files. 175*333d2b36SAndroid Build Coastguard Worker testCases := []struct { 176*333d2b36SAndroid Build Coastguard Worker withTidy, allowLocalTidyTrue string // "_" means undefined 177*333d2b36SAndroid Build Coastguard Worker needTidyFile []bool // for {libfoo_0, libfoo_1} and {libbar_0, libbar_1} 178*333d2b36SAndroid Build Coastguard Worker }{ 179*333d2b36SAndroid Build Coastguard Worker {"_", "_", []bool{false, false, false}}, 180*333d2b36SAndroid Build Coastguard Worker {"_", "0", []bool{false, false, false}}, 181*333d2b36SAndroid Build Coastguard Worker {"_", "1", []bool{false, true, false}}, 182*333d2b36SAndroid Build Coastguard Worker {"_", "true", []bool{false, true, false}}, 183*333d2b36SAndroid Build Coastguard Worker {"0", "_", []bool{false, false, false}}, 184*333d2b36SAndroid Build Coastguard Worker {"0", "1", []bool{false, true, false}}, 185*333d2b36SAndroid Build Coastguard Worker {"1", "_", []bool{true, true, false}}, 186*333d2b36SAndroid Build Coastguard Worker {"1", "false", []bool{true, true, false}}, 187*333d2b36SAndroid Build Coastguard Worker {"1", "1", []bool{true, true, false}}, 188*333d2b36SAndroid Build Coastguard Worker {"true", "_", []bool{true, true, false}}, 189*333d2b36SAndroid Build Coastguard Worker } 190*333d2b36SAndroid Build Coastguard Worker bp := ` 191*333d2b36SAndroid Build Coastguard Worker cc_library_shared { 192*333d2b36SAndroid Build Coastguard Worker name: "libfoo_0", // depends on .tidy if WITH_TIDY=1 193*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 194*333d2b36SAndroid Build Coastguard Worker } 195*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // depends on .tidy if WITH_TIDY=1 or ALLOW_LOCAL_TIDY_TRUE=1 196*333d2b36SAndroid Build Coastguard Worker name: "libfoo_1", 197*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 198*333d2b36SAndroid Build Coastguard Worker tidy: true, 199*333d2b36SAndroid Build Coastguard Worker } 200*333d2b36SAndroid Build Coastguard Worker cc_library_shared { // no .tidy 201*333d2b36SAndroid Build Coastguard Worker name: "libfoo_2", 202*333d2b36SAndroid Build Coastguard Worker srcs: ["foo.c"], 203*333d2b36SAndroid Build Coastguard Worker tidy: false, 204*333d2b36SAndroid Build Coastguard Worker } 205*333d2b36SAndroid Build Coastguard Worker cc_library_static { 206*333d2b36SAndroid Build Coastguard Worker name: "libbar_0", // depends on .tidy if WITH_TIDY=1 207*333d2b36SAndroid Build Coastguard Worker srcs: ["bar.c"], 208*333d2b36SAndroid Build Coastguard Worker } 209*333d2b36SAndroid Build Coastguard Worker cc_library_static { // depends on .tidy if WITH_TIDY=1 or ALLOW_LOCAL_TIDY_TRUE=1 210*333d2b36SAndroid Build Coastguard Worker name: "libbar_1", 211*333d2b36SAndroid Build Coastguard Worker srcs: ["bar.c"], 212*333d2b36SAndroid Build Coastguard Worker tidy: true, 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker cc_library_static { // no .tidy 215*333d2b36SAndroid Build Coastguard Worker name: "libbar_2", 216*333d2b36SAndroid Build Coastguard Worker srcs: ["bar.c"], 217*333d2b36SAndroid Build Coastguard Worker tidy: false, 218*333d2b36SAndroid Build Coastguard Worker }` 219*333d2b36SAndroid Build Coastguard Worker for index, test := range testCases { 220*333d2b36SAndroid Build Coastguard Worker testName := fmt.Sprintf("case%d,%v,%v", index, test.withTidy, test.allowLocalTidyTrue) 221*333d2b36SAndroid Build Coastguard Worker t.Run(testName, func(t *testing.T) { 222*333d2b36SAndroid Build Coastguard Worker testEnv := map[string]string{} 223*333d2b36SAndroid Build Coastguard Worker if test.withTidy != "_" { 224*333d2b36SAndroid Build Coastguard Worker testEnv["WITH_TIDY"] = test.withTidy 225*333d2b36SAndroid Build Coastguard Worker } 226*333d2b36SAndroid Build Coastguard Worker if test.allowLocalTidyTrue != "_" { 227*333d2b36SAndroid Build Coastguard Worker testEnv["ALLOW_LOCAL_TIDY_TRUE"] = test.allowLocalTidyTrue 228*333d2b36SAndroid Build Coastguard Worker } 229*333d2b36SAndroid Build Coastguard Worker ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp) 230*333d2b36SAndroid Build Coastguard Worker for n := 0; n < 3; n++ { 231*333d2b36SAndroid Build Coastguard Worker checkLibraryRule := func(foo, variant, ruleName string) { 232*333d2b36SAndroid Build Coastguard Worker libName := fmt.Sprintf("lib%s_%d", foo, n) 233*333d2b36SAndroid Build Coastguard Worker tidyFile := "out/soong/.intermediates/" + libName + "/" + variant + "/obj/" + foo + ".tidy" 234*333d2b36SAndroid Build Coastguard Worker depFiles := ctx.ModuleForTests(libName, variant).Rule(ruleName).Validations.Strings() 235*333d2b36SAndroid Build Coastguard Worker if test.needTidyFile[n] { 236*333d2b36SAndroid Build Coastguard Worker android.AssertStringListContains(t, libName+" needs .tidy file", depFiles, tidyFile) 237*333d2b36SAndroid Build Coastguard Worker } else { 238*333d2b36SAndroid Build Coastguard Worker android.AssertStringListDoesNotContain(t, libName+" does not need .tidy file", depFiles, tidyFile) 239*333d2b36SAndroid Build Coastguard Worker } 240*333d2b36SAndroid Build Coastguard Worker } 241*333d2b36SAndroid Build Coastguard Worker checkLibraryRule("foo", "android_arm64_armv8-a_shared", "ld") 242*333d2b36SAndroid Build Coastguard Worker checkLibraryRule("bar", "android_arm64_armv8-a_static", "ar") 243*333d2b36SAndroid Build Coastguard Worker } 244*333d2b36SAndroid Build Coastguard Worker }) 245*333d2b36SAndroid Build Coastguard Worker } 246*333d2b36SAndroid Build Coastguard Worker} 247*333d2b36SAndroid Build Coastguard Worker 248*333d2b36SAndroid Build Coastguard Workerfunc TestWithGeneratedCode(t *testing.T) { 249*333d2b36SAndroid Build Coastguard Worker bp := ` 250*333d2b36SAndroid Build Coastguard Worker cc_library_shared { 251*333d2b36SAndroid Build Coastguard Worker name: "libfoo", 252*333d2b36SAndroid Build Coastguard Worker srcs: ["foo_1.y", "foo_2.yy", "foo_3.l", "foo_4.ll", "foo_5.proto", 253*333d2b36SAndroid Build Coastguard Worker "foo_6.aidl", "foo_7.rscript", "foo_8.fs", "foo_9.sysprop", 254*333d2b36SAndroid Build Coastguard Worker "foo_src.cpp"], 255*333d2b36SAndroid Build Coastguard Worker tidy: true, 256*333d2b36SAndroid Build Coastguard Worker }` 257*333d2b36SAndroid Build Coastguard Worker variant := "android_arm64_armv8-a_shared" 258*333d2b36SAndroid Build Coastguard Worker 259*333d2b36SAndroid Build Coastguard Worker testEnv := map[string]string{} 260*333d2b36SAndroid Build Coastguard Worker testEnv["ALLOW_LOCAL_TIDY_TRUE"] = "1" 261*333d2b36SAndroid Build Coastguard Worker 262*333d2b36SAndroid Build Coastguard Worker ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp) 263*333d2b36SAndroid Build Coastguard Worker 264*333d2b36SAndroid Build Coastguard Worker t.Run("tidy should be only run for source code, not for generated code", func(t *testing.T) { 265*333d2b36SAndroid Build Coastguard Worker depFiles := ctx.ModuleForTests("libfoo", variant).Rule("ld").Validations.Strings() 266*333d2b36SAndroid Build Coastguard Worker 267*333d2b36SAndroid Build Coastguard Worker tidyFileForCpp := "out/soong/.intermediates/libfoo/" + variant + "/obj/foo_src.tidy" 268*333d2b36SAndroid Build Coastguard Worker 269*333d2b36SAndroid Build Coastguard Worker android.AssertArrayString(t, 270*333d2b36SAndroid Build Coastguard Worker "only one .tidy file for source code should exist for libfoo", 271*333d2b36SAndroid Build Coastguard Worker []string{tidyFileForCpp}, depFiles) 272*333d2b36SAndroid Build Coastguard Worker }) 273*333d2b36SAndroid Build Coastguard Worker} 274