bazel_overlay_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright 2020 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 main
  15. import (
  16. "android/soong/android"
  17. "io/ioutil"
  18. "os"
  19. "strings"
  20. "testing"
  21. "github.com/google/blueprint/bootstrap/bpdoc"
  22. )
  23. var buildDir string
  24. func setUp() {
  25. var err error
  26. buildDir, err = ioutil.TempDir("", "bazel_overlay_test")
  27. if err != nil {
  28. panic(err)
  29. }
  30. }
  31. func tearDown() {
  32. os.RemoveAll(buildDir)
  33. }
  34. func TestMain(m *testing.M) {
  35. run := func() int {
  36. setUp()
  37. defer tearDown()
  38. return m.Run()
  39. }
  40. os.Exit(run())
  41. }
  42. type customModule struct {
  43. android.ModuleBase
  44. }
  45. func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  46. // nothing for now.
  47. }
  48. func customModuleFactory() android.Module {
  49. module := &customModule{}
  50. android.InitAndroidModule(module)
  51. return module
  52. }
  53. func TestGenerateBazelOverlayFromBlueprint(t *testing.T) {
  54. testCases := []struct {
  55. bp string
  56. expectedBazelTarget string
  57. }{
  58. {
  59. bp: `custom {
  60. name: "foo",
  61. }
  62. `,
  63. expectedBazelTarget: `soong_module(
  64. name = "foo",
  65. module_name = "foo",
  66. module_type = "custom",
  67. module_variant = "",
  68. module_deps = [
  69. ],
  70. )`,
  71. },
  72. {
  73. bp: `custom {
  74. name: "foo",
  75. ramdisk: true,
  76. }
  77. `,
  78. expectedBazelTarget: `soong_module(
  79. name = "foo",
  80. module_name = "foo",
  81. module_type = "custom",
  82. module_variant = "",
  83. module_deps = [
  84. ],
  85. ramdisk = True,
  86. )`,
  87. },
  88. {
  89. bp: `custom {
  90. name: "foo",
  91. owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
  92. }
  93. `,
  94. expectedBazelTarget: `soong_module(
  95. name = "foo",
  96. module_name = "foo",
  97. module_type = "custom",
  98. module_variant = "",
  99. module_deps = [
  100. ],
  101. owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
  102. )`,
  103. },
  104. {
  105. bp: `custom {
  106. name: "foo",
  107. required: ["bar"],
  108. }
  109. `,
  110. expectedBazelTarget: `soong_module(
  111. name = "foo",
  112. module_name = "foo",
  113. module_type = "custom",
  114. module_variant = "",
  115. module_deps = [
  116. ],
  117. required = [
  118. "bar",
  119. ],
  120. )`,
  121. },
  122. {
  123. bp: `custom {
  124. name: "foo",
  125. target_required: ["qux", "bazqux"],
  126. }
  127. `,
  128. expectedBazelTarget: `soong_module(
  129. name = "foo",
  130. module_name = "foo",
  131. module_type = "custom",
  132. module_variant = "",
  133. module_deps = [
  134. ],
  135. target_required = [
  136. "qux",
  137. "bazqux",
  138. ],
  139. )`,
  140. },
  141. {
  142. bp: `custom {
  143. name: "foo",
  144. dist: {
  145. targets: ["goal_foo"],
  146. tag: ".foo",
  147. },
  148. dists: [
  149. {
  150. targets: ["goal_bar"],
  151. tag: ".bar",
  152. },
  153. ],
  154. }
  155. `,
  156. expectedBazelTarget: `soong_module(
  157. name = "foo",
  158. module_name = "foo",
  159. module_type = "custom",
  160. module_variant = "",
  161. module_deps = [
  162. ],
  163. dist = {
  164. "tag": ".foo",
  165. "targets": [
  166. "goal_foo",
  167. ],
  168. },
  169. dists = [
  170. {
  171. "tag": ".bar",
  172. "targets": [
  173. "goal_bar",
  174. ],
  175. },
  176. ],
  177. )`,
  178. },
  179. {
  180. bp: `custom {
  181. name: "foo",
  182. required: ["bar"],
  183. target_required: ["qux", "bazqux"],
  184. ramdisk: true,
  185. owner: "custom_owner",
  186. dists: [
  187. {
  188. tag: ".tag",
  189. targets: ["my_goal"],
  190. },
  191. ],
  192. }
  193. `,
  194. expectedBazelTarget: `soong_module(
  195. name = "foo",
  196. module_name = "foo",
  197. module_type = "custom",
  198. module_variant = "",
  199. module_deps = [
  200. ],
  201. dists = [
  202. {
  203. "tag": ".tag",
  204. "targets": [
  205. "my_goal",
  206. ],
  207. },
  208. ],
  209. owner = "custom_owner",
  210. ramdisk = True,
  211. required = [
  212. "bar",
  213. ],
  214. target_required = [
  215. "qux",
  216. "bazqux",
  217. ],
  218. )`,
  219. },
  220. }
  221. for _, testCase := range testCases {
  222. config := android.TestConfig(buildDir, nil, testCase.bp, nil)
  223. ctx := android.NewTestContext()
  224. ctx.RegisterModuleType("custom", customModuleFactory)
  225. ctx.Register(config)
  226. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  227. android.FailIfErrored(t, errs)
  228. _, errs = ctx.PrepareBuildActions(config)
  229. android.FailIfErrored(t, errs)
  230. module := ctx.ModuleForTests("foo", "").Module().(*customModule)
  231. blueprintCtx := ctx.Context.Context
  232. actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module)
  233. if actualBazelTarget != testCase.expectedBazelTarget {
  234. t.Errorf(
  235. "Expected generated Bazel target to be '%s', got '%s'",
  236. testCase.expectedBazelTarget,
  237. actualBazelTarget,
  238. )
  239. }
  240. }
  241. }
  242. func createPackageFixtures() []*bpdoc.Package {
  243. properties := []bpdoc.Property{
  244. bpdoc.Property{
  245. Name: "int64_prop",
  246. Type: "int64",
  247. },
  248. bpdoc.Property{
  249. Name: "int_prop",
  250. Type: "int",
  251. },
  252. bpdoc.Property{
  253. Name: "bool_prop",
  254. Type: "bool",
  255. },
  256. bpdoc.Property{
  257. Name: "string_prop",
  258. Type: "string",
  259. },
  260. bpdoc.Property{
  261. Name: "string_list_prop",
  262. Type: "list of strings",
  263. },
  264. bpdoc.Property{
  265. Name: "nested_prop",
  266. Type: "",
  267. Properties: []bpdoc.Property{
  268. bpdoc.Property{
  269. Name: "int_prop",
  270. Type: "int",
  271. },
  272. bpdoc.Property{
  273. Name: "bool_prop",
  274. Type: "bool",
  275. },
  276. bpdoc.Property{
  277. Name: "string_prop",
  278. Type: "string",
  279. },
  280. },
  281. },
  282. bpdoc.Property{
  283. Name: "unknown_type",
  284. Type: "unknown",
  285. },
  286. }
  287. fooPropertyStruct := &bpdoc.PropertyStruct{
  288. Name: "FooProperties",
  289. Properties: properties,
  290. }
  291. moduleTypes := []*bpdoc.ModuleType{
  292. &bpdoc.ModuleType{
  293. Name: "foo_library",
  294. PropertyStructs: []*bpdoc.PropertyStruct{
  295. fooPropertyStruct,
  296. },
  297. },
  298. &bpdoc.ModuleType{
  299. Name: "foo_binary",
  300. PropertyStructs: []*bpdoc.PropertyStruct{
  301. fooPropertyStruct,
  302. },
  303. },
  304. &bpdoc.ModuleType{
  305. Name: "foo_test",
  306. PropertyStructs: []*bpdoc.PropertyStruct{
  307. fooPropertyStruct,
  308. },
  309. },
  310. }
  311. return [](*bpdoc.Package){
  312. &bpdoc.Package{
  313. Name: "foo_language",
  314. Path: "android/soong/foo",
  315. ModuleTypes: moduleTypes,
  316. },
  317. }
  318. }
  319. func TestGenerateModuleRuleShims(t *testing.T) {
  320. ruleShims, err := createRuleShims(createPackageFixtures())
  321. if err != nil {
  322. panic(err)
  323. }
  324. if len(ruleShims) != 1 {
  325. t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
  326. }
  327. fooRuleShim := ruleShims["foo"]
  328. expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
  329. if len(fooRuleShim.rules) != 3 {
  330. t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
  331. }
  332. for i, rule := range fooRuleShim.rules {
  333. if rule != expectedRules[i] {
  334. t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
  335. }
  336. }
  337. expectedBzl := `load(":providers.bzl", "SoongModuleInfo")
  338. def _foo_binary_impl(ctx):
  339. return [SoongModuleInfo()]
  340. foo_binary = rule(
  341. implementation = _foo_binary_impl,
  342. attrs = {
  343. "module_name": attr.string(mandatory = True),
  344. "module_variant": attr.string(),
  345. "module_deps": attr.label_list(providers = [SoongModuleInfo]),
  346. "bool_prop": attr.bool(),
  347. "int64_prop": attr.int(),
  348. "int_prop": attr.int(),
  349. # "nested_prop__int_prop": attr.int(),
  350. # "nested_prop__bool_prop": attr.bool(),
  351. # "nested_prop__string_prop": attr.string(),
  352. "string_list_prop": attr.string_list(),
  353. "string_prop": attr.string(),
  354. },
  355. )
  356. def _foo_library_impl(ctx):
  357. return [SoongModuleInfo()]
  358. foo_library = rule(
  359. implementation = _foo_library_impl,
  360. attrs = {
  361. "module_name": attr.string(mandatory = True),
  362. "module_variant": attr.string(),
  363. "module_deps": attr.label_list(providers = [SoongModuleInfo]),
  364. "bool_prop": attr.bool(),
  365. "int64_prop": attr.int(),
  366. "int_prop": attr.int(),
  367. # "nested_prop__int_prop": attr.int(),
  368. # "nested_prop__bool_prop": attr.bool(),
  369. # "nested_prop__string_prop": attr.string(),
  370. "string_list_prop": attr.string_list(),
  371. "string_prop": attr.string(),
  372. },
  373. )
  374. def _foo_test__impl(ctx):
  375. return [SoongModuleInfo()]
  376. foo_test_ = rule(
  377. implementation = _foo_test__impl,
  378. attrs = {
  379. "module_name": attr.string(mandatory = True),
  380. "module_variant": attr.string(),
  381. "module_deps": attr.label_list(providers = [SoongModuleInfo]),
  382. "bool_prop": attr.bool(),
  383. "int64_prop": attr.int(),
  384. "int_prop": attr.int(),
  385. # "nested_prop__int_prop": attr.int(),
  386. # "nested_prop__bool_prop": attr.bool(),
  387. # "nested_prop__string_prop": attr.string(),
  388. "string_list_prop": attr.string_list(),
  389. "string_prop": attr.string(),
  390. },
  391. )
  392. `
  393. if fooRuleShim.content != expectedBzl {
  394. t.Errorf(
  395. "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
  396. expectedBzl,
  397. fooRuleShim.content)
  398. }
  399. }
  400. func TestGenerateSoongModuleBzl(t *testing.T) {
  401. ruleShims, err := createRuleShims(createPackageFixtures())
  402. if err != nil {
  403. panic(err)
  404. }
  405. actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
  406. expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
  407. expectedRuleMap := `soong_module_rule_map = {
  408. "foo_binary": foo_binary,
  409. "foo_library": foo_library,
  410. "foo_test_": foo_test_,
  411. }`
  412. if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
  413. t.Errorf(
  414. "Generated soong_module.bzl:\n\n%s\n\n"+
  415. "Could not find the load statement in the generated soong_module.bzl:\n%s",
  416. actualSoongModuleBzl,
  417. expectedLoad)
  418. }
  419. if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
  420. t.Errorf(
  421. "Generated soong_module.bzl:\n\n%s\n\n"+
  422. "Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
  423. actualSoongModuleBzl,
  424. expectedRuleMap)
  425. }
  426. }