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