// Copyright 2020 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package java import ( "fmt" "path/filepath" "testing" "android/soong/android" "github.com/google/blueprint/proptools" ) func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer { return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.BootJars = android.CreateTestConfiguredJarList(bootJars) }) } func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer { return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir }) } var hiddenApiFixtureFactory = android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithHiddenApiBuildComponents) func TestHiddenAPISingleton(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, } `) hiddenAPI := result.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPIIndexSingleton(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("bar"), fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"), ).RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, hiddenapi_additional_annotations: [ "foo-hiddenapi-annotations", ], } java_library { name: "foo-hiddenapi-annotations", srcs: ["a.java"], compile_dex: true, } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: false, } java_sdk_library { name: "bar", srcs: ["a.java"], compile_dex: true, } `) hiddenAPIIndex := result.SingletonForTests("hiddenapi_index") indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") CheckHiddenAPIRuleInputs(t, ` .intermediates/bar/android_common/hiddenapi/index.csv .intermediates/foo/android_common/hiddenapi/index.csv `, indexRule) // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that // creates the index.csv file. foo := result.ModuleForTests("foo", "android_common") indexParams := foo.Output("hiddenapi/index.csv") CheckHiddenAPIRuleInputs(t, ` .intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar .intermediates/foo/android_common/javac/foo.jar `, indexParams) } func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) { expectedErrorMessage := "hiddenapi has determined that the source module \"foo\" should be ignored as it has been" + " replaced by the prebuilt module \"prebuilt_foo\" but unfortunately it does not provide a" + " suitable boot dex jar" android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)). RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, } java_import { name: "foo", jars: ["a.jar"], prefer: true, } `) } func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_import { name: "foo", jars: ["a.jar"], compile_dex: true, } `) hiddenAPI := result.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: false, } `) hiddenAPI := result.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) prebuiltJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/dex/foo.jar" android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) } func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: true, } `) hiddenAPI := result.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") prebuiltJarArg := "--boot-dex=out/soong/.intermediates/prebuilt_foo/android_common/dex/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) } func TestHiddenAPISingletonSdks(t *testing.T) { testCases := []struct { name string unbundledBuild bool publicStub string systemStub string testStub string corePlatformStub string // Additional test preparer preparer android.FixturePreparer }{ { name: "testBundled", unbundledBuild: false, publicStub: "android_stubs_current", systemStub: "android_system_stubs_current", testStub: "android_test_stubs_current", corePlatformStub: "legacy.core.platform.api.stubs", preparer: android.GroupFixturePreparers(), }, { name: "testUnbundled", unbundledBuild: true, publicStub: "sdk_public_current_android", systemStub: "sdk_system_current_android", testStub: "sdk_test_current_android", corePlatformStub: "legacy.core.platform.api.stubs", preparer: PrepareForTestWithPrebuiltsOfCurrentApi, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, tc.preparer, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild) }), ).RunTest(t) hiddenAPI := result.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantSystemStubs) wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantTestStubs) wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(defaultJavaDir, tc.corePlatformStub) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) }) } } func generateDexedPath(subDir, dex, module string) string { return fmt.Sprintf("out/soong/.intermediates/%s/android_common/%s/%s.jar", subDir, dex, module) } func generateDexPath(moduleDir string, module string) string { return generateDexedPath(filepath.Join(moduleDir, module), "dex", module) } func generateSdkDexPath(module string, unbundled bool) string { if unbundled { return generateDexedPath("prebuilts/sdk/"+module, "dex", module) } return generateDexPath(defaultJavaDir, module) } func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { // The idea behind this test is to ensure that when the build is // confugured with a PrebuiltHiddenApiDir that the rules for the // hiddenapi singleton copy the prebuilts to the typical output // location, and then use that output location for the hiddenapi encode // dex step. // Where to find the prebuilt hiddenapi files: prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" result := android.GroupFixturePreparers( hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir), ).RunTestWithBp(t, ` java_import { name: "foo", jars: ["a.jar"], compile_dex: true, } `) expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" expectedCpOutput := "out/soong/hiddenapi/hiddenapi-flags.csv" expectedFlagsCsv := "out/soong/hiddenapi/hiddenapi-flags.csv" foo := result.ModuleForTests("foo", "android_common") hiddenAPI := result.SingletonForTests("hiddenapi") cpRule := hiddenAPI.Rule("Cp") actualCpInput := cpRule.BuildParams.Input actualCpOutput := cpRule.BuildParams.Output encodeDexRule := foo.Rule("hiddenAPIEncodeDex") actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule input", expectedCpInput, actualCpInput) android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule output", expectedCpOutput, actualCpOutput) android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv) }