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