1// Copyright 2015 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
21func TestSrcIsModule(t *testing.T) {
22	type args struct {
23		s string
24	}
25	tests := []struct {
26		name       string
27		args       args
28		wantModule string
29	}{
30		{
31			name: "file",
32			args: args{
33				s: "foo",
34			},
35			wantModule: "",
36		},
37		{
38			name: "module",
39			args: args{
40				s: ":foo",
41			},
42			wantModule: "foo",
43		},
44		{
45			name: "tag",
46			args: args{
47				s: ":foo{.bar}",
48			},
49			wantModule: "foo{.bar}",
50		},
51		{
52			name: "extra colon",
53			args: args{
54				s: ":foo:bar",
55			},
56			wantModule: "foo:bar",
57		},
58	}
59	for _, tt := range tests {
60		t.Run(tt.name, func(t *testing.T) {
61			if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule {
62				t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule)
63			}
64		})
65	}
66}
67
68func TestSrcIsModuleWithTag(t *testing.T) {
69	type args struct {
70		s string
71	}
72	tests := []struct {
73		name       string
74		args       args
75		wantModule string
76		wantTag    string
77	}{
78		{
79			name: "file",
80			args: args{
81				s: "foo",
82			},
83			wantModule: "",
84			wantTag:    "",
85		},
86		{
87			name: "module",
88			args: args{
89				s: ":foo",
90			},
91			wantModule: "foo",
92			wantTag:    "",
93		},
94		{
95			name: "tag",
96			args: args{
97				s: ":foo{.bar}",
98			},
99			wantModule: "foo",
100			wantTag:    ".bar",
101		},
102		{
103			name: "empty tag",
104			args: args{
105				s: ":foo{}",
106			},
107			wantModule: "foo",
108			wantTag:    "",
109		},
110		{
111			name: "extra colon",
112			args: args{
113				s: ":foo:bar",
114			},
115			wantModule: "foo:bar",
116		},
117		{
118			name: "invalid tag",
119			args: args{
120				s: ":foo{.bar",
121			},
122			wantModule: "foo{.bar",
123		},
124		{
125			name: "invalid tag 2",
126			args: args{
127				s: ":foo.bar}",
128			},
129			wantModule: "foo.bar}",
130		},
131	}
132	for _, tt := range tests {
133		t.Run(tt.name, func(t *testing.T) {
134			gotModule, gotTag := SrcIsModuleWithTag(tt.args.s)
135			if gotModule != tt.wantModule {
136				t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule)
137			}
138			if gotTag != tt.wantTag {
139				t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag)
140			}
141		})
142	}
143}
144
145type depsModule struct {
146	ModuleBase
147	props struct {
148		Deps []string
149	}
150}
151
152func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
153}
154
155func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
156	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
157}
158
159func depsModuleFactory() Module {
160	m := &depsModule{}
161	m.AddProperties(&m.props)
162	InitAndroidModule(m)
163	return m
164}
165
166var prepareForModuleTests = FixtureRegisterWithContext(func(ctx RegistrationContext) {
167	ctx.RegisterModuleType("deps", depsModuleFactory)
168})
169
170func TestErrorDependsOnDisabledModule(t *testing.T) {
171	bp := `
172		deps {
173			name: "foo",
174			deps: ["bar"],
175		}
176		deps {
177			name: "bar",
178			enabled: false,
179		}
180	`
181
182	prepareForModuleTests.
183		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)).
184		RunTestWithBp(t, bp)
185}
186
187func TestValidateCorrectBuildParams(t *testing.T) {
188	config := TestConfig(t.TempDir(), nil, "", nil)
189	pathContext := PathContextForTesting(config)
190	bparams := convertBuildParams(BuildParams{
191		// Test with Output
192		Output:        PathForOutput(pathContext, "undeclared_symlink"),
193		SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"),
194	})
195
196	err := validateBuildParams(bparams)
197	if err != nil {
198		t.Error(err)
199	}
200
201	bparams = convertBuildParams(BuildParams{
202		// Test with ImplicitOutput
203		ImplicitOutput: PathForOutput(pathContext, "undeclared_symlink"),
204		SymlinkOutput:  PathForOutput(pathContext, "undeclared_symlink"),
205	})
206
207	err = validateBuildParams(bparams)
208	if err != nil {
209		t.Error(err)
210	}
211}
212
213func TestValidateIncorrectBuildParams(t *testing.T) {
214	config := TestConfig(t.TempDir(), nil, "", nil)
215	pathContext := PathContextForTesting(config)
216	params := BuildParams{
217		Output:          PathForOutput(pathContext, "regular_output"),
218		Outputs:         PathsForOutput(pathContext, []string{"out1", "out2"}),
219		ImplicitOutput:  PathForOutput(pathContext, "implicit_output"),
220		ImplicitOutputs: PathsForOutput(pathContext, []string{"i_out1", "_out2"}),
221		SymlinkOutput:   PathForOutput(pathContext, "undeclared_symlink"),
222	}
223
224	bparams := convertBuildParams(params)
225	err := validateBuildParams(bparams)
226	if err != nil {
227		FailIfNoMatchingErrors(t, "undeclared_symlink is not a declared output or implicit output", []error{err})
228	} else {
229		t.Errorf("Expected build params to fail validation: %+v", bparams)
230	}
231}
232
233func TestDistErrorChecking(t *testing.T) {
234	bp := `
235		deps {
236			name: "foo",
237      dist: {
238        dest: "../invalid-dest",
239        dir: "../invalid-dir",
240        suffix: "invalid/suffix",
241      },
242      dists: [
243        {
244          dest: "../invalid-dest0",
245          dir: "../invalid-dir0",
246          suffix: "invalid/suffix0",
247        },
248        {
249          dest: "../invalid-dest1",
250          dir: "../invalid-dir1",
251          suffix: "invalid/suffix1",
252        },
253      ],
254 		}
255	`
256
257	expectedErrs := []string{
258		"\\QAndroid.bp:5:13: module \"foo\": dist.dest: Path is outside directory: ../invalid-dest\\E",
259		"\\QAndroid.bp:6:12: module \"foo\": dist.dir: Path is outside directory: ../invalid-dir\\E",
260		"\\QAndroid.bp:7:15: module \"foo\": dist.suffix: Suffix may not contain a '/' character.\\E",
261		"\\QAndroid.bp:11:15: module \"foo\": dists[0].dest: Path is outside directory: ../invalid-dest0\\E",
262		"\\QAndroid.bp:12:14: module \"foo\": dists[0].dir: Path is outside directory: ../invalid-dir0\\E",
263		"\\QAndroid.bp:13:17: module \"foo\": dists[0].suffix: Suffix may not contain a '/' character.\\E",
264		"\\QAndroid.bp:16:15: module \"foo\": dists[1].dest: Path is outside directory: ../invalid-dest1\\E",
265		"\\QAndroid.bp:17:14: module \"foo\": dists[1].dir: Path is outside directory: ../invalid-dir1\\E",
266		"\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E",
267	}
268
269	prepareForModuleTests.
270		ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
271		RunTestWithBp(t, bp)
272}
273