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

Commit 3cb603eb authored by Paul Duffin's avatar Paul Duffin
Browse files

Add tests for exported generated headers

Improves the test coverage for exporting of generated headers. These
tests highlight the bug described in b/180712399.

Follow up changes will refactor and fix bugs in this code. Adding the
tests separately help ensure that those changes do not inadvertantly
change the behavior.

Test: m nothing
Bug: 180712399
Change-Id: I0225b0cf53259071edb99a94be5014ed0e019bde
parent 052398b1
Loading
Loading
Loading
Loading
+292 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import (
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"
	"testing"

@@ -3910,3 +3911,294 @@ func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
	checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
	checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
}

func TestIncludeDirsExporting(t *testing.T) {

	// Trim spaces from the beginning, end and immediately after any newline characters. Leaves
	// embedded newline characters alone.
	trimIndentingSpaces := func(s string) string {
		return strings.TrimSpace(regexp.MustCompile("(^|\n)\\s+").ReplaceAllString(s, "$1"))
	}

	checkPaths := func(t *testing.T, message string, expected string, paths android.Paths) {
		t.Helper()
		expected = trimIndentingSpaces(expected)
		actual := trimIndentingSpaces(strings.Join(android.FirstUniqueStrings(android.NormalizePathsForTesting(paths)), "\n"))
		if expected != actual {
			t.Errorf("%s: expected:\n%s\n actual:\n%s\n", message, expected, actual)
		}
	}

	type exportedChecker func(t *testing.T, name string, exported FlagExporterInfo)

	checkIncludeDirs := func(t *testing.T, ctx *android.TestContext, module android.Module, checkers ...exportedChecker) {
		t.Helper()
		exported := ctx.ModuleProvider(module, FlagExporterInfoProvider).(FlagExporterInfo)
		name := module.Name()

		for _, checker := range checkers {
			checker(t, name, exported)
		}
	}

	expectedIncludeDirs := func(expectedPaths string) exportedChecker {
		return func(t *testing.T, name string, exported FlagExporterInfo) {
			t.Helper()
			checkPaths(t, fmt.Sprintf("%s: include dirs", name), expectedPaths, exported.IncludeDirs)
		}
	}

	expectedSystemIncludeDirs := func(expectedPaths string) exportedChecker {
		return func(t *testing.T, name string, exported FlagExporterInfo) {
			t.Helper()
			checkPaths(t, fmt.Sprintf("%s: system include dirs", name), expectedPaths, exported.SystemIncludeDirs)
		}
	}

	expectedGeneratedHeaders := func(expectedPaths string) exportedChecker {
		return func(t *testing.T, name string, exported FlagExporterInfo) {
			t.Helper()
			checkPaths(t, fmt.Sprintf("%s: generated headers", name), expectedPaths, exported.GeneratedHeaders)
		}
	}

	expectedOrderOnlyDeps := func(expectedPaths string) exportedChecker {
		return func(t *testing.T, name string, exported FlagExporterInfo) {
			t.Helper()
			checkPaths(t, fmt.Sprintf("%s: order only deps", name), expectedPaths, exported.Deps)
		}
	}

	genRuleModules := `
		genrule {
			name: "genrule_foo",
			cmd: "generate-foo",
			out: [
				"generated_headers/foo/generated_header.h",
			],
			export_include_dirs: [
				"generated_headers",
			],
		}

		genrule {
			name: "genrule_bar",
			cmd: "generate-bar",
			out: [
				"generated_headers/bar/generated_header.h",
			],
			export_include_dirs: [
				"generated_headers",
			],
		}
	`

	t.Run("ensure exported include dirs are not automatically re-exported from shared_libs", func(t *testing.T) {
		ctx := testCc(t, genRuleModules+`
		cc_library {
			name: "libfoo",
			srcs: ["foo.c"],
			export_include_dirs: ["foo/standard"],
			export_system_include_dirs: ["foo/system"],
			generated_headers: ["genrule_foo"],
			export_generated_headers: ["genrule_foo"],
		}

		cc_library {
			name: "libbar",
			srcs: ["bar.c"],
			shared_libs: ["libfoo"],
			export_include_dirs: ["bar/standard"],
			export_system_include_dirs: ["bar/system"],
			generated_headers: ["genrule_bar"],
			export_generated_headers: ["genrule_bar"],
		}
		`)
		foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, foo,
			expectedIncludeDirs(`
				foo/standard
				.intermediates/genrule_foo/gen/generated_headers
			`),
			expectedSystemIncludeDirs(`foo/system`),
			expectedGeneratedHeaders(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`),
			expectedOrderOnlyDeps(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`),
		)

		bar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, bar,
			expectedIncludeDirs(`
				bar/standard
				.intermediates/genrule_bar/gen/generated_headers
			`),
			expectedSystemIncludeDirs(`bar/system`),
			expectedGeneratedHeaders(`.intermediates/genrule_bar/gen/generated_headers/bar/generated_header.h`),
			expectedOrderOnlyDeps(`.intermediates/genrule_bar/gen/generated_headers/bar/generated_header.h`),
		)
	})

	t.Run("ensure exported include dirs are automatically re-exported from whole_static_libs", func(t *testing.T) {
		ctx := testCc(t, genRuleModules+`
		cc_library {
			name: "libfoo",
			srcs: ["foo.c"],
			export_include_dirs: ["foo/standard"],
			export_system_include_dirs: ["foo/system"],
			generated_headers: ["genrule_foo"],
			export_generated_headers: ["genrule_foo"],
		}

		cc_library {
			name: "libbar",
			srcs: ["bar.c"],
			whole_static_libs: ["libfoo"],
			export_include_dirs: ["bar/standard"],
			export_system_include_dirs: ["bar/system"],
			generated_headers: ["genrule_bar"],
			export_generated_headers: ["genrule_bar"],
		}
		`)
		foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, foo,
			expectedIncludeDirs(`
				foo/standard
				.intermediates/genrule_foo/gen/generated_headers
			`),
			expectedSystemIncludeDirs(`foo/system`),
			expectedGeneratedHeaders(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`),
			expectedOrderOnlyDeps(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`),
		)

		bar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, bar,
			expectedIncludeDirs(`
				bar/standard
				foo/standard
				.intermediates/genrule_foo/gen/generated_headers
				.intermediates/genrule_bar/gen/generated_headers
			`),
			expectedSystemIncludeDirs(`
				bar/system
				foo/system
			`),
			expectedGeneratedHeaders(`
				.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h
				.intermediates/genrule_bar/gen/generated_headers/bar/generated_header.h
			`),
			expectedOrderOnlyDeps(`
				.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h
				.intermediates/genrule_bar/gen/generated_headers/bar/generated_header.h
			`),
		)
	})

	// TODO: fix this test as it exports all generated headers.
	t.Run("ensure only aidl headers are exported", func(t *testing.T) {
		ctx := testCc(t, genRuleModules+`
		cc_library_shared {
			name: "libfoo",
			srcs: [
				"foo.c",
				"b.aidl",
				"a.proto",
			],
			aidl: {
				export_aidl_headers: true,
			}
		}
		`)
		foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, foo,
			expectedIncludeDirs(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl
			`),
			expectedSystemIncludeDirs(``),
			expectedGeneratedHeaders(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
			expectedOrderOnlyDeps(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
		)
	})

	// TODO: fix this test as it exports all generated headers.
	t.Run("ensure only proto headers are exported", func(t *testing.T) {
		ctx := testCc(t, genRuleModules+`
		cc_library_shared {
			name: "libfoo",
			srcs: [
				"foo.c",
				"b.aidl",
				"a.proto",
			],
			proto: {
				export_proto_headers: true,
			}
		}
		`)
		foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, foo,
			expectedIncludeDirs(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto
			`),
			expectedSystemIncludeDirs(``),
			expectedGeneratedHeaders(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
			expectedOrderOnlyDeps(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
		)
	})

	// TODO: fix this test as it exports all generated headers including public and non-public.
	t.Run("ensure only non-public sysprop headers are exported", func(t *testing.T) {
		ctx := testCc(t, genRuleModules+`
		cc_library_shared {
			name: "libfoo",
			srcs: [
				"foo.c",
				"a.sysprop",
				"b.aidl",
				"a.proto",
			],
		}
		`)
		foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
		checkIncludeDirs(t, ctx, foo,
			expectedIncludeDirs(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include
			`),
			expectedSystemIncludeDirs(``),
			expectedGeneratedHeaders(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/a.sysprop.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/public/include/a.sysprop.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
			expectedOrderOnlyDeps(`
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/a.sysprop.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/public/include/a.sysprop.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto/a.pb.h
			`),
		)
	})
}