blob: 85e0bed61c0f6cc84ef78e3496f4f7b3d1688f43 [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//
33// FixtureFactory
34// ==============
35// 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//
46// FixturePreparers are only ever invoked once per test fixture. Prior to invocation the list of
47// FixturePreparers are flattened and deduped while preserving the order they first appear in the
48// list. This makes it easy to reuse, group and combine FixturePreparers together.
49//
50// Each small self contained piece of test setup should be their own FixturePreparer. e.g.
51// * A group of related modules.
52// * A group of related mutators.
53// * A combination of both.
54// * Configuration.
55//
56// They should not overlap, e.g. the same module type should not be registered by different
57// FixturePreparers as using them both would cause a build error. In that case the preparer should
58// be split into separate parts and combined together using FixturePreparers(...).
59//
60// e.g. attempting to use AllPreparers in preparing a Fixture would break as it would attempt to
61// register module bar twice:
62// var Preparer1 = FixtureRegisterWithContext(RegisterModuleFooAndBar)
63// var Preparer2 = FixtureRegisterWithContext(RegisterModuleBarAndBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000064// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000065//
66// However, when restructured like this it would work fine:
67// var PreparerFoo = FixtureRegisterWithContext(RegisterModuleFoo)
68// var PreparerBar = FixtureRegisterWithContext(RegisterModuleBar)
69// var PreparerBaz = FixtureRegisterWithContext(RegisterModuleBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000070// var Preparer1 = GroupFixturePreparers(RegisterModuleFoo, RegisterModuleBar)
71// var Preparer2 = GroupFixturePreparers(RegisterModuleBar, RegisterModuleBaz)
72// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000073//
74// As after deduping and flattening AllPreparers would result in the following preparers being
75// applied:
76// 1. PreparerFoo
77// 2. PreparerBar
78// 3. PreparerBaz
79//
80// Preparers can be used for both integration and unit tests.
81//
82// Integration tests typically use all the module types, mutators and singletons that are available
83// for that package to try and replicate the behavior of the runtime build as closely as possible.
84// However, that realism comes at a cost of increased fragility (as they can be broken by changes in
85// many different parts of the build) and also increased runtime, especially if they use lots of
86// singletons and mutators.
87//
88// Unit tests on the other hand try and minimize the amount of code being tested which makes them
89// less susceptible to changes elsewhere in the build and quick to run but at a cost of potentially
90// not testing realistic scenarios.
91//
92// Supporting unit tests effectively require that preparers are available at the lowest granularity
93// possible. Supporting integration tests effectively require that the preparers are organized into
94// groups that provide all the functionality available.
95//
96// At least in terms of tests that check the behavior of build components via processing
97// `Android.bp` there is no clear separation between a unit test and an integration test. Instead
98// they vary from one end that tests a single module (e.g. filegroup) to the other end that tests a
99// whole system of modules, mutators and singletons (e.g. apex + hiddenapi).
100//
101// TestResult
102// ==========
103// These are created by running tests in a Fixture and provide access to the Config and TestContext
104// in which the tests were run.
105//
106// Example
107// =======
108//
109// An exported preparer for use by other packages that need to use java modules.
110//
111// package java
Paul Duffina560d5a2021-02-28 01:38:51 +0000112// var PrepareForIntegrationTestWithJava = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000113// android.PrepareForIntegrationTestWithAndroid,
114// FixtureRegisterWithContext(RegisterAGroupOfRelatedModulesMutatorsAndSingletons),
115// FixtureRegisterWithContext(RegisterAnotherGroupOfRelatedModulesMutatorsAndSingletons),
116// ...
117// )
118//
119// Some files to use in tests in the java package.
120//
121// var javaMockFS = android.MockFS{
122// "api/current.txt": nil,
123// "api/removed.txt": nil,
124// ...
125// }
126//
127// A package private factory for use for testing java within the java package.
128//
129// var javaFixtureFactory = NewFixtureFactory(
130// PrepareForIntegrationTestWithJava,
131// FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
132// ctx.RegisterModuleType("test_module", testModule)
133// }),
134// javaMockFS.AddToFixture(),
135// ...
136// }
137//
138// func TestJavaStuff(t *testing.T) {
139// result := javaFixtureFactory.RunTest(t,
140// android.FixtureWithRootAndroidBp(`java_library {....}`),
141// android.MockFS{...}.AddToFixture(),
142// )
143// ... test result ...
144// }
145//
146// package cc
Paul Duffina560d5a2021-02-28 01:38:51 +0000147// var PrepareForTestWithCC = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000148// android.PrepareForArchMutator,
149// android.prepareForPrebuilts,
150// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
151// ...
152// )
153//
154// package apex
155//
Paul Duffina560d5a2021-02-28 01:38:51 +0000156// var PrepareForApex = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000157// ...
158// )
159//
160// Use modules and mutators from java, cc and apex. Any duplicate preparers (like
161// android.PrepareForArchMutator) will be automatically deduped.
162//
163// var apexFixtureFactory = android.NewFixtureFactory(
164// PrepareForJava,
165// PrepareForCC,
166// PrepareForApex,
167// )
168
169// Factory for Fixture objects.
170//
171// This is configured with a set of FixturePreparer objects that are used to
172// initialize each Fixture instance this creates.
173type FixtureFactory interface {
174
175 // Creates a copy of this instance and adds some additional preparers.
176 //
177 // Before the preparers are used they are combined with the preparers provided when the factory
178 // was created, any groups of preparers are flattened, and the list is deduped so that each
179 // preparer is only used once. See the file documentation in android/fixture.go for more details.
180 Extend(preparers ...FixturePreparer) FixtureFactory
181
182 // Create a Fixture.
183 Fixture(t *testing.T, preparers ...FixturePreparer) Fixture
184
Paul Duffin46e37742021-03-09 11:55:20 +0000185 // ExtendWithErrorHandler creates a new FixtureFactory that will use the supplied error handler
186 // to check the errors (may be 0) reported by the test.
Paul Duffincfd33742021-02-27 11:59:02 +0000187 //
188 // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
189 // errors are reported.
Paul Duffin46e37742021-03-09 11:55:20 +0000190 ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory
Paul Duffincfd33742021-02-27 11:59:02 +0000191
192 // Run the test, checking any errors reported and returning a TestResult instance.
Paul Duffin35816122021-02-24 01:49:52 +0000193 //
194 // Shorthand for Fixture(t, preparers...).RunTest()
195 RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult
196
197 // Run the test with the supplied Android.bp file.
198 //
199 // Shorthand for RunTest(t, android.FixtureWithRootAndroidBp(bp))
200 RunTestWithBp(t *testing.T, bp string) *TestResult
Paul Duffin72018ad2021-03-04 19:36:49 +0000201
202 // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
203 // the test fixture.
204 //
205 // In order to allow the Config object to be customized separately to the TestContext a lot of
206 // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
207 // from the test and then have the TestContext created and configured automatically. e.g.
208 // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
209 //
210 // This method allows those methods to be migrated to use the test fixture pattern without
211 // requiring that every test that uses those methods be migrated at the same time. That allows
212 // those tests to benefit from correctness in the order of registration quickly.
213 //
214 // This method discards the config (along with its mock file system, product variables,
215 // environment, etc.) that may have been set up by FixturePreparers.
216 //
217 // deprecated
218 RunTestWithConfig(t *testing.T, config Config) *TestResult
Paul Duffin35816122021-02-24 01:49:52 +0000219}
220
221// Create a new FixtureFactory that will apply the supplied preparers.
222//
223// The buildDirSupplier is a pointer to the package level buildDir variable that is initialized by
224// 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 +0000225// have been initialized at the time the factory is created. If it is nil then a test specific
226// temporary directory will be created instead.
Paul Duffin35816122021-02-24 01:49:52 +0000227func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory {
228 return &fixtureFactory{
229 buildDirSupplier: buildDirSupplier,
230 preparers: dedupAndFlattenPreparers(nil, preparers),
231 }
232}
233
234// A set of mock files to add to the mock file system.
235type MockFS map[string][]byte
236
Paul Duffin6e9a4002021-03-11 19:01:26 +0000237// Merge adds the extra entries from the supplied map to this one.
238//
239// Fails if the supplied map files with the same paths are present in both of them.
Paul Duffin35816122021-02-24 01:49:52 +0000240func (fs MockFS) Merge(extra map[string][]byte) {
241 for p, c := range extra {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000242 validateFixtureMockFSPath(p)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000243 if _, ok := fs[p]; ok {
244 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
245 }
Paul Duffin35816122021-02-24 01:49:52 +0000246 fs[p] = c
247 }
248}
249
Paul Duffin80f4cea2021-03-16 14:08:00 +0000250// Ensure that tests cannot add paths into the mock file system which would not be allowed in the
251// runtime, e.g. absolute paths, paths relative to the 'out/' directory.
252func validateFixtureMockFSPath(path string) {
253 // This uses validateSafePath rather than validatePath because the latter prevents adding files
254 // that include a $ but there are tests that allow files with a $ to be used, albeit only by
255 // globbing.
256 validatedPath, err := validateSafePath(path)
257 if err != nil {
258 panic(err)
259 }
260
261 // Make sure that the path is canonical.
262 if validatedPath != path {
263 panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath))
264 }
265
266 if path == "out" || strings.HasPrefix(path, "out/") {
267 panic(fmt.Errorf("cannot add output path %q to the mock file system", path))
268 }
269}
270
Paul Duffin35816122021-02-24 01:49:52 +0000271func (fs MockFS) AddToFixture() FixturePreparer {
272 return FixtureMergeMockFs(fs)
273}
274
Paul Duffinae542a52021-03-09 03:15:28 +0000275// FixtureCustomPreparer allows for the modification of any aspect of the fixture.
276//
277// This should only be used if one of the other more specific preparers are not suitable.
278func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer {
279 return newSimpleFixturePreparer(func(f *fixture) {
280 mutator(f)
281 })
282}
283
Paul Duffin35816122021-02-24 01:49:52 +0000284// Modify the config
285func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
286 return newSimpleFixturePreparer(func(f *fixture) {
287 mutator(f.config)
288 })
289}
290
291// Modify the config and context
292func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer {
293 return newSimpleFixturePreparer(func(f *fixture) {
294 mutator(f.config, f.ctx)
295 })
296}
297
298// Modify the context
299func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer {
300 return newSimpleFixturePreparer(func(f *fixture) {
301 mutator(f.ctx)
302 })
303}
304
305func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
306 return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
307}
308
309// Modify the mock filesystem
310func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
311 return newSimpleFixturePreparer(func(f *fixture) {
312 mutator(f.mockFS)
Paul Duffin80f4cea2021-03-16 14:08:00 +0000313
314 // Make sure that invalid paths were not added to the mock filesystem.
315 for p, _ := range f.mockFS {
316 validateFixtureMockFSPath(p)
317 }
Paul Duffin35816122021-02-24 01:49:52 +0000318 })
319}
320
321// Merge the supplied file system into the mock filesystem.
322//
323// Paths that already exist in the mock file system are overridden.
324func FixtureMergeMockFs(mockFS MockFS) FixturePreparer {
325 return FixtureModifyMockFS(func(fs MockFS) {
326 fs.Merge(mockFS)
327 })
328}
329
330// Add a file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000331//
332// Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
Paul Duffin35816122021-02-24 01:49:52 +0000333func FixtureAddFile(path string, contents []byte) FixturePreparer {
334 return FixtureModifyMockFS(func(fs MockFS) {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000335 validateFixtureMockFSPath(path)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000336 if _, ok := fs[path]; ok {
337 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
338 }
Paul Duffin35816122021-02-24 01:49:52 +0000339 fs[path] = contents
340 })
341}
342
343// Add a text file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000344//
345// Fail if the filesystem already contains a file with that path.
Paul Duffin35816122021-02-24 01:49:52 +0000346func FixtureAddTextFile(path string, contents string) FixturePreparer {
347 return FixtureAddFile(path, []byte(contents))
348}
349
Paul Duffin6e9a4002021-03-11 19:01:26 +0000350// Override a file in the mock filesystem
351//
352// If the file does not exist this behaves as FixtureAddFile.
353func FixtureOverrideFile(path string, contents []byte) FixturePreparer {
354 return FixtureModifyMockFS(func(fs MockFS) {
355 fs[path] = contents
356 })
357}
358
359// Override a text file in the mock filesystem
360//
361// If the file does not exist this behaves as FixtureAddTextFile.
362func FixtureOverrideTextFile(path string, contents string) FixturePreparer {
363 return FixtureOverrideFile(path, []byte(contents))
364}
365
Paul Duffin35816122021-02-24 01:49:52 +0000366// Add the root Android.bp file with the supplied contents.
367func FixtureWithRootAndroidBp(contents string) FixturePreparer {
368 return FixtureAddTextFile("Android.bp", contents)
369}
370
Paul Duffinbbccfcf2021-03-03 00:44:00 +0000371// Merge some environment variables into the fixture.
372func FixtureMergeEnv(env map[string]string) FixturePreparer {
373 return FixtureModifyConfig(func(config Config) {
374 for k, v := range env {
375 if k == "PATH" {
376 panic("Cannot set PATH environment variable")
377 }
378 config.env[k] = v
379 }
380 })
381}
382
383// Modify the env.
384//
385// Will panic if the mutator changes the PATH environment variable.
386func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer {
387 return FixtureModifyConfig(func(config Config) {
388 oldPath := config.env["PATH"]
389 mutator(config.env)
390 newPath := config.env["PATH"]
391 if newPath != oldPath {
392 panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath))
393 }
394 })
395}
396
Paul Duffin2e0323d2021-03-04 15:11:01 +0000397// Allow access to the product variables when preparing the fixture.
398type FixtureProductVariables struct {
399 *productVariables
400}
401
402// Modify product variables.
403func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer {
404 return FixtureModifyConfig(func(config Config) {
405 productVariables := FixtureProductVariables{&config.productVariables}
406 mutator(productVariables)
407 })
408}
409
Paul Duffina560d5a2021-02-28 01:38:51 +0000410// GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of
411// the supplied FixturePreparer instances in order.
412//
413// Before preparing the fixture the list of preparers is flattened by replacing each
414// instance of GroupFixturePreparers with its contents.
415func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
Paul Duffin35816122021-02-24 01:49:52 +0000416 return &compositeFixturePreparer{dedupAndFlattenPreparers(nil, preparers)}
417}
418
Paul Duffin50deaae2021-03-16 17:46:12 +0000419// NullFixturePreparer is a preparer that does nothing.
420var NullFixturePreparer = GroupFixturePreparers()
421
422// OptionalFixturePreparer will return the supplied preparer if it is non-nil, otherwise it will
423// return the NullFixturePreparer
424func OptionalFixturePreparer(preparer FixturePreparer) FixturePreparer {
425 if preparer == nil {
426 return NullFixturePreparer
427 } else {
428 return preparer
429 }
430}
431
Paul Duffin35816122021-02-24 01:49:52 +0000432// FixturePreparer is an opaque interface that can change a fixture.
433type FixturePreparer interface {
Paul Duffin4ca67522021-03-20 01:25:12 +0000434 // Return the flattened and deduped list of simpleFixturePreparer pointers.
435 list() []*simpleFixturePreparer
Paul Duffin35816122021-02-24 01:49:52 +0000436}
437
438// dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
439// instances.
440//
441// base - a list of already flattened and deduped preparers that will be applied first before
442// the list of additional preparers. Any duplicates of these in the additional preparers
443// will be ignored.
444//
445// preparers - a list of additional unflattened, undeduped preparers that will be applied after the
446// base preparers.
447//
Paul Duffin59251822021-03-15 22:20:12 +0000448// Returns a deduped and flattened list of the preparers starting with the ones in base with any
449// additional ones from the preparers list added afterwards.
Paul Duffin4ca67522021-03-20 01:25:12 +0000450func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer {
Paul Duffin59251822021-03-15 22:20:12 +0000451 if len(preparers) == 0 {
452 return base
453 }
454
455 list := make([]*simpleFixturePreparer, len(base))
Paul Duffin35816122021-02-24 01:49:52 +0000456 visited := make(map[*simpleFixturePreparer]struct{})
457
458 // Mark the already flattened and deduped preparers, if any, as having been seen so that
Paul Duffin59251822021-03-15 22:20:12 +0000459 // duplicates of these in the additional preparers will be discarded. Add them to the output
460 // list.
461 for i, s := range base {
Paul Duffin35816122021-02-24 01:49:52 +0000462 visited[s] = struct{}{}
Paul Duffin59251822021-03-15 22:20:12 +0000463 list[i] = s
Paul Duffin35816122021-02-24 01:49:52 +0000464 }
465
Paul Duffin4ca67522021-03-20 01:25:12 +0000466 for _, p := range preparers {
467 for _, s := range p.list() {
468 if _, seen := visited[s]; !seen {
469 visited[s] = struct{}{}
470 list = append(list, s)
471 }
Paul Duffin35816122021-02-24 01:49:52 +0000472 }
Paul Duffin4ca67522021-03-20 01:25:12 +0000473 }
474
Paul Duffin35816122021-02-24 01:49:52 +0000475 return list
476}
477
478// compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
479type compositeFixturePreparer struct {
Paul Duffin4ca67522021-03-20 01:25:12 +0000480 // The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this
481 // composite preparer.
Paul Duffin35816122021-02-24 01:49:52 +0000482 preparers []*simpleFixturePreparer
483}
484
Paul Duffin4ca67522021-03-20 01:25:12 +0000485func (c *compositeFixturePreparer) list() []*simpleFixturePreparer {
486 return c.preparers
Paul Duffin35816122021-02-24 01:49:52 +0000487}
488
489// simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
490type simpleFixturePreparer struct {
491 function func(fixture *fixture)
492}
493
Paul Duffin4ca67522021-03-20 01:25:12 +0000494func (s *simpleFixturePreparer) list() []*simpleFixturePreparer {
495 return []*simpleFixturePreparer{s}
Paul Duffin35816122021-02-24 01:49:52 +0000496}
497
498func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
499 return &simpleFixturePreparer{function: preparer}
500}
501
Paul Duffincfd33742021-02-27 11:59:02 +0000502// FixtureErrorHandler determines how to respond to errors reported by the code under test.
503//
504// Some possible responses:
505// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
506// * Fail the test if at least one error that matches a pattern is not reported see
507// FixtureExpectsAtLeastOneErrorMatchingPattern
508// * Fail the test if any unexpected errors are reported.
509//
510// Although at the moment all the error handlers are implemented as simply a wrapper around a
511// function this is defined as an interface to allow future enhancements, e.g. provide different
512// ways other than patterns to match an error and to combine handlers together.
513type FixtureErrorHandler interface {
514 // CheckErrors checks the errors reported.
515 //
516 // The supplied result can be used to access the state of the code under test just as the main
517 // body of the test would but if any errors other than ones expected are reported the state may
518 // be indeterminate.
Paul Duffinc81854a2021-03-12 12:22:27 +0000519 CheckErrors(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000520}
521
522type simpleErrorHandler struct {
Paul Duffinc81854a2021-03-12 12:22:27 +0000523 function func(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000524}
525
Paul Duffinc81854a2021-03-12 12:22:27 +0000526func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) {
527 t.Helper()
528 h.function(t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000529}
530
531// The default fixture error handler.
532//
533// Will fail the test immediately if any errors are reported.
Paul Duffinea8a3862021-03-04 17:58:33 +0000534//
535// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
536// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000537var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
Paul Duffinc81854a2021-03-12 12:22:27 +0000538 func(t *testing.T, result *TestResult) {
539 t.Helper()
540 FailIfErrored(t, result.Errs)
Paul Duffincfd33742021-02-27 11:59:02 +0000541 },
542)
543
Paul Duffin85034e92021-03-17 00:20:34 +0000544// FixtureIgnoreErrors ignores any errors.
545//
546// If this is used then it is the responsibility of the test to check the TestResult.Errs does not
547// contain any unexpected errors.
548var FixtureIgnoreErrors = FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
549 // Ignore the errors
550})
551
Paul Duffincfd33742021-02-27 11:59:02 +0000552// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
553// if at least one error that matches the regular expression is not found.
554//
555// The test will be failed if:
556// * No errors are reported.
557// * One or more errors are reported but none match the pattern.
558//
559// The test will not fail if:
560// * Multiple errors are reported that do not match the pattern as long as one does match.
Paul Duffinea8a3862021-03-04 17:58:33 +0000561//
562// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
563// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000564func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000565 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
566 t.Helper()
567 if !FailIfNoMatchingErrors(t, pattern, result.Errs) {
568 t.FailNow()
Paul Duffinea8a3862021-03-04 17:58:33 +0000569 }
Paul Duffincfd33742021-02-27 11:59:02 +0000570 })
571}
572
573// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
574// if there are any unexpected errors.
575//
576// The test will be failed if:
577// * The number of errors reported does not exactly match the patterns.
578// * One or more of the reported errors do not match a pattern.
579// * No patterns are provided and one or more errors are reported.
580//
581// The test will not fail if:
582// * One or more of the patterns does not match an error.
Paul Duffinea8a3862021-03-04 17:58:33 +0000583//
584// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
585// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000586func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000587 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
588 t.Helper()
589 CheckErrorsAgainstExpectations(t, result.Errs, patterns)
Paul Duffincfd33742021-02-27 11:59:02 +0000590 })
591}
592
593// FixtureCustomErrorHandler creates a custom error handler
Paul Duffinc81854a2021-03-12 12:22:27 +0000594func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler {
Paul Duffincfd33742021-02-27 11:59:02 +0000595 return simpleErrorHandler{
596 function: function,
597 }
598}
599
Paul Duffin35816122021-02-24 01:49:52 +0000600// Fixture defines the test environment.
601type Fixture interface {
Paul Duffinae542a52021-03-09 03:15:28 +0000602 // Config returns the fixture's configuration.
603 Config() Config
604
605 // Context returns the fixture's test context.
606 Context() *TestContext
607
608 // MockFS returns the fixture's mock filesystem.
609 MockFS() MockFS
610
Paul Duffincfd33742021-02-27 11:59:02 +0000611 // Run the test, checking any errors reported and returning a TestResult instance.
Paul Duffin35816122021-02-24 01:49:52 +0000612 RunTest() *TestResult
613}
614
Paul Duffin35816122021-02-24 01:49:52 +0000615// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
616type testContext struct {
617 *TestContext
618}
619
620// The result of running a test.
621type TestResult struct {
Paul Duffin35816122021-02-24 01:49:52 +0000622 testContext
623
624 fixture *fixture
625 Config Config
Paul Duffin942481b2021-03-04 18:58:11 +0000626
627 // The errors that were reported during the test.
628 Errs []error
Paul Duffin78c36212021-03-16 23:57:12 +0000629
630 // The ninja deps is a list of the ninja files dependencies that were added by the modules and
631 // singletons via the *.AddNinjaFileDeps() methods.
632 NinjaDeps []string
Paul Duffin35816122021-02-24 01:49:52 +0000633}
634
635var _ FixtureFactory = (*fixtureFactory)(nil)
636
637type fixtureFactory struct {
638 buildDirSupplier *string
639 preparers []*simpleFixturePreparer
640}
641
642func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory {
Paul Duffin59251822021-03-15 22:20:12 +0000643 all := dedupAndFlattenPreparers(f.preparers, preparers)
644
Paul Duffincfd33742021-02-27 11:59:02 +0000645 // Copy the existing factory.
646 extendedFactory := &fixtureFactory{}
647 *extendedFactory = *f
648 // Use the extended list of preparers.
649 extendedFactory.preparers = all
650 return extendedFactory
Paul Duffin35816122021-02-24 01:49:52 +0000651}
652
653func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
Paul Duffindff5ff02021-03-15 15:42:40 +0000654 var buildDir string
655 if f.buildDirSupplier == nil {
656 // Create a new temporary directory for this run. It will be automatically cleaned up when the
657 // test finishes.
658 buildDir = t.TempDir()
659 } else {
660 // Retrieve the buildDir from the supplier.
661 buildDir = *f.buildDirSupplier
662 }
Paul Duffin59251822021-03-15 22:20:12 +0000663
664 // Construct an array of all preparers, those from this factory and the additional ones passed to
665 // this method.
666 all := dedupAndFlattenPreparers(f.preparers, preparers)
667
Paul Duffindff5ff02021-03-15 15:42:40 +0000668 config := TestConfig(buildDir, nil, "", nil)
Paul Duffin35816122021-02-24 01:49:52 +0000669 ctx := NewTestContext(config)
670 fixture := &fixture{
Paul Duffincff464f2021-03-19 18:13:46 +0000671 preparers: all,
672 t: t,
673 config: config,
674 ctx: ctx,
675 mockFS: make(MockFS),
676 // Set the default error handler.
677 errorHandler: FixtureExpectsNoErrors,
Paul Duffin35816122021-02-24 01:49:52 +0000678 }
679
Paul Duffin59251822021-03-15 22:20:12 +0000680 for _, preparer := range all {
Paul Duffin35816122021-02-24 01:49:52 +0000681 preparer.function(fixture)
682 }
683
684 return fixture
685}
686
Paul Duffin46e37742021-03-09 11:55:20 +0000687func (f *fixtureFactory) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory {
Paul Duffincff464f2021-03-19 18:13:46 +0000688 return f.Extend(newSimpleFixturePreparer(func(fixture *fixture) {
689 fixture.errorHandler = errorHandler
690 }))
Paul Duffincfd33742021-02-27 11:59:02 +0000691}
692
Paul Duffin35816122021-02-24 01:49:52 +0000693func (f *fixtureFactory) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult {
694 t.Helper()
695 fixture := f.Fixture(t, preparers...)
696 return fixture.RunTest()
697}
698
699func (f *fixtureFactory) RunTestWithBp(t *testing.T, bp string) *TestResult {
700 t.Helper()
701 return f.RunTest(t, FixtureWithRootAndroidBp(bp))
702}
703
Paul Duffin72018ad2021-03-04 19:36:49 +0000704func (f *fixtureFactory) RunTestWithConfig(t *testing.T, config Config) *TestResult {
705 t.Helper()
706 // Create the fixture as normal.
707 fixture := f.Fixture(t).(*fixture)
708
709 // Discard the mock filesystem as otherwise that will override the one in the config.
710 fixture.mockFS = nil
711
712 // Replace the config with the supplied one in the fixture.
713 fixture.config = config
714
715 // Ditto with config derived information in the TestContext.
716 ctx := fixture.ctx
717 ctx.config = config
718 ctx.SetFs(ctx.config.fs)
719 if ctx.config.mockBpList != "" {
720 ctx.SetModuleListFile(ctx.config.mockBpList)
721 }
722
723 return fixture.RunTest()
724}
725
Paul Duffin35816122021-02-24 01:49:52 +0000726type fixture struct {
Paul Duffin59251822021-03-15 22:20:12 +0000727 // The preparers used to create this fixture.
728 preparers []*simpleFixturePreparer
Paul Duffincfd33742021-02-27 11:59:02 +0000729
730 // The gotest state of the go test within which this was created.
731 t *testing.T
732
733 // The configuration prepared for this fixture.
734 config Config
735
736 // The test context prepared for this fixture.
737 ctx *TestContext
738
739 // The mock filesystem prepared for this fixture.
740 mockFS MockFS
741
742 // The error handler used to check the errors, if any, that are reported.
743 errorHandler FixtureErrorHandler
Paul Duffin35816122021-02-24 01:49:52 +0000744}
745
Paul Duffinae542a52021-03-09 03:15:28 +0000746func (f *fixture) Config() Config {
747 return f.config
748}
749
750func (f *fixture) Context() *TestContext {
751 return f.ctx
752}
753
754func (f *fixture) MockFS() MockFS {
755 return f.mockFS
756}
757
Paul Duffin35816122021-02-24 01:49:52 +0000758func (f *fixture) RunTest() *TestResult {
759 f.t.Helper()
760
761 ctx := f.ctx
762
Paul Duffin72018ad2021-03-04 19:36:49 +0000763 // Do not use the fixture's mockFS to initialize the config's mock file system if it has been
764 // cleared by RunTestWithConfig.
765 if f.mockFS != nil {
766 // The TestConfig() method assumes that the mock filesystem is available when creating so
767 // creates the mock file system immediately. Similarly, the NewTestContext(Config) method
768 // assumes that the supplied Config's FileSystem has been properly initialized before it is
769 // called and so it takes its own reference to the filesystem. However, fixtures create the
770 // Config and TestContext early so they can be modified by preparers at which time the mockFS
771 // has not been populated (because it too is modified by preparers). So, this reinitializes the
772 // Config and TestContext's FileSystem using the now populated mockFS.
773 f.config.mockFileSystem("", f.mockFS)
774
775 ctx.SetFs(ctx.config.fs)
776 if ctx.config.mockBpList != "" {
777 ctx.SetModuleListFile(ctx.config.mockBpList)
778 }
Paul Duffin35816122021-02-24 01:49:52 +0000779 }
780
781 ctx.Register()
Paul Duffin78c36212021-03-16 23:57:12 +0000782 var ninjaDeps []string
783 extraNinjaDeps, errs := ctx.ParseBlueprintsFiles("ignored")
Paul Duffincfd33742021-02-27 11:59:02 +0000784 if len(errs) == 0 {
Paul Duffin78c36212021-03-16 23:57:12 +0000785 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
786 extraNinjaDeps, errs = ctx.PrepareBuildActions(f.config)
787 if len(errs) == 0 {
788 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
789 }
Paul Duffincfd33742021-02-27 11:59:02 +0000790 }
Paul Duffin35816122021-02-24 01:49:52 +0000791
792 result := &TestResult{
Paul Duffin35816122021-02-24 01:49:52 +0000793 testContext: testContext{ctx},
794 fixture: f,
795 Config: f.config,
Paul Duffin942481b2021-03-04 18:58:11 +0000796 Errs: errs,
Paul Duffin78c36212021-03-16 23:57:12 +0000797 NinjaDeps: ninjaDeps,
Paul Duffin35816122021-02-24 01:49:52 +0000798 }
Paul Duffincfd33742021-02-27 11:59:02 +0000799
Paul Duffinc81854a2021-03-12 12:22:27 +0000800 f.errorHandler.CheckErrors(f.t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000801
Paul Duffin35816122021-02-24 01:49:52 +0000802 return result
803}
804
805// NormalizePathForTesting removes the test invocation specific build directory from the supplied
806// path.
807//
808// If the path is within the build directory (e.g. an OutputPath) then this returns the relative
809// path to avoid tests having to deal with the dynamically generated build directory.
810//
811// Otherwise, this returns the supplied path as it is almost certainly a source path that is
812// relative to the root of the source tree.
813//
814// Even though some information is removed from some paths and not others it should be possible to
815// differentiate between them by the paths themselves, e.g. output paths will likely include
816// ".intermediates" but source paths won't.
817func (r *TestResult) NormalizePathForTesting(path Path) string {
818 pathContext := PathContextForTesting(r.Config)
819 pathAsString := path.String()
820 if rel, isRel := MaybeRel(pathContext, r.Config.BuildDir(), pathAsString); isRel {
821 return rel
822 }
823 return pathAsString
824}
825
826// NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized
827// forms.
828func (r *TestResult) NormalizePathsForTesting(paths Paths) []string {
829 var result []string
830 for _, path := range paths {
831 result = append(result, r.NormalizePathForTesting(path))
832 }
833 return result
834}
835
Paul Duffin59251822021-03-15 22:20:12 +0000836// Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture
837// that produced this result.
838//
839// e.g. assuming that this result was created by running:
840// factory.Extend(preparer1, preparer2).RunTest(t, preparer3, preparer4)
841//
842// Then this method will be equivalent to running:
843// GroupFixturePreparers(preparer1, preparer2, preparer3, preparer4)
844//
845// This is intended for use by tests whose output is Android.bp files to verify that those files
846// are valid, e.g. tests of the snapshots produced by the sdk module type.
847func (r *TestResult) Preparer() FixturePreparer {
848 return &compositeFixturePreparer{r.fixture.preparers}
849}
850
Paul Duffin35816122021-02-24 01:49:52 +0000851// Module returns the module with the specific name and of the specified variant.
852func (r *TestResult) Module(name string, variant string) Module {
853 return r.ModuleForTests(name, variant).Module()
854}