blob: 6dd394178721261128ca747273fd0e76eb4b843c [file] [log] [blame]
Jooyung Han12df5fb2019-07-11 16:18:47 +09001// Copyright 2019 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 android
16
17import (
Jingwen Chen40fd90a2020-06-15 05:24:19 +000018 "fmt"
Jooyung Han12df5fb2019-07-11 16:18:47 +090019 "io"
20 "reflect"
Paul Duffin8b0349c2020-11-26 14:33:21 +000021 "strings"
Jooyung Han12df5fb2019-07-11 16:18:47 +090022 "testing"
23)
24
25type customModule struct {
26 ModuleBase
Jingwen Chen40fd90a2020-06-15 05:24:19 +000027 data AndroidMkData
28 distFiles TaggedDistFiles
Jooyung Han12df5fb2019-07-11 16:18:47 +090029}
30
31func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Jingwen Chen40fd90a2020-06-15 05:24:19 +000032 m.distFiles = m.GenerateTaggedDistFiles(ctx)
Jooyung Han12df5fb2019-07-11 16:18:47 +090033}
34
35func (m *customModule) AndroidMk() AndroidMkData {
36 return AndroidMkData{
37 Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
38 m.data = data
39 },
40 }
41}
42
Jingwen Chen40fd90a2020-06-15 05:24:19 +000043func (m *customModule) OutputFiles(tag string) (Paths, error) {
44 switch tag {
45 case "":
46 return PathsForTesting("one.out"), nil
47 case ".multiple":
48 return PathsForTesting("two.out", "three/four.out"), nil
Jingwen Chen84811862020-07-21 11:32:19 +000049 case ".another-tag":
50 return PathsForTesting("another.out"), nil
Jingwen Chen40fd90a2020-06-15 05:24:19 +000051 default:
52 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
53 }
54}
55
56func (m *customModule) AndroidMkEntries() []AndroidMkEntries {
57 return []AndroidMkEntries{
58 {
59 Class: "CUSTOM_MODULE",
60 DistFiles: m.distFiles,
61 },
62 }
63}
64
Jooyung Han12df5fb2019-07-11 16:18:47 +090065func customModuleFactory() Module {
66 module := &customModule{}
67 InitAndroidModule(module)
68 return module
69}
70
Paul Duffin103aaae2020-11-26 17:36:46 +000071// buildConfigAndCustomModuleFoo creates a config object, processes the supplied
72// bp module and then returns the config and the custom module called "foo".
73func buildConfigAndCustomModuleFoo(t *testing.T, bp string) (Config, *customModule) {
74 t.Helper()
Colin Cross98be1bb2019-12-13 20:41:13 -080075 config := TestConfig(buildDir, nil, bp, nil)
Jingwen Chencda22c92020-11-23 00:22:30 -050076 config.katiEnabled = true // Enable androidmk Singleton
Colin Cross98be1bb2019-12-13 20:41:13 -080077
Colin Crossae8600b2020-10-29 17:09:13 -070078 ctx := NewTestContext(config)
Colin Cross98be1bb2019-12-13 20:41:13 -080079 ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
80 ctx.RegisterModuleType("custom", customModuleFactory)
Colin Crossae8600b2020-10-29 17:09:13 -070081 ctx.Register()
Jooyung Han12df5fb2019-07-11 16:18:47 +090082
83 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
84 FailIfErrored(t, errs)
85 _, errs = ctx.PrepareBuildActions(config)
86 FailIfErrored(t, errs)
87
Paul Duffin103aaae2020-11-26 17:36:46 +000088 module := ctx.ModuleForTests("foo", "").Module().(*customModule)
89 return config, module
90}
91
92func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testing.T) {
93 bp := `
94 custom {
95 name: "foo",
96 required: ["bar"],
97 host_required: ["baz"],
98 target_required: ["qux"],
99 }
100 `
101
102 _, m := buildConfigAndCustomModuleFoo(t, bp)
Jooyung Han12df5fb2019-07-11 16:18:47 +0900103
104 assertEqual := func(expected interface{}, actual interface{}) {
105 if !reflect.DeepEqual(expected, actual) {
106 t.Errorf("%q expected, but got %q", expected, actual)
107 }
108 }
109 assertEqual([]string{"bar"}, m.data.Required)
110 assertEqual([]string{"baz"}, m.data.Host_required)
111 assertEqual([]string{"qux"}, m.data.Target_required)
112}
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000113
Paul Duffin8b0349c2020-11-26 14:33:21 +0000114func TestGenerateDistContributionsForMake(t *testing.T) {
115 dc := &distContributions{
116 copiesForGoals: []*copiesForGoals{
117 {
118 goals: "my_goal",
119 copies: []distCopy{
120 distCopyForTest("one.out", "one.out"),
121 distCopyForTest("two.out", "other.out"),
122 },
123 },
124 },
125 }
126
127 makeOutput := generateDistContributionsForMake(dc)
128
129 assertStringEquals(t, `.PHONY: my_goal
130$(call dist-for-goals,my_goal,one.out:one.out)
131$(call dist-for-goals,my_goal,two.out:other.out)
132`, strings.Join(makeOutput, ""))
133}
134
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000135func TestGetDistForGoals(t *testing.T) {
136 testCases := []struct {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000137 name string
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000138 bp string
139 expectedAndroidMkLines []string
140 }{
141 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000142 name: "dist-without-tag",
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000143 bp: `
144 custom {
145 name: "foo",
146 dist: {
147 targets: ["my_goal"]
148 }
149 }
150 `,
151 expectedAndroidMkLines: []string{
152 ".PHONY: my_goal\n",
153 "$(call dist-for-goals,my_goal,one.out:one.out)\n",
154 },
155 },
156 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000157 name: "dist-with-tag",
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000158 bp: `
159 custom {
160 name: "foo",
Jingwen Chen84811862020-07-21 11:32:19 +0000161 dist: {
162 targets: ["my_goal"],
163 tag: ".another-tag",
164 }
165 }
166 `,
167 expectedAndroidMkLines: []string{
168 ".PHONY: my_goal\n",
169 "$(call dist-for-goals,my_goal,another.out:another.out)\n",
170 },
171 },
172 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000173 name: "dists-with-tag",
Jingwen Chen84811862020-07-21 11:32:19 +0000174 bp: `
175 custom {
176 name: "foo",
177 dists: [
178 {
179 targets: ["my_goal"],
180 tag: ".another-tag",
181 },
182 ],
183 }
184 `,
185 expectedAndroidMkLines: []string{
186 ".PHONY: my_goal\n",
187 "$(call dist-for-goals,my_goal,another.out:another.out)\n",
188 },
189 },
190 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000191 name: "multiple-dists-with-and-without-tag",
Jingwen Chen84811862020-07-21 11:32:19 +0000192 bp: `
193 custom {
194 name: "foo",
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000195 dists: [
196 {
197 targets: ["my_goal"],
198 },
199 {
200 targets: ["my_second_goal", "my_third_goal"],
201 },
202 ],
203 }
204 `,
205 expectedAndroidMkLines: []string{
206 ".PHONY: my_goal\n",
207 "$(call dist-for-goals,my_goal,one.out:one.out)\n",
208 ".PHONY: my_second_goal my_third_goal\n",
209 "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
210 },
211 },
212 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000213 name: "dist-plus-dists-without-tags",
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000214 bp: `
215 custom {
216 name: "foo",
217 dist: {
218 targets: ["my_goal"],
219 },
220 dists: [
221 {
222 targets: ["my_second_goal", "my_third_goal"],
223 },
224 ],
225 }
226 `,
227 expectedAndroidMkLines: []string{
228 ".PHONY: my_second_goal my_third_goal\n",
229 "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
230 ".PHONY: my_goal\n",
231 "$(call dist-for-goals,my_goal,one.out:one.out)\n",
232 },
233 },
234 {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000235 name: "dist-plus-dists-with-tags",
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000236 bp: `
237 custom {
238 name: "foo",
239 dist: {
240 targets: ["my_goal", "my_other_goal"],
241 tag: ".multiple",
242 },
243 dists: [
244 {
245 targets: ["my_second_goal"],
246 tag: ".multiple",
247 },
248 {
249 targets: ["my_third_goal"],
250 dir: "test/dir",
251 },
252 {
253 targets: ["my_fourth_goal"],
254 suffix: ".suffix",
255 },
256 {
257 targets: ["my_fifth_goal"],
258 dest: "new-name",
259 },
260 {
261 targets: ["my_sixth_goal"],
262 dest: "new-name",
263 dir: "some/dir",
264 suffix: ".suffix",
265 },
266 ],
267 }
268 `,
269 expectedAndroidMkLines: []string{
270 ".PHONY: my_second_goal\n",
271 "$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
272 "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
273 ".PHONY: my_third_goal\n",
274 "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
275 ".PHONY: my_fourth_goal\n",
276 "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
277 ".PHONY: my_fifth_goal\n",
278 "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
279 ".PHONY: my_sixth_goal\n",
280 "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
281 ".PHONY: my_goal my_other_goal\n",
282 "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
283 "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
284 },
285 },
286 }
287
288 for _, testCase := range testCases {
Paul Duffin0cc047a2020-11-25 16:39:30 +0000289 t.Run(testCase.name, func(t *testing.T) {
Paul Duffin103aaae2020-11-26 17:36:46 +0000290 config, module := buildConfigAndCustomModuleFoo(t, testCase.bp)
Paul Duffin0cc047a2020-11-25 16:39:30 +0000291 entries := AndroidMkEntriesForTest(t, config, "", module)
292 if len(entries) != 1 {
293 t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
294 }
295 androidMkLines := entries[0].GetDistForGoals(module)
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000296
Paul Duffin0cc047a2020-11-25 16:39:30 +0000297 if len(androidMkLines) != len(testCase.expectedAndroidMkLines) {
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000298 t.Errorf(
Paul Duffin0cc047a2020-11-25 16:39:30 +0000299 "Expected %d AndroidMk lines, got %d:\n%v",
300 len(testCase.expectedAndroidMkLines),
301 len(androidMkLines),
302 androidMkLines,
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000303 )
304 }
Paul Duffin0cc047a2020-11-25 16:39:30 +0000305 for idx, line := range androidMkLines {
306 expectedLine := testCase.expectedAndroidMkLines[idx]
307 if line != expectedLine {
308 t.Errorf(
309 "Expected AndroidMk line to be '%s', got '%s'",
310 expectedLine,
311 line,
312 )
313 }
314 }
315 })
Jingwen Chen40fd90a2020-06-15 05:24:19 +0000316 }
317}
Paul Duffin8b0349c2020-11-26 14:33:21 +0000318
319func distCopyForTest(from, to string) distCopy {
320 return distCopy{PathForTesting(from), to}
321}
322
323func TestGetDistContributions(t *testing.T) {
324 compareContributions := func(d1 *distContributions, d2 *distContributions) error {
325 if d1 == nil || d2 == nil {
326 if d1 != d2 {
327 return fmt.Errorf("pointer mismatch, expected both to be nil but they were %p and %p", d1, d2)
328 } else {
329 return nil
330 }
331 }
332 if expected, actual := len(d1.copiesForGoals), len(d2.copiesForGoals); expected != actual {
333 return fmt.Errorf("length mismatch, expected %d found %d", expected, actual)
334 }
335
336 for i, copies1 := range d1.copiesForGoals {
337 copies2 := d2.copiesForGoals[i]
338 if expected, actual := copies1.goals, copies2.goals; expected != actual {
339 return fmt.Errorf("goals mismatch at position %d: expected %q found %q", i, expected, actual)
340 }
341
342 if expected, actual := len(copies1.copies), len(copies2.copies); expected != actual {
343 return fmt.Errorf("length mismatch in copy instructions at position %d, expected %d found %d", i, expected, actual)
344 }
345
346 for j, c1 := range copies1.copies {
347 c2 := copies2.copies[j]
348 if expected, actual := NormalizePathForTesting(c1.from), NormalizePathForTesting(c2.from); expected != actual {
349 return fmt.Errorf("paths mismatch at position %d.%d: expected %q found %q", i, j, expected, actual)
350 }
351
352 if expected, actual := c1.dest, c2.dest; expected != actual {
353 return fmt.Errorf("dest mismatch at position %d.%d: expected %q found %q", i, j, expected, actual)
354 }
355 }
356 }
357
358 return nil
359 }
360
361 formatContributions := func(d *distContributions) string {
362 buf := &strings.Builder{}
363 if d == nil {
364 fmt.Fprint(buf, "nil")
365 } else {
366 for _, copiesForGoals := range d.copiesForGoals {
367 fmt.Fprintf(buf, " Goals: %q {\n", copiesForGoals.goals)
368 for _, c := range copiesForGoals.copies {
369 fmt.Fprintf(buf, " %s -> %s\n", NormalizePathForTesting(c.from), c.dest)
370 }
371 fmt.Fprint(buf, " }\n")
372 }
373 }
374 return buf.String()
375 }
376
377 testHelper := func(t *testing.T, name, bp string, expectedContributions *distContributions) {
378 t.Helper()
379 t.Run(name, func(t *testing.T) {
380 t.Helper()
381
382 config, module := buildConfigAndCustomModuleFoo(t, bp)
383 entries := AndroidMkEntriesForTest(t, config, "", module)
384 if len(entries) != 1 {
385 t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
386 }
387 distContributions := entries[0].getDistContributions(module)
388
389 if err := compareContributions(expectedContributions, distContributions); err != nil {
390 t.Errorf("%s\nExpected Contributions\n%sActualContributions\n%s",
391 err,
392 formatContributions(expectedContributions),
393 formatContributions(distContributions))
394 }
395 })
396 }
397
398 testHelper(t, "dist-without-tag", `
399 custom {
400 name: "foo",
401 dist: {
402 targets: ["my_goal"]
403 }
404 }
405`,
406 &distContributions{
407 copiesForGoals: []*copiesForGoals{
408 {
409 goals: "my_goal",
410 copies: []distCopy{
411 distCopyForTest("one.out", "one.out"),
412 },
413 },
414 },
415 })
416
417 testHelper(t, "dist-with-tag", `
418 custom {
419 name: "foo",
420 dist: {
421 targets: ["my_goal"],
422 tag: ".another-tag",
423 }
424 }
425`,
426 &distContributions{
427 copiesForGoals: []*copiesForGoals{
428 {
429 goals: "my_goal",
430 copies: []distCopy{
431 distCopyForTest("another.out", "another.out"),
432 },
433 },
434 },
435 })
436
437 testHelper(t, "dists-with-tag", `
438 custom {
439 name: "foo",
440 dists: [
441 {
442 targets: ["my_goal"],
443 tag: ".another-tag",
444 },
445 ],
446 }
447`,
448 &distContributions{
449 copiesForGoals: []*copiesForGoals{
450 {
451 goals: "my_goal",
452 copies: []distCopy{
453 distCopyForTest("another.out", "another.out"),
454 },
455 },
456 },
457 })
458
459 testHelper(t, "multiple-dists-with-and-without-tag", `
460 custom {
461 name: "foo",
462 dists: [
463 {
464 targets: ["my_goal"],
465 },
466 {
467 targets: ["my_second_goal", "my_third_goal"],
468 },
469 ],
470 }
471`,
472 &distContributions{
473 copiesForGoals: []*copiesForGoals{
474 {
475 goals: "my_goal",
476 copies: []distCopy{
477 distCopyForTest("one.out", "one.out"),
478 },
479 },
480 {
481 goals: "my_second_goal my_third_goal",
482 copies: []distCopy{
483 distCopyForTest("one.out", "one.out"),
484 },
485 },
486 },
487 })
488
489 testHelper(t, "dist-plus-dists-without-tags", `
490 custom {
491 name: "foo",
492 dist: {
493 targets: ["my_goal"],
494 },
495 dists: [
496 {
497 targets: ["my_second_goal", "my_third_goal"],
498 },
499 ],
500 }
501`,
502 &distContributions{
503 copiesForGoals: []*copiesForGoals{
504 {
505 goals: "my_second_goal my_third_goal",
506 copies: []distCopy{
507 distCopyForTest("one.out", "one.out"),
508 },
509 },
510 {
511 goals: "my_goal",
512 copies: []distCopy{
513 distCopyForTest("one.out", "one.out"),
514 },
515 },
516 },
517 })
518
519 testHelper(t, "dist-plus-dists-with-tags", `
520 custom {
521 name: "foo",
522 dist: {
523 targets: ["my_goal", "my_other_goal"],
524 tag: ".multiple",
525 },
526 dists: [
527 {
528 targets: ["my_second_goal"],
529 tag: ".multiple",
530 },
531 {
532 targets: ["my_third_goal"],
533 dir: "test/dir",
534 },
535 {
536 targets: ["my_fourth_goal"],
537 suffix: ".suffix",
538 },
539 {
540 targets: ["my_fifth_goal"],
541 dest: "new-name",
542 },
543 {
544 targets: ["my_sixth_goal"],
545 dest: "new-name",
546 dir: "some/dir",
547 suffix: ".suffix",
548 },
549 ],
550 }
551`,
552 &distContributions{
553 copiesForGoals: []*copiesForGoals{
554 {
555 goals: "my_second_goal",
556 copies: []distCopy{
557 distCopyForTest("two.out", "two.out"),
558 distCopyForTest("three/four.out", "four.out"),
559 },
560 },
561 {
562 goals: "my_third_goal",
563 copies: []distCopy{
564 distCopyForTest("one.out", "test/dir/one.out"),
565 },
566 },
567 {
568 goals: "my_fourth_goal",
569 copies: []distCopy{
570 distCopyForTest("one.out", "one.suffix.out"),
571 },
572 },
573 {
574 goals: "my_fifth_goal",
575 copies: []distCopy{
576 distCopyForTest("one.out", "new-name"),
577 },
578 },
579 {
580 goals: "my_sixth_goal",
581 copies: []distCopy{
582 distCopyForTest("one.out", "some/dir/new-name.suffix"),
583 },
584 },
585 {
586 goals: "my_goal my_other_goal",
587 copies: []distCopy{
588 distCopyForTest("two.out", "two.out"),
589 distCopyForTest("three/four.out", "four.out"),
590 },
591 },
592 },
593 })
594}