// Copyright 2021 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" "regexp" "testing" "android/soong/android" "github.com/google/blueprint/proptools" ) func TestJavaSdkLibrary(t *testing.T) { result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "28": {"foo"}, "29": {"foo"}, "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"}, }), ).RunTestWithBp(t, ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", path: ".", } java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], api_packages: ["foo"], } java_sdk_library { name: "bar", srcs: ["a.java", "b.java"], api_packages: ["bar"], exclude_kotlinc_generated_files: true, } java_library { name: "baz", srcs: ["c.java"], libs: ["foo", "bar.stubs"], sdk_version: "system_current", } java_sdk_library { name: "barney", srcs: ["c.java"], api_only: true, } java_sdk_library { name: "betty", srcs: ["c.java"], shared_library: false, } java_sdk_library_import { name: "quuz", public: { jars: ["c.jar"], }, } java_sdk_library_import { name: "fred", public: { jars: ["b.jar"], }, } java_sdk_library_import { name: "wilma", public: { jars: ["b.jar"], }, shared_library: false, } java_library { name: "qux", srcs: ["c.java"], libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"], sdk_version: "system_current", } java_library { name: "baz-test", srcs: ["c.java"], libs: ["foo"], sdk_version: "test_current", } java_library { name: "baz-29", srcs: ["c.java"], libs: ["foo"], sdk_version: "system_29", } java_library { name: "baz-module-30", srcs: ["c.java"], libs: ["foo"], sdk_version: "module_30", } `) // check the existence of the internal modules foo := result.ModuleForTests("foo", "android_common") result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common") result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common") result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common") result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common") result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common") result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common") result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common") result.ModuleForTests("foo.api.public.28", "") result.ModuleForTests("foo.api.system.28", "") result.ModuleForTests("foo.api.test.28", "") exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo) expectedFooExportedComponents := []string{ "foo.stubs", "foo.stubs.source", "foo.stubs.source.system", "foo.stubs.source.test", "foo.stubs.system", "foo.stubs.test", } android.AssertArrayString(t, "foo exported components", expectedFooExportedComponents, exportedComponentsInfo.Components) bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") // tests if baz is actually linked to the stubs lib android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar") // ... and not to the impl lib android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar") // test if baz is not linked to the system variant of foo android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar") bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac") // tests if baz-test is actually linked to the test stubs lib android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar") baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac") // tests if baz-29 is actually linked to the system 29 stubs lib android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac") // tests if "baz-module-30" is actually linked to the module 30 stubs lib android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") // test if baz has exported SDK lib names foo and bar to qux qux := result.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { requiredSdkLibs, optionalSdkLibs := quxLib.ClassLoaderContexts().UsesLibs() android.AssertDeepEquals(t, "qux exports (required)", []string{"fred", "quuz", "foo", "bar"}, requiredSdkLibs) android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs) } fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8") // tests if kotlinc generated files are NOT excluded from output of foo. android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") barDexJar := result.ModuleForTests("bar", "android_common").Rule("d8") // tests if kotlinc generated files are excluded from output of bar. android.AssertStringDoesContain(t, "bar dex", barDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") } func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "28": {"foo"}, "29": {"foo"}, "30": {"foo", "fooUpdatable", "fooUpdatableErr"}, }), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W", "X"} }), ).RunTestWithBp(t, ` java_sdk_library { name: "fooUpdatable", srcs: ["a.java", "b.java"], api_packages: ["foo"], on_bootclasspath_since: "U", on_bootclasspath_before: "V", min_device_sdk: "W", max_device_sdk: "X", min_sdk_version: "S", } java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], api_packages: ["foo"], } `) // test that updatability attributes are passed on correctly fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml") android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"U\"`) android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"V\"`) android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"W\"`) android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"X\"`) // double check that updatability attributes are not written if they don't exist in the bp file // the permissions file for the foo library defined above fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`) android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`) android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`) android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`) } func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) { android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "30": {"fooUpdatable", "fooUpdatableErr"}, }), ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( []string{ `on_bootclasspath_since: "aaa" could not be parsed as an integer and is not a recognized codename`, `on_bootclasspath_before: "bbc" could not be parsed as an integer and is not a recognized codename`, `min_device_sdk: "ccc" could not be parsed as an integer and is not a recognized codename`, `max_device_sdk: "current" is not an allowed value for this attribute`, })).RunTestWithBp(t, ` java_sdk_library { name: "fooUpdatableErr", srcs: ["a.java", "b.java"], api_packages: ["foo"], on_bootclasspath_since: "aaa", on_bootclasspath_before: "bbc", min_device_sdk: "ccc", max_device_sdk: "current", } `) } func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) { android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "28": {"foo"}, }), ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( []string{ "on_bootclasspath_since: Attribute value needs to be at least T", "on_bootclasspath_before: Attribute value needs to be at least T", "min_device_sdk: Attribute value needs to be at least T", "max_device_sdk: Attribute value needs to be at least T", }, )).RunTestWithBp(t, ` java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], api_packages: ["foo"], on_bootclasspath_since: "S", on_bootclasspath_before: "S", min_device_sdk: "S", max_device_sdk: "S", min_sdk_version: "S", } `) } func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) { android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "28": {"foo"}, }), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"} }), ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( []string{ "min_device_sdk can't be greater than max_device_sdk", }, )).RunTestWithBp(t, ` java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], api_packages: ["foo"], min_device_sdk: "V", max_device_sdk: "U", min_sdk_version: "S", } `) } func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) { android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "28": {"foo"}, }), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"} }), ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( []string{ regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"), regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"), }, )).RunTestWithBp(t, ` java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], api_packages: ["foo"], min_device_sdk: "U", max_device_sdk: "U", min_sdk_version: "V", } `) } func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) { result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithPrebuiltApis(map[string][]string{ "30": {"foo"}, }), ).RunTestWithBp(t, ` java_sdk_library { name: "foo", srcs: ["a.java", "b.java"], min_device_sdk: "Tiramisu", min_sdk_version: "S", } `) // test that updatability attributes are passed on correctly fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `