tidy_test.go 7.9 KB

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