blob: 5fc668a8b148348df80658355bbdafa602b29d21 [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
Paul Duffin4814bb82021-03-29 01:55:10 +010029// created and mutated by FixturePreparer instances. They are created by first creating a base
30// Fixture (which is essentially empty) and then applying FixturePreparer instances to it to modify
31// the environment.
Paul Duffin35816122021-02-24 01:49:52 +000032//
33// FixturePreparer
34// ===============
35// These are responsible for modifying a Fixture in preparation for it to run a test. Preparers are
36// intended to be immutable and able to prepare multiple Fixture objects simultaneously without
37// them sharing any data.
38//
Paul Duffinff2aa692021-03-19 18:20:59 +000039// They provide the basic capabilities for running tests too.
40//
41// FixturePreparers are only ever applied once per test fixture. Prior to application the list of
Paul Duffin35816122021-02-24 01:49:52 +000042// FixturePreparers are flattened and deduped while preserving the order they first appear in the
43// list. This makes it easy to reuse, group and combine FixturePreparers together.
44//
45// Each small self contained piece of test setup should be their own FixturePreparer. e.g.
46// * A group of related modules.
47// * A group of related mutators.
48// * A combination of both.
49// * Configuration.
50//
51// They should not overlap, e.g. the same module type should not be registered by different
52// FixturePreparers as using them both would cause a build error. In that case the preparer should
53// be split into separate parts and combined together using FixturePreparers(...).
54//
55// e.g. attempting to use AllPreparers in preparing a Fixture would break as it would attempt to
56// register module bar twice:
57// var Preparer1 = FixtureRegisterWithContext(RegisterModuleFooAndBar)
58// var Preparer2 = FixtureRegisterWithContext(RegisterModuleBarAndBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000059// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000060//
61// However, when restructured like this it would work fine:
62// var PreparerFoo = FixtureRegisterWithContext(RegisterModuleFoo)
63// var PreparerBar = FixtureRegisterWithContext(RegisterModuleBar)
64// var PreparerBaz = FixtureRegisterWithContext(RegisterModuleBaz)
Paul Duffina560d5a2021-02-28 01:38:51 +000065// var Preparer1 = GroupFixturePreparers(RegisterModuleFoo, RegisterModuleBar)
66// var Preparer2 = GroupFixturePreparers(RegisterModuleBar, RegisterModuleBaz)
67// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
Paul Duffin35816122021-02-24 01:49:52 +000068//
69// As after deduping and flattening AllPreparers would result in the following preparers being
70// applied:
71// 1. PreparerFoo
72// 2. PreparerBar
73// 3. PreparerBaz
74//
75// Preparers can be used for both integration and unit tests.
76//
77// Integration tests typically use all the module types, mutators and singletons that are available
78// for that package to try and replicate the behavior of the runtime build as closely as possible.
79// However, that realism comes at a cost of increased fragility (as they can be broken by changes in
80// many different parts of the build) and also increased runtime, especially if they use lots of
81// singletons and mutators.
82//
83// Unit tests on the other hand try and minimize the amount of code being tested which makes them
84// less susceptible to changes elsewhere in the build and quick to run but at a cost of potentially
85// not testing realistic scenarios.
86//
87// Supporting unit tests effectively require that preparers are available at the lowest granularity
88// possible. Supporting integration tests effectively require that the preparers are organized into
89// groups that provide all the functionality available.
90//
91// At least in terms of tests that check the behavior of build components via processing
92// `Android.bp` there is no clear separation between a unit test and an integration test. Instead
93// they vary from one end that tests a single module (e.g. filegroup) to the other end that tests a
94// whole system of modules, mutators and singletons (e.g. apex + hiddenapi).
95//
96// TestResult
97// ==========
98// These are created by running tests in a Fixture and provide access to the Config and TestContext
99// in which the tests were run.
100//
101// Example
102// =======
103//
104// An exported preparer for use by other packages that need to use java modules.
105//
106// package java
Paul Duffina560d5a2021-02-28 01:38:51 +0000107// var PrepareForIntegrationTestWithJava = GroupFixturePreparers(
Paul Duffin35816122021-02-24 01:49:52 +0000108// android.PrepareForIntegrationTestWithAndroid,
109// FixtureRegisterWithContext(RegisterAGroupOfRelatedModulesMutatorsAndSingletons),
110// FixtureRegisterWithContext(RegisterAnotherGroupOfRelatedModulesMutatorsAndSingletons),
111// ...
112// )
113//
114// Some files to use in tests in the java package.
115//
116// var javaMockFS = android.MockFS{
Paul Duffinff2aa692021-03-19 18:20:59 +0000117// "api/current.txt": nil,
118// "api/removed.txt": nil,
Paul Duffin35816122021-02-24 01:49:52 +0000119// ...
120// }
121//
Paul Duffinff2aa692021-03-19 18:20:59 +0000122// A package private preparer for use for testing java within the java package.
Paul Duffin35816122021-02-24 01:49:52 +0000123//
Paul Duffinff2aa692021-03-19 18:20:59 +0000124// var prepareForJavaTest = android.GroupFixturePreparers(
125// PrepareForIntegrationTestWithJava,
126// FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
127// ctx.RegisterModuleType("test_module", testModule)
128// }),
129// javaMockFS.AddToFixture(),
130// ...
131// }
132//
133// func TestJavaStuff(t *testing.T) {
Paul Duffin3cb2c062021-03-22 19:24:26 +0000134// result := android.GroupFixturePreparers(
Paul Duffinff2aa692021-03-19 18:20:59 +0000135// prepareForJavaTest,
136// android.FixtureWithRootAndroidBp(`java_library {....}`),
137// android.MockFS{...}.AddToFixture(),
138// ).RunTest(t)
139// ... test result ...
140// }
141//
142// package cc
143// var PrepareForTestWithCC = android.GroupFixturePreparers(
144// android.PrepareForArchMutator,
145// android.prepareForPrebuilts,
146// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
147// ...
148// )
149//
150// package apex
151//
152// var PrepareForApex = GroupFixturePreparers(
153// ...
154// )
155//
156// Use modules and mutators from java, cc and apex. Any duplicate preparers (like
157// android.PrepareForArchMutator) will be automatically deduped.
158//
159// var prepareForApexTest = android.GroupFixturePreparers(
160// PrepareForJava,
161// PrepareForCC,
162// PrepareForApex,
163// )
164//
Paul Duffin35816122021-02-24 01:49:52 +0000165
166// A set of mock files to add to the mock file system.
167type MockFS map[string][]byte
168
Paul Duffin6e9a4002021-03-11 19:01:26 +0000169// Merge adds the extra entries from the supplied map to this one.
170//
171// Fails if the supplied map files with the same paths are present in both of them.
Paul Duffin35816122021-02-24 01:49:52 +0000172func (fs MockFS) Merge(extra map[string][]byte) {
173 for p, c := range extra {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000174 validateFixtureMockFSPath(p)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000175 if _, ok := fs[p]; ok {
176 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
177 }
Paul Duffin35816122021-02-24 01:49:52 +0000178 fs[p] = c
179 }
180}
181
Paul Duffin80f4cea2021-03-16 14:08:00 +0000182// Ensure that tests cannot add paths into the mock file system which would not be allowed in the
183// runtime, e.g. absolute paths, paths relative to the 'out/' directory.
184func validateFixtureMockFSPath(path string) {
185 // This uses validateSafePath rather than validatePath because the latter prevents adding files
186 // that include a $ but there are tests that allow files with a $ to be used, albeit only by
187 // globbing.
188 validatedPath, err := validateSafePath(path)
189 if err != nil {
190 panic(err)
191 }
192
193 // Make sure that the path is canonical.
194 if validatedPath != path {
195 panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath))
196 }
197
198 if path == "out" || strings.HasPrefix(path, "out/") {
199 panic(fmt.Errorf("cannot add output path %q to the mock file system", path))
200 }
201}
202
Paul Duffin35816122021-02-24 01:49:52 +0000203func (fs MockFS) AddToFixture() FixturePreparer {
204 return FixtureMergeMockFs(fs)
205}
206
Paul Duffinae542a52021-03-09 03:15:28 +0000207// FixtureCustomPreparer allows for the modification of any aspect of the fixture.
208//
209// This should only be used if one of the other more specific preparers are not suitable.
210func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer {
211 return newSimpleFixturePreparer(func(f *fixture) {
212 mutator(f)
213 })
214}
215
Paul Duffin35816122021-02-24 01:49:52 +0000216// Modify the config
217func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
218 return newSimpleFixturePreparer(func(f *fixture) {
219 mutator(f.config)
220 })
221}
222
223// Modify the config and context
224func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer {
225 return newSimpleFixturePreparer(func(f *fixture) {
226 mutator(f.config, f.ctx)
227 })
228}
229
230// Modify the context
231func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer {
232 return newSimpleFixturePreparer(func(f *fixture) {
233 mutator(f.ctx)
234 })
235}
236
237func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
238 return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
239}
240
241// Modify the mock filesystem
242func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
243 return newSimpleFixturePreparer(func(f *fixture) {
244 mutator(f.mockFS)
Paul Duffin80f4cea2021-03-16 14:08:00 +0000245
246 // Make sure that invalid paths were not added to the mock filesystem.
247 for p, _ := range f.mockFS {
248 validateFixtureMockFSPath(p)
249 }
Paul Duffin35816122021-02-24 01:49:52 +0000250 })
251}
252
253// Merge the supplied file system into the mock filesystem.
254//
255// Paths that already exist in the mock file system are overridden.
256func FixtureMergeMockFs(mockFS MockFS) FixturePreparer {
257 return FixtureModifyMockFS(func(fs MockFS) {
258 fs.Merge(mockFS)
259 })
260}
261
262// Add a file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000263//
264// Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
Paul Duffin35816122021-02-24 01:49:52 +0000265func FixtureAddFile(path string, contents []byte) FixturePreparer {
266 return FixtureModifyMockFS(func(fs MockFS) {
Paul Duffin80f4cea2021-03-16 14:08:00 +0000267 validateFixtureMockFSPath(path)
Paul Duffin6e9a4002021-03-11 19:01:26 +0000268 if _, ok := fs[path]; ok {
269 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
270 }
Paul Duffin35816122021-02-24 01:49:52 +0000271 fs[path] = contents
272 })
273}
274
275// Add a text file to the mock filesystem
Paul Duffin6e9a4002021-03-11 19:01:26 +0000276//
277// Fail if the filesystem already contains a file with that path.
Paul Duffin35816122021-02-24 01:49:52 +0000278func FixtureAddTextFile(path string, contents string) FixturePreparer {
279 return FixtureAddFile(path, []byte(contents))
280}
281
Paul Duffin6e9a4002021-03-11 19:01:26 +0000282// Override a file in the mock filesystem
283//
284// If the file does not exist this behaves as FixtureAddFile.
285func FixtureOverrideFile(path string, contents []byte) FixturePreparer {
286 return FixtureModifyMockFS(func(fs MockFS) {
287 fs[path] = contents
288 })
289}
290
291// Override a text file in the mock filesystem
292//
293// If the file does not exist this behaves as FixtureAddTextFile.
294func FixtureOverrideTextFile(path string, contents string) FixturePreparer {
295 return FixtureOverrideFile(path, []byte(contents))
296}
297
Paul Duffin35816122021-02-24 01:49:52 +0000298// Add the root Android.bp file with the supplied contents.
299func FixtureWithRootAndroidBp(contents string) FixturePreparer {
300 return FixtureAddTextFile("Android.bp", contents)
301}
302
Paul Duffinbbccfcf2021-03-03 00:44:00 +0000303// Merge some environment variables into the fixture.
304func FixtureMergeEnv(env map[string]string) FixturePreparer {
305 return FixtureModifyConfig(func(config Config) {
306 for k, v := range env {
307 if k == "PATH" {
308 panic("Cannot set PATH environment variable")
309 }
310 config.env[k] = v
311 }
312 })
313}
314
315// Modify the env.
316//
317// Will panic if the mutator changes the PATH environment variable.
318func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer {
319 return FixtureModifyConfig(func(config Config) {
320 oldPath := config.env["PATH"]
321 mutator(config.env)
322 newPath := config.env["PATH"]
323 if newPath != oldPath {
324 panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath))
325 }
326 })
327}
328
Paul Duffin2e0323d2021-03-04 15:11:01 +0000329// Allow access to the product variables when preparing the fixture.
330type FixtureProductVariables struct {
331 *productVariables
332}
333
334// Modify product variables.
335func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer {
336 return FixtureModifyConfig(func(config Config) {
337 productVariables := FixtureProductVariables{&config.productVariables}
338 mutator(productVariables)
339 })
340}
341
Paul Duffina560d5a2021-02-28 01:38:51 +0000342// GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of
343// the supplied FixturePreparer instances in order.
344//
345// Before preparing the fixture the list of preparers is flattened by replacing each
346// instance of GroupFixturePreparers with its contents.
347func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000348 all := dedupAndFlattenPreparers(nil, preparers)
349 return newFixturePreparer(all)
Paul Duffin35816122021-02-24 01:49:52 +0000350}
351
Paul Duffin50deaae2021-03-16 17:46:12 +0000352// NullFixturePreparer is a preparer that does nothing.
353var NullFixturePreparer = GroupFixturePreparers()
354
355// OptionalFixturePreparer will return the supplied preparer if it is non-nil, otherwise it will
356// return the NullFixturePreparer
357func OptionalFixturePreparer(preparer FixturePreparer) FixturePreparer {
358 if preparer == nil {
359 return NullFixturePreparer
360 } else {
361 return preparer
362 }
363}
364
Paul Duffinff2aa692021-03-19 18:20:59 +0000365// FixturePreparer provides the ability to create, modify and then run tests within a fixture.
Paul Duffin35816122021-02-24 01:49:52 +0000366type FixturePreparer interface {
Paul Duffin4ca67522021-03-20 01:25:12 +0000367 // Return the flattened and deduped list of simpleFixturePreparer pointers.
368 list() []*simpleFixturePreparer
Paul Duffinff2aa692021-03-19 18:20:59 +0000369
Paul Duffinff2aa692021-03-19 18:20:59 +0000370 // Create a Fixture.
Paul Duffin34a7fff2021-03-30 22:11:24 +0100371 Fixture(t *testing.T) Fixture
Paul Duffinff2aa692021-03-19 18:20:59 +0000372
373 // ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler
374 // to check the errors (may be 0) reported by the test.
375 //
376 // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
377 // errors are reported.
378 ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer
379
380 // Run the test, checking any errors reported and returning a TestResult instance.
381 //
Paul Duffin55e740e2021-03-29 02:06:19 +0100382 // Shorthand for Fixture(t).RunTest()
383 RunTest(t *testing.T) *TestResult
Paul Duffinff2aa692021-03-19 18:20:59 +0000384
385 // Run the test with the supplied Android.bp file.
386 //
Paul Duffin55e740e2021-03-29 02:06:19 +0100387 // preparer.RunTestWithBp(t, bp) is shorthand for
388 // android.GroupFixturePreparers(preparer, android.FixtureWithRootAndroidBp(bp)).RunTest(t)
Paul Duffinff2aa692021-03-19 18:20:59 +0000389 RunTestWithBp(t *testing.T, bp string) *TestResult
390
391 // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
392 // the test fixture.
393 //
394 // In order to allow the Config object to be customized separately to the TestContext a lot of
395 // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
396 // from the test and then have the TestContext created and configured automatically. e.g.
397 // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
398 //
399 // This method allows those methods to be migrated to use the test fixture pattern without
400 // requiring that every test that uses those methods be migrated at the same time. That allows
401 // those tests to benefit from correctness in the order of registration quickly.
402 //
403 // This method discards the config (along with its mock file system, product variables,
404 // environment, etc.) that may have been set up by FixturePreparers.
405 //
406 // deprecated
407 RunTestWithConfig(t *testing.T, config Config) *TestResult
Paul Duffin35816122021-02-24 01:49:52 +0000408}
409
410// dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
411// instances.
412//
413// base - a list of already flattened and deduped preparers that will be applied first before
414// the list of additional preparers. Any duplicates of these in the additional preparers
415// will be ignored.
416//
417// preparers - a list of additional unflattened, undeduped preparers that will be applied after the
418// base preparers.
419//
Paul Duffin59251822021-03-15 22:20:12 +0000420// Returns a deduped and flattened list of the preparers starting with the ones in base with any
421// additional ones from the preparers list added afterwards.
Paul Duffin4ca67522021-03-20 01:25:12 +0000422func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer {
Paul Duffin59251822021-03-15 22:20:12 +0000423 if len(preparers) == 0 {
424 return base
425 }
426
427 list := make([]*simpleFixturePreparer, len(base))
Paul Duffin35816122021-02-24 01:49:52 +0000428 visited := make(map[*simpleFixturePreparer]struct{})
429
430 // Mark the already flattened and deduped preparers, if any, as having been seen so that
Paul Duffin59251822021-03-15 22:20:12 +0000431 // duplicates of these in the additional preparers will be discarded. Add them to the output
432 // list.
433 for i, s := range base {
Paul Duffin35816122021-02-24 01:49:52 +0000434 visited[s] = struct{}{}
Paul Duffin59251822021-03-15 22:20:12 +0000435 list[i] = s
Paul Duffin35816122021-02-24 01:49:52 +0000436 }
437
Paul Duffin4ca67522021-03-20 01:25:12 +0000438 for _, p := range preparers {
439 for _, s := range p.list() {
440 if _, seen := visited[s]; !seen {
441 visited[s] = struct{}{}
442 list = append(list, s)
443 }
Paul Duffin35816122021-02-24 01:49:52 +0000444 }
Paul Duffin4ca67522021-03-20 01:25:12 +0000445 }
446
Paul Duffin35816122021-02-24 01:49:52 +0000447 return list
448}
449
450// compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
451type compositeFixturePreparer struct {
Paul Duffinff2aa692021-03-19 18:20:59 +0000452 baseFixturePreparer
Paul Duffin4ca67522021-03-20 01:25:12 +0000453 // The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this
454 // composite preparer.
Paul Duffin35816122021-02-24 01:49:52 +0000455 preparers []*simpleFixturePreparer
456}
457
Paul Duffin4ca67522021-03-20 01:25:12 +0000458func (c *compositeFixturePreparer) list() []*simpleFixturePreparer {
459 return c.preparers
Paul Duffin35816122021-02-24 01:49:52 +0000460}
461
Paul Duffinff2aa692021-03-19 18:20:59 +0000462func newFixturePreparer(preparers []*simpleFixturePreparer) FixturePreparer {
463 if len(preparers) == 1 {
464 return preparers[0]
465 }
466 p := &compositeFixturePreparer{
467 preparers: preparers,
468 }
469 p.initBaseFixturePreparer(p)
470 return p
471}
472
Paul Duffin35816122021-02-24 01:49:52 +0000473// simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
474type simpleFixturePreparer struct {
Paul Duffinff2aa692021-03-19 18:20:59 +0000475 baseFixturePreparer
Paul Duffin35816122021-02-24 01:49:52 +0000476 function func(fixture *fixture)
477}
478
Paul Duffin4ca67522021-03-20 01:25:12 +0000479func (s *simpleFixturePreparer) list() []*simpleFixturePreparer {
480 return []*simpleFixturePreparer{s}
Paul Duffin35816122021-02-24 01:49:52 +0000481}
482
483func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000484 p := &simpleFixturePreparer{function: preparer}
485 p.initBaseFixturePreparer(p)
486 return p
Paul Duffin35816122021-02-24 01:49:52 +0000487}
488
Paul Duffincfd33742021-02-27 11:59:02 +0000489// FixtureErrorHandler determines how to respond to errors reported by the code under test.
490//
491// Some possible responses:
492// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
493// * Fail the test if at least one error that matches a pattern is not reported see
494// FixtureExpectsAtLeastOneErrorMatchingPattern
495// * Fail the test if any unexpected errors are reported.
496//
497// Although at the moment all the error handlers are implemented as simply a wrapper around a
498// function this is defined as an interface to allow future enhancements, e.g. provide different
499// ways other than patterns to match an error and to combine handlers together.
500type FixtureErrorHandler interface {
501 // CheckErrors checks the errors reported.
502 //
503 // The supplied result can be used to access the state of the code under test just as the main
504 // body of the test would but if any errors other than ones expected are reported the state may
505 // be indeterminate.
Paul Duffinc81854a2021-03-12 12:22:27 +0000506 CheckErrors(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000507}
508
509type simpleErrorHandler struct {
Paul Duffinc81854a2021-03-12 12:22:27 +0000510 function func(t *testing.T, result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000511}
512
Paul Duffinc81854a2021-03-12 12:22:27 +0000513func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) {
514 t.Helper()
515 h.function(t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000516}
517
518// The default fixture error handler.
519//
520// Will fail the test immediately if any errors are reported.
Paul Duffinea8a3862021-03-04 17:58:33 +0000521//
522// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
523// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000524var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
Paul Duffinc81854a2021-03-12 12:22:27 +0000525 func(t *testing.T, result *TestResult) {
526 t.Helper()
527 FailIfErrored(t, result.Errs)
Paul Duffincfd33742021-02-27 11:59:02 +0000528 },
529)
530
Paul Duffin85034e92021-03-17 00:20:34 +0000531// FixtureIgnoreErrors ignores any errors.
532//
533// If this is used then it is the responsibility of the test to check the TestResult.Errs does not
534// contain any unexpected errors.
535var FixtureIgnoreErrors = FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
536 // Ignore the errors
537})
538
Paul Duffincfd33742021-02-27 11:59:02 +0000539// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
540// if at least one error that matches the regular expression is not found.
541//
542// The test will be failed if:
543// * No errors are reported.
544// * One or more errors are reported but none match the pattern.
545//
546// The test will not fail if:
547// * Multiple errors are reported that do not match the pattern as long as one does match.
Paul Duffinea8a3862021-03-04 17:58:33 +0000548//
549// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
550// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000551func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000552 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
553 t.Helper()
554 if !FailIfNoMatchingErrors(t, pattern, result.Errs) {
555 t.FailNow()
Paul Duffinea8a3862021-03-04 17:58:33 +0000556 }
Paul Duffincfd33742021-02-27 11:59:02 +0000557 })
558}
559
560// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
561// if there are any unexpected errors.
562//
563// The test will be failed if:
564// * The number of errors reported does not exactly match the patterns.
565// * One or more of the reported errors do not match a pattern.
566// * No patterns are provided and one or more errors are reported.
567//
568// The test will not fail if:
569// * One or more of the patterns does not match an error.
Paul Duffinea8a3862021-03-04 17:58:33 +0000570//
571// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
572// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000573func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
Paul Duffinc81854a2021-03-12 12:22:27 +0000574 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
575 t.Helper()
576 CheckErrorsAgainstExpectations(t, result.Errs, patterns)
Paul Duffincfd33742021-02-27 11:59:02 +0000577 })
578}
579
580// FixtureCustomErrorHandler creates a custom error handler
Paul Duffinc81854a2021-03-12 12:22:27 +0000581func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler {
Paul Duffincfd33742021-02-27 11:59:02 +0000582 return simpleErrorHandler{
583 function: function,
584 }
585}
586
Paul Duffin35816122021-02-24 01:49:52 +0000587// Fixture defines the test environment.
588type Fixture interface {
Paul Duffinae542a52021-03-09 03:15:28 +0000589 // Config returns the fixture's configuration.
590 Config() Config
591
592 // Context returns the fixture's test context.
593 Context() *TestContext
594
595 // MockFS returns the fixture's mock filesystem.
596 MockFS() MockFS
597
Paul Duffincfd33742021-02-27 11:59:02 +0000598 // Run the test, checking any errors reported and returning a TestResult instance.
Paul Duffin35816122021-02-24 01:49:52 +0000599 RunTest() *TestResult
600}
601
Paul Duffin35816122021-02-24 01:49:52 +0000602// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
603type testContext struct {
604 *TestContext
605}
606
607// The result of running a test.
608type TestResult struct {
Paul Duffin35816122021-02-24 01:49:52 +0000609 testContext
610
611 fixture *fixture
612 Config Config
Paul Duffin942481b2021-03-04 18:58:11 +0000613
614 // The errors that were reported during the test.
615 Errs []error
Paul Duffin78c36212021-03-16 23:57:12 +0000616
617 // The ninja deps is a list of the ninja files dependencies that were added by the modules and
618 // singletons via the *.AddNinjaFileDeps() methods.
619 NinjaDeps []string
Paul Duffin35816122021-02-24 01:49:52 +0000620}
621
Paul Duffin34a7fff2021-03-30 22:11:24 +0100622func createFixture(t *testing.T, buildDir string, preparers []*simpleFixturePreparer) Fixture {
Paul Duffindff5ff02021-03-15 15:42:40 +0000623 config := TestConfig(buildDir, nil, "", nil)
Paul Duffin35816122021-02-24 01:49:52 +0000624 ctx := NewTestContext(config)
625 fixture := &fixture{
Paul Duffin34a7fff2021-03-30 22:11:24 +0100626 preparers: preparers,
Paul Duffincff464f2021-03-19 18:13:46 +0000627 t: t,
628 config: config,
629 ctx: ctx,
630 mockFS: make(MockFS),
631 // Set the default error handler.
632 errorHandler: FixtureExpectsNoErrors,
Paul Duffin35816122021-02-24 01:49:52 +0000633 }
634
Paul Duffin34a7fff2021-03-30 22:11:24 +0100635 for _, preparer := range preparers {
Paul Duffin35816122021-02-24 01:49:52 +0000636 preparer.function(fixture)
637 }
638
639 return fixture
640}
641
Paul Duffinff2aa692021-03-19 18:20:59 +0000642type baseFixturePreparer struct {
643 self FixturePreparer
644}
645
646func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) {
647 b.self = self
648}
649
Paul Duffin34a7fff2021-03-30 22:11:24 +0100650func (b *baseFixturePreparer) Fixture(t *testing.T) Fixture {
651 return createFixture(t, t.TempDir(), b.self.list())
Paul Duffinff2aa692021-03-19 18:20:59 +0000652}
653
654func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer {
Paul Duffin79abe572021-03-29 02:16:14 +0100655 return GroupFixturePreparers(b.self, newSimpleFixturePreparer(func(fixture *fixture) {
Paul Duffincff464f2021-03-19 18:13:46 +0000656 fixture.errorHandler = errorHandler
657 }))
Paul Duffincfd33742021-02-27 11:59:02 +0000658}
659
Paul Duffin55e740e2021-03-29 02:06:19 +0100660func (b *baseFixturePreparer) RunTest(t *testing.T) *TestResult {
Paul Duffin35816122021-02-24 01:49:52 +0000661 t.Helper()
Paul Duffin55e740e2021-03-29 02:06:19 +0100662 fixture := b.self.Fixture(t)
Paul Duffin35816122021-02-24 01:49:52 +0000663 return fixture.RunTest()
664}
665
Paul Duffinff2aa692021-03-19 18:20:59 +0000666func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult {
Paul Duffin35816122021-02-24 01:49:52 +0000667 t.Helper()
Paul Duffin55e740e2021-03-29 02:06:19 +0100668 return GroupFixturePreparers(b.self, FixtureWithRootAndroidBp(bp)).RunTest(t)
Paul Duffin35816122021-02-24 01:49:52 +0000669}
670
Paul Duffinff2aa692021-03-19 18:20:59 +0000671func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult {
Paul Duffin72018ad2021-03-04 19:36:49 +0000672 t.Helper()
673 // Create the fixture as normal.
Paul Duffinff2aa692021-03-19 18:20:59 +0000674 fixture := b.self.Fixture(t).(*fixture)
Paul Duffin72018ad2021-03-04 19:36:49 +0000675
676 // Discard the mock filesystem as otherwise that will override the one in the config.
677 fixture.mockFS = nil
678
679 // Replace the config with the supplied one in the fixture.
680 fixture.config = config
681
682 // Ditto with config derived information in the TestContext.
683 ctx := fixture.ctx
684 ctx.config = config
685 ctx.SetFs(ctx.config.fs)
686 if ctx.config.mockBpList != "" {
687 ctx.SetModuleListFile(ctx.config.mockBpList)
688 }
689
690 return fixture.RunTest()
691}
692
Paul Duffin35816122021-02-24 01:49:52 +0000693type fixture struct {
Paul Duffin59251822021-03-15 22:20:12 +0000694 // The preparers used to create this fixture.
695 preparers []*simpleFixturePreparer
Paul Duffincfd33742021-02-27 11:59:02 +0000696
697 // The gotest state of the go test within which this was created.
698 t *testing.T
699
700 // The configuration prepared for this fixture.
701 config Config
702
703 // The test context prepared for this fixture.
704 ctx *TestContext
705
706 // The mock filesystem prepared for this fixture.
707 mockFS MockFS
708
709 // The error handler used to check the errors, if any, that are reported.
710 errorHandler FixtureErrorHandler
Paul Duffin35816122021-02-24 01:49:52 +0000711}
712
Paul Duffinae542a52021-03-09 03:15:28 +0000713func (f *fixture) Config() Config {
714 return f.config
715}
716
717func (f *fixture) Context() *TestContext {
718 return f.ctx
719}
720
721func (f *fixture) MockFS() MockFS {
722 return f.mockFS
723}
724
Paul Duffin35816122021-02-24 01:49:52 +0000725func (f *fixture) RunTest() *TestResult {
726 f.t.Helper()
727
728 ctx := f.ctx
729
Paul Duffin72018ad2021-03-04 19:36:49 +0000730 // Do not use the fixture's mockFS to initialize the config's mock file system if it has been
731 // cleared by RunTestWithConfig.
732 if f.mockFS != nil {
733 // The TestConfig() method assumes that the mock filesystem is available when creating so
734 // creates the mock file system immediately. Similarly, the NewTestContext(Config) method
735 // assumes that the supplied Config's FileSystem has been properly initialized before it is
736 // called and so it takes its own reference to the filesystem. However, fixtures create the
737 // Config and TestContext early so they can be modified by preparers at which time the mockFS
738 // has not been populated (because it too is modified by preparers). So, this reinitializes the
739 // Config and TestContext's FileSystem using the now populated mockFS.
740 f.config.mockFileSystem("", f.mockFS)
741
742 ctx.SetFs(ctx.config.fs)
743 if ctx.config.mockBpList != "" {
744 ctx.SetModuleListFile(ctx.config.mockBpList)
745 }
Paul Duffin35816122021-02-24 01:49:52 +0000746 }
747
748 ctx.Register()
Paul Duffin78c36212021-03-16 23:57:12 +0000749 var ninjaDeps []string
750 extraNinjaDeps, errs := ctx.ParseBlueprintsFiles("ignored")
Paul Duffincfd33742021-02-27 11:59:02 +0000751 if len(errs) == 0 {
Paul Duffin78c36212021-03-16 23:57:12 +0000752 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
753 extraNinjaDeps, errs = ctx.PrepareBuildActions(f.config)
754 if len(errs) == 0 {
755 ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
756 }
Paul Duffincfd33742021-02-27 11:59:02 +0000757 }
Paul Duffin35816122021-02-24 01:49:52 +0000758
759 result := &TestResult{
Paul Duffin35816122021-02-24 01:49:52 +0000760 testContext: testContext{ctx},
761 fixture: f,
762 Config: f.config,
Paul Duffin942481b2021-03-04 18:58:11 +0000763 Errs: errs,
Paul Duffin78c36212021-03-16 23:57:12 +0000764 NinjaDeps: ninjaDeps,
Paul Duffin35816122021-02-24 01:49:52 +0000765 }
Paul Duffincfd33742021-02-27 11:59:02 +0000766
Paul Duffinc81854a2021-03-12 12:22:27 +0000767 f.errorHandler.CheckErrors(f.t, result)
Paul Duffincfd33742021-02-27 11:59:02 +0000768
Paul Duffin35816122021-02-24 01:49:52 +0000769 return result
770}
771
772// NormalizePathForTesting removes the test invocation specific build directory from the supplied
773// path.
774//
775// If the path is within the build directory (e.g. an OutputPath) then this returns the relative
776// path to avoid tests having to deal with the dynamically generated build directory.
777//
778// Otherwise, this returns the supplied path as it is almost certainly a source path that is
779// relative to the root of the source tree.
780//
781// Even though some information is removed from some paths and not others it should be possible to
782// differentiate between them by the paths themselves, e.g. output paths will likely include
783// ".intermediates" but source paths won't.
784func (r *TestResult) NormalizePathForTesting(path Path) string {
785 pathContext := PathContextForTesting(r.Config)
786 pathAsString := path.String()
787 if rel, isRel := MaybeRel(pathContext, r.Config.BuildDir(), pathAsString); isRel {
788 return rel
789 }
790 return pathAsString
791}
792
793// NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized
794// forms.
795func (r *TestResult) NormalizePathsForTesting(paths Paths) []string {
796 var result []string
797 for _, path := range paths {
798 result = append(result, r.NormalizePathForTesting(path))
799 }
800 return result
801}
802
Paul Duffin59251822021-03-15 22:20:12 +0000803// Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture
804// that produced this result.
805//
806// e.g. assuming that this result was created by running:
Paul Duffin4814bb82021-03-29 01:55:10 +0100807// GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t)
Paul Duffin59251822021-03-15 22:20:12 +0000808//
809// Then this method will be equivalent to running:
Paul Duffin4814bb82021-03-29 01:55:10 +0100810// GroupFixturePreparers(preparer1, preparer2, preparer3)
Paul Duffin59251822021-03-15 22:20:12 +0000811//
812// This is intended for use by tests whose output is Android.bp files to verify that those files
813// are valid, e.g. tests of the snapshots produced by the sdk module type.
814func (r *TestResult) Preparer() FixturePreparer {
Paul Duffinff2aa692021-03-19 18:20:59 +0000815 return newFixturePreparer(r.fixture.preparers)
Paul Duffin59251822021-03-15 22:20:12 +0000816}
817
Paul Duffin35816122021-02-24 01:49:52 +0000818// Module returns the module with the specific name and of the specified variant.
819func (r *TestResult) Module(name string, variant string) Module {
820 return r.ModuleForTests(name, variant).Module()
821}