1// 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 (
18	"testing"
19)
20
21type pathDepsMutatorTestModule struct {
22	ModuleBase
23	props struct {
24		Foo string   `android:"path"`
25		Bar []string `android:"path,arch_variant"`
26		Baz *string  `android:"path"`
27		Qux string
28		V   *struct {
29			W string `android:"path"`
30		}
31	}
32
33	// A second property struct with a duplicate property name
34	props2 struct {
35		Foo string `android:"path"`
36	}
37
38	// nested slices of struct
39	props3 struct {
40		X []struct {
41			Y []struct {
42				Z []string `android:"path"`
43			}
44		}
45	}
46
47	sourceDeps []string
48}
49
50func pathDepsMutatorTestModuleFactory() Module {
51	module := &pathDepsMutatorTestModule{}
52	module.AddProperties(&module.props, &module.props2, &module.props3)
53	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
54	return module
55}
56
57func (p *pathDepsMutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
58	ctx.VisitDirectDeps(func(dep Module) {
59		if _, ok := ctx.OtherModuleDependencyTag(dep).(sourceOrOutputDependencyTag); ok {
60			p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep))
61		}
62	})
63
64	if p.props.Foo != "" {
65		// Make sure there is only one dependency on a module listed in a property present in multiple property structs
66		if ctx.GetDirectDepWithTag(SrcIsModule(p.props.Foo), sourceOrOutputDepTag("")) == nil {
67			ctx.ModuleErrorf("GetDirectDepWithTag failed")
68		}
69	}
70}
71
72func TestPathDepsMutator(t *testing.T) {
73	tests := []struct {
74		name string
75		bp   string
76		deps []string
77	}{
78		{
79			name: "all",
80			bp: `
81			test {
82				name: "foo",
83				foo: ":a",
84				bar: [":b"],
85				baz: ":c{.bar}",
86				qux: ":d",
87				x: [
88					{
89						y: [
90							{
91								z: [":x", ":y"],
92							},
93							{
94								z: [":z"],
95							},
96						],
97					},
98				],
99				v: {
100					w: ":w",
101				},
102			}`,
103			deps: []string{"a", "b", "c", "w", "x", "y", "z"},
104		},
105		{
106			name: "arch variant",
107			bp: `
108			test {
109				name: "foo",
110				arch: {
111					arm64: {
112						bar: [":a"],
113					},
114					arm: {
115						bar: [":b"],
116					},
117				},
118				bar: [":c"],
119			}`,
120			deps: []string{"c", "a"},
121		},
122	}
123
124	for _, test := range tests {
125		t.Run(test.name, func(t *testing.T) {
126			bp := test.bp + `
127				filegroup {
128					name: "a",
129				}
130
131				filegroup {
132					name: "b",
133				}
134
135				filegroup {
136					name: "c",
137				}
138
139				filegroup {
140					name: "d",
141				}
142
143				filegroup {
144					name: "w",
145				}
146
147				filegroup {
148					name: "x",
149				}
150
151				filegroup {
152					name: "y",
153				}
154
155				filegroup {
156					name: "z",
157				}
158			`
159
160			result := GroupFixturePreparers(
161				PrepareForTestWithArchMutator,
162				PrepareForTestWithFilegroup,
163				FixtureRegisterWithContext(func(ctx RegistrationContext) {
164					ctx.RegisterModuleType("test", pathDepsMutatorTestModuleFactory)
165				}),
166				FixtureWithRootAndroidBp(bp),
167			).RunTest(t)
168
169			m := result.Module("foo", "android_arm64_armv8-a").(*pathDepsMutatorTestModule)
170
171			AssertDeepEquals(t, "deps", test.deps, m.sourceDeps)
172		})
173	}
174}
175