Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ea01e3c authored by mrziwang's avatar mrziwang
Browse files

Use OutputFilesProvider in module_test

In the context of incremental soong, the output files
inter-module-communication will be through OutputFilesProvider.
The OutputFileProducer interface will be deprecated.

Test: CI
Bug: 339477385
Change-Id: Iaf0b039b17d34e1a696f2c87df2f0db39307fc6d
parent 50fe598e
Loading
Loading
Loading
Loading
+8 −13
Original line number Diff line number Diff line
@@ -2491,18 +2491,9 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string)
	if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet {
		return outputFilesFromProvider, err
	}
	// TODO: add error when outputFilesFromProvider and err are both nil after
	// OutputFileProducer and SourceFileProducer are deprecated.
	if outputFileProducer, ok := module.(OutputFileProducer); ok {
		paths, err := outputFileProducer.OutputFiles(tag)
		if err != nil {
			return nil, fmt.Errorf("failed to get output file from module %q at tag %q: %s",
				pathContextName(ctx, module), tag, err.Error())
		}
		return paths, nil
	} else if sourceFileProducer, ok := module.(SourceFileProducer); ok {
	if sourceFileProducer, ok := module.(SourceFileProducer); ok {
		if tag != "" {
			return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag)
			return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag)
		}
		paths := sourceFileProducer.Srcs()
		return paths, nil
@@ -2521,7 +2512,12 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module,
	var outputFiles OutputFilesInfo
	fromProperty := false

	if mctx, isMctx := ctx.(ModuleContext); isMctx {
	type OutputFilesProviderModuleContext interface {
		OtherModuleProviderContext
		Module() Module
	}

	if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx {
		if mctx.Module() != module {
			outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider)
		} else {
@@ -2535,7 +2531,6 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module,
	// TODO: Add a check for skipped context

	if outputFiles.isEmpty() {
		// TODO: Add a check for param module not having OutputFilesProvider set
		return nil, OutputFilesProviderNotSet
	}

+97 −39
Original line number Diff line number Diff line
@@ -935,31 +935,54 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
	}
}

type fakeBlueprintModule struct{}
type sourceProducerTestModule struct {
	ModuleBase
	props struct {
		// A represents the source file
		A string
	}
}

func (fakeBlueprintModule) Name() string { return "foo" }
func sourceProducerTestModuleFactory() Module {
	module := &sourceProducerTestModule{}
	module.AddProperties(&module.props)
	InitAndroidModule(module)
	return module
}

func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {}
func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {}

type sourceProducerTestModule struct {
	fakeBlueprintModule
	source Path
}
func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) }

func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} }
type outputFilesTestModule struct {
	ModuleBase
	props struct {
		// A represents the tag
		A string
		// B represents the output file for tag A
		B string
	}
}

type outputFileProducerTestModule struct {
	fakeBlueprintModule
	output map[string]Path
	error  map[string]error
func outputFilesTestModuleFactory() Module {
	module := &outputFilesTestModule{}
	module.AddProperties(&module.props)
	InitAndroidModule(module)
	return module
}

func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) {
	return PathsIfNonNil(o.output[tag]), o.error[tag]
func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
	if o.props.A != "" || o.props.B != "" {
		ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A)
	}
	// This is to simulate the case that some module uses an object to set its
	// OutputFilesProvider, but the object itself is empty.
	ctx.SetOutputFiles(Paths{}, "missing")
}

type pathContextAddMissingDependenciesWrapper struct {
	PathContext
	OtherModuleProviderContext
	missingDeps []string
}

@@ -970,52 +993,87 @@ func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module bluepr
	return module.Name()
}

func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil }

func TestOutputFileForModule(t *testing.T) {
	testcases := []struct {
		name        string
		module      blueprint.Module
		bp          string
		tag         string
		env         map[string]string
		config      func(*config)
		expected    string
		missingDeps []string
		env         map[string]string
		config      func(*config)
	}{
		{
			name: "SourceFileProducer",
			module:   &sourceProducerTestModule{source: PathForTesting("foo.txt")},
			expected: "foo.txt",
			bp: `spt_module {
					name: "test_module",
					a: "spt.txt",
				}
			`,
			tag:      "",
			expected: "spt.txt",
		},
		{
			name:     "OutputFileProducer",
			module:   &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}},
			expected: "foo.txt",
			name: "OutputFileProviderEmptyStringTag",
			bp: `oft_module {
					name: "test_module",
					a: "",
					b: "empty.txt",
				}
		`,
			tag:      "",
			expected: "empty.txt",
		},
		{
			name:     "OutputFileProducer_tag",
			module:   &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}},
			name: "OutputFileProviderTag",
			bp: `oft_module {
					name: "test_module",
					a: "foo",
					b: "foo.txt",
				}
			`,
			tag:      "foo",
			expected: "foo.txt",
		},
		{
			name: "OutputFileProducer_AllowMissingDependencies",
			name: "OutputFileAllowMissingDependencies",
			bp: `oft_module {
				name: "test_module",
			}
		`,
			tag:         "missing",
			expected:    "missing_output_file/test_module",
			missingDeps: []string{"test_module"},
			config: func(config *config) {
				config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
			},
			module:      &outputFileProducerTestModule{},
			missingDeps: []string{"foo"},
			expected:    "missing_output_file/foo",
		},
	}

	for _, tt := range testcases {
		config := TestConfig(buildDir, tt.env, "", nil)
		t.Run(tt.name, func(t *testing.T) {
			result := GroupFixturePreparers(
				PrepareForTestWithDefaults,
				FixtureRegisterWithContext(func(ctx RegistrationContext) {
					ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory)
					ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory)
				}),
				FixtureWithRootAndroidBp(tt.bp),
			).RunTest(t)

			config := TestConfig(buildDir, tt.env, tt.bp, nil)
			if tt.config != nil {
				tt.config(config.config)
			}
			ctx := &pathContextAddMissingDependenciesWrapper{
				PathContext:                PathContextForTesting(config),
				OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
			}
		got := OutputFileForModule(ctx, tt.module, tt.tag)
		AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got)
			got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag)
			AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got)
			AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
		})
	}
}