| // Copyright 2017 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 ( |
| "android/soong/android" |
| "fmt" |
| "path/filepath" |
| "reflect" |
| "sort" |
| "strings" |
| "testing" |
| ) |
| |
| var ( |
| resourceFiles = []string{ |
| "res/layout/layout.xml", |
| "res/values/strings.xml", |
| "res/values-en-rUS/strings.xml", |
| } |
| |
| compiledResourceFiles = []string{ |
| "aapt2/res/layout_layout.xml.flat", |
| "aapt2/res/values_strings.arsc.flat", |
| "aapt2/res/values-en-rUS_strings.arsc.flat", |
| } |
| ) |
| |
| func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext { |
| appFS := map[string][]byte{} |
| for k, v := range fs { |
| appFS[k] = v |
| } |
| |
| for _, file := range resourceFiles { |
| appFS[file] = nil |
| } |
| |
| return testContext(config, bp, appFS) |
| } |
| |
| func testApp(t *testing.T, bp string) *android.TestContext { |
| config := testConfig(nil) |
| |
| ctx := testAppContext(config, bp, nil) |
| |
| run(t, ctx, config) |
| |
| return ctx |
| } |
| |
| func TestApp(t *testing.T) { |
| for _, moduleType := range []string{"android_app", "android_library"} { |
| t.Run(moduleType, func(t *testing.T) { |
| ctx := testApp(t, moduleType+` { |
| name: "foo", |
| srcs: ["a.java"], |
| } |
| `) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| |
| var expectedLinkImplicits []string |
| |
| manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml") |
| expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String()) |
| |
| frameworkRes := ctx.ModuleForTests("framework-res", "android_common") |
| expectedLinkImplicits = append(expectedLinkImplicits, |
| frameworkRes.Output("package-res.apk").Output.String()) |
| |
| // Test the mapping from input files to compiled output file names |
| compile := foo.Output(compiledResourceFiles[0]) |
| if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) { |
| t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v", |
| resourceFiles, compile.Inputs.Strings()) |
| } |
| |
| compiledResourceOutputs := compile.Outputs.Strings() |
| sort.Strings(compiledResourceOutputs) |
| |
| expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...) |
| |
| list := foo.Output("aapt2/res.list") |
| expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String()) |
| |
| // Check that the link rule uses |
| res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk") |
| if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) { |
| t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v", |
| expectedLinkImplicits, res.Implicits.Strings()) |
| } |
| }) |
| } |
| } |
| |
| var testEnforceRROTests = []struct { |
| name string |
| enforceRROTargets []string |
| enforceRROExcludedOverlays []string |
| fooOverlayFiles []string |
| fooRRODirs []string |
| barOverlayFiles []string |
| barRRODirs []string |
| }{ |
| { |
| name: "no RRO", |
| enforceRROTargets: nil, |
| enforceRROExcludedOverlays: nil, |
| fooOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| "device/vendor/blah/overlay/foo/res/values/strings.xml", |
| }, |
| fooRRODirs: nil, |
| barOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml", |
| "device/vendor/blah/overlay/bar/res/values/strings.xml", |
| }, |
| barRRODirs: nil, |
| }, |
| { |
| name: "enforce RRO on foo", |
| enforceRROTargets: []string{"foo"}, |
| enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"}, |
| fooOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| }, |
| fooRRODirs: []string{ |
| "device/vendor/blah/overlay/foo/res", |
| }, |
| barOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml", |
| "device/vendor/blah/overlay/bar/res/values/strings.xml", |
| }, |
| barRRODirs: nil, |
| }, |
| { |
| name: "enforce RRO on all", |
| enforceRROTargets: []string{"*"}, |
| enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"}, |
| fooOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| }, |
| fooRRODirs: []string{ |
| "device/vendor/blah/overlay/foo/res", |
| }, |
| barOverlayFiles: []string{ |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml", |
| }, |
| barRRODirs: []string{ |
| "device/vendor/blah/overlay/bar/res", |
| }, |
| }, |
| } |
| |
| func TestEnforceRRO(t *testing.T) { |
| resourceOverlays := []string{ |
| "device/vendor/blah/overlay", |
| "device/vendor/blah/overlay2", |
| "device/vendor/blah/static_overlay", |
| } |
| |
| fs := map[string][]byte{ |
| "foo/res/res/values/strings.xml": nil, |
| "bar/res/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay/foo/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay/bar/res/values/strings.xml": nil, |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil, |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay2/res/values/strings.xml": nil, |
| } |
| |
| bp := ` |
| android_app { |
| name: "foo", |
| resource_dirs: ["foo/res"], |
| } |
| |
| android_app { |
| name: "bar", |
| resource_dirs: ["bar/res"], |
| } |
| ` |
| |
| for _, testCase := range testEnforceRROTests { |
| t.Run(testCase.name, func(t *testing.T) { |
| config := testConfig(nil) |
| config.TestProductVariables.ResourceOverlays = &resourceOverlays |
| if testCase.enforceRROTargets != nil { |
| config.TestProductVariables.EnforceRROTargets = &testCase.enforceRROTargets |
| } |
| if testCase.enforceRROExcludedOverlays != nil { |
| config.TestProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays |
| } |
| |
| ctx := testAppContext(config, bp, fs) |
| run(t, ctx, config) |
| |
| getOverlays := func(moduleName string) ([]string, []string) { |
| module := ctx.ModuleForTests(moduleName, "android_common") |
| overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings() |
| |
| var overlayFiles []string |
| for _, o := range overlayCompiledPaths { |
| overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...) |
| } |
| |
| rroDirs := module.Module().(*AndroidApp).rroDirs.Strings() |
| |
| return overlayFiles, rroDirs |
| } |
| |
| fooOverlayFiles, fooRRODirs := getOverlays("foo") |
| barOverlayFiles, barRRODirs := getOverlays("bar") |
| |
| if !reflect.DeepEqual(fooOverlayFiles, testCase.fooOverlayFiles) { |
| t.Errorf("expected foo overlay files:\n %#v\n got:\n %#v", |
| testCase.fooOverlayFiles, fooOverlayFiles) |
| } |
| if !reflect.DeepEqual(fooRRODirs, testCase.fooRRODirs) { |
| t.Errorf("expected foo rroDirs: %#v\n got:\n %#v", |
| testCase.fooRRODirs, fooRRODirs) |
| } |
| |
| if !reflect.DeepEqual(barOverlayFiles, testCase.barOverlayFiles) { |
| t.Errorf("expected bar overlay files:\n %#v\n got:\n %#v", |
| testCase.barOverlayFiles, barOverlayFiles) |
| } |
| if !reflect.DeepEqual(barRRODirs, testCase.barRRODirs) { |
| t.Errorf("expected bar rroDirs: %#v\n got:\n %#v", |
| testCase.barRRODirs, barRRODirs) |
| } |
| |
| }) |
| } |
| } |
| |
| func TestAppSdkVersion(t *testing.T) { |
| testCases := []struct { |
| name string |
| sdkVersion string |
| platformSdkInt int |
| platformSdkCodename string |
| platformSdkFinal bool |
| expectedMinSdkVersion string |
| }{ |
| { |
| name: "current final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 27, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| expectedMinSdkVersion: "27", |
| }, |
| { |
| name: "current non-final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 27, |
| platformSdkCodename: "OMR1", |
| platformSdkFinal: false, |
| expectedMinSdkVersion: "OMR1", |
| }, |
| { |
| name: "default final SDK", |
| sdkVersion: "", |
| platformSdkInt: 27, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| expectedMinSdkVersion: "27", |
| }, |
| { |
| name: "default non-final SDK", |
| sdkVersion: "", |
| platformSdkInt: 27, |
| platformSdkCodename: "OMR1", |
| platformSdkFinal: false, |
| expectedMinSdkVersion: "OMR1", |
| }, |
| { |
| name: "14", |
| sdkVersion: "14", |
| expectedMinSdkVersion: "14", |
| }, |
| } |
| |
| for _, moduleType := range []string{"android_app", "android_library"} { |
| for _, test := range testCases { |
| t.Run(moduleType+" "+test.name, func(t *testing.T) { |
| bp := fmt.Sprintf(`%s { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "%s", |
| }`, moduleType, test.sdkVersion) |
| |
| config := testConfig(nil) |
| config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt |
| config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename |
| config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal |
| |
| ctx := testAppContext(config, bp, nil) |
| |
| run(t, ctx, config) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| link := foo.Output("package-res.apk") |
| linkFlags := strings.Split(link.Args["flags"], " ") |
| min := android.IndexList("--min-sdk-version", linkFlags) |
| target := android.IndexList("--target-sdk-version", linkFlags) |
| |
| if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { |
| t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) |
| } |
| |
| gotMinSdkVersion := linkFlags[min+1] |
| gotTargetSdkVersion := linkFlags[target+1] |
| |
| if gotMinSdkVersion != test.expectedMinSdkVersion { |
| t.Errorf("incorrect --min-sdk-version, expected %q got %q", |
| test.expectedMinSdkVersion, gotMinSdkVersion) |
| } |
| |
| if gotTargetSdkVersion != test.expectedMinSdkVersion { |
| t.Errorf("incorrect --target-sdk-version, expected %q got %q", |
| test.expectedMinSdkVersion, gotTargetSdkVersion) |
| } |
| }) |
| } |
| } |
| } |
| |
| func TestJNI(t *testing.T) { |
| ctx := testJava(t, ` |
| toolchain_library { |
| name: "libcompiler_rt-extras", |
| src: "", |
| } |
| |
| toolchain_library { |
| name: "libatomic", |
| src: "", |
| } |
| |
| toolchain_library { |
| name: "libgcc", |
| src: "", |
| } |
| |
| toolchain_library { |
| name: "libclang_rt.builtins-aarch64-android", |
| src: "", |
| } |
| |
| toolchain_library { |
| name: "libclang_rt.builtins-arm-android", |
| src: "", |
| } |
| |
| cc_object { |
| name: "crtbegin_so", |
| stl: "none", |
| } |
| |
| cc_object { |
| name: "crtend_so", |
| stl: "none", |
| } |
| |
| cc_library { |
| name: "libjni", |
| system_shared_libs: [], |
| stl: "none", |
| } |
| |
| android_test { |
| name: "test", |
| no_framework_libs: true, |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_first", |
| no_framework_libs: true, |
| compile_multilib: "first", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_both", |
| no_framework_libs: true, |
| compile_multilib: "both", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_32", |
| no_framework_libs: true, |
| compile_multilib: "32", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_64", |
| no_framework_libs: true, |
| compile_multilib: "64", |
| jni_libs: ["libjni"], |
| } |
| `) |
| |
| // check the existence of the internal modules |
| ctx.ModuleForTests("test", "android_common") |
| ctx.ModuleForTests("test_first", "android_common") |
| ctx.ModuleForTests("test_both", "android_common") |
| ctx.ModuleForTests("test_32", "android_common") |
| ctx.ModuleForTests("test_64", "android_common") |
| |
| testCases := []struct { |
| name string |
| abis []string |
| }{ |
| {"test", []string{"arm64-v8a"}}, |
| {"test_first", []string{"arm64-v8a"}}, |
| {"test_both", []string{"arm64-v8a", "armeabi-v7a"}}, |
| {"test_32", []string{"armeabi-v7a"}}, |
| {"test_64", []string{"arm64-v8a"}}, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(test.name, "android_common") |
| jniLibZip := app.Output("jnilibs.zip") |
| var abis []string |
| args := strings.Fields(jniLibZip.Args["jarArgs"]) |
| for i := 0; i < len(args); i++ { |
| if args[i] == "-P" { |
| abis = append(abis, filepath.Base(args[i+1])) |
| i++ |
| } |
| } |
| if !reflect.DeepEqual(abis, test.abis) { |
| t.Errorf("want abis %v, got %v", test.abis, abis) |
| } |
| }) |
| } |
| } |