blob: 696efb6f8166bb3c7d6d31f8652c0f70cc8b583e [file] [log] [blame]
Colin Crosscec81712017-07-13 14:43:27 -07001// Copyright 2017 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 "fmt"
Paul Duffin9b478b02019-12-10 13:41:51 +000019 "path/filepath"
Logan Chienee97c3e2018-03-12 16:34:26 +080020 "regexp"
Martin Stjernholm4c021242020-05-13 01:13:50 +010021 "sort"
Colin Crosscec81712017-07-13 14:43:27 -070022 "strings"
Logan Chien42039712018-03-12 16:29:17 +080023 "testing"
Colin Crosscec81712017-07-13 14:43:27 -070024
25 "github.com/google/blueprint"
26)
27
28func NewTestContext() *TestContext {
Jeff Gaston088e29e2017-11-29 16:47:17 -080029 namespaceExportFilter := func(namespace *Namespace) bool {
30 return true
31 }
Jeff Gastonb274ed32017-12-01 17:10:33 -080032
33 nameResolver := NewNameResolver(namespaceExportFilter)
34 ctx := &TestContext{
Colin Cross4c83e5c2019-02-25 14:54:28 -080035 Context: &Context{blueprint.NewContext()},
Jeff Gastonb274ed32017-12-01 17:10:33 -080036 NameResolver: nameResolver,
37 }
38
39 ctx.SetNameInterface(nameResolver)
Jeff Gaston088e29e2017-11-29 16:47:17 -080040
Colin Cross1b488422019-03-04 22:33:56 -080041 ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator)
42
Jeff Gaston088e29e2017-11-29 16:47:17 -080043 return ctx
Colin Crosscec81712017-07-13 14:43:27 -070044}
45
Colin Crossae4c6182017-09-15 17:33:55 -070046func NewTestArchContext() *TestContext {
47 ctx := NewTestContext()
48 ctx.preDeps = append(ctx.preDeps, registerArchMutator)
49 return ctx
50}
51
Colin Crosscec81712017-07-13 14:43:27 -070052type TestContext struct {
Colin Cross4c83e5c2019-02-25 14:54:28 -080053 *Context
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000054 preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
55 NameResolver *NameResolver
56 config Config
Colin Crosscec81712017-07-13 14:43:27 -070057}
58
59func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
60 ctx.preArch = append(ctx.preArch, f)
61}
62
Paul Duffina80ef842020-01-14 12:09:36 +000063func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) {
64 // Register mutator function as normal for testing.
65 ctx.PreArchMutators(f)
66}
67
Colin Crosscec81712017-07-13 14:43:27 -070068func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) {
69 ctx.preDeps = append(ctx.preDeps, f)
70}
71
72func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) {
73 ctx.postDeps = append(ctx.postDeps, f)
74}
75
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000076func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) {
77 ctx.finalDeps = append(ctx.finalDeps, f)
78}
79
Colin Cross98be1bb2019-12-13 20:41:13 -080080func (ctx *TestContext) Register(config Config) {
81 ctx.SetFs(config.fs)
82 if config.mockBpList != "" {
83 ctx.SetModuleListFile(config.mockBpList)
84 }
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000085 registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
Colin Crosscec81712017-07-13 14:43:27 -070086
Colin Cross4b49b762019-11-22 15:25:03 -080087 ctx.RegisterSingletonType("env", EnvSingleton)
Colin Cross31a738b2019-12-30 18:45:15 -080088
89 ctx.config = config
90}
91
92func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
93 // This function adapts the old style ParseFileList calls that are spread throughout the tests
94 // to the new style that takes a config.
95 return ctx.Context.ParseFileList(rootDir, filePaths, ctx.config)
96}
97
98func (ctx *TestContext) ParseBlueprintsFiles(rootDir string) (deps []string, errs []error) {
99 // This function adapts the old style ParseBlueprintsFiles calls that are spread throughout the
100 // tests to the new style that takes a config.
101 return ctx.Context.ParseBlueprintsFiles(rootDir, ctx.config)
Colin Cross4b49b762019-11-22 15:25:03 -0800102}
103
104func (ctx *TestContext) RegisterModuleType(name string, factory ModuleFactory) {
105 ctx.Context.RegisterModuleType(name, ModuleFactoryAdaptor(factory))
106}
107
108func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
109 ctx.Context.RegisterSingletonType(name, SingletonFactoryAdaptor(factory))
Colin Crosscec81712017-07-13 14:43:27 -0700110}
111
112func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
113 var module Module
114 ctx.VisitAllModules(func(m blueprint.Module) {
115 if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
116 module = m.(Module)
117 }
118 })
119
120 if module == nil {
Jeff Gaston294356f2017-09-27 17:05:30 -0700121 // find all the modules that do exist
122 allModuleNames := []string{}
123 ctx.VisitAllModules(func(m blueprint.Module) {
124 allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")")
125 })
Martin Stjernholm4c021242020-05-13 01:13:50 +0100126 sort.Strings(allModuleNames)
Jeff Gaston294356f2017-09-27 17:05:30 -0700127
Martin Stjernholm4c021242020-05-13 01:13:50 +0100128 panic(fmt.Errorf("failed to find module %q variant %q. All modules:\n %s",
129 name, variant, strings.Join(allModuleNames, "\n ")))
Colin Crosscec81712017-07-13 14:43:27 -0700130 }
131
132 return TestingModule{module}
133}
134
Jiyong Park37b25202018-07-11 10:49:27 +0900135func (ctx *TestContext) ModuleVariantsForTests(name string) []string {
136 var variants []string
137 ctx.VisitAllModules(func(m blueprint.Module) {
138 if ctx.ModuleName(m) == name {
139 variants = append(variants, ctx.ModuleSubDir(m))
140 }
141 })
142 return variants
143}
144
Colin Cross4c83e5c2019-02-25 14:54:28 -0800145// SingletonForTests returns a TestingSingleton for the singleton registered with the given name.
146func (ctx *TestContext) SingletonForTests(name string) TestingSingleton {
147 allSingletonNames := []string{}
148 for _, s := range ctx.Singletons() {
149 n := ctx.SingletonName(s)
150 if n == name {
151 return TestingSingleton{
152 singleton: s.(*singletonAdaptor).Singleton,
153 provider: s.(testBuildProvider),
154 }
155 }
156 allSingletonNames = append(allSingletonNames, n)
157 }
158
159 panic(fmt.Errorf("failed to find singleton %q."+
160 "\nall singletons: %v", name, allSingletonNames))
161}
162
Colin Cross4c83e5c2019-02-25 14:54:28 -0800163type testBuildProvider interface {
164 BuildParamsForTests() []BuildParams
165 RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
166}
167
168type TestingBuildParams struct {
169 BuildParams
170 RuleParams blueprint.RuleParams
171}
172
173func newTestingBuildParams(provider testBuildProvider, bparams BuildParams) TestingBuildParams {
174 return TestingBuildParams{
175 BuildParams: bparams,
176 RuleParams: provider.RuleParamsForTests()[bparams.Rule],
177 }
178}
179
180func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
181 for _, p := range provider.BuildParamsForTests() {
182 if strings.Contains(p.Rule.String(), rule) {
183 return newTestingBuildParams(provider, p)
184 }
185 }
186 return TestingBuildParams{}
187}
188
189func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
190 p := maybeBuildParamsFromRule(provider, rule)
191 if p.Rule == nil {
192 panic(fmt.Errorf("couldn't find rule %q", rule))
193 }
194 return p
195}
196
197func maybeBuildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
198 for _, p := range provider.BuildParamsForTests() {
Colin Crossb88b3c52019-06-10 15:15:17 -0700199 if strings.Contains(p.Description, desc) {
Colin Cross4c83e5c2019-02-25 14:54:28 -0800200 return newTestingBuildParams(provider, p)
201 }
202 }
203 return TestingBuildParams{}
204}
205
206func buildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
207 p := maybeBuildParamsFromDescription(provider, desc)
208 if p.Rule == nil {
209 panic(fmt.Errorf("couldn't find description %q", desc))
210 }
211 return p
212}
213
214func maybeBuildParamsFromOutput(provider testBuildProvider, file string) (TestingBuildParams, []string) {
215 var searchedOutputs []string
216 for _, p := range provider.BuildParamsForTests() {
217 outputs := append(WritablePaths(nil), p.Outputs...)
Colin Cross1d2cf042019-03-29 15:33:06 -0700218 outputs = append(outputs, p.ImplicitOutputs...)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800219 if p.Output != nil {
220 outputs = append(outputs, p.Output)
221 }
222 for _, f := range outputs {
223 if f.String() == file || f.Rel() == file {
224 return newTestingBuildParams(provider, p), nil
225 }
226 searchedOutputs = append(searchedOutputs, f.Rel())
227 }
228 }
229 return TestingBuildParams{}, searchedOutputs
230}
231
232func buildParamsFromOutput(provider testBuildProvider, file string) TestingBuildParams {
233 p, searchedOutputs := maybeBuildParamsFromOutput(provider, file)
234 if p.Rule == nil {
235 panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v",
236 file, searchedOutputs))
237 }
238 return p
239}
240
241func allOutputs(provider testBuildProvider) []string {
242 var outputFullPaths []string
243 for _, p := range provider.BuildParamsForTests() {
244 outputs := append(WritablePaths(nil), p.Outputs...)
Colin Cross1d2cf042019-03-29 15:33:06 -0700245 outputs = append(outputs, p.ImplicitOutputs...)
Colin Cross4c83e5c2019-02-25 14:54:28 -0800246 if p.Output != nil {
247 outputs = append(outputs, p.Output)
248 }
249 outputFullPaths = append(outputFullPaths, outputs.Strings()...)
250 }
251 return outputFullPaths
252}
253
Colin Crossb77ffc42019-01-05 22:09:19 -0800254// TestingModule is wrapper around an android.Module that provides methods to find information about individual
255// ctx.Build parameters for verification in tests.
Colin Crosscec81712017-07-13 14:43:27 -0700256type TestingModule struct {
257 module Module
258}
259
Colin Crossb77ffc42019-01-05 22:09:19 -0800260// Module returns the Module wrapped by the TestingModule.
Colin Crosscec81712017-07-13 14:43:27 -0700261func (m TestingModule) Module() Module {
262 return m.module
263}
264
Colin Crossb77ffc42019-01-05 22:09:19 -0800265// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
266// BuildParams if no rule is found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800267func (m TestingModule) MaybeRule(rule string) TestingBuildParams {
268 return maybeBuildParamsFromRule(m.module, rule)
Colin Crosscec81712017-07-13 14:43:27 -0700269}
270
Colin Crossb77ffc42019-01-05 22:09:19 -0800271// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800272func (m TestingModule) Rule(rule string) TestingBuildParams {
273 return buildParamsFromRule(m.module, rule)
Colin Crossb77ffc42019-01-05 22:09:19 -0800274}
275
276// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string. Returns an empty
277// BuildParams if no rule is found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800278func (m TestingModule) MaybeDescription(desc string) TestingBuildParams {
279 return maybeBuildParamsFromDescription(m.module, desc)
Nan Zhanged19fc32017-10-19 13:06:22 -0700280}
281
Colin Crossb77ffc42019-01-05 22:09:19 -0800282// Description finds a call to ctx.Build with BuildParams.Description set to a the given string. Panics if no rule is
283// found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800284func (m TestingModule) Description(desc string) TestingBuildParams {
285 return buildParamsFromDescription(m.module, desc)
Colin Crossb77ffc42019-01-05 22:09:19 -0800286}
287
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800288// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
Colin Crossb77ffc42019-01-05 22:09:19 -0800289// value matches the provided string. Returns an empty BuildParams if no rule is found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800290func (m TestingModule) MaybeOutput(file string) TestingBuildParams {
291 p, _ := maybeBuildParamsFromOutput(m.module, file)
Colin Crossb77ffc42019-01-05 22:09:19 -0800292 return p
293}
294
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800295// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
Colin Crossb77ffc42019-01-05 22:09:19 -0800296// value matches the provided string. Panics if no rule is found.
Colin Cross4c83e5c2019-02-25 14:54:28 -0800297func (m TestingModule) Output(file string) TestingBuildParams {
298 return buildParamsFromOutput(m.module, file)
Colin Crosscec81712017-07-13 14:43:27 -0700299}
Logan Chien42039712018-03-12 16:29:17 +0800300
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800301// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
302func (m TestingModule) AllOutputs() []string {
Colin Cross4c83e5c2019-02-25 14:54:28 -0800303 return allOutputs(m.module)
304}
305
306// TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual
307// ctx.Build parameters for verification in tests.
308type TestingSingleton struct {
309 singleton Singleton
310 provider testBuildProvider
311}
312
313// Singleton returns the Singleton wrapped by the TestingSingleton.
314func (s TestingSingleton) Singleton() Singleton {
315 return s.singleton
316}
317
318// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
319// BuildParams if no rule is found.
320func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams {
321 return maybeBuildParamsFromRule(s.provider, rule)
322}
323
324// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
325func (s TestingSingleton) Rule(rule string) TestingBuildParams {
326 return buildParamsFromRule(s.provider, rule)
327}
328
329// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string. Returns an empty
330// BuildParams if no rule is found.
331func (s TestingSingleton) MaybeDescription(desc string) TestingBuildParams {
332 return maybeBuildParamsFromDescription(s.provider, desc)
333}
334
335// Description finds a call to ctx.Build with BuildParams.Description set to a the given string. Panics if no rule is
336// found.
337func (s TestingSingleton) Description(desc string) TestingBuildParams {
338 return buildParamsFromDescription(s.provider, desc)
339}
340
341// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
342// value matches the provided string. Returns an empty BuildParams if no rule is found.
343func (s TestingSingleton) MaybeOutput(file string) TestingBuildParams {
344 p, _ := maybeBuildParamsFromOutput(s.provider, file)
345 return p
346}
347
348// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
349// value matches the provided string. Panics if no rule is found.
350func (s TestingSingleton) Output(file string) TestingBuildParams {
351 return buildParamsFromOutput(s.provider, file)
352}
353
354// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
355func (s TestingSingleton) AllOutputs() []string {
356 return allOutputs(s.provider)
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800357}
358
Logan Chien42039712018-03-12 16:29:17 +0800359func FailIfErrored(t *testing.T, errs []error) {
360 t.Helper()
361 if len(errs) > 0 {
362 for _, err := range errs {
363 t.Error(err)
364 }
365 t.FailNow()
366 }
367}
Logan Chienee97c3e2018-03-12 16:34:26 +0800368
369func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) {
370 t.Helper()
371
372 matcher, err := regexp.Compile(pattern)
373 if err != nil {
374 t.Errorf("failed to compile regular expression %q because %s", pattern, err)
375 }
376
377 found := false
378 for _, err := range errs {
379 if matcher.FindStringIndex(err.Error()) != nil {
380 found = true
381 break
382 }
383 }
384 if !found {
385 t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs))
386 for i, err := range errs {
387 t.Errorf("errs[%d] = %s", i, err)
388 }
389 }
390}
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700391
Paul Duffin91e38192019-08-05 15:07:57 +0100392func CheckErrorsAgainstExpectations(t *testing.T, errs []error, expectedErrorPatterns []string) {
393 t.Helper()
394
395 if expectedErrorPatterns == nil {
396 FailIfErrored(t, errs)
397 } else {
398 for _, expectedError := range expectedErrorPatterns {
399 FailIfNoMatchingErrors(t, expectedError, errs)
400 }
401 if len(errs) > len(expectedErrorPatterns) {
402 t.Errorf("additional errors found, expected %d, found %d",
403 len(expectedErrorPatterns), len(errs))
404 for i, expectedError := range expectedErrorPatterns {
405 t.Errorf("expectedErrors[%d] = %s", i, expectedError)
406 }
407 for i, err := range errs {
408 t.Errorf("errs[%d] = %s", i, err)
409 }
410 }
411 }
412
413}
414
Paul Duffin8c3fec42020-03-04 20:15:08 +0000415func SetInMakeForTests(config Config) {
416 config.inMake = true
417}
418
Jiyong Park0b0e1b92019-12-03 13:24:29 +0900419func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) []AndroidMkEntries {
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700420 var p AndroidMkEntriesProvider
421 var ok bool
422 if p, ok = mod.(AndroidMkEntriesProvider); !ok {
Roland Levillaindfe75b32019-07-23 16:53:32 +0100423 t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name())
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700424 }
Jiyong Park0b0e1b92019-12-03 13:24:29 +0900425
426 entriesList := p.AndroidMkEntries()
427 for i, _ := range entriesList {
428 entriesList[i].fillInEntries(config, bpPath, mod)
429 }
430 return entriesList
Jaewoong Jung9aa3ab12019-04-03 15:47:29 -0700431}
Jooyung Han12df5fb2019-07-11 16:18:47 +0900432
433func AndroidMkDataForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkData {
434 var p AndroidMkDataProvider
435 var ok bool
436 if p, ok = mod.(AndroidMkDataProvider); !ok {
Roland Levillaindfe75b32019-07-23 16:53:32 +0100437 t.Errorf("module does not implement AndroidMkDataProvider: " + mod.Name())
Jooyung Han12df5fb2019-07-11 16:18:47 +0900438 }
439 data := p.AndroidMk()
440 data.fillInData(config, bpPath, mod)
441 return data
442}
Paul Duffin9b478b02019-12-10 13:41:51 +0000443
444// Normalize the path for testing.
445//
446// If the path is relative to the build directory then return the relative path
447// to avoid tests having to deal with the dynamically generated build directory.
448//
449// Otherwise, return the supplied path as it is almost certainly a source path
450// that is relative to the root of the source tree.
451//
452// The build and source paths should be distinguishable based on their contents.
453func NormalizePathForTesting(path Path) string {
454 p := path.String()
455 if w, ok := path.(WritablePath); ok {
456 rel, err := filepath.Rel(w.buildDir(), p)
457 if err != nil {
458 panic(err)
459 }
460 return rel
461 }
462 return p
463}
464
465func NormalizePathsForTesting(paths Paths) []string {
466 var result []string
467 for _, path := range paths {
468 relative := NormalizePathForTesting(path)
469 result = append(result, relative)
470 }
471 return result
472}