From 0a75e524604d63da90d68f86b1d1a67e983d85b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Wed, 7 Oct 2020 14:30:03 +0200 Subject: [PATCH] rust: refactor tests setup Move to a builder pattern to increase flexibility when generating the test configuration. The testRust, testRustCov and testRustError are kept as main entry points for standard tests. Add documentation. Test: m nothing Change-Id: I891bec982ff2d65413f150d2395edf0fb0d68a43 --- rust/project_json_test.go | 41 ++++--------- rust/rust_test.go | 120 +++++++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 69 deletions(-) diff --git a/rust/project_json_test.go b/rust/project_json_test.go index 11964f345..69288fcfa 100644 --- a/rust/project_json_test.go +++ b/rust/project_json_test.go @@ -22,22 +22,15 @@ import ( "testing" "android/soong/android" - "android/soong/cc" ) // testProjectJson run the generation of rust-project.json. It returns the raw // content of the generated file. -func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte { - cc.GatherRequiredFilesForTest(fs) - - env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} - config := android.TestArchConfig(buildDir, env, bp, fs) - ctx := CreateTestContext() - ctx.Register(config) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) +func testProjectJson(t *testing.T, bp string) []byte { + tctx := newTestRustCtx(t, bp) + tctx.env = map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} + tctx.generateConfig() + tctx.parse(t) // The JSON file is generated via WriteFileToOutputDir. Therefore, it // won't appear in the Output of the TestingSingleton. Manually verify @@ -87,12 +80,8 @@ func TestProjectJsonDep(t *testing.T) { crate_name: "b", rlibs: ["liba"], } - ` + GatherRequiredDepsForTest() - fs := map[string][]byte{ - "a/src/lib.rs": nil, - "b/src/lib.rs": nil, - } - jsonContent := testProjectJson(t, bp, fs) + ` + jsonContent := testProjectJson(t, bp) validateJsonCrates(t, jsonContent) } @@ -123,11 +112,8 @@ func TestProjectJsonBindGen(t *testing.T) { source_stem: "bindings2", wrapper_src: "src/any.h", } - ` + GatherRequiredDepsForTest() - fs := map[string][]byte{ - "src/lib.rs": nil, - } - jsonContent := testProjectJson(t, bp, fs) + ` + jsonContent := testProjectJson(t, bp) crates := validateJsonCrates(t, jsonContent) for _, c := range crates { crate, ok := c.(map[string]interface{}) @@ -166,13 +152,8 @@ func TestProjectJsonMultiVersion(t *testing.T) { crate_name: "b", rustlibs: ["liba1", "liba2"], } - ` + GatherRequiredDepsForTest() - fs := map[string][]byte{ - "a1/src/lib.rs": nil, - "a2/src/lib.rs": nil, - "b/src/lib.rs": nil, - } - jsonContent := testProjectJson(t, bp, fs) + ` + jsonContent := testProjectJson(t, bp) crates := validateJsonCrates(t, jsonContent) for _, crate := range crates { c := crate.(map[string]interface{}) diff --git a/rust/rust_test.go b/rust/rust_test.go index 26e943a42..ec78860b7 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -54,10 +54,58 @@ func TestMain(m *testing.M) { os.Exit(run()) } -func testConfig(bp string) android.Config { - bp = bp + GatherRequiredDepsForTest() +// testRust returns a TestContext in which a basic environment has been setup. +// This environment contains a few mocked files. See testRustCtx.useMockedFs +// for the list of these files. +func testRust(t *testing.T, bp string) *android.TestContext { + tctx := newTestRustCtx(t, bp) + tctx.useMockedFs() + tctx.generateConfig() + return tctx.parse(t) +} - fs := map[string][]byte{ +// testRustCov returns a TestContext in which a basic environment has been +// setup. This environment explicitly enables coverage. +func testRustCov(t *testing.T, bp string) *android.TestContext { + tctx := newTestRustCtx(t, bp) + tctx.useMockedFs() + tctx.generateConfig() + tctx.enableCoverage(t) + return tctx.parse(t) +} + +// testRustError ensures that at least one error was raised and its value +// matches the pattern provided. The error can be either in the parsing of the +// Blueprint or when generating the build actions. +func testRustError(t *testing.T, pattern string, bp string) { + tctx := newTestRustCtx(t, bp) + tctx.useMockedFs() + tctx.generateConfig() + tctx.parseError(t, pattern) +} + +// testRustCtx is used to build a particular test environment. Unless your +// tests requires a specific setup, prefer the wrapping functions: testRust, +// testRustCov or testRustError. +type testRustCtx struct { + bp string + fs map[string][]byte + env map[string]string + config *android.Config +} + +// newTestRustCtx returns a new testRustCtx for the Blueprint definition argument. +func newTestRustCtx(t *testing.T, bp string) *testRustCtx { + // TODO (b/140435149) + if runtime.GOOS != "linux" { + t.Skip("Rust Soong tests can only be run on Linux hosts currently") + } + return &testRustCtx{bp: bp} +} + +// useMockedFs setup a default mocked filesystem for the test environment. +func (tctx *testRustCtx) useMockedFs() { + tctx.fs = map[string][]byte{ "foo.rs": nil, "foo.c": nil, "src/bar.rs": nil, @@ -66,57 +114,51 @@ func testConfig(bp string) android.Config { "liby.so": nil, "libz.so": nil, } - - cc.GatherRequiredFilesForTest(fs) - - return android.TestArchConfig(buildDir, nil, bp, fs) } -func testRust(t *testing.T, bp string) *android.TestContext { - return testRustContext(t, bp, false) +// generateConfig creates the android.Config based on the bp, fs and env +// attributes of the testRustCtx. +func (tctx *testRustCtx) generateConfig() { + tctx.bp = tctx.bp + GatherRequiredDepsForTest() + cc.GatherRequiredFilesForTest(tctx.fs) + config := android.TestArchConfig(buildDir, tctx.env, tctx.bp, tctx.fs) + tctx.config = &config } -func testRustCov(t *testing.T, bp string) *android.TestContext { - return testRustContext(t, bp, true) -} - -func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContext { - // TODO (b/140435149) - if runtime.GOOS != "linux" { - t.Skip("Only the Linux toolchain is supported for Rust") +// enableCoverage configures the test to enable coverage. +func (tctx *testRustCtx) enableCoverage(t *testing.T) { + if tctx.config == nil { + t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") } + tctx.config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true) + tctx.config.TestProductVariables.Native_coverage = proptools.BoolPtr(true) + tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"} +} - t.Helper() - config := testConfig(bp) - - if coverage { - config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true) - config.TestProductVariables.Native_coverage = proptools.BoolPtr(true) - config.TestProductVariables.NativeCoveragePaths = []string{"*"} +// parse validates the configuration and parses the Blueprint file. It returns +// a TestContext which can be used to retrieve the generated modules via +// ModuleForTests. +func (tctx testRustCtx) parse(t *testing.T) *android.TestContext { + if tctx.config == nil { + t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") } - ctx := CreateTestContext() - ctx.Register(config) - + ctx.Register(*tctx.config) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) + _, errs = ctx.PrepareBuildActions(*tctx.config) android.FailIfErrored(t, errs) - return ctx } -func testRustError(t *testing.T, pattern string, bp string) { - // TODO (b/140435149) - if runtime.GOOS != "linux" { - t.Skip("Only the Linux toolchain is supported for Rust") +// parseError parses the Blueprint file and ensure that at least one error +// matching the provided pattern is observed. +func (tctx testRustCtx) parseError(t *testing.T, pattern string) { + if tctx.config == nil { + t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") } - - t.Helper() - config := testConfig(bp) - ctx := CreateTestContext() - ctx.Register(config) + ctx.Register(*tctx.config) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) if len(errs) > 0 { @@ -124,7 +166,7 @@ func testRustError(t *testing.T, pattern string, bp string) { return } - _, errs = ctx.PrepareBuildActions(config) + _, errs = ctx.PrepareBuildActions(*tctx.config) if len(errs) > 0 { android.FailIfNoMatchingErrors(t, pattern, errs) return