blob: 1eb53a295b92a5d71d2f255c745b1de0b128d5f6 [file] [log] [blame]
Paul Duffin35816122021-02-24 01:49:52 +00001// Copyright 2021 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 (
Paul Duffinbbccfcf2021-03-03 00:44:00 +000018 "fmt"
Paul Duffin80f4cea2021-03-16 14:08:00 +000019 "strings"
Paul Duffin35816122021-02-24 01:49:52 +000020 "testing"
21)
22
23// Provides support for creating test fixtures on which tests can be run. Reduces duplication
24// of test setup by allow tests to easily reuse setup code.
25//
26// Fixture
27// =======
28// These determine the environment within which a test can be run. Fixtures are mutable and are
29// created by FixtureFactory instances and mutated by FixturePreparer instances. They are created by
30// first creating a base Fixture (which is essentially empty) and then applying FixturePreparer
31// instances to it to modify the environment.
32//
Paul Duffinff2aa692021-03-19 18:20:59 +000033// FixtureFactory (deprecated)
34// ===========================
Paul Duffin35816122021-02-24 01:49:52 +000035// These are responsible for creating fixtures. Factories are immutable and are intended to be
36// initialized once and reused to create multiple fixtures. Each factory has a list of fixture
37// preparers that prepare a fixture for running a test. Factories can also be used to create other
38// factories by extending them with additional fixture preparers.
39//
40// FixturePreparer
41// ===============
42// These are responsible for modifying a Fixture in preparation for it to run a test. Preparers are
43// intended to be immutable and able to prepare multiple Fixture objects simultaneously without
44// them sharing any data.
45//
Paul Duffinff2aa692021-03-19 18:20:59 +000046// They provide the basic capabilities for running tests too.
47//
48// FixturePreparers are only ever applied once per test fixture. Prior to application the list of
Paul Duffin35816122021-02-24 01:49:52 +000049// FixturePreparers are flattened and deduped while preserving the order they first appear in the
50// list. This makes it easy to reuse, group and combine FixturePreparers together.
51//
52// Each small self contained piece of test setup should be their own FixturePreparer. e.g.
53// * A group of related modules.
54// * A group of related mutators.
55// * A combination of both.
56// * Configuration.
57//
58// They should not overlap, e.g. the same module type should not be registered by different
59// FixturePreparers as using them both would cause a build error. In that case the preparer should
60// be split into separate parts and combined together using FixturePreparers(...).
61//
62// e.g. attempting to use AllPreparers in preparing a Fixture would break as it would attempt to
63// register module bar twice:
64// var Preparer1 = FixtureRegisterWithContext(RegisterModuleFooAndBar)
65// var Preparer2 = FixtureRegisterWithContext(RegisterModuleBarAndBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000066// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000067//
68// However, when restructured like this it would work fine:
69// var PreparerFoo = FixtureRegisterWithContext(RegisterModuleFoo)
70// var PreparerBar = FixtureRegisterWithContext(RegisterModuleBar)
71// var PreparerBaz = FixtureRegisterWithContext(RegisterModuleBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000072// var Preparer1 = GroupFixturePreparers(RegisterModuleFoo, RegisterModuleBar)
73// var Preparer2 = GroupFixturePreparers(RegisterModuleBar, RegisterModuleBaz)
74// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000075//
76// As after deduping and flattening AllPreparers would result in the following preparers being
77// applied:
78// 1. PreparerFoo
79// 2. PreparerBar
80// 3. PreparerBaz
81//
82// Preparers can be used for both integration and unit tests.
83//
84// Integration tests typically use all the module types, mutators and singletons that are available
85// for that package to try and replicate the behavior of the runtime build as closely as possible.
86// However, that realism comes at a cost of increased fragility (as they can be broken by changes in
87// many different parts of the build) and also increased runtime, especially if they use lots of
88// singletons and mutators.
89//
90// Unit tests on the other hand try and minimize the amount of code being tested which makes them
91// less susceptible to changes elsewhere in the build and quick to run but at a cost of potentially
92// not testing realistic scenarios.
93//
94// Supporting unit tests effectively require that preparers are available at the lowest granularity
95// possible. Supporting integration tests effectively require that the preparers are organized into
96// groups that provide all the functionality available.
97//
98// At least in terms of tests that check the behavior of build components via processing
99// `Android.bp` there is no clear separation between a unit test and an integration test. Instead
100// they vary from one end that tests a single module (e.g. filegroup) to the other end that tests a
101// whole system of modules, mutators and singletons (e.g. apex + hiddenapi).
102//
103// TestResult
104// ==========
105// These are created by running tests in a Fixture and provide access to the Config and TestContext
106// in which the tests were run.
107//
108// Example
109// =======
110//
111// An exported preparer for use by other packages that need to use java modules.
112//
113// package java
Paul Duffina560d5a2021-02-28 01:38:51 +0000114// var PrepareForIntegrationTestWithJava = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000115// android.PrepareForIntegrationTestWithAndroid,
116// FixtureRegisterWithContext(RegisterAGroupOfRelatedModulesMutatorsAndSingletons),
117// FixtureRegisterWithContext(RegisterAnotherGroupOfRelatedModulesMutatorsAndSingletons),
118// ...
119// )
120//
121// Some files to use in tests in the java package.
122//
123// var javaMockFS = android.MockFS{
Paul Duffinff2aa692021-03-19 18:20:59 +0000124// "api/current.txt": nil,
125// "api/removed.txt": nil,
Paul Duffin35816122021-02-24 01:49:52 +0000126// ...
127// }
128//
Paul Duffinff2aa692021-03-19 18:20:59 +0000129// A package private preparer for use for testing java within the java package.
Paul Duffin35816122021-02-24 01:49:52 +0000130//
Paul Duffinff2aa692021-03-19 18:20:59 +0000131// var prepareForJavaTest = android.GroupFixturePreparers(
132// PrepareForIntegrationTestWithJava,
133// FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
134// ctx.RegisterModuleType("test_module", testModule)
135// }),
136// javaMockFS.AddToFixture(),
137// ...
138// }
139//
140// func TestJavaStuff(t *testing.T) {
Paul Duffin3cb2c062021-03-22 19:24:26 +0000141// result := android.GroupFixturePreparers(
Paul Duffinff2aa692021-03-19 18:20:59 +0000142// prepareForJavaTest,
143// android.FixtureWithRootAndroidBp(`java_library {....}`),
144// android.MockFS{...}.AddToFixture(),
145// ).RunTest(t)
146// ... test result ...
147// }
148//
149// package cc
150// var PrepareForTestWithCC = android.GroupFixturePreparers(
151// android.PrepareForArchMutator,
152// android.prepareForPrebuilts,
153// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
154// ...
155// )
156//
157// package apex
158//
159// var PrepareForApex = GroupFixturePreparers(
160// ...
161// )
162//
163// Use modules and mutators from java, cc and apex. Any duplicate preparers (like
164// android.PrepareForArchMutator) will be automatically deduped.
165//
166// var prepareForApexTest = android.GroupFixturePreparers(
167// PrepareForJava,
168// PrepareForCC,
169// PrepareForApex,
170// )
171//
172// // FixtureFactory instances have been deprecated, this remains for informational purposes to
173// // help explain some of the existing code but will be removed along with FixtureFactory.
174//
175// var javaFixtureFactory = android.NewFixtureFactory(
Paul Duffin35816122021-02-24 01:49:52 +0000176// PrepareForIntegrationTestWithJava,
177// FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
178// ctx.RegisterModuleType("test_module", testModule)
179// }),
180// javaMockFS.AddToFixture(),
181// ...
182// }
183//
184// func TestJavaStuff(t *testing.T) {
185// result := javaFixtureFactory.RunTest(t,
186// android.FixtureWithRootAndroidBp(`java_library {....}`),
187// android.MockFS{...}.AddToFixture(),
188// )
189// ... test result ...
190// }
191//
192// package cc
Paul Duffina560d5a2021-02-28 01:38:51 +0000193// var PrepareForTestWithCC = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000194// android.PrepareForArchMutator,
Paul Duffinff2aa692021-03-19 18:20:59 +0000195// android.prepareForPrebuilts,
Paul Duffin35816122021-02-24 01:49:52 +0000196// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
197// ...
198// )
199//
200// package apex
201//
Paul Duffina560d5a2021-02-28 01:38:51 +0000202// var PrepareForApex = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000203// ...
204// )
205//
206// Use modules and mutators from java, cc and apex. Any duplicate preparers (like
207// android.PrepareForArchMutator) will be automatically deduped.
208//
209// var apexFixtureFactory = android.NewFixtureFactory(
210// PrepareForJava,
211// PrepareForCC,
212// PrepareForApex,
213// )
214
215// Factory for Fixture objects.
216//
217// This is configured with a set of FixturePreparer objects that are used to
218// initialize each Fixture instance this creates.
Paul Duffinff2aa692021-03-19 18:20:59 +0000219//
220// deprecated: Use FixturePreparer instead.
Paul Duffin35816122021-02-24 01:49:52 +0000221type FixtureFactory interface {
Paul Duffinff2aa692021-03-19 18:20:59 +0000222 FixturePreparer
Paul Duffin35816122021-02-24 01:49:52 +0000223}
224
225// Create a new FixtureFactory that will apply the supplied preparers.
226//
227// The buildDirSupplier is a pointer to the package level buildDir variable that is initialized by
228// the package level setUp method. It has to be a pointer to the variable as the variable will not
Paul Duffindff5ff02021-03-15 15:42:40 +0000229// have been initialized at the time the factory is created. If it is nil then a test specific
230// temporary directory will be created instead.
Paul Duffinff2aa692021-03-19 18:20:59 +0000231//
232// deprecated: The functionality provided by FixtureFactory will be merged into FixturePreparer
Paul Duffin35816122021-02-24 01:49:52 +0000233func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory {
Paul Duffinff2aa692021-03-19 18:20:59 +0000234 f := &fixtureFactory{
Paul Duffin35816122021-02-24 01:49:52 +0000235 buildDirSupplier: buildDirSupplier,
Paul Duffinff2aa692021-03-19 18:20:59 +0000236 compositeFixturePreparer: compositeFixturePreparer{
237 preparers: dedupAndFlattenPreparers(nil, preparers),
238 },
Paul Duffin35816122021-02-24 01:49:52 +0000239 }
Paul Duffinff2aa692021-03-19 18:20:59 +0000240 f.initBaseFixturePreparer(f)
241 return f
Paul Duffin35816122021-02-24 01:49:52 +0000242}
243
244// A set of mock files to add to the mock file system.
245type MockFS map[string][]byte
246
Paul Duffin6e9a4002021-03-11 19:01:26 +0000247// Merge adds the extra entries from the supplied map to this one.
248//
249// Fails if the supplied map files with the same paths are present in both of them.
Paul Duffin35816122021-02-24 01:49:52 +0000250func (fs MockFS) Merge(extra map[string][]byte) {
251 for p, c := range extra {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000252 validateFixtureMockFSPath(p)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000253 if _, ok := fs[p]; ok {
254 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
255 }
Paul Duffin35816122021-02-24 01:49:52 +0000256 fs[p] = c
257 }
258}
259
Paul Duffin80f4cea2021-03-16 14:08:00 +0000260// Ensure that tests cannot add paths into the mock file system which would not be allowed in the
261// runtime, e.g. absolute paths, paths relative to the 'out/' directory.
262func validateFixtureMockFSPath(path string) {
263 // This uses validateSafePath rather than validatePath because the latter prevents adding files
264 // that include a $ but there are tests that allow files with a $ to be used, albeit only by
265 // globbing.
266 validatedPath, err := validateSafePath(path)
267 if err != nil {
268 panic(err)
269 }
270
271 // Make sure that the path is canonical.
272 if validatedPath != path {
273 panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath))
274 }
275
276 if path == "out" || strings.HasPrefix(path, "out/") {
277 panic(fmt.Errorf("cannot add output path %q to the mock file system", path))
278 }
279}
280
Paul Duffin35816122021-02-24 01:49:52 +0000281func (fs MockFS) AddToFixture() FixturePreparer {
282 return FixtureMergeMockFs(fs)
283}
284
Paul Duffinae542a52021-03-09 03:15:28 +0000285// FixtureCustomPreparer allows for the modification of any aspect of the fixture.
286//
287// This should only be used if one of the other more specific preparers are not suitable.
288func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer {
289 return newSimpleFixturePreparer(func(f *fixture) {
290 mutator(f)
291 })
292}
293
Paul Duffin35816122021-02-24 01:49:52 +0000294// Modify the config
295func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
296 return newSimpleFixturePreparer(func(f *fixture) {
297 mutator(f.config)
298 })
299}
300
301// Modify the config and context
302func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer {
303 return newSimpleFixturePreparer(func(f *fixture) {
304 mutator(f.config, f.ctx)
305 })
306}
307
308// Modify the context
309func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer {
310 return newSimpleFixturePreparer(func(f *fixture) {
311 mutator(f.ctx)
312 })
313}
314
315func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
316 return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
317}
318
319// Modify the mock filesystem
320func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
321 return newSimpleFixturePreparer(func(f *fixture) {
322 mutator(f.mockFS)
Paul Duffin80f4cea2021-03-16 14:08:00 +0000323
324 // Make sure that invalid paths were not added to the mock filesystem.
325 for p, _ := range f.mockFS {
326 validateFixtureMockFSPath(p)
327 }
Paul Duffin35816122021-02-24 01:49:52 +0000328 })
329}
330
331// Merge the supplied file system into the mock filesystem.
332//
333// Paths that already exist in the mock file system are overridden.
334func FixtureMergeMockFs(mockFS MockFS) FixturePreparer {
335 return FixtureModifyMockFS(func(fs MockFS) {
336 fs.Merge(mockFS)
337 })
338}
339
340// Add a file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000341//
342// Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
Paul Duffin35816122021-02-24 01:49:52 +0000343func FixtureAddFile(path string, contents []byte) FixturePreparer {
344 return FixtureModifyMockFS(func(fs MockFS) {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000345 validateFixtureMockFSPath(path)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000346 if _, ok := fs[path]; ok {
347 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
348 }
Paul Duffin35816122021-02-24 01:49:52 +0000349 fs[path] = contents
350 })
351}
352
353// Add a text file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000354//
355// Fail if the filesystem already contains a file with that path.
Paul Duffin35816122021-02-24 01:49:52 +0000356func FixtureAddTextFile(path string, contents string) FixturePreparer {
357 return FixtureAddFile(path, []byte(contents))
358}
359
Paul Duffin6e9a4002021-03-11 19:01:26 +0000360// Override a file in the mock filesystem
361//
362// If the file does not exist this behaves as FixtureAddFile.
363func FixtureOverrideFile(path string, contents []byte) FixturePreparer {
364 return FixtureModifyMockFS(func(fs MockFS) {
365 fs[path] = contents
366 })
367}
368
369// Override a text file in the mock filesystem
370//
371// If the file does not exist this behaves as FixtureAddTextFile.
372func FixtureOverrideTextFile(path string, contents string) FixturePreparer {
373 return FixtureOverrideFile(path, []byte(contents))
374}
375
Paul Duffin35816122021-02-24 01:49:52 +0000376// Add the root Android.bp file with the supplied contents.
377func FixtureWithRootAndroidBp(contents string) FixturePreparer {
378 return FixtureAddTextFile("Android.bp", contents)
379}
380
Paul Duffinbbccfcf2021-03-03 00:44:00 +0000381// Merge some environment variables into the fixture.
382func FixtureMergeEnv(env map[string]string) FixturePreparer {
383 return FixtureModifyConfig(func(config Config) {
384 for k, v := range env {
385 if k == "PATH" {
386 panic("Cannot set PATH environment variable")
387 }
388 config.env[k] = v
389 }
390 })
391}
392
393// Modify the env.
394//
395// Will panic if the mutator changes the PATH environment variable.
396func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer {
397 return FixtureModifyConfig(func(config Config) {
398 oldPath := config.env["PATH"]
399 mutator(config.env)
400 newPath := config.env["PATH"]
401 if newPath != oldPath {
402 panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath))
403 }
404 })
405}
406
Paul Duffin2e0323d2021-03-04 15:11:01 +0000407// Allow access to the product variables when preparing the fixture.
408type FixtureProductVariables struct {
409 *productVariables
410}
411
412// Modify product variables.
413func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer {
414 return FixtureModifyConfig(func(config Config) {
415 productVariables := FixtureProductVariables{&config.productVariables}
416 mutator(productVariables)
417 })
418}
419
Paul Duffina560d5a2021-02-28 01:38:51 +0000420// GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of
421// the supplied FixturePreparer instances in order.
422//
423// Before preparing the fixture the list of preparers is flattened by replacing each
424// instance of GroupFixturePreparers with its contents.
425func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000426 all := dedupAndFlattenPreparers(nil, preparers)
427 return newFixturePreparer(all)
Paul Duffin35816122021-02-24 01:49:52 +0000428}
429
Paul Duffin50deaae2021-03-16 17:46:12 +0000430// NullFixturePreparer is a preparer that does nothing.
431var NullFixturePreparer = GroupFixturePreparers()
432
433// OptionalFixturePreparer will return the supplied preparer if it is non-nil, otherwise it will
434// return the NullFixturePreparer
435func OptionalFixturePreparer(preparer FixturePreparer) FixturePreparer {
436 if preparer == nil {
437 return NullFixturePreparer
438 } else {
439 return preparer
440 }
441}
442
Paul Duffinff2aa692021-03-19 18:20:59 +0000443// FixturePreparer provides the ability to create, modify and then run tests within a fixture.
Paul Duffin35816122021-02-24 01:49:52 +0000444type FixturePreparer interface {
Paul Duffin4ca67522021-03-20 01:25:12 +0000445 // Return the flattened and deduped list of simpleFixturePreparer pointers.
446 list() []*simpleFixturePreparer
Paul Duffinff2aa692021-03-19 18:20:59 +0000447
448 // Creates a copy of this instance and adds some additional preparers.
449 //
450 // Before the preparers are used they are combined with the preparers provided when the factory
451 // was created, any groups of preparers are flattened, and the list is deduped so that each
452 // preparer is only used once. See the file documentation in android/fixture.go for more details.
453 //
454 // deprecated: Use GroupFixturePreparers() instead.
455 Extend(preparers ...FixturePreparer) FixturePreparer
456
457 // Create a Fixture.
458 Fixture(t *testing.T, preparers ...FixturePreparer) Fixture
459
460 // ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler
461 // to check the errors (may be 0) reported by the test.
462 //
463 // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
464 // errors are reported.
465 ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer
466
467 // Run the test, checking any errors reported and returning a TestResult instance.
468 //
Paul Duffin55e740e2021-03-29 02:06:19 +0100469 // Shorthand for Fixture(t).RunTest()
470 RunTest(t *testing.T) *TestResult
Paul Duffinff2aa692021-03-19 18:20:59 +0000471
472 // Run the test with the supplied Android.bp file.
473 //
Paul Duffin55e740e2021-03-29 02:06:19 +0100474 // preparer.RunTestWithBp(t, bp) is shorthand for
475 // android.GroupFixturePreparers(preparer, android.FixtureWithRootAndroidBp(bp)).RunTest(t)
Paul Duffinff2aa692021-03-19 18:20:59 +0000476 RunTestWithBp(t *testing.T, bp string) *TestResult
477
478 // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
479 // the test fixture.
480 //
481 // In order to allow the Config object to be customized separately to the TestContext a lot of
482 // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
483 // from the test and then have the TestContext created and configured automatically. e.g.
484 // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
485 //
486 // This method allows those methods to be migrated to use the test fixture pattern without
487 // requiring that every test that uses those methods be migrated at the same time. That allows
488 // those tests to benefit from correctness in the order of registration quickly.
489 //
490 // This method discards the config (along with its mock file system, product variables,
491 // environment, etc.) that may have been set up by FixturePreparers.
492 //
493 // deprecated
494 RunTestWithConfig(t *testing.T, config Config) *TestResult
Paul Duffin35816122021-02-24 01:49:52 +0000495}
496
497// dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
498// instances.
499//
500// base - a list of already flattened and deduped preparers that will be applied first before
501// the list of additional preparers. Any duplicates of these in the additional preparers
502// will be ignored.
503//
504// preparers - a list of additional unflattened, undeduped preparers that will be applied after the
505// base preparers.
506//
Paul Duffin59251822021-03-15 22:20:12 +0000507// Returns a deduped and flattened list of the preparers starting with the ones in base with any
508// additional ones from the preparers list added afterwards.
Paul Duffin4ca67522021-03-20 01:25:12 +0000509func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer {
Paul Duffin59251822021-03-15 22:20:12 +0000510 if len(preparers) == 0 {
511 return base
512 }
513
514 list := make([]*simpleFixturePreparer, len(base))
Paul Duffin35816122021-02-24 01:49:52 +0000515 visited := make(map[*simpleFixturePreparer]struct{})
516
517 // Mark the already flattened and deduped preparers, if any, as having been seen so that
Paul Duffin59251822021-03-15 22:20:12 +0000518 // duplicates of these in the additional preparers will be discarded. Add them to the output
519 // list.
520 for i, s := range base {
Paul Duffin35816122021-02-24 01:49:52 +0000521 visited[s] = struct{}{}
Paul Duffin59251822021-03-15 22:20:12 +0000522 list[i] = s
Paul Duffin35816122021-02-24 01:49:52 +0000523 }
524
Paul Duffin4ca67522021-03-20 01:25:12 +0000525 for _, p := range preparers {
526 for _, s := range p.list() {
527 if _, seen := visited[s]; !seen {
528 visited[s] = struct{}{}
529 list = append(list, s)
530 }
Paul Duffin35816122021-02-24 01:49:52 +0000531 }
Paul Duffin4ca67522021-03-20 01:25:12 +0000532 }
533
Paul Duffin35816122021-02-24 01:49:52 +0000534 return list
535}
536
537// compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
538type compositeFixturePreparer struct {
Paul Duffinff2aa692021-03-19 18:20:59 +0000539 baseFixturePreparer
Paul Duffin4ca67522021-03-20 01:25:12 +0000540 // The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this
541 // composite preparer.
Paul Duffin35816122021-02-24 01:49:52 +0000542 preparers []*simpleFixturePreparer
543}
544
Paul Duffin4ca67522021-03-20 01:25:12 +0000545func (c *compositeFixturePreparer) list() []*simpleFixturePreparer {
546 return c.preparers
Paul Duffin35816122021-02-24 01:49:52 +0000547}
548
Paul Duffinff2aa692021-03-19 18:20:59 +0000549func newFixturePreparer(preparers []*simpleFixturePreparer) FixturePreparer {
550 if len(preparers) == 1 {
551 return preparers[0]
552 }
553 p := &compositeFixturePreparer{
554 preparers: preparers,
555 }
556 p.initBaseFixturePreparer(p)
557 return p
558}
559
Paul Duffin35816122021-02-24 01:49:52 +0000560// simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
561type simpleFixturePreparer struct {
Paul Duffinff2aa692021-03-19 18:20:59 +0000562 baseFixturePreparer
Paul Duffin35816122021-02-24 01:49:52 +0000563 function func(fixture *fixture)
564}
565
Paul Duffin4ca67522021-03-20 01:25:12 +0000566func (s *simpleFixturePreparer) list() []*simpleFixturePreparer {
567 return []*simpleFixturePreparer{s}
Paul Duffin35816122021-02-24 01:49:52 +0000568}
569
570func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000571 p := &simpleFixturePreparer{function: preparer}
572 p.initBaseFixturePreparer(p)
573 return p
Paul Duffin35816122021-02-24 01:49:52 +0000574}
575
Paul Duffincfd33742021-02-27 11:59:02 +0000576// FixtureErrorHandler determines how to respond to errors reported by the code under test.
577//
578// Some possible responses:
579// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
580// * Fail the test if at least one error that matches a pattern is not reported see
581// FixtureExpectsAtLeastOneErrorMatchingPattern
582// * Fail the test if any unexpected errors are reported.
583//
584// Although at the moment all the error handlers are implemented as simply a wrapper around a
585// function this is defined as an interface to allow future enhancements, e.g. provide different
586// ways other than patterns to match an error and to combine handlers together.
587type FixtureErrorHandler interface {
588 // CheckErrors checks the errors reported.
589 //
590 // The supplied result can be used to access the state of the code under test just as the main
591 // body of the test would but if any errors other than ones expected are reported the state may
592 // be indeterminate.
Paul Duffinc81854a2021-03-12 12:22:27 +0000593 CheckErrors(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000594}
595
596type simpleErrorHandler struct {
Paul Duffinc81854a2021-03-12 12:22:27 +0000597 function func(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000598}
599
Paul Duffinc81854a2021-03-12 12:22:27 +0000600func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) {
601 t.Helper()
602 h.function(t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000603}
604
605// The default fixture error handler.
606//
607// Will fail the test immediately if any errors are reported.
Paul Duffinea8a3862021-03-04 17:58:33 +0000608//
609// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
610// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000611var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
Paul Duffinc81854a2021-03-12 12:22:27 +0000612 func(t *testing.T, result *TestResult) {
613 t.Helper()
614 FailIfErrored(t, result.Errs)
Paul Duffincfd33742021-02-27 11:59:02 +0000615 },
616)
617
Paul Duffin85034e92021-03-17 00:20:34 +0000618// FixtureIgnoreErrors ignores any errors.
619//
620// If this is used then it is the responsibility of the test to check the TestResult.Errs does not
621// contain any unexpected errors.
622var FixtureIgnoreErrors = FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
623 // Ignore the errors
624})
625
Paul Duffincfd33742021-02-27 11:59:02 +0000626// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
627// if at least one error that matches the regular expression is not found.
628//
629// The test will be failed if:
630// * No errors are reported.
631// * One or more errors are reported but none match the pattern.
632//
633// The test will not fail if:
634// * Multiple errors are reported that do not match the pattern as long as one does match.
Paul Duffinea8a3862021-03-04 17:58:33 +0000635//
636// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
637// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000638func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000639 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
640 t.Helper()
641 if !FailIfNoMatchingErrors(t, pattern, result.Errs) {
642 t.FailNow()
Paul Duffinea8a3862021-03-04 17:58:33 +0000643 }
Paul Duffincfd33742021-02-27 11:59:02 +0000644 })
645}
646
647// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
648// if there are any unexpected errors.
649//
650// The test will be failed if:
651// * The number of errors reported does not exactly match the patterns.
652// * One or more of the reported errors do not match a pattern.
653// * No patterns are provided and one or more errors are reported.
654//
655// The test will not fail if:
656// * One or more of the patterns does not match an error.
Paul Duffinea8a3862021-03-04 17:58:33 +0000657//
658// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
659// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000660func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000661 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
662 t.Helper()
663 CheckErrorsAgainstExpectations(t, result.Errs, patterns)
Paul Duffincfd33742021-02-27 11:59:02 +0000664 })
665}
666
667// FixtureCustomErrorHandler creates a custom error handler
Paul Duffinc81854a2021-03-12 12:22:27 +0000668func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler {
Paul Duffincfd33742021-02-27 11:59:02 +0000669 return simpleErrorHandler{
670 function: function,
671 }
672}
673
Paul Duffin35816122021-02-24 01:49:52 +0000674// Fixture defines the test environment.
675type Fixture interface {
Paul Duffinae542a52021-03-09 03:15:28 +0000676 // Config returns the fixture's configuration.
677 Config() Config
678
679 // Context returns the fixture's test context.
680 Context() *TestContext
681
682 // MockFS returns the fixture's mock filesystem.
683 MockFS() MockFS
684
Paul Duffincfd33742021-02-27 11:59:02 +0000685 // Run the test, checking any errors reported and returning a TestResult instance.
Paul Duffin35816122021-02-24 01:49:52 +0000686 RunTest() *TestResult
687}
688
Paul Duffin35816122021-02-24 01:49:52 +0000689// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
690type testContext struct {
691 *TestContext
692}
693
694// The result of running a test.
695type TestResult struct {
Paul Duffin35816122021-02-24 01:49:52 +0000696 testContext
697
698 fixture *fixture
699 Config Config
Paul Duffin942481b2021-03-04 18:58:11 +0000700
701 // The errors that were reported during the test.
702 Errs []error
Paul Duffin78c36212021-03-16 23:57:12 +0000703
704 // The ninja deps is a list of the ninja files dependencies that were added by the modules and
705 // singletons via the *.AddNinjaFileDeps() methods.
706 NinjaDeps []string
Paul Duffin35816122021-02-24 01:49:52 +0000707}
708
Paul Duffinff2aa692021-03-19 18:20:59 +0000709func createFixture(t *testing.T, buildDir string, base []*simpleFixturePreparer, extra []FixturePreparer) Fixture {
710 all := dedupAndFlattenPreparers(base, extra)
Paul Duffin59251822021-03-15 22:20:12 +0000711
Paul Duffindff5ff02021-03-15 15:42:40 +0000712 config := TestConfig(buildDir, nil, "", nil)
Paul Duffin35816122021-02-24 01:49:52 +0000713 ctx := NewTestContext(config)
714 fixture := &fixture{
Paul Duffincff464f2021-03-19 18:13:46 +0000715 preparers: all,
716 t: t,
717 config: config,
718 ctx: ctx,
719 mockFS: make(MockFS),
720 // Set the default error handler.
721 errorHandler: FixtureExpectsNoErrors,
Paul Duffin35816122021-02-24 01:49:52 +0000722 }
723
Paul Duffin59251822021-03-15 22:20:12 +0000724 for _, preparer := range all {
Paul Duffin35816122021-02-24 01:49:52 +0000725 preparer.function(fixture)
726 }
727
728 return fixture
729}
730
Paul Duffinff2aa692021-03-19 18:20:59 +0000731type baseFixturePreparer struct {
732 self FixturePreparer
733}
734
735func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) {
736 b.self = self
737}
738
739func (b *baseFixturePreparer) Extend(preparers ...FixturePreparer) FixturePreparer {
740 all := dedupAndFlattenPreparers(b.self.list(), preparers)
741 return newFixturePreparer(all)
742}
743
744func (b *baseFixturePreparer) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
745 return createFixture(t, t.TempDir(), b.self.list(), preparers)
746}
747
748func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer {
749 return b.self.Extend(newSimpleFixturePreparer(func(fixture *fixture) {
Paul Duffincff464f2021-03-19 18:13:46 +0000750 fixture.errorHandler = errorHandler
751 }))
Paul Duffincfd33742021-02-27 11:59:02 +0000752}
753
Paul Duffin55e740e2021-03-29 02:06:19 +0100754func (b *baseFixturePreparer) RunTest(t *testing.T) *TestResult {
Paul Duffin35816122021-02-24 01:49:52 +0000755 t.Helper()
Paul Duffin55e740e2021-03-29 02:06:19 +0100756 fixture := b.self.Fixture(t)
Paul Duffin35816122021-02-24 01:49:52 +0000757 return fixture.RunTest()
758}
759
Paul Duffinff2aa692021-03-19 18:20:59 +0000760func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult {
Paul Duffin35816122021-02-24 01:49:52 +0000761 t.Helper()
Paul Duffin55e740e2021-03-29 02:06:19 +0100762 return GroupFixturePreparers(b.self, FixtureWithRootAndroidBp(bp)).RunTest(t)
Paul Duffin35816122021-02-24 01:49:52 +0000763}
764
Paul Duffinff2aa692021-03-19 18:20:59 +0000765func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult {
Paul Duffin72018ad2021-03-04 19:36:49 +0000766 t.Helper()
767 // Create the fixture as normal.
Paul Duffinff2aa692021-03-19 18:20:59 +0000768 fixture := b.self.Fixture(t).(*fixture)
Paul Duffin72018ad2021-03-04 19:36:49 +0000769
770 // Discard the mock filesystem as otherwise that will override the one in the config.
771 fixture.mockFS = nil
772
773 // Replace the config with the supplied one in the fixture.
774 fixture.config = config
775
776 // Ditto with config derived information in the TestContext.
777 ctx := fixture.ctx
778 ctx.config = config
779 ctx.SetFs(ctx.config.fs)
780 if ctx.config.mockBpList != "" {
781 ctx.SetModuleListFile(ctx.config.mockBpList)
782 }
783
784 return fixture.RunTest()
785}
786
Paul Duffinff2aa692021-03-19 18:20:59 +0000787var _ FixtureFactory = (*fixtureFactory)(nil)
788
789type fixtureFactory struct {
790 compositeFixturePreparer
791
792 buildDirSupplier *string
793}
794
795// Override to preserve the buildDirSupplier.
796func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixturePreparer {
797 // If there is no buildDirSupplier then just use the default implementation.
798 if f.buildDirSupplier == nil {
799 return f.baseFixturePreparer.Extend(preparers...)
800 }
801
802 all := dedupAndFlattenPreparers(f.preparers, preparers)
803
804 // Create a new factory which uses the same buildDirSupplier as the previous one.
805 extendedFactory := &fixtureFactory{
806 buildDirSupplier: f.buildDirSupplier,
807 compositeFixturePreparer: compositeFixturePreparer{
808 preparers: all,
809 },
810 }
811 extendedFactory.initBaseFixturePreparer(extendedFactory)
812 return extendedFactory
813}
814
815func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
816 // If there is no buildDirSupplier then just use the default implementation.
817 if f.buildDirSupplier == nil {
818 return f.baseFixturePreparer.Fixture(t, preparers...)
819 }
820
821 // Retrieve the buildDir from the supplier.
822 buildDir := *f.buildDirSupplier
823
824 return createFixture(t, buildDir, f.preparers, preparers)
825}
826
Paul Duffin35816122021-02-24 01:49:52 +0000827type fixture struct {
Paul Duffin59251822021-03-15 22:20:12 +0000828 // The preparers used to create this fixture.
829 preparers []*simpleFixturePreparer
Paul Duffincfd33742021-02-27 11:59:02 +0000830
831 // The gotest state of the go test within which this was created.
832 t *testing.T
833
834 // The configuration prepared for this fixture.
835 config Config
836
837 // The test context prepared for this fixture.
838 ctx *TestContext
839
840 // The mock filesystem prepared for this fixture.
841 mockFS MockFS
842
843 // The error handler used to check the errors, if any, that are reported.
844 errorHandler FixtureErrorHandler
Paul Duffin35816122021-02-24 01:49:52 +0000845}
846
Paul Duffinae542a52021-03-09 03:15:28 +0000847func (f *fixture) Config() Config {
848 return f.config
849}
850
851func (f *fixture) Context() *TestContext {
852 return f.ctx
853}
854
855func (f *fixture) MockFS() MockFS {
856 return f.mockFS
857}
858
Paul Duffin35816122021-02-24 01:49:52 +0000859func (f *fixture) RunTest() *TestResult {
860 f.t.Helper()
861
862 ctx := f.ctx
863
Paul Duffin72018ad2021-03-04 19:36:49 +0000864 // Do not use the fixture's mockFS to initialize the config's mock file system if it has been
865 // cleared by RunTestWithConfig.
866 if f.mockFS != nil {
867 // The TestConfig() method assumes that the mock filesystem is available when creating so
868 // creates the mock file system immediately. Similarly, the NewTestContext(Config) method
869 // assumes that the supplied Config's FileSystem has been properly initialized before it is
870 // called and so it takes its own reference to the filesystem. However, fixtures create the
871 // Config and TestContext early so they can be modified by preparers at which time the mockFS
872 // has not been populated (because it too is modified by preparers). So, this reinitializes the
873 // Config and TestContext's FileSystem using the now populated mockFS.
874 f.config.mockFileSystem("", f.mockFS)
875
876 ctx.SetFs(ctx.config.fs)
877 if ctx.config.mockBpList != "" {
878 ctx.SetModuleListFile(ctx.config.mockBpList)
879 }
Paul Duffin35816122021-02-24 01:49:52 +0000880 }
881
882 ctx.Register()
Paul Duffin78c36212021-03-16 23:57:12 +0000883 var ninjaDeps []string
884 extraNinjaDeps, errs := ctx.ParseBlueprintsFiles("ignored")
Paul Duffincfd33742021-02-27 11:59:02 +0000885 if len(errs) == 0 {
Paul Duffin78c36212021-03-16 23:57:12 +0000886 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
887 extraNinjaDeps, errs = ctx.PrepareBuildActions(f.config)
888 if len(errs) == 0 {
889 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
890 }
Paul Duffincfd33742021-02-27 11:59:02 +0000891 }
Paul Duffin35816122021-02-24 01:49:52 +0000892
893 result := &TestResult{
Paul Duffin35816122021-02-24 01:49:52 +0000894 testContext: testContext{ctx},
895 fixture: f,
896 Config: f.config,
Paul Duffin942481b2021-03-04 18:58:11 +0000897 Errs: errs,
Paul Duffin78c36212021-03-16 23:57:12 +0000898 NinjaDeps: ninjaDeps,
Paul Duffin35816122021-02-24 01:49:52 +0000899 }
Paul Duffincfd33742021-02-27 11:59:02 +0000900
Paul Duffinc81854a2021-03-12 12:22:27 +0000901 f.errorHandler.CheckErrors(f.t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000902
Paul Duffin35816122021-02-24 01:49:52 +0000903 return result
904}
905
906// NormalizePathForTesting removes the test invocation specific build directory from the supplied
907// path.
908//
909// If the path is within the build directory (e.g. an OutputPath) then this returns the relative
910// path to avoid tests having to deal with the dynamically generated build directory.
911//
912// Otherwise, this returns the supplied path as it is almost certainly a source path that is
913// relative to the root of the source tree.
914//
915// Even though some information is removed from some paths and not others it should be possible to
916// differentiate between them by the paths themselves, e.g. output paths will likely include
917// ".intermediates" but source paths won't.
918func (r *TestResult) NormalizePathForTesting(path Path) string {
919 pathContext := PathContextForTesting(r.Config)
920 pathAsString := path.String()
921 if rel, isRel := MaybeRel(pathContext, r.Config.BuildDir(), pathAsString); isRel {
922 return rel
923 }
924 return pathAsString
925}
926
927// NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized
928// forms.
929func (r *TestResult) NormalizePathsForTesting(paths Paths) []string {
930 var result []string
931 for _, path := range paths {
932 result = append(result, r.NormalizePathForTesting(path))
933 }
934 return result
935}
936
Paul Duffin59251822021-03-15 22:20:12 +0000937// Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture
938// that produced this result.
939//
940// e.g. assuming that this result was created by running:
941// factory.Extend(preparer1, preparer2).RunTest(t, preparer3, preparer4)
942//
943// Then this method will be equivalent to running:
944// GroupFixturePreparers(preparer1, preparer2, preparer3, preparer4)
945//
946// This is intended for use by tests whose output is Android.bp files to verify that those files
947// are valid, e.g. tests of the snapshots produced by the sdk module type.
948func (r *TestResult) Preparer() FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000949 return newFixturePreparer(r.fixture.preparers)
Paul Duffin59251822021-03-15 22:20:12 +0000950}
951
Paul Duffin35816122021-02-24 01:49:52 +0000952// Module returns the module with the specific name and of the specified variant.
953func (r *TestResult) Module(name string, variant string) Module {
954 return r.ModuleForTests(name, variant).Module()
955}