1// Copyright 2021 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package java 16 17import ( 18 "fmt" 19 "reflect" 20 "regexp" 21 "strings" 22 "testing" 23 24 "android/soong/android" 25) 26 27func TestDroidstubs(t *testing.T) { 28 ctx, _ := testJavaWithFS(t, ` 29 droiddoc_exported_dir { 30 name: "droiddoc-templates-sdk", 31 path: ".", 32 } 33 34 droidstubs { 35 name: "bar-stubs", 36 srcs: ["bar-doc/a.java"], 37 api_levels_annotations_dirs: ["droiddoc-templates-sdk"], 38 api_levels_annotations_enabled: true, 39 } 40 41 droidstubs { 42 name: "bar-stubs-other", 43 srcs: ["bar-doc/a.java"], 44 high_mem: true, 45 api_levels_annotations_dirs: ["droiddoc-templates-sdk"], 46 api_levels_annotations_enabled: true, 47 api_levels_jar_filename: "android.other.jar", 48 } 49 50 droidstubs { 51 name: "stubs-applying-api-versions", 52 srcs: ["bar-doc/a.java"], 53 api_levels_module: "bar-stubs-other", 54 } 55 `, 56 map[string][]byte{ 57 "bar-doc/a.java": nil, 58 }) 59 testcases := []struct { 60 moduleName string 61 expectedJarFilename string 62 generate_xml bool 63 high_mem bool 64 }{ 65 { 66 moduleName: "bar-stubs", 67 generate_xml: true, 68 expectedJarFilename: "android.jar", 69 high_mem: false, 70 }, 71 { 72 moduleName: "bar-stubs-other", 73 generate_xml: true, 74 expectedJarFilename: "android.other.jar", 75 high_mem: true, 76 }, 77 { 78 moduleName: "stubs-applying-api-versions", 79 generate_xml: false, 80 }, 81 } 82 for _, c := range testcases { 83 m := ctx.ModuleForTests(c.moduleName, "android_common") 84 manifest := m.Output("metalava.sbox.textproto") 85 sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest) 86 cmdline := String(sboxProto.Commands[0].Command) 87 android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml) 88 if c.expectedJarFilename != "" { 89 expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename 90 if !strings.Contains(cmdline, expected) { 91 t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, cmdline) 92 } 93 } 94 95 metalava := m.Rule("metalava") 96 rp := metalava.RuleParams 97 if actual := rp.Pool != nil && strings.Contains(rp.Pool.String(), "highmem"); actual != c.high_mem { 98 t.Errorf("Expected %q high_mem to be %v, was %v", c.moduleName, c.high_mem, actual) 99 } 100 } 101} 102 103// runs a test for droidstubs with a customizable sdkType argument and returns 104// the list of jar patterns that is passed as `--android-jar-pattern` 105func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string { 106 ctx, _ := testJavaWithFS(t, fmt.Sprintf(` 107 droiddoc_exported_dir { 108 name: "some-exported-dir", 109 path: "somedir", 110 } 111 112 droiddoc_exported_dir { 113 name: "some-other-exported-dir", 114 path: "someotherdir", 115 } 116 117 droidstubs { 118 name: "foo-stubs", 119 srcs: ["foo-doc/a.java"], 120 api_levels_annotations_dirs: [ 121 "some-exported-dir", 122 "some-other-exported-dir", 123 ], 124 api_levels_annotations_enabled: true, 125 api_levels_sdk_type: "%s", 126 } 127 `, sdkType), 128 map[string][]byte{ 129 "foo-doc/a.java": nil, 130 }) 131 132 m := ctx.ModuleForTests("foo-stubs", "android_common") 133 manifest := m.Output("metalava.sbox.textproto") 134 cmd := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command) 135 r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`) 136 return r.FindAllString(cmd, -1) 137} 138 139func TestPublicDroidstubs(t *testing.T) { 140 patterns := getAndroidJarPatternsForDroidstubs(t, "public") 141 142 android.AssertArrayString(t, "order of patterns", []string{ 143 "--android-jar-pattern somedir/%/public/android.jar", 144 "--android-jar-pattern someotherdir/%/public/android.jar", 145 }, patterns) 146} 147 148func TestSystemDroidstubs(t *testing.T) { 149 patterns := getAndroidJarPatternsForDroidstubs(t, "system") 150 151 android.AssertArrayString(t, "order of patterns", []string{ 152 "--android-jar-pattern somedir/%/system/android.jar", 153 "--android-jar-pattern someotherdir/%/system/android.jar", 154 "--android-jar-pattern somedir/%/public/android.jar", 155 "--android-jar-pattern someotherdir/%/public/android.jar", 156 }, patterns) 157} 158 159func TestModuleLibDroidstubs(t *testing.T) { 160 patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib") 161 162 android.AssertArrayString(t, "order of patterns", []string{ 163 "--android-jar-pattern somedir/%/module-lib/android.jar", 164 "--android-jar-pattern someotherdir/%/module-lib/android.jar", 165 "--android-jar-pattern somedir/%/system/android.jar", 166 "--android-jar-pattern someotherdir/%/system/android.jar", 167 "--android-jar-pattern somedir/%/public/android.jar", 168 "--android-jar-pattern someotherdir/%/public/android.jar", 169 }, patterns) 170} 171 172func TestSystemServerDroidstubs(t *testing.T) { 173 patterns := getAndroidJarPatternsForDroidstubs(t, "system-server") 174 175 android.AssertArrayString(t, "order of patterns", []string{ 176 "--android-jar-pattern somedir/%/system-server/android.jar", 177 "--android-jar-pattern someotherdir/%/system-server/android.jar", 178 "--android-jar-pattern somedir/%/module-lib/android.jar", 179 "--android-jar-pattern someotherdir/%/module-lib/android.jar", 180 "--android-jar-pattern somedir/%/system/android.jar", 181 "--android-jar-pattern someotherdir/%/system/android.jar", 182 "--android-jar-pattern somedir/%/public/android.jar", 183 "--android-jar-pattern someotherdir/%/public/android.jar", 184 }, patterns) 185} 186 187func TestDroidstubsSandbox(t *testing.T) { 188 ctx, _ := testJavaWithFS(t, ` 189 genrule { 190 name: "foo", 191 out: ["foo.txt"], 192 cmd: "touch $(out)", 193 } 194 195 droidstubs { 196 name: "bar-stubs", 197 srcs: ["bar-doc/a.java"], 198 199 args: "--reference $(location :foo)", 200 arg_files: [":foo"], 201 } 202 `, 203 map[string][]byte{ 204 "bar-doc/a.java": nil, 205 }) 206 207 m := ctx.ModuleForTests("bar-stubs", "android_common") 208 metalava := m.Rule("metalava") 209 if g, w := metalava.Inputs.Strings(), []string{"bar-doc/a.java"}; !reflect.DeepEqual(w, g) { 210 t.Errorf("Expected inputs %q, got %q", w, g) 211 } 212 213 manifest := android.RuleBuilderSboxProtoForTests(t, m.Output("metalava.sbox.textproto")) 214 if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) { 215 t.Errorf("Expected command to contain %q, got %q", w, g) 216 } 217} 218 219func TestDroidstubsWithSystemModules(t *testing.T) { 220 ctx, _ := testJava(t, ` 221 droidstubs { 222 name: "stubs-source-system-modules", 223 srcs: [ 224 "bar-doc/a.java", 225 ], 226 sdk_version: "none", 227 system_modules: "source-system-modules", 228 } 229 230 java_library { 231 name: "source-jar", 232 srcs: [ 233 "a.java", 234 ], 235 } 236 237 java_system_modules { 238 name: "source-system-modules", 239 libs: ["source-jar"], 240 } 241 242 droidstubs { 243 name: "stubs-prebuilt-system-modules", 244 srcs: [ 245 "bar-doc/a.java", 246 ], 247 sdk_version: "none", 248 system_modules: "prebuilt-system-modules", 249 } 250 251 java_import { 252 name: "prebuilt-jar", 253 jars: ["a.jar"], 254 } 255 256 java_system_modules_import { 257 name: "prebuilt-system-modules", 258 libs: ["prebuilt-jar"], 259 } 260 `) 261 262 checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar") 263 264 checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar") 265} 266 267func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) { 268 metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava") 269 var systemJars []string 270 for _, i := range metalavaRule.Implicits { 271 systemJars = append(systemJars, i.Base()) 272 } 273 if len(systemJars) < 1 || systemJars[0] != systemJar { 274 t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars) 275 } 276} 277 278func TestDroidstubsWithSdkExtensions(t *testing.T) { 279 ctx, _ := testJavaWithFS(t, ` 280 droiddoc_exported_dir { 281 name: "sdk-dir", 282 path: "sdk", 283 } 284 285 droidstubs { 286 name: "baz-stubs", 287 api_levels_annotations_dirs: ["sdk-dir"], 288 api_levels_annotations_enabled: true, 289 extensions_info_file: ":info-file", 290 } 291 292 filegroup { 293 name: "info-file", 294 srcs: ["sdk/extensions/info.txt"], 295 } 296 `, 297 map[string][]byte{ 298 "sdk/extensions/1/public/some-mainline-module-stubs.jar": nil, 299 "sdk/extensions/info.txt": nil, 300 }) 301 m := ctx.ModuleForTests("baz-stubs", "android_common") 302 manifest := m.Output("metalava.sbox.textproto") 303 cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command) 304 android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions") 305 android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt") 306} 307 308func TestApiSurfaceFromDroidStubsName(t *testing.T) { 309 testCases := []struct { 310 desc string 311 name string 312 expectedApiSurface string 313 }{ 314 { 315 desc: "Default is publicapi", 316 name: "mydroidstubs", 317 expectedApiSurface: "publicapi", 318 }, 319 { 320 desc: "name contains system substring", 321 name: "mydroidstubs.system.suffix", 322 expectedApiSurface: "systemapi", 323 }, 324 { 325 desc: "name contains system_server substring", 326 name: "mydroidstubs.system_server.suffix", 327 expectedApiSurface: "system-serverapi", 328 }, 329 { 330 desc: "name contains module_lib substring", 331 name: "mydroidstubs.module_lib.suffix", 332 expectedApiSurface: "module-libapi", 333 }, 334 { 335 desc: "name contains test substring", 336 name: "mydroidstubs.test.suffix", 337 expectedApiSurface: "testapi", 338 }, 339 { 340 desc: "name contains intra.core substring", 341 name: "mydroidstubs.intra.core.suffix", 342 expectedApiSurface: "intracoreapi", 343 }, 344 } 345 for _, tc := range testCases { 346 android.AssertStringEquals(t, tc.desc, tc.expectedApiSurface, bazelApiSurfaceName(tc.name)) 347 } 348} 349 350func TestDroidStubsApiContributionGeneration(t *testing.T) { 351 ctx, _ := testJavaWithFS(t, ` 352 droidstubs { 353 name: "foo", 354 srcs: ["A/a.java"], 355 api_surface: "public", 356 check_api: { 357 current: { 358 api_file: "A/current.txt", 359 removed_api_file: "A/removed.txt", 360 } 361 } 362 } 363 `, 364 map[string][]byte{ 365 "A/a.java": nil, 366 "A/current.txt": nil, 367 "A/removed.txt": nil, 368 }, 369 ) 370 371 ctx.ModuleForTests("foo.api.contribution", "") 372} 373 374func TestGeneratedApiContributionVisibilityTest(t *testing.T) { 375 library_bp := ` 376 java_api_library { 377 name: "bar", 378 api_surface: "public", 379 api_contributions: ["foo.api.contribution"], 380 } 381 ` 382 ctx, _ := testJavaWithFS(t, ` 383 droidstubs { 384 name: "foo", 385 srcs: ["A/a.java"], 386 api_surface: "public", 387 check_api: { 388 current: { 389 api_file: "A/current.txt", 390 removed_api_file: "A/removed.txt", 391 } 392 }, 393 visibility: ["//a"], 394 } 395 `, 396 map[string][]byte{ 397 "a/a.java": nil, 398 "a/current.txt": nil, 399 "a/removed.txt": nil, 400 "b/Android.bp": []byte(library_bp), 401 }, 402 ) 403 404 ctx.ModuleForTests("bar", "android_common") 405} 406