blob: 9471a9137980fb5d799ce219bc76fd721bfac0ac [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
Paul Duffinaf970a22020-11-23 23:32:56 +000056// OutputFiles is needed because some instances of this module use dist with a
57// tag property which requires the module implements OutputFileProducer.
58func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
59 return android.PathsForTesting("path" + tag), nil
60}
61
Jingwen Chen69d4cbe2020-08-07 14:16:34 +000062func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
63 // nothing for now.
64}
65
66func customModuleFactory() android.Module {
67 module := &customModule{}
68 android.InitAndroidModule(module)
69 return module
70}
71
Jingwen Chen50f93d22020-11-05 07:42:11 -050072func TestGenerateBazelQueryViewFromBlueprint(t *testing.T) {
Jingwen Chen69d4cbe2020-08-07 14:16:34 +000073 testCases := []struct {
74 bp string
75 expectedBazelTarget string
76 }{
77 {
78 bp: `custom {
79 name: "foo",
80}
81 `,
82 expectedBazelTarget: `soong_module(
83 name = "foo",
84 module_name = "foo",
85 module_type = "custom",
86 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +000087 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +000088 ],
89)`,
90 },
91 {
92 bp: `custom {
93 name: "foo",
94 ramdisk: true,
95}
96 `,
97 expectedBazelTarget: `soong_module(
98 name = "foo",
99 module_name = "foo",
100 module_type = "custom",
101 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000102 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000103 ],
104 ramdisk = True,
105)`,
106 },
107 {
108 bp: `custom {
109 name: "foo",
110 owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
111}
112 `,
113 expectedBazelTarget: `soong_module(
114 name = "foo",
115 module_name = "foo",
116 module_type = "custom",
117 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000118 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000119 ],
120 owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
121)`,
122 },
123 {
124 bp: `custom {
125 name: "foo",
126 required: ["bar"],
127}
128 `,
129 expectedBazelTarget: `soong_module(
130 name = "foo",
131 module_name = "foo",
132 module_type = "custom",
133 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000134 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000135 ],
136 required = [
137 "bar",
138 ],
139)`,
140 },
141 {
142 bp: `custom {
143 name: "foo",
144 target_required: ["qux", "bazqux"],
145}
146 `,
147 expectedBazelTarget: `soong_module(
148 name = "foo",
149 module_name = "foo",
150 module_type = "custom",
151 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000152 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000153 ],
154 target_required = [
155 "qux",
156 "bazqux",
157 ],
158)`,
159 },
160 {
161 bp: `custom {
162 name: "foo",
163 dist: {
164 targets: ["goal_foo"],
165 tag: ".foo",
166 },
167 dists: [
168 {
169 targets: ["goal_bar"],
170 tag: ".bar",
171 },
172 ],
173}
174 `,
175 expectedBazelTarget: `soong_module(
176 name = "foo",
177 module_name = "foo",
178 module_type = "custom",
179 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000180 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000181 ],
182 dist = {
183 "tag": ".foo",
184 "targets": [
185 "goal_foo",
186 ],
187 },
188 dists = [
189 {
190 "tag": ".bar",
191 "targets": [
192 "goal_bar",
193 ],
194 },
195 ],
196)`,
197 },
198 {
199 bp: `custom {
200 name: "foo",
201 required: ["bar"],
202 target_required: ["qux", "bazqux"],
203 ramdisk: true,
204 owner: "custom_owner",
205 dists: [
206 {
207 tag: ".tag",
208 targets: ["my_goal"],
209 },
210 ],
211}
212 `,
213 expectedBazelTarget: `soong_module(
214 name = "foo",
215 module_name = "foo",
216 module_type = "custom",
217 module_variant = "",
Jingwen Chence3d46f2020-08-25 05:34:43 +0000218 module_deps = [
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000219 ],
220 dists = [
221 {
222 "tag": ".tag",
223 "targets": [
224 "my_goal",
225 ],
226 },
227 ],
228 owner = "custom_owner",
229 ramdisk = True,
230 required = [
231 "bar",
232 ],
233 target_required = [
234 "qux",
235 "bazqux",
236 ],
237)`,
238 },
239 }
240
241 for _, testCase := range testCases {
242 config := android.TestConfig(buildDir, nil, testCase.bp, nil)
Colin Crossae8600b2020-10-29 17:09:13 -0700243 ctx := android.NewTestContext(config)
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000244 ctx.RegisterModuleType("custom", customModuleFactory)
Colin Crossae8600b2020-10-29 17:09:13 -0700245 ctx.Register()
Jingwen Chen69d4cbe2020-08-07 14:16:34 +0000246
247 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
248 android.FailIfErrored(t, errs)
249 _, errs = ctx.PrepareBuildActions(config)
250 android.FailIfErrored(t, errs)
251
252 module := ctx.ModuleForTests("foo", "").Module().(*customModule)
253 blueprintCtx := ctx.Context.Context
254
255 actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module)
256 if actualBazelTarget != testCase.expectedBazelTarget {
257 t.Errorf(
258 "Expected generated Bazel target to be '%s', got '%s'",
259 testCase.expectedBazelTarget,
260 actualBazelTarget,
261 )
262 }
263 }
264}
Jingwen Chend8004ef2020-08-27 09:40:43 +0000265
266func createPackageFixtures() []*bpdoc.Package {
267 properties := []bpdoc.Property{
268 bpdoc.Property{
269 Name: "int64_prop",
270 Type: "int64",
271 },
272 bpdoc.Property{
273 Name: "int_prop",
274 Type: "int",
275 },
276 bpdoc.Property{
277 Name: "bool_prop",
278 Type: "bool",
279 },
280 bpdoc.Property{
281 Name: "string_prop",
282 Type: "string",
283 },
284 bpdoc.Property{
285 Name: "string_list_prop",
Jingwen Chen222ff4d2020-11-05 03:52:34 -0500286 Type: "list of string",
Jingwen Chend8004ef2020-08-27 09:40:43 +0000287 },
288 bpdoc.Property{
289 Name: "nested_prop",
290 Type: "",
291 Properties: []bpdoc.Property{
292 bpdoc.Property{
293 Name: "int_prop",
294 Type: "int",
295 },
296 bpdoc.Property{
297 Name: "bool_prop",
298 Type: "bool",
299 },
300 bpdoc.Property{
301 Name: "string_prop",
302 Type: "string",
303 },
304 },
305 },
306 bpdoc.Property{
307 Name: "unknown_type",
308 Type: "unknown",
309 },
310 }
311
312 fooPropertyStruct := &bpdoc.PropertyStruct{
313 Name: "FooProperties",
314 Properties: properties,
315 }
316
317 moduleTypes := []*bpdoc.ModuleType{
318 &bpdoc.ModuleType{
319 Name: "foo_library",
320 PropertyStructs: []*bpdoc.PropertyStruct{
321 fooPropertyStruct,
322 },
323 },
324
325 &bpdoc.ModuleType{
326 Name: "foo_binary",
327 PropertyStructs: []*bpdoc.PropertyStruct{
328 fooPropertyStruct,
329 },
330 },
331 &bpdoc.ModuleType{
332 Name: "foo_test",
333 PropertyStructs: []*bpdoc.PropertyStruct{
334 fooPropertyStruct,
335 },
336 },
337 }
338
339 return [](*bpdoc.Package){
340 &bpdoc.Package{
341 Name: "foo_language",
342 Path: "android/soong/foo",
343 ModuleTypes: moduleTypes,
344 },
345 }
346}
347
348func TestGenerateModuleRuleShims(t *testing.T) {
349 ruleShims, err := createRuleShims(createPackageFixtures())
350 if err != nil {
351 panic(err)
352 }
353
354 if len(ruleShims) != 1 {
355 t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
356 }
357
358 fooRuleShim := ruleShims["foo"]
359 expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
360
361 if len(fooRuleShim.rules) != 3 {
362 t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
363 }
364
365 for i, rule := range fooRuleShim.rules {
366 if rule != expectedRules[i] {
367 t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
368 }
369 }
370
Jingwen Chen50f93d22020-11-05 07:42:11 -0500371 expectedBzl := `load("//build/bazel/queryview_rules:providers.bzl", "SoongModuleInfo")
Jingwen Chend8004ef2020-08-27 09:40:43 +0000372
373def _foo_binary_impl(ctx):
374 return [SoongModuleInfo()]
375
376foo_binary = rule(
377 implementation = _foo_binary_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
393def _foo_library_impl(ctx):
394 return [SoongModuleInfo()]
395
396foo_library = rule(
397 implementation = _foo_library_impl,
398 attrs = {
399 "module_name": attr.string(mandatory = True),
400 "module_variant": attr.string(),
401 "module_deps": attr.label_list(providers = [SoongModuleInfo]),
402 "bool_prop": attr.bool(),
403 "int64_prop": attr.int(),
404 "int_prop": attr.int(),
405# "nested_prop__int_prop": attr.int(),
406# "nested_prop__bool_prop": attr.bool(),
407# "nested_prop__string_prop": attr.string(),
408 "string_list_prop": attr.string_list(),
409 "string_prop": attr.string(),
410 },
411)
412
413def _foo_test__impl(ctx):
414 return [SoongModuleInfo()]
415
416foo_test_ = rule(
417 implementation = _foo_test__impl,
418 attrs = {
419 "module_name": attr.string(mandatory = True),
420 "module_variant": attr.string(),
421 "module_deps": attr.label_list(providers = [SoongModuleInfo]),
422 "bool_prop": attr.bool(),
423 "int64_prop": attr.int(),
424 "int_prop": attr.int(),
425# "nested_prop__int_prop": attr.int(),
426# "nested_prop__bool_prop": attr.bool(),
427# "nested_prop__string_prop": attr.string(),
428 "string_list_prop": attr.string_list(),
429 "string_prop": attr.string(),
430 },
431)
432`
433
434 if fooRuleShim.content != expectedBzl {
435 t.Errorf(
436 "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
437 expectedBzl,
438 fooRuleShim.content)
439 }
440}
441
442func TestGenerateSoongModuleBzl(t *testing.T) {
443 ruleShims, err := createRuleShims(createPackageFixtures())
444 if err != nil {
445 panic(err)
446 }
447 actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
448
Jingwen Chen50f93d22020-11-05 07:42:11 -0500449 expectedLoad := "load(\"//build/bazel/queryview_rules:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
Jingwen Chend8004ef2020-08-27 09:40:43 +0000450 expectedRuleMap := `soong_module_rule_map = {
451 "foo_binary": foo_binary,
452 "foo_library": foo_library,
453 "foo_test_": foo_test_,
454}`
455 if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
456 t.Errorf(
457 "Generated soong_module.bzl:\n\n%s\n\n"+
458 "Could not find the load statement in the generated soong_module.bzl:\n%s",
459 actualSoongModuleBzl,
460 expectedLoad)
461 }
462
463 if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
464 t.Errorf(
465 "Generated soong_module.bzl:\n\n%s\n\n"+
466 "Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
467 actualSoongModuleBzl,
468 expectedRuleMap)
469 }
470}