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