blob: 2085e43ed20f78f38b8f8fd609a0a7c8e4174b2d [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 (
18 "reflect"
19 "strings"
20 "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 Duffin52323b52021-03-04 19:15:47 +0000185 // SetErrorHandler creates a new FixtureFactory that will use the supplied error handler to check
186 // 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.
190 SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory
191
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
201}
202
203// Create a new FixtureFactory that will apply the supplied preparers.
204//
205// The buildDirSupplier is a pointer to the package level buildDir variable that is initialized by
206// the package level setUp method. It has to be a pointer to the variable as the variable will not
207// have been initialized at the time the factory is created.
208func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory {
209 return &fixtureFactory{
210 buildDirSupplier: buildDirSupplier,
211 preparers: dedupAndFlattenPreparers(nil, preparers),
Paul Duffincfd33742021-02-27 11:59:02 +0000212
213 // Set the default error handler.
214 errorHandler: FixtureExpectsNoErrors,
Paul Duffin35816122021-02-24 01:49:52 +0000215 }
216}
217
218// A set of mock files to add to the mock file system.
219type MockFS map[string][]byte
220
221func (fs MockFS) Merge(extra map[string][]byte) {
222 for p, c := range extra {
223 fs[p] = c
224 }
225}
226
227func (fs MockFS) AddToFixture() FixturePreparer {
228 return FixtureMergeMockFs(fs)
229}
230
231// Modify the config
232func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
233 return newSimpleFixturePreparer(func(f *fixture) {
234 mutator(f.config)
235 })
236}
237
238// Modify the config and context
239func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer {
240 return newSimpleFixturePreparer(func(f *fixture) {
241 mutator(f.config, f.ctx)
242 })
243}
244
245// Modify the context
246func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer {
247 return newSimpleFixturePreparer(func(f *fixture) {
248 mutator(f.ctx)
249 })
250}
251
252func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
253 return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
254}
255
256// Modify the mock filesystem
257func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
258 return newSimpleFixturePreparer(func(f *fixture) {
259 mutator(f.mockFS)
260 })
261}
262
263// Merge the supplied file system into the mock filesystem.
264//
265// Paths that already exist in the mock file system are overridden.
266func FixtureMergeMockFs(mockFS MockFS) FixturePreparer {
267 return FixtureModifyMockFS(func(fs MockFS) {
268 fs.Merge(mockFS)
269 })
270}
271
272// Add a file to the mock filesystem
273func FixtureAddFile(path string, contents []byte) FixturePreparer {
274 return FixtureModifyMockFS(func(fs MockFS) {
275 fs[path] = contents
276 })
277}
278
279// Add a text file to the mock filesystem
280func FixtureAddTextFile(path string, contents string) FixturePreparer {
281 return FixtureAddFile(path, []byte(contents))
282}
283
284// Add the root Android.bp file with the supplied contents.
285func FixtureWithRootAndroidBp(contents string) FixturePreparer {
286 return FixtureAddTextFile("Android.bp", contents)
287}
288
Paul Duffina560d5a2021-02-28 01:38:51 +0000289// GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of
290// the supplied FixturePreparer instances in order.
291//
292// Before preparing the fixture the list of preparers is flattened by replacing each
293// instance of GroupFixturePreparers with its contents.
294func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
Paul Duffin35816122021-02-24 01:49:52 +0000295 return &compositeFixturePreparer{dedupAndFlattenPreparers(nil, preparers)}
296}
297
298type simpleFixturePreparerVisitor func(preparer *simpleFixturePreparer)
299
300// FixturePreparer is an opaque interface that can change a fixture.
301type FixturePreparer interface {
302 // visit calls the supplied visitor with each *simpleFixturePreparer instances in this preparer,
303 visit(simpleFixturePreparerVisitor)
304}
305
306type fixturePreparers []FixturePreparer
307
308func (f fixturePreparers) visit(visitor simpleFixturePreparerVisitor) {
309 for _, p := range f {
310 p.visit(visitor)
311 }
312}
313
314// dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
315// instances.
316//
317// base - a list of already flattened and deduped preparers that will be applied first before
318// the list of additional preparers. Any duplicates of these in the additional preparers
319// will be ignored.
320//
321// preparers - a list of additional unflattened, undeduped preparers that will be applied after the
322// base preparers.
323//
324// Returns a deduped and flattened list of the preparers minus any that exist in the base preparers.
325func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers fixturePreparers) []*simpleFixturePreparer {
326 var list []*simpleFixturePreparer
327 visited := make(map[*simpleFixturePreparer]struct{})
328
329 // Mark the already flattened and deduped preparers, if any, as having been seen so that
330 // duplicates of these in the additional preparers will be discarded.
331 for _, s := range base {
332 visited[s] = struct{}{}
333 }
334
335 preparers.visit(func(preparer *simpleFixturePreparer) {
336 if _, seen := visited[preparer]; !seen {
337 visited[preparer] = struct{}{}
338 list = append(list, preparer)
339 }
340 })
341 return list
342}
343
344// compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
345type compositeFixturePreparer struct {
346 preparers []*simpleFixturePreparer
347}
348
349func (c *compositeFixturePreparer) visit(visitor simpleFixturePreparerVisitor) {
350 for _, p := range c.preparers {
351 p.visit(visitor)
352 }
353}
354
355// simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
356type simpleFixturePreparer struct {
357 function func(fixture *fixture)
358}
359
360func (s *simpleFixturePreparer) visit(visitor simpleFixturePreparerVisitor) {
361 visitor(s)
362}
363
364func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
365 return &simpleFixturePreparer{function: preparer}
366}
367
Paul Duffincfd33742021-02-27 11:59:02 +0000368// FixtureErrorHandler determines how to respond to errors reported by the code under test.
369//
370// Some possible responses:
371// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
372// * Fail the test if at least one error that matches a pattern is not reported see
373// FixtureExpectsAtLeastOneErrorMatchingPattern
374// * Fail the test if any unexpected errors are reported.
375//
376// Although at the moment all the error handlers are implemented as simply a wrapper around a
377// function this is defined as an interface to allow future enhancements, e.g. provide different
378// ways other than patterns to match an error and to combine handlers together.
379type FixtureErrorHandler interface {
380 // CheckErrors checks the errors reported.
381 //
382 // The supplied result can be used to access the state of the code under test just as the main
383 // body of the test would but if any errors other than ones expected are reported the state may
384 // be indeterminate.
Paul Duffin942481b2021-03-04 18:58:11 +0000385 CheckErrors(result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000386}
387
388type simpleErrorHandler struct {
Paul Duffin942481b2021-03-04 18:58:11 +0000389 function func(result *TestResult)
Paul Duffincfd33742021-02-27 11:59:02 +0000390}
391
Paul Duffin942481b2021-03-04 18:58:11 +0000392func (h simpleErrorHandler) CheckErrors(result *TestResult) {
393 result.Helper()
394 h.function(result)
Paul Duffincfd33742021-02-27 11:59:02 +0000395}
396
397// The default fixture error handler.
398//
399// Will fail the test immediately if any errors are reported.
Paul Duffinea8a3862021-03-04 17:58:33 +0000400//
401// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
402// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000403var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
Paul Duffin942481b2021-03-04 18:58:11 +0000404 func(result *TestResult) {
405 result.Helper()
406 FailIfErrored(result.T, result.Errs)
Paul Duffincfd33742021-02-27 11:59:02 +0000407 },
408)
409
410// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
411// if at least one error that matches the regular expression is not found.
412//
413// The test will be failed if:
414// * No errors are reported.
415// * One or more errors are reported but none match the pattern.
416//
417// The test will not fail if:
418// * Multiple errors are reported that do not match the pattern as long as one does match.
Paul Duffinea8a3862021-03-04 17:58:33 +0000419//
420// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
421// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000422func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
Paul Duffin942481b2021-03-04 18:58:11 +0000423 return FixtureCustomErrorHandler(func(result *TestResult) {
424 result.Helper()
425 if !FailIfNoMatchingErrors(result.T, pattern, result.Errs) {
Paul Duffinea8a3862021-03-04 17:58:33 +0000426 result.FailNow()
427 }
Paul Duffincfd33742021-02-27 11:59:02 +0000428 })
429}
430
431// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
432// if there are any unexpected errors.
433//
434// The test will be failed if:
435// * The number of errors reported does not exactly match the patterns.
436// * One or more of the reported errors do not match a pattern.
437// * No patterns are provided and one or more errors are reported.
438//
439// The test will not fail if:
440// * One or more of the patterns does not match an error.
Paul Duffinea8a3862021-03-04 17:58:33 +0000441//
442// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
443// which the test is being run which means that the RunTest() method will not return.
Paul Duffincfd33742021-02-27 11:59:02 +0000444func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
Paul Duffin942481b2021-03-04 18:58:11 +0000445 return FixtureCustomErrorHandler(func(result *TestResult) {
446 result.Helper()
447 CheckErrorsAgainstExpectations(result.T, result.Errs, patterns)
Paul Duffincfd33742021-02-27 11:59:02 +0000448 })
449}
450
451// FixtureCustomErrorHandler creates a custom error handler
Paul Duffin942481b2021-03-04 18:58:11 +0000452func FixtureCustomErrorHandler(function func(result *TestResult)) FixtureErrorHandler {
Paul Duffincfd33742021-02-27 11:59:02 +0000453 return simpleErrorHandler{
454 function: function,
455 }
456}
457
Paul Duffin35816122021-02-24 01:49:52 +0000458// Fixture defines the test environment.
459type Fixture interface {
Paul Duffincfd33742021-02-27 11:59:02 +0000460 // Run the test, checking any errors reported and returning a TestResult instance.
Paul Duffin35816122021-02-24 01:49:52 +0000461 RunTest() *TestResult
462}
463
464// Provides general test support.
465type TestHelper struct {
466 *testing.T
467}
468
469// AssertBoolEquals checks if the expected and actual values are equal and if they are not then it
470// reports an error prefixed with the supplied message and including a reason for why it failed.
471func (h *TestHelper) AssertBoolEquals(message string, expected bool, actual bool) {
472 h.Helper()
473 if actual != expected {
474 h.Errorf("%s: expected %t, actual %t", message, expected, actual)
475 }
476}
477
478// AssertStringEquals checks if the expected and actual values are equal and if they are not then
479// it reports an error prefixed with the supplied message and including a reason for why it failed.
480func (h *TestHelper) AssertStringEquals(message string, expected string, actual string) {
481 h.Helper()
482 if actual != expected {
483 h.Errorf("%s: expected %s, actual %s", message, expected, actual)
484 }
485}
486
487// AssertTrimmedStringEquals checks if the expected and actual values are the same after trimming
488// leading and trailing spaces from them both. If they are not then it reports an error prefixed
489// with the supplied message and including a reason for why it failed.
490func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) {
491 h.Helper()
492 h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
493}
494
495// AssertStringDoesContain checks if the string contains the expected substring. If it does not
496// then it reports an error prefixed with the supplied message and including a reason for why it
497// failed.
498func (h *TestHelper) AssertStringDoesContain(message string, s string, expectedSubstring string) {
499 h.Helper()
500 if !strings.Contains(s, expectedSubstring) {
501 h.Errorf("%s: could not find %q within %q", message, expectedSubstring, s)
502 }
503}
504
505// AssertStringDoesNotContain checks if the string contains the expected substring. If it does then
506// it reports an error prefixed with the supplied message and including a reason for why it failed.
507func (h *TestHelper) AssertStringDoesNotContain(message string, s string, unexpectedSubstring string) {
508 h.Helper()
509 if strings.Contains(s, unexpectedSubstring) {
510 h.Errorf("%s: unexpectedly found %q within %q", message, unexpectedSubstring, s)
511 }
512}
513
514// AssertArrayString checks if the expected and actual values are equal and if they are not then it
515// reports an error prefixed with the supplied message and including a reason for why it failed.
516func (h *TestHelper) AssertArrayString(message string, expected, actual []string) {
517 h.Helper()
518 if len(actual) != len(expected) {
519 h.Errorf("%s: expected %d (%q), actual (%d) %q", message, len(expected), expected, len(actual), actual)
520 return
521 }
522 for i := range actual {
523 if actual[i] != expected[i] {
524 h.Errorf("%s: expected %d-th, %q (%q), actual %q (%q)",
525 message, i, expected[i], expected, actual[i], actual)
526 return
527 }
528 }
529}
530
531// AssertArrayString checks if the expected and actual values are equal using reflect.DeepEqual and
532// if they are not then it reports an error prefixed with the supplied message and including a
533// reason for why it failed.
534func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
535 h.Helper()
536 if !reflect.DeepEqual(actual, expected) {
537 h.Errorf("%s: expected:\n %#v\n got:\n %#v", message, expected, actual)
538 }
539}
540
541// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
542type testContext struct {
543 *TestContext
544}
545
546// The result of running a test.
547type TestResult struct {
548 TestHelper
549 testContext
550
551 fixture *fixture
552 Config Config
Paul Duffin942481b2021-03-04 18:58:11 +0000553
554 // The errors that were reported during the test.
555 Errs []error
Paul Duffin35816122021-02-24 01:49:52 +0000556}
557
558var _ FixtureFactory = (*fixtureFactory)(nil)
559
560type fixtureFactory struct {
561 buildDirSupplier *string
562 preparers []*simpleFixturePreparer
Paul Duffincfd33742021-02-27 11:59:02 +0000563 errorHandler FixtureErrorHandler
Paul Duffin35816122021-02-24 01:49:52 +0000564}
565
566func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory {
Paul Duffinfa298852021-03-08 15:05:24 +0000567 // Create a new slice to avoid accidentally sharing the preparers slice from this factory with
568 // the extending factories.
569 var all []*simpleFixturePreparer
570 all = append(all, f.preparers...)
571 all = append(all, dedupAndFlattenPreparers(f.preparers, preparers)...)
Paul Duffincfd33742021-02-27 11:59:02 +0000572 // Copy the existing factory.
573 extendedFactory := &fixtureFactory{}
574 *extendedFactory = *f
575 // Use the extended list of preparers.
576 extendedFactory.preparers = all
577 return extendedFactory
Paul Duffin35816122021-02-24 01:49:52 +0000578}
579
580func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
581 config := TestConfig(*f.buildDirSupplier, nil, "", nil)
582 ctx := NewTestContext(config)
583 fixture := &fixture{
Paul Duffincfd33742021-02-27 11:59:02 +0000584 factory: f,
585 t: t,
586 config: config,
587 ctx: ctx,
588 mockFS: make(MockFS),
589 errorHandler: f.errorHandler,
Paul Duffin35816122021-02-24 01:49:52 +0000590 }
591
592 for _, preparer := range f.preparers {
593 preparer.function(fixture)
594 }
595
596 for _, preparer := range dedupAndFlattenPreparers(f.preparers, preparers) {
597 preparer.function(fixture)
598 }
599
600 return fixture
601}
602
Paul Duffincfd33742021-02-27 11:59:02 +0000603func (f *fixtureFactory) SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory {
Paul Duffin52323b52021-03-04 19:15:47 +0000604 newFactory := &fixtureFactory{}
605 *newFactory = *f
606 newFactory.errorHandler = errorHandler
607 return newFactory
Paul Duffincfd33742021-02-27 11:59:02 +0000608}
609
Paul Duffin35816122021-02-24 01:49:52 +0000610func (f *fixtureFactory) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult {
611 t.Helper()
612 fixture := f.Fixture(t, preparers...)
613 return fixture.RunTest()
614}
615
616func (f *fixtureFactory) RunTestWithBp(t *testing.T, bp string) *TestResult {
617 t.Helper()
618 return f.RunTest(t, FixtureWithRootAndroidBp(bp))
619}
620
621type fixture struct {
Paul Duffincfd33742021-02-27 11:59:02 +0000622 // The factory used to create this fixture.
Paul Duffin35816122021-02-24 01:49:52 +0000623 factory *fixtureFactory
Paul Duffincfd33742021-02-27 11:59:02 +0000624
625 // The gotest state of the go test within which this was created.
626 t *testing.T
627
628 // The configuration prepared for this fixture.
629 config Config
630
631 // The test context prepared for this fixture.
632 ctx *TestContext
633
634 // The mock filesystem prepared for this fixture.
635 mockFS MockFS
636
637 // The error handler used to check the errors, if any, that are reported.
638 errorHandler FixtureErrorHandler
Paul Duffin35816122021-02-24 01:49:52 +0000639}
640
641func (f *fixture) RunTest() *TestResult {
642 f.t.Helper()
643
644 ctx := f.ctx
645
646 // The TestConfig() method assumes that the mock filesystem is available when creating so creates
647 // the mock file system immediately. Similarly, the NewTestContext(Config) method assumes that the
648 // supplied Config's FileSystem has been properly initialized before it is called and so it takes
649 // its own reference to the filesystem. However, fixtures create the Config and TestContext early
650 // so they can be modified by preparers at which time the mockFS has not been populated (because
651 // it too is modified by preparers). So, this reinitializes the Config and TestContext's
652 // FileSystem using the now populated mockFS.
653 f.config.mockFileSystem("", f.mockFS)
654 ctx.SetFs(ctx.config.fs)
655 if ctx.config.mockBpList != "" {
656 ctx.SetModuleListFile(ctx.config.mockBpList)
657 }
658
659 ctx.Register()
660 _, errs := ctx.ParseBlueprintsFiles("ignored")
Paul Duffincfd33742021-02-27 11:59:02 +0000661 if len(errs) == 0 {
662 _, errs = ctx.PrepareBuildActions(f.config)
663 }
Paul Duffin35816122021-02-24 01:49:52 +0000664
665 result := &TestResult{
666 TestHelper: TestHelper{T: f.t},
667 testContext: testContext{ctx},
668 fixture: f,
669 Config: f.config,
Paul Duffin942481b2021-03-04 18:58:11 +0000670 Errs: errs,
Paul Duffin35816122021-02-24 01:49:52 +0000671 }
Paul Duffincfd33742021-02-27 11:59:02 +0000672
Paul Duffin942481b2021-03-04 18:58:11 +0000673 f.errorHandler.CheckErrors(result)
Paul Duffincfd33742021-02-27 11:59:02 +0000674
Paul Duffin35816122021-02-24 01:49:52 +0000675 return result
676}
677
678// NormalizePathForTesting removes the test invocation specific build directory from the supplied
679// path.
680//
681// If the path is within the build directory (e.g. an OutputPath) then this returns the relative
682// path to avoid tests having to deal with the dynamically generated build directory.
683//
684// Otherwise, this returns the supplied path as it is almost certainly a source path that is
685// relative to the root of the source tree.
686//
687// Even though some information is removed from some paths and not others it should be possible to
688// differentiate between them by the paths themselves, e.g. output paths will likely include
689// ".intermediates" but source paths won't.
690func (r *TestResult) NormalizePathForTesting(path Path) string {
691 pathContext := PathContextForTesting(r.Config)
692 pathAsString := path.String()
693 if rel, isRel := MaybeRel(pathContext, r.Config.BuildDir(), pathAsString); isRel {
694 return rel
695 }
696 return pathAsString
697}
698
699// NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized
700// forms.
701func (r *TestResult) NormalizePathsForTesting(paths Paths) []string {
702 var result []string
703 for _, path := range paths {
704 result = append(result, r.NormalizePathForTesting(path))
705 }
706 return result
707}
708
709// NewFixture creates a new test fixture that is based on the one that created this result. It is
710// intended to test the output of module types that generate content to be processed by the build,
711// e.g. sdk snapshots.
712func (r *TestResult) NewFixture(preparers ...FixturePreparer) Fixture {
713 return r.fixture.factory.Fixture(r.T, preparers...)
714}
715
716// RunTest is shorthand for NewFixture(preparers...).RunTest().
717func (r *TestResult) RunTest(preparers ...FixturePreparer) *TestResult {
718 r.Helper()
719 return r.fixture.factory.Fixture(r.T, preparers...).RunTest()
720}
721
722// Module returns the module with the specific name and of the specified variant.
723func (r *TestResult) Module(name string, variant string) Module {
724 return r.ModuleForTests(name, variant).Module()
725}
726
727// Create a *TestResult object suitable for use within a subtest.
728//
729// This ensures that any errors reported by the TestResult, e.g. from within one of its
730// Assert... methods, will be associated with the sub test and not the main test.
731//
732// result := ....RunTest()
733// t.Run("subtest", func(t *testing.T) {
734// subResult := result.ResultForSubTest(t)
735// subResult.AssertStringEquals("something", ....)
736// })
737func (r *TestResult) ResultForSubTest(t *testing.T) *TestResult {
738 subTestResult := *r
739 r.T = t
740 return &subTestResult
741}