aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ajmichael <ajmichael@google.com>2017-09-13 20:37:20 +0200
committerGravatar Philipp Wollermann <philwo@google.com>2017-09-14 18:46:20 +0200
commitd60e0d02eb56e27f98086d764c6d9f88898d920d (patch)
treea13381d9a784f9dda1f02beee23a79142d8cd072
parenta615d288b008c36c659fdc17965207bb62d95d8d (diff)
Open source tests for Android desugarer.
These tests will fail with a helpful error message if you do not have android_sdk_repository set up. They currently require that platform 25 be installed in your SDK. RELNOTES: None PiperOrigin-RevId: 168570577
-rw-r--r--src/test/java/com/google/devtools/build/android/BUILD1
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/BUILD1776
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/Bug62456849TestDataGenerator.java104
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java234
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarCoreLibraryFunctionalTest.java34
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarDefaultMethodsFunctionalTest.java29
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarFunctionalTest.java339
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarJava8FunctionalTest.java397
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarJava8LikeAndroidStudioFunctionalTest.java31
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarLongCompareTest.java135
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarMainClassTest.java82
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarObjectsRequireNonNullTest.java153
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DesugarTryWithResourcesFunctionalTest.java99
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/FieldInfoTest.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/IndexedInputsTest.java136
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/Java7CompatibilityTest.java122
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/MethodInfoTest.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/StackMapBugTest.java45
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java414
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/capture_lambda_disassembled_golden.txt21
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/class_with_inherited_abstract_method_disassembled_golden.txt4
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/class_with_lambdas_in_implemented_interface_disassembled_golden.txt8
-rwxr-xr-xsrc/test/java/com/google/devtools/build/android/desugar/diff.sh16
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/interface_with_desugared_method_bodies_disassembled_golden.txt7
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/jacoco_0_7_5_default_method.jarbin0 -> 1393 bytes
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/jacoco_legacy_default_method_companion_disassembled_golden.txt37
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/mocked_android_framework/android/os/Build.java31
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/runtime/BUILD98
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/runtime/ConcurrentWeakIdentityHashMapTest.java262
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTest.java453
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTestUtility.java64
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/simple_instance_method_reference_disassembled_golden.txt21
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/stateless_lambda_disassembled_golden.txt24
-rwxr-xr-xsrc/test/java/com/google/devtools/build/android/desugar/static_initializer_of_functional_interface_should_not_execute.sh22
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java51
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java53
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java88
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java54
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java56
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java31
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java51
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java25
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java60
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java35
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java88
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java37
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java39
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java22
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java36
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java56
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java43
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java28
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java37
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java172
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java66
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java78
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java60
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java97
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java49
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java41
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java45
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java56
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java72
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java36
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java23
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java33
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java22
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java32
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java21
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt1
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_core_library_jar_toc_golden.txt18
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt65
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_try_with_resources_jar_toc_golden.txt72
-rwxr-xr-xsrc/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_test.sh44
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_toc_golden.txt72
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_java8_jar_toc_golden.txt145
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_without_lambda_desugared_jar_toc_golden.txt36
-rw-r--r--src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java33
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/BUILD4
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/runtime/BUILD8
83 files changed, 7653 insertions, 2 deletions
diff --git a/src/test/java/com/google/devtools/build/android/BUILD b/src/test/java/com/google/devtools/build/android/BUILD
index 77bb8dfa07..2984c27894 100644
--- a/src/test/java/com/google/devtools/build/android/BUILD
+++ b/src/test/java/com/google/devtools/build/android/BUILD
@@ -2,6 +2,7 @@ filegroup(
name = "srcs",
srcs = glob(["**"]) + [
"//src/test/java/com/google/devtools/build/android/idlclass:srcs",
+ "//src/test/java/com/google/devtools/build/android/desugar:srcs",
"//src/test/java/com/google/devtools/build/android/dexer:srcs",
"//src/test/java/com/google/devtools/build/android/junctions:srcs",
"//src/test/java/com/google/devtools/build/android/resources:srcs",
diff --git a/src/test/java/com/google/devtools/build/android/desugar/BUILD b/src/test/java/com/google/devtools/build/android/desugar/BUILD
new file mode 100644
index 0000000000..6d0187ef1c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/BUILD
@@ -0,0 +1,1776 @@
+# Description:
+# Tests for the Java 8 desugaring tool for Android.
+package(
+ default_testonly = 1,
+ default_visibility = ["//src/test/java/com/google/devtools/build/android/desugar:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ testonly = 0,
+ srcs = glob(["**"]) + [
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:srcs",
+ ],
+ visibility = ["//src/test/java/com/google/devtools/build/android:__pkg__"],
+)
+
+filegroup(
+ name = "android_jar_for_testing",
+ srcs = select({
+ # TODO(ajmichael): Use //tools/defaults:android_jar here once it supplies runfiles.
+ "//external:has_androidsdk": ["@androidsdk//:platforms/android-25/android.jar"],
+ "//conditions:default": ["@bazel_tools//tools/android:error_message.jar"],
+ }),
+)
+
+java_test(
+ name = "DesugarFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared", # Make tests run against desugared library
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarIdempotencyFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_twice", # Make tests run against twice-desugared library
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+# Test for b/62456849. If a synthetic method is named "lambda$XXX", but not used in invokedynamic,
+# then Desugar should keep it in the class, rather than renaming it.
+java_test(
+ name = "DesugarFunctionalTestForSyntheticMethodsWithLambdaNames",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":desugar_testdata_with_synthetic_methods_with_lambda_names",
+ ":separate",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarLongCompareTest",
+ size = "small",
+ srcs = [
+ "DesugarLongCompareTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared", # Make tests run against desugared library
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarObjectsRequireNonNullTest",
+ size = "small",
+ srcs = [
+ "DesugarObjectsRequireNonNullTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared", # Make tests run against desugared library
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarObjectsRequireNonNullTestForAndroidLintMode",
+ size = "small",
+ srcs = ["DesugarObjectsRequireNonNullTest.java"],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarObjectsRequireNonNullTest",
+ deps = [
+ ":desugar_testdata_by_disabling_lambda_desugaring", # Make tests run against desugared library
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarJava8FunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ "DesugarJava8FunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared_java8", # Make tests run against desugared library
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarJava8LikeAndroidStudioFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ "DesugarJava8FunctionalTest.java",
+ "DesugarJava8LikeAndroidStudioFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":libseparate.jar",
+ ":testdata_desugared_java8_like_in_android_studio.jar", # Make tests run against desugared library
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarDefaultMethodsFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarDefaultMethodsFunctionalTest.java",
+ "DesugarFunctionalTest.java",
+ "DesugarJava8FunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared_default_methods", # Make tests run against desugared library
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarDefaultMethodsIdempotencyFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarDefaultMethodsFunctionalTest.java",
+ "DesugarFunctionalTest.java",
+ "DesugarJava8FunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarDefaultMethodsFunctionalTest",
+ deps = [
+ ":testdata_desugared_default_methods_twice", # Make tests run against 2x desugared library
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarLikeAndroidStudioFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_like_in_android_studio", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarFunctionalTestWithMultipleInputs",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_with_multiple_inputs", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarFunctionalTestFromDirectoryToJar",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_from_directory_to_jar", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarFunctionalTestFromDirectoryToDirectory",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_from_directory_to_directory", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarFunctionalTestWithClasspathDirectory",
+ size = "small",
+ srcs = [
+ "DesugarFunctionalTest.java",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarFunctionalTest",
+ deps = [
+ ":testdata_desugared_with_classpath_directory", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarCoreLibraryFunctionalTest",
+ size = "small",
+ srcs = [
+ "DesugarCoreLibraryFunctionalTest.java",
+ ],
+ jvm_flags = ["-Xbootclasspath/p:$(location :testdata_desugared_core_library):$(location //third_party/java/jacoco:blaze-agent)"],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared_core_library", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ ],
+)
+
+java_test(
+ name = "StackMapBugTest",
+ size = "small",
+ srcs = [
+ "StackMapBugTest.java",
+ ],
+ jvm_flags = ["-Xbootclasspath/p:$(location //third_party/java/jacoco:blaze-agent)"],
+ tags = ["no_windows"],
+ deps = [
+ ":testdata_desugared_core_library", # Make tests run against desugared library
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ ],
+)
+
+java_test(
+ name = "DefaultMethodClassFixerTest",
+ size = "small",
+ srcs = ["DefaultMethodClassFixerTest.java"],
+ data = [
+ ":android_jar_for_testing",
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_java8",
+ ],
+ jvm_flags = [
+ "-DDefaultMethodClassFixerTest.bootclasspath=$(location :android_jar_for_testing)",
+ "-DDefaultMethodClassFixerTest.classpath=$(location :separate):$(location :guava_base_classpath.jar):$(location //third_party/java/jacoco:blaze-agent)",
+ "-DDefaultMethodClassFixerTest.input=$(location :testdata_java8)",
+ ],
+ tags = ["no_windows"],
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:asm",
+ "//third_party:asm-tree",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ "//third_party/java/jacoco:blaze-agent",
+ ],
+)
+
+java_test(
+ name = "MethodInfoTest",
+ size = "small",
+ srcs = ["MethodInfoTest.java"],
+ tags = ["no_windows"],
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "FieldInfoTest",
+ size = "small",
+ srcs = ["FieldInfoTest.java"],
+ tags = ["no_windows"],
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "Java7CompatibilityTest",
+ size = "small",
+ srcs = ["Java7CompatibilityTest.java"],
+ tags = ["no_windows"],
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:asm",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "IndexedInputsTest",
+ size = "small",
+ srcs = ["IndexedInputsTest.java"],
+ tags = ["no_windows"],
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "TryWithResourcesRewriterUnitTestWithReuseStrategy",
+ size = "small",
+ srcs = [
+ "TryWithResourcesRewriterTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=19",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$ReuseDesugaringStrategy'",
+ ],
+ test_class = "com.google.devtools.build.android.desugar.TryWithResourcesRewriterTest",
+ deps = [
+ ":mocked_android_os_sdk_for_testing",
+ ":testdata",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "TryWithResourcesRewriterUnitTestWithMimicStrategy",
+ size = "small",
+ srcs = [
+ "TryWithResourcesRewriterTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$MimicDesugaringStrategy'",
+ ],
+ test_class = "com.google.devtools.build.android.desugar.TryWithResourcesRewriterTest",
+ deps = [
+ ":mocked_android_os_sdk_for_testing",
+ ":testdata",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "TryWithResourcesRewriterUnitTestWithNullStrategy",
+ size = "small",
+ srcs = [
+ "TryWithResourcesRewriterTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "-Dcom.google.devtools.build.android.desugar.runtime.twr_disable_mimic=true",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$NullDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.TryWithResourcesRewriterTest",
+ deps = [
+ ":mocked_android_os_sdk_for_testing",
+ ":testdata",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+# This test sets the lambda dump directory via the system property in the command line
+# (i.e., jvm_flags). So the dump directory is expected to succeed.
+java_test(
+ name = "DesugarMainCLassTestLambdaDirectoryCorrectlySet",
+ size = "small",
+ srcs = ["DesugarMainClassTest.java"],
+ jvm_flags = ["-Djdk.internal.lambda.dumpProxyClasses=$$(mktemp -d)"],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarMainClassTest",
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+# Different from the test target above, this test does not set the lambda dump directory in the
+# command line. Instead, it sets the system property in the test code, which is expected to fail.
+java_test(
+ name = "DesugarMainCLassTestLambdaDirectoryIncorrectlySet",
+ size = "small",
+ srcs = ["DesugarMainClassTest.java"],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarMainClassTest",
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+sh_test(
+ name = "testdata_desugared_jar_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared.jar)",
+ "$(location testdata_desugared_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared.jar",
+ "testdata_desugared_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+# Make sure desugaring twice doesn't add any files
+sh_test(
+ name = "testdata_desugared_twice_jar_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_twice.jar)",
+ "$(location testdata_desugared_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_jar_toc_golden.txt",
+ "testdata_desugared_twice.jar",
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+sh_test(
+ name = "testdata_desugared_java8_jar_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_java8.jar)",
+ "$(location testdata_desugared_java8_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_java8.jar",
+ "testdata_desugared_java8_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+# TODO(b/37110951): Add jar content test for desugared default methods that works with coverage on
+
+sh_test(
+ name = "testdata_desugared_core_library_jar_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_core_library.jar)",
+ "$(location testdata_desugared_core_library_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_core_library.jar",
+ "testdata_desugared_core_library_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+sh_test(
+ name = "testdata_desugared_for_try_with_resources_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_for_try_with_resources.jar)",
+ "$(location testdata_desugared_for_try_with_resources_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_for_try_with_resources.jar",
+ "testdata_desugared_for_try_with_resources_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+sh_test(
+ name = "testdata_desugared_for_try_with_resources_test_twice",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_for_try_with_resources_twice.jar)",
+ "$(location testdata_desugared_for_try_with_resources_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_for_try_with_resources_jar_toc_golden.txt", # Golden file
+ "testdata_desugared_for_try_with_resources_twice.jar",
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+# Test for b/63900665
+sh_test(
+ name = "testdata_desugared_for_disabling_try_with_resources_with_large_minsdkversion_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_for_NO_desugaring_try_with_resources.jar)",
+ "$(location testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_for_NO_desugaring_try_with_resources.jar",
+ "testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+# Test for b/62047432
+sh_test(
+ name = "initializer_of_functional_interface_should_not_execute",
+ size = "small",
+ srcs = ["static_initializer_of_functional_interface_should_not_execute.sh"],
+ args = [
+ "$(location :desugar_testdata_with_default_methods_for_static_initializer_test) ",
+ ],
+ data = [
+ ":desugar_testdata_with_default_methods_for_static_initializer_test",
+ ],
+ tags = ["no_windows"],
+)
+
+java_library(
+ name = "testdata",
+ srcs = glob(["testdata/*.java"]),
+ resources = ["testdata/testresource.txt"],
+ deps = [
+ ":separate",
+ "//third_party:guava",
+ ],
+)
+
+java_library(
+ name = "testdata_java8",
+ srcs = glob([
+ "testdata/*.java",
+ "testdata/java8/**/*.java",
+ ]),
+ resources = ["testdata/testresource.txt"],
+ deps = [
+ ":separate",
+ "//third_party:guava",
+ ],
+)
+
+java_library(
+ name = "testdata_core_library",
+ srcs = glob([
+ "testdata/core_library/**/*.java",
+ ]),
+ resources = ["testdata/testresource.txt"],
+ deps = [
+ "//third_party:error_prone",
+ "//third_party:guava",
+ ],
+)
+
+java_library(
+ name = "separate",
+ srcs = glob(["testdata/separate/*.java"]),
+)
+
+java_library(
+ name = "testdata_like_in_android_studio",
+ srcs = glob(["testdata/*.java"]),
+ resources = ["testdata/testresource.txt"],
+ deps = [
+ ":libseparate.jar", # puts full Jar instead of header Jar on the classpath
+ "//third_party:guava",
+ ],
+)
+
+java_library(
+ name = "testdata_java8_like_in_android_studio",
+ srcs = glob([
+ "testdata/*.java",
+ "testdata/java8/**/*.java",
+ ]),
+ resources = ["testdata/testresource.txt"],
+ deps = [
+ ":libseparate.jar", # puts full Jar instead of header Jar on the classpath
+ "//third_party:guava",
+ ],
+)
+
+# The golden file for this target should NEVER contain generated lambda classes.
+sh_test(
+ name = "desugar_testdata_by_disabling_lambda_desugaring_test",
+ size = "small",
+ srcs = ["testdata_desugared_jar_test.sh"],
+ args = [
+ "$(location testdata_desugared_without_lambda_desugared.jar)",
+ "$(location testdata_desugared_without_lambda_desugared_jar_toc_golden.txt)",
+ "$(JAVABASE)",
+ ],
+ data = [
+ "testdata_desugared_without_lambda_desugared.jar",
+ "testdata_desugared_without_lambda_desugared_jar_toc_golden.txt", # Golden file
+ "@bazel_tools//tools/jdk",
+ ],
+ tags = ["no_windows"],
+)
+
+# The following genrules run the code tested here as a build tool. While that's
+# very similar to how Blaze will invoke it natively, the downside is that
+# running the tested tool in a genrule doesn't contribute code coverage
+# information for the tested tool. Note that the code in :testdata doesn't
+# appear in coverage reports when depending on this target regardless because
+# the needed metadata doesn't survive these genrules.
+genrule(
+ name = "desugar_testdata",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :testdata) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+# Convert human-written methods whose names start with "lambda$XXX" to synthetic methods, so we can
+# test for b/62456849.
+genrule(
+ name = "generate_synthetic_methods_with_lambda_names_in_test_data",
+ srcs = [":testdata"],
+ outs = ["testdata_with_generated_synthetic_methods_with_lambda_names.jar"],
+ cmd = "$(location :generate_synthetic_method_with_lambda_name_convention) " +
+ " $(location :testdata) " +
+ " $@ ",
+ tags = ["no_windows"],
+ tools = [":generate_synthetic_method_with_lambda_name_convention"],
+)
+
+# Desugar the test data for b/62456849
+genrule(
+ name = "desugar_testdata_with_synthetic_methods_with_lambda_names",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":generate_synthetic_methods_with_lambda_names_in_test_data",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_with_synthetic_methods_with_lambda_names.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :generate_synthetic_methods_with_lambda_names_in_test_data) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_again",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_desugared.jar",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_twice.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :testdata_desugared.jar) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+# This target tests the flag --allow_desugaring_lambda_for_lint=true, which is introduced to solve
+# the incompatibility issue with Android Lint. When the issue is addressed, this target and the
+# flag will be removed.
+genrule(
+ name = "desugar_testdata_by_disabling_lambda_desugaring",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_without_lambda_desugared.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--min_sdk_version 17 -i $(location :testdata) -o $@ " +
+ "--nodesugar_try_with_resources_if_needed " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar) " +
+ "--only_desugar_javac9_for_lint",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithNullStrategy",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "-Dcom.google.devtools.build.android.desugar.runtime.twr_disable_mimic=true",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$NullDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ "mocked_android_os_sdk_for_testing",
+ ":desugar_testdata_by_desugaring_try_with_resources",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithNullStrategyTwice",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "-Dcom.google.devtools.build.android.desugar.runtime.twr_disable_mimic=true",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$NullDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ "mocked_android_os_sdk_for_testing",
+ ":desugar_testdata_by_desugaring_try_with_resources_twice", # the lib desugared twice
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithMimicStrategy",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$MimicDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ ":desugar_testdata_by_desugaring_try_with_resources",
+ ":mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithMimicStrategyTwice",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$MimicDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ ":desugar_testdata_by_desugaring_try_with_resources_twice", # the lib desugared twice.
+ ":mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithReuseStrategy",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=19",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$ReuseDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ ":desugar_testdata_by_desugaring_try_with_resources",
+ ":mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "DesugarTryWithResourcesFunctionalTestWithReuseStrategyTwice",
+ size = "small",
+ srcs = [
+ "DesugarTryWithResourcesFunctionalTest.java",
+ ],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=19",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$ReuseDesugaringStrategy'",
+ ],
+ tags = ["no_windows"],
+ test_class = "com.google.devtools.build.android.desugar.DesugarTryWithResourcesFunctionalTest",
+ deps = [
+ ":desugar_testdata_by_desugaring_try_with_resources_twice", # the lib desugared twice.
+ ":mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/android/desugar/runtime:throwable_extension_test_utility",
+ "//third_party:asm",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_library(
+ name = "mocked_android_os_sdk_for_testing",
+ srcs = ["mocked_android_framework/android/os/Build.java"],
+)
+
+genrule(
+ name = "desugar_testdata_java8",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_java8",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_java8.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--min_sdk_version 24 -i $(location :testdata_java8) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_java8_like_in_android_studio",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_java8_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_java8_like_in_android_studio.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--copy_bridges_from_classpath " +
+ "--legacy_jacoco_fix " +
+ "--min_sdk_version 24 " +
+ "-i $(location :testdata_java8_like_in_android_studio) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_with_default_methods",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_java8",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_default_methods.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--desugar_interface_method_bodies_if_needed -i $(location :testdata_java8) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_with_default_methods_for_static_initializer_test",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_java8",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_default_methods.output.txt"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--desugar_interface_method_bodies_if_needed -i $(location :testdata_java8) " +
+ "-o desugar_testdata_with_default_methods_for_static_initializer_test.jar " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar) " +
+ " &> $@",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_with_default_methods_again",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_desugared_default_methods.jar",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_default_methods_twice.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--desugar_interface_method_bodies_if_needed -i $(location :testdata_desugared_default_methods.jar) -o $@ " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_core_library",
+ srcs = [
+ ":testdata_core_library",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_core_library.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--core_library -i $(location :testdata_core_library) -o $@ " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_like_in_android_studio",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_like_in_android_studio.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--min_sdk_version 23 " +
+ "--legacy_jacoco_fix " +
+ "--nodesugar_interface_method_bodies_if_needed " +
+ "-i $(location :testdata_like_in_android_studio) -o $@ " +
+ "--copy_bridges_from_classpath " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_and_separate_with_multiple_inputs",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = [
+ "testdata_desugared_with_multiple_inputs.jar",
+ "separate_desugared_with_multiple_inputs.jar",
+ ],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--min_sdk_version 23 --nodesugar_interface_method_bodies_if_needed " +
+ "-i $(location :testdata_like_in_android_studio) -o $(location testdata_desugared_with_multiple_inputs.jar) " +
+ "-i $(location :separate) -o $(location separate_desugared_with_multiple_inputs.jar) " +
+ "--copy_bridges_from_classpath " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_from_directory_to_jar",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = [
+ "testdata_desugared_from_directory_to_jar.jar",
+ ],
+ cmd = """
+ tmpdir=$$(mktemp -d)
+ # unzip input jar in order to pass a folder to desugar
+ pwddir=$$PWD
+ (cd $$tmpdir; $$pwddir/$(location //tools/zip:zipper) x $$pwddir/$(location :testdata_like_in_android_studio))
+ $(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) \
+ --min_sdk_version 23 --nodesugar_interface_method_bodies_if_needed \
+ -i $$tmpdir -o $(location testdata_desugared_from_directory_to_jar.jar) \
+ --copy_bridges_from_classpath \
+ --classpath_entry $(location :separate) \
+ --classpath_entry $(location :guava_base_classpath.jar) \
+ --classpath_entry $(location //third_party/java/jacoco:blaze-agent) \
+ --bootclasspath_entry $(location //tools/defaults:android_jar)
+ rm -rf $$tmpdir
+ """,
+ tags = ["no_windows"],
+ tools = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar",
+ "//tools/zip:zipper",
+ ],
+)
+
+genrule(
+ name = "desugar_testdata_from_directory_to_directory",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = [
+ "testdata_desugared_from_directory_to_directory.jar",
+ ],
+ cmd = """
+ tmpdirIn=$$(mktemp -d)
+ tmpdirOut=$$(mktemp -d)
+ # unzip input jar in order to pass a folder to desugar
+ pwddir=$$PWD
+ (cd $$tmpdirIn; $$pwddir/$(location //tools/zip:zipper) x $$pwddir/$(location :testdata_like_in_android_studio))
+ $(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) \
+ --min_sdk_version 23 --nodesugar_interface_method_bodies_if_needed \
+ -i $$tmpdirIn -o $$tmpdirOut \
+ --copy_bridges_from_classpath \
+ --classpath_entry $(location :separate) \
+ --classpath_entry $(location :guava_base_classpath.jar) \
+ --classpath_entry $(location //third_party/java/jacoco:blaze-agent) \
+ --bootclasspath_entry $(location //tools/defaults:android_jar)
+ pushd $$tmpdirOut
+ $$pwddir/$(location //tools/zip:zipper) c $$pwddir/$(location testdata_desugared_from_directory_to_directory.jar) $$(find *)
+ popd
+ rm -rf $$tmpdirIn
+ rm -rf $$tmpdirOut
+ """,
+ tags = ["no_windows"],
+ tools = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar",
+ "//tools/zip:zipper",
+ ],
+)
+
+genrule(
+ name = "desugar_testdata_with_classpath_directory",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata_like_in_android_studio",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = [
+ "testdata_desugared_with_classpath_directory.jar",
+ ],
+ cmd = """
+ tmpdir=$$(mktemp -d)
+ # unzip a classpath entry jar in order to pass a folder to desugar
+ pwddir=$$PWD
+ (cd $$tmpdir; $$pwddir/$(location //tools/zip:zipper) x $$pwddir/$(location :separate))
+ $(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) \
+ --min_sdk_version 23 --nodesugar_interface_method_bodies_if_needed \
+ -i $(location :testdata_like_in_android_studio) -o $(location testdata_desugared_with_classpath_directory.jar) \
+ --copy_bridges_from_classpath \
+ --classpath_entry $$tmpdir \
+ --classpath_entry $(location :guava_base_classpath.jar) \
+ --classpath_entry $(location //third_party/java/jacoco:blaze-agent) \
+ --bootclasspath_entry $(location //tools/defaults:android_jar)
+ rm -rf $$tmpdir
+ """,
+ tags = ["no_windows"],
+ tools = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar",
+ "//tools/zip:zipper",
+ ],
+)
+
+# This target tests the flag -desugar_try_with_resources_if_needed, for desugaring
+# try-with-resources statements.
+genrule(
+ name = "desugar_testdata_by_desugaring_try_with_resources",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_for_try_with_resources.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :testdata) -o $@ " +
+ "--min_sdk_version 17 --desugar_try_with_resources_if_needed " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+# Desugars an interface with a default and a static interface method that was
+# processed by a legacy version of JaCoCo that doesn't emit interface markers
+# when calling methods it generated in interfaces (b/62623509).
+genrule(
+ name = "desugar_default_method_with_legacy_coverage",
+ srcs = [
+ "jacoco_0_7_5_default_method.jar",
+ # Depend on Jacoco runtime in case :testdata_java8 was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["jacoco_0_7_5_default_method_desugared.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--copy_bridges_from_classpath " +
+ "--legacy_jacoco_fix " +
+ "--min_sdk_version 19 " +
+ "-i $(location :jacoco_0_7_5_default_method.jar) -o $@ " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+# Disable desugaring try-with-resources by specifying a min_sdk_version above 18.
+genrule(
+ name = "desugar_testdata_by_disabling_desugaring_try_with_resources_with_minsdkversion_above_18",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":testdata",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_for_NO_desugaring_try_with_resources.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :testdata) -o $@ " +
+ "--min_sdk_version 19 --desugar_try_with_resources_if_needed " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_testdata_by_desugaring_try_with_resources_twice",
+ srcs = [
+ ":guava_base_classpath.jar",
+ ":separate",
+ ":desugar_testdata_by_desugaring_try_with_resources",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["testdata_desugared_for_try_with_resources_twice.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "--nodesugar_interface_method_bodies_if_needed -i $(location :desugar_testdata_by_desugaring_try_with_resources) -o $@ " +
+ "--min_sdk_version 17 --desugar_try_with_resources_if_needed " +
+ "--classpath_entry $(location :separate) " +
+ "--classpath_entry $(location :guava_base_classpath.jar) " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+# This target allows using the desugared jar as a regular dependency of the test
+java_import(
+ name = "testdata_desugared",
+ jars = ["testdata_desugared.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_twice",
+ jars = ["testdata_desugared_twice.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_java8",
+ jars = ["testdata_desugared_java8.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_java8_like_in_android_studio",
+ jars = ["testdata_desugared_java8_like_in_android_studio.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_default_methods",
+ jars = ["testdata_desugared_default_methods.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_default_methods_twice",
+ jars = ["testdata_desugared_default_methods_twice.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_core_library",
+ jars = ["testdata_desugared_core_library.jar"],
+)
+
+java_import(
+ name = "separate_desugared_with_multiple_inputs",
+ jars = ["separate_desugared_with_multiple_inputs.jar"],
+)
+
+java_import(
+ name = "testdata_desugared_with_multiple_inputs",
+ jars = ["testdata_desugared_with_multiple_inputs.jar"],
+ deps = [":separate_desugared_with_multiple_inputs"],
+)
+
+java_import(
+ name = "testdata_desugared_from_directory_to_jar",
+ jars = ["testdata_desugared_from_directory_to_jar.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_from_directory_to_directory",
+ jars = ["testdata_desugared_from_directory_to_directory.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_with_classpath_directory",
+ jars = ["testdata_desugared_with_classpath_directory.jar"],
+ deps = [":separate"],
+)
+
+java_import(
+ name = "testdata_desugared_like_in_android_studio",
+ jars = ["testdata_desugared_like_in_android_studio.jar"],
+ deps = [":separate"],
+)
+
+sh_test(
+ name = "stateless_lambda_has_no_factory_method_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location stateless_lambda_disassembled_golden.txt)",
+ "$(location stateless_lambda_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show a $instance field and *no* get$Lambda() method
+ "stateless_lambda_disassembled_golden.txt",
+ ":stateless_lambda_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_stateless_lambda",
+ srcs = [":testdata_desugared.jar"],
+ outs = ["stateless_lambda_disassembled.txt"],
+ cmd = """
+$(JAVABASE)/bin/javap -c -p -cp $< 'com.google.devtools.build.android.desugar.testdata.Lambda$$$$Lambda$$0' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "capture_lambda_has_no_factory_method_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location capture_lambda_disassembled_golden.txt)",
+ "$(location capture_lambda_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show a package-private constructor and *no* get$Lambda() method
+ "capture_lambda_disassembled_golden.txt",
+ ":capture_lambda_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_capture_lambda",
+ srcs = [":testdata_desugared.jar"],
+ outs = ["capture_lambda_disassembled.txt"],
+ cmd = """
+$(JAVABASE)/bin/javap -c -p -cp $< 'com.google.devtools.build.android.desugar.testdata.CaptureLambda$$$$Lambda$$0' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "simple_method_reference_has_no_factory_method_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location simple_instance_method_reference_disassembled_golden.txt)",
+ "$(location simple_instance_method_reference_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show a package-private constructor and *no* get$Lambda() method
+ "simple_instance_method_reference_disassembled_golden.txt",
+ ":simple_instance_method_reference_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_simple_instance_method_reference",
+ srcs = [":testdata_desugared.jar"],
+ outs = ["simple_instance_method_reference_disassembled.txt"],
+ cmd = """
+$(JAVABASE)/bin/javap -c -p -cp $< 'com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass$$$$Lambda$$0' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "interface_has_method_bodies_removed",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location interface_with_desugared_method_bodies_disassembled_golden.txt)",
+ "$(location interface_with_desugared_method_bodies_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show abstract methods only and *no* static methods
+ "interface_with_desugared_method_bodies_disassembled_golden.txt",
+ ":interface_with_desugared_method_bodies_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_interface_with_method_bodies",
+ srcs = [":testdata_desugared_default_methods.jar"],
+ outs = ["interface_with_desugared_method_bodies_disassembled.txt"],
+ # drop jacoco fields and static initializers, which jacoco may add, so the output is stable
+ # with or without coverage instrumentation
+ cmd = """
+$(JAVABASE)/bin/javap -p -cp $< 'com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod' | grep -v 'jacoco' | grep -v 'static {}' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "inherited_abstract_method_gets_no_default_method_stub",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location class_with_inherited_abstract_method_disassembled_golden.txt)",
+ "$(location class_with_inherited_abstract_method_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show *no* methods
+ "class_with_inherited_abstract_method_disassembled_golden.txt",
+ ":class_with_inherited_abstract_method_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_class_with_inherited_abstract_method",
+ srcs = [":testdata_desugared_default_methods.jar"],
+ outs = ["class_with_inherited_abstract_method_disassembled.txt"],
+ # drop jacoco fields and static initializers, which jacoco may add, so the output is stable
+ # with or without coverage instrumentation
+ cmd = """
+$(JAVABASE)/bin/javap -p -cp $< 'com.google.devtools.build.android.desugar.testdata.java8.Named$$AbstractName' | grep -v 'jacoco' | grep -v 'static {}' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "no_stubs_for_lambdas_in_implemented_interface",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location class_with_lambdas_in_implemented_interface_disassembled_golden.txt)",
+ "$(location class_with_lambdas_in_implemented_interface_disassembled.txt)",
+ ],
+ data = [
+ # Golden file should show *no* lambda$xxx methods (and 4 stubs for default methods)
+ "class_with_lambdas_in_implemented_interface_disassembled_golden.txt",
+ ":class_with_lambdas_in_implemented_interface_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_class_with_lambdas_in_implemented_interface",
+ srcs = [":testdata_desugared_default_methods.jar"],
+ outs = ["class_with_lambdas_in_implemented_interface_disassembled.txt"],
+ # drop jacoco fields and static initializers, which jacoco may add, so the output is stable
+ # with or without coverage instrumentation
+ cmd = """
+$(JAVABASE)/bin/javap -p -cp $< 'com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod$$Concrete' | grep -v 'jacoco' | grep -v 'static {}' > $@
+""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+sh_test(
+ name = "desugar_idempotency_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location :capture_lambda_desugared.jar)",
+ "$(location :capture_lambda_desugared_twice.jar)",
+ ],
+ data = [
+ ":capture_lambda_desugared.jar",
+ ":capture_lambda_desugared_twice.jar",
+ ],
+ tags = ["no_windows"],
+)
+
+# Smaller Jar used for idempotency test. CaptureLambda can be desugared without
+# any need to fix up the resulting lambda class. Running the desugaring tool
+# over lambda classes that required fixes somehow perturbs the constant pool
+# (but nothing else) so for simplicity we use this Jar for the idempotency test
+# we don't run into the perturbance issue.
+java_library(
+ name = "capture_lambda",
+ srcs = ["testdata/CaptureLambda.java"],
+)
+
+genrule(
+ name = "desugar_capture_lambda",
+ srcs = [
+ ":capture_lambda",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["capture_lambda_desugared.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "-i $(location :capture_lambda) -o $@ " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+genrule(
+ name = "desugar_capture_lambda_again",
+ srcs = [
+ ":capture_lambda_desugared.jar",
+ # Depend on Jacoco runtime in case :testdata was instrumented with
+ # --collect_code_coverage or by running "blaze coverage"
+ "//third_party/java/jacoco:blaze-agent",
+ "//tools/defaults:android_jar",
+ ],
+ outs = ["capture_lambda_desugared_twice.jar"],
+ cmd = "$(location //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar) " +
+ "-i $(location :capture_lambda_desugared.jar) -o $@ " +
+ "--classpath_entry $(location //third_party/java/jacoco:blaze-agent) " +
+ "--bootclasspath_entry $(location //tools/defaults:android_jar)",
+ tags = ["no_windows"],
+ tools = ["//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar"],
+)
+
+sh_test(
+ name = "testdata_sanity_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location :baseclass_lambda_signature.txt)",
+ "$(location :subclass_lambda_signature.txt)",
+ ],
+ data = [
+ ":baseclass_lambda_signature.txt",
+ ":subclass_lambda_signature.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "baseclass_lambda_signature",
+ srcs = [":testdata"],
+ outs = [
+ "baseclass_disassembled.txt",
+ "baseclass_lambda_signature.txt",
+ ],
+ cmd = """
+$(JAVABASE)/bin/javap -p -cp $< com.google.devtools.build.android.desugar.testdata.OuterReferenceLambda > $(location baseclass_disassembled.txt)
+grep lambda $(location baseclass_disassembled.txt) > $(location baseclass_lambda_signature.txt)""",
+ tags = ["no_windows"],
+ tools = ["@bazel_tools//tools/jdk"],
+)
+
+genrule(
+ name = "subclass_lambda_signature",
+ srcs = [":testdata"],
+ outs = [
+ "subclass_disassembled.txt",
+ "subclass_lambda_signature.txt",
+ ],
+ cmd = """
+$(JAVABASE)/bin/javap -p -cp $< com.google.devtools.build.android.desugar.testdata.LambdaInOverride > $(location subclass_disassembled.txt)
+grep lambda $(location subclass_disassembled.txt) > $(location subclass_lambda_signature.txt)""",
+ tags = ["no_windows"],
+ tools = [
+ "@bazel_tools//tools/jdk",
+ ],
+)
+
+# b/62623509 regression test. Calls to jacoco-generated method in interface
+# need to be rewritten to call the companion class even though the original
+# bytecode falsely doesn't indicate that the method is declared in an
+# interface. Jacoco-generated field is *not* moved.
+sh_test(
+ name = "jacoco_legacy_default_method_regression_test",
+ srcs = ["diff.sh"],
+ args = [
+ "$(location :jacoco_legacy_default_method_companion_disassembled_golden.txt)",
+ "$(location :jacoco_legacy_default_method_companion_disassembled.txt)",
+ ],
+ data = [
+ "jacoco_legacy_default_method_companion_disassembled_golden.txt",
+ ":jacoco_legacy_default_method_companion_disassembled.txt",
+ ],
+ tags = ["no_windows"],
+)
+
+genrule(
+ name = "dump_jacoco_legacy_default_method_companion",
+ srcs = [":jacoco_0_7_5_default_method_desugared.jar"],
+ outs = ["jacoco_legacy_default_method_companion_disassembled.txt"],
+ cmd = """$(JAVABASE)/bin/javap -c -p -cp $< 'com/example/gavra/java8coverage/Defaults$$$$CC' > $@""",
+ tags = ["no_windows"],
+ tools = [
+ "@bazel_tools//tools/jdk",
+ ],
+)
+
+alias(
+ name = "guava_base_classpath.jar",
+ actual = "//third_party:guava/guava-21.0.jar",
+)
+
+java_binary(
+ name = "generate_synthetic_method_with_lambda_name_convention",
+ srcs = ["Bug62456849TestDataGenerator.java"],
+ main_class = "com.google.devtools.build.android.desugar.Bug62456849TestDataGenerator",
+ deps = [
+ "//third_party:asm",
+ "//third_party:guava",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/android/desugar/Bug62456849TestDataGenerator.java b/src/test/java/com/google/devtools/build/android/desugar/Bug62456849TestDataGenerator.java
new file mode 100644
index 0000000000..627b6c7ccd
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/Bug62456849TestDataGenerator.java
@@ -0,0 +1,104 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.UnmodifiableIterator;
+import com.google.common.io.ByteStreams;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Test data generator for b/62456849. This class converts methods satisfying the following
+ * conditions to synthetic methods.
+ * <li>The name starts with "lambda$"
+ * <li>Not synthetic
+ */
+public class Bug62456849TestDataGenerator {
+
+ public static void main(String[] args) throws IOException {
+ checkArgument(
+ args.length == 2,
+ "Usage: %s <input-jar> <output-jar>",
+ Bug62456849TestDataGenerator.class.getName());
+ Path inputJar = Paths.get(args[0]);
+ checkArgument(Files.isRegularFile(inputJar), "The input jar %s is not a file", inputJar);
+ Path outputJar = Paths.get(args[1]);
+
+ try (ZipFile inputZip = new ZipFile(inputJar.toFile());
+ ZipOutputStream outZip =
+ new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(outputJar)))) {
+ for (UnmodifiableIterator<? extends ZipEntry> it =
+ Iterators.forEnumeration(inputZip.entries());
+ it.hasNext(); ) {
+ ZipEntry entry = it.next();
+ String entryName = entry.getName();
+ byte[] content =
+ entryName.endsWith(".class")
+ ? convertClass(inputZip, entry)
+ : readEntry(inputZip, entry);
+ writeToZipFile(outZip, entryName, content);
+ }
+ }
+ }
+
+ private static void writeToZipFile(ZipOutputStream outZip, String entryName, byte[] content)
+ throws IOException {
+ ZipEntry result = new ZipEntry(entryName);
+ result.setTime(0L);
+ outZip.putNextEntry(result);
+ outZip.write(content);
+ outZip.closeEntry();
+ }
+
+ private static byte[] readEntry(ZipFile file, ZipEntry entry) throws IOException {
+ try (InputStream is = file.getInputStream(entry)) {
+ return ByteStreams.toByteArray(is);
+ }
+ }
+
+ private static byte[] convertClass(ZipFile file, ZipEntry entry) throws IOException {
+ try (InputStream content = file.getInputStream(entry)) {
+ ClassReader reader = new ClassReader(content);
+ ClassWriter writer = new ClassWriter(0);
+ ClassVisitor converter =
+ new ClassVisitor(Opcodes.ASM5, writer) {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ if (name.startsWith("lambda$") && (access & Opcodes.ACC_SYNTHETIC) == 0) {
+ access |= Opcodes.ACC_SYNTHETIC;
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+ };
+ reader.accept(converter, 0);
+ return writer.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java b/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java
new file mode 100644
index 0000000000..cdc32639b3
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java
@@ -0,0 +1,234 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.DefaultMethodClassFixer.InterfaceComparator.INSTANCE;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Closer;
+import com.google.devtools.build.android.desugar.Desugar.ThrowingClassLoader;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/** Unit Test for {@link DefaultMethodClassFixer} */
+@RunWith(JUnit4.class)
+public class DefaultMethodClassFixerTest {
+
+ private ClassReaderFactory classpathReader;
+ private ClassReaderFactory bootclassPath;
+ private ClassLoader classLoader;
+ private Closer closer;
+
+ @Before
+ public void setup() throws IOException {
+ closer = Closer.create();
+ CoreLibraryRewriter rewriter = new CoreLibraryRewriter("");
+
+ IndexedInputs indexedInputs =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.input"));
+ IndexedInputs indexedClasspath =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.classpath"));
+ IndexedInputs indexedBootclasspath =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.bootclasspath"));
+
+ bootclassPath = new ClassReaderFactory(indexedBootclasspath, rewriter);
+ IndexedInputs indexedClasspathAndInputFiles = indexedClasspath.withParent(indexedInputs);
+ classpathReader = new ClassReaderFactory(indexedClasspathAndInputFiles, rewriter);
+ ClassLoader bootclassloader =
+ new HeaderClassLoader(indexedBootclasspath, rewriter, new ThrowingClassLoader());
+ classLoader = new HeaderClassLoader(indexedClasspathAndInputFiles, rewriter, bootclassloader);
+ }
+
+ @After
+ public void teardown() throws IOException {
+ closer.close();
+ }
+
+ private static IndexedInputs toIndexedInputs(Closer closer, String stringPathList)
+ throws IOException {
+ final List<Path> pathList = readPathListFromString(stringPathList);
+ return new IndexedInputs(Desugar.toRegisteredInputFileProvider(closer, pathList));
+ }
+
+ private static List<Path> readPathListFromString(String pathList) {
+ return Arrays.stream(checkNotNull(pathList).split(File.pathSeparator))
+ .map(Paths::get)
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ private byte[] desugar(String classname) {
+ ClassReader reader = classpathReader.readIfKnown(classname);
+ return desugar(reader);
+ }
+
+ private byte[] desugar(ClassReader reader) {
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ DefaultMethodClassFixer fixer =
+ new DefaultMethodClassFixer(writer, classpathReader, bootclassPath, classLoader);
+ reader.accept(fixer, 0);
+ return writer.toByteArray();
+ }
+
+ private byte[] desugar(byte[] classContent) {
+ ClassReader reader = new ClassReader(classContent);
+ return desugar(reader);
+ }
+
+ @Test
+ public void testDesugaringDirectImplementation() {
+ byte[] desugaredClass =
+ desugar(
+ ("com.google.devtools.build.android.desugar.testdata.java8."
+ + "DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne$C")
+ .replace('.', '/'));
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(desugaredClass);
+
+ byte[] desugaredClassAgain = desugar(desugaredClass);
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ desugaredClassAgain);
+
+ desugaredClassAgain = desugar(desugaredClassAgain);
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ desugar(desugaredClassAgain));
+ }
+
+ private void checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ byte[] classContent) {
+ ClassReader reader = new ClassReader(classContent);
+ reader.accept(
+ new ClassVisitor(Opcodes.ASM5) {
+
+ class ClinitMethod extends MethodNode {
+
+ public ClinitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ super(Opcodes.ASM5, access, name, desc, signature, exceptions);
+ }
+ }
+
+ private ClinitMethod clinit;
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ if ("<clinit>".equals(name)) {
+ assertThat(clinit).isNull();
+ clinit = new ClinitMethod(access, name, desc, signature, exceptions);
+ return clinit;
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ @Override
+ public void visitEnd() {
+ assertThat(clinit).isNotNull();
+ assertThat(clinit.instructions.size()).isEqualTo(3);
+ AbstractInsnNode instruction = clinit.instructions.getFirst();
+ {
+ assertThat(instruction).isInstanceOf(MethodInsnNode.class);
+ MethodInsnNode field = (MethodInsnNode) instruction;
+ assertThat(field.owner)
+ .isEqualTo(
+ "com/google/devtools/build/android/desugar/testdata/java8/"
+ + "DefaultInterfaceMethodWithStaticInitializer"
+ + "$TestInterfaceSetOne$I1$$CC");
+ assertThat(field.name)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME);
+ assertThat(field.desc)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
+ }
+ {
+ instruction = instruction.getNext();
+ assertThat(instruction).isInstanceOf(MethodInsnNode.class);
+ MethodInsnNode field = (MethodInsnNode) instruction;
+ assertThat(field.owner)
+ .isEqualTo(
+ "com/google/devtools/build/android/desugar/testdata/java8/"
+ + "DefaultInterfaceMethodWithStaticInitializer"
+ + "$TestInterfaceSetOne$I2$$CC");
+ assertThat(field.name)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME);
+ assertThat(field.desc)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
+ }
+ {
+ instruction = instruction.getNext();
+ assertThat(instruction).isInstanceOf(InsnNode.class);
+ assertThat(instruction.getOpcode()).isEqualTo(Opcodes.RETURN);
+ }
+ }
+ },
+ 0);
+ }
+
+ @Test
+ public void testInterfaceComparator() {
+ assertThat(INSTANCE.compare(Runnable.class, Runnable.class)).isEqualTo(0);
+ assertThat(INSTANCE.compare(Runnable.class, MyRunnable1.class)).isEqualTo(1);
+ assertThat(INSTANCE.compare(MyRunnable2.class, Runnable.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable3.class, Runnable.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable1.class, MyRunnable3.class)).isEqualTo(1);
+ assertThat(INSTANCE.compare(MyRunnable3.class, MyRunnable2.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable2.class, MyRunnable1.class)).isGreaterThan(0);
+ assertThat(INSTANCE.compare(Runnable.class, Serializable.class)).isGreaterThan(0);
+ assertThat(INSTANCE.compare(Serializable.class, Runnable.class)).isLessThan(0);
+
+ TreeSet<Class<?>> orderedSet = new TreeSet<>(INSTANCE);
+ orderedSet.add(Serializable.class);
+ orderedSet.add(Runnable.class);
+ orderedSet.add(MyRunnable2.class);
+ orderedSet.add(Callable.class);
+ orderedSet.add(Serializable.class);
+ orderedSet.add(MyRunnable1.class);
+ orderedSet.add(MyRunnable3.class);
+ assertThat(orderedSet)
+ .containsExactly(
+ MyRunnable3.class, // subtype before supertype(s)
+ MyRunnable1.class,
+ MyRunnable2.class,
+ Serializable.class, // java... comes textually after com.google...
+ Runnable.class,
+ Callable.class)
+ .inOrder();
+ }
+
+ private static interface MyRunnable1 extends Runnable {}
+
+ private static interface MyRunnable2 extends Runnable {}
+
+ private static interface MyRunnable3 extends MyRunnable1, MyRunnable2 {}
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarCoreLibraryFunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarCoreLibraryFunctionalTest.java
new file mode 100644
index 0000000000..cebbfc9462
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarCoreLibraryFunctionalTest.java
@@ -0,0 +1,34 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test that exercises classes in the {@code testdata} package. This is meant to be run against a
+ * desugared version of those classes, which in turn exercise various desugaring features.
+ */
+@RunWith(JUnit4.class)
+public class DesugarCoreLibraryFunctionalTest {
+
+ @Test
+ public void testAutoboxedTypeLambda() {
+ AutoboxedTypes.Lambda lambdaUse = AutoboxedTypes.autoboxedTypeLambda(1);
+ assertThat(lambdaUse.charAt("Karen")).isEqualTo("a");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarDefaultMethodsFunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarDefaultMethodsFunctionalTest.java
new file mode 100644
index 0000000000..97d02a48a7
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarDefaultMethodsFunctionalTest.java
@@ -0,0 +1,29 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Variant of {@link DesugarJava8FunctionalTest} that expects default and static interface methods
+ * to be desugared
+ */
+@RunWith(JUnit4.class)
+public final class DesugarDefaultMethodsFunctionalTest extends DesugarJava8FunctionalTest {
+
+ public DesugarDefaultMethodsFunctionalTest() {
+ super(/*expectBridgesFromSeparateTarget*/ true, /*expectDefaultMethods*/ false);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarFunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarFunctionalTest.java
new file mode 100644
index 0000000000..14e8f37491
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarFunctionalTest.java
@@ -0,0 +1,339 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.lang.reflect.Modifier.isFinal;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.ByteStreams;
+import com.google.devtools.build.android.desugar.testdata.CaptureLambda;
+import com.google.devtools.build.android.desugar.testdata.ConcreteFunction;
+import com.google.devtools.build.android.desugar.testdata.ConstructorReference;
+import com.google.devtools.build.android.desugar.testdata.GuavaLambda;
+import com.google.devtools.build.android.desugar.testdata.InnerClassLambda;
+import com.google.devtools.build.android.desugar.testdata.InterfaceWithLambda;
+import com.google.devtools.build.android.desugar.testdata.Lambda;
+import com.google.devtools.build.android.desugar.testdata.LambdaInOverride;
+import com.google.devtools.build.android.desugar.testdata.MethodReference;
+import com.google.devtools.build.android.desugar.testdata.MethodReferenceInSubclass;
+import com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass;
+import com.google.devtools.build.android.desugar.testdata.OuterReferenceLambda;
+import com.google.devtools.build.android.desugar.testdata.SpecializedFunction;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test that exercises classes in the {@code testdata} package. This is meant to be run against a
+ * desugared version of those classes, which in turn exercise various desugaring features.
+ */
+@RunWith(JUnit4.class)
+public class DesugarFunctionalTest {
+
+ private final int expectedBridgesFromSameTarget;
+ private final int expectedBridgesFromSeparateTarget;
+ private final boolean expectLambdaMethodsInInterfaces;
+
+ public DesugarFunctionalTest() {
+ this(3, 1, false);
+ }
+
+ /** Constructor for testing desugar while allowing default and static interface methods. */
+ protected DesugarFunctionalTest(
+ boolean expectBridgesFromSeparateTarget, boolean expectDefaultMethods) {
+ this(
+ expectDefaultMethods ? 0 : 3,
+ expectBridgesFromSeparateTarget ? 1 : 0,
+ expectDefaultMethods);
+ }
+
+ private DesugarFunctionalTest(int bridgesFromSameTarget, int bridgesFromSeparateTarget,
+ boolean lambdaMethodsInInterfaces) {
+ this.expectedBridgesFromSameTarget = bridgesFromSameTarget;
+ this.expectedBridgesFromSeparateTarget = bridgesFromSeparateTarget;
+ this.expectLambdaMethodsInInterfaces = lambdaMethodsInInterfaces;
+ }
+
+ @Test
+ public void testGuavaLambda() {
+ GuavaLambda lambdaUse = new GuavaLambda(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(lambdaUse.as()).containsExactly("Alex");
+ }
+
+ @Test
+ public void testJavaLambda() {
+ Lambda lambdaUse = new Lambda(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(lambdaUse.as()).containsExactly("Alex");
+ }
+
+ @Test
+ public void testLambdaForIntersectionType() throws Exception {
+ assertThat(Lambda.hello().call()).isEqualTo("hello");
+ }
+
+ @Test
+ public void testCapturingLambda() {
+ CaptureLambda lambdaUse = new CaptureLambda(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(lambdaUse.prefixed("L")).containsExactly("Larry");
+ }
+
+ @Test
+ public void testOuterReferenceLambda() throws Exception {
+ OuterReferenceLambda lambdaUse = new OuterReferenceLambda(ImmutableList.of("Sergey", "Larry"));
+ assertThat(lambdaUse.filter(ImmutableList.of("Larry", "Alex"))).containsExactly("Larry");
+ assertThat(
+ isFinal(
+ OuterReferenceLambda.class
+ .getDeclaredMethod("lambda$filter$0$OuterReferenceLambda", String.class)
+ .getModifiers()))
+ .isTrue();
+ }
+
+ /**
+ * Tests a lambda in a subclass whose generated lambda$ method has the same name and signature
+ * as a lambda$ method generated by Javac in a superclass and both of these methods are used
+ * in the implementation of the subclass (by calling super). Naively this leads to wrong
+ * behavior (in this case, return a non-empty list) because the lambda$ in the superclass is never
+ * used once its made non-private during desugaring.
+ */
+ @Test
+ public void testOuterReferenceLambdaInOverride() throws Exception {
+ OuterReferenceLambda lambdaUse = new LambdaInOverride(ImmutableList.of("Sergey", "Larry"));
+ assertThat(lambdaUse.filter(ImmutableList.of("Larry", "Alex"))).isEmpty();
+ assertThat(
+ isFinal(
+ LambdaInOverride.class
+ .getDeclaredMethod("lambda$filter$0$LambdaInOverride", String.class)
+ .getModifiers()))
+ .isTrue();
+ }
+
+ @Test
+ public void testLambdaInAnonymousClassReferencesSurroundingMethodParameter() throws Exception {
+ assertThat(Lambda.mult(21).apply(2).call()).isEqualTo(42);
+ }
+
+ /** Tests a lambda that accesses a method parameter across 2 nested anonymous classes. */
+ @Test
+ public void testLambdaInNestedAnonymousClass() throws Exception {
+ InnerClassLambda lambdaUse = new InnerClassLambda(ImmutableList.of("Sergey", "Larry"));
+ assertThat(lambdaUse.prefixFilter("L").apply(ImmutableList.of("Lois", "Larry")).call())
+ .containsExactly("Larry");
+ }
+
+ @Test
+ public void testClassMethodReference() {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ StringBuilder dest = new StringBuilder();
+ methodrefUse.appendAll(dest);
+ assertThat(dest.toString()).isEqualTo("SergeyLarryAlex");
+ }
+
+ // Regression test for b/33378312
+ @Test
+ public void testHiddenMethodReference() {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(methodrefUse.intersect(ImmutableList.of("Alex", "Sundar"))).containsExactly("Alex");
+ }
+
+ // Regression test for b/33378312
+ @Test
+ public void testHiddenStaticMethodReference() {
+ MethodReference methodrefUse =
+ new MethodReference(ImmutableList.of("Sergey", "Larry", "Sundar"));
+ assertThat(methodrefUse.some()).containsExactly("Sergey", "Sundar");
+ }
+
+ @Test
+ public void testDuplicateHiddenMethodReference() {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(methodrefUse.onlyIn(ImmutableList.of("Alex", "Sundar"))).containsExactly("Sundar");
+ }
+
+ // Regression test for b/36201257
+ @Test
+ public void testMethodReferenceThatNeedsBridgeInSubclass() {
+ MethodReferenceInSubclass methodrefUse =
+ new MethodReferenceInSubclass(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(methodrefUse.containsE()).containsExactly("Sergey", "Alex");
+ assertThat(methodrefUse.startsWithL()).containsExactly("Larry");
+ // Test sanity: make sure sub- and superclass have bridge methods with matching descriptors but
+ // different names
+ Method superclassBridge = findOnlyBridge(MethodReferenceSuperclass.class);
+ Method subclassBridge = findOnlyBridge(MethodReferenceInSubclass.class);
+ assertThat(superclassBridge.getName()).isNotEqualTo(subclassBridge.getName());
+ assertThat(superclassBridge.getParameterTypes()).isEqualTo(subclassBridge.getParameterTypes());
+ }
+
+ private Method findOnlyBridge(Class<?> clazz) {
+ Method result = null;
+ for (Method m : clazz.getDeclaredMethods()) {
+ if (m.getName().startsWith("bridge$")) {
+ assertThat(result).named(m.getName()).isNull();
+ result = m;
+ }
+ }
+ assertThat(result).named(clazz.getSimpleName()).isNotNull();
+ return result;
+ }
+
+ // Regression test for b/33378312
+ @Test
+ public void testThrowingPrivateMethodReference() throws Exception {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry"));
+ Callable<?> stringer = methodrefUse.stringer();
+ try {
+ stringer.call();
+ fail("IOException expected");
+ } catch (IOException expected) {
+ assertThat(expected).hasMessage("SergeyLarry");
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ // Regression test for b/33304582
+ @Test
+ public void testInterfaceMethodReference() {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ MethodReference.Transformer<String> transform = new MethodReference.Transformer<String>() {
+ @Override
+ public String transform(String input) {
+ return input.substring(1);
+ }
+ };
+ assertThat(methodrefUse.transform(transform)).containsExactly("ergey", "arry", "lex");
+ }
+
+ @Test
+ public void testConstructorReference() {
+ ConstructorReference initRefUse = new ConstructorReference(ImmutableList.of("1", "2", "42"));
+ assertThat(initRefUse.toInt()).containsExactly(1, 2, 42);
+ }
+
+ // Regression test for b/33304582
+ @Test
+ public void testPrivateConstructorReference() {
+ ConstructorReference initRefUse = ConstructorReference.singleton().apply("17");
+ assertThat(initRefUse.toInt()).containsExactly(17);
+ }
+
+ // This test is similar to testPrivateConstructorReference but the private constructor of an inner
+ // class is used as a method reference. That causes Javac to generate a bridge constructor and
+ // a lambda body method that calls it, so the desugaring step doesn't need to do anything to make
+ // the private constructor visible. This is mostly to double-check that we don't interfere with
+ // this "already-working" scenario.
+ @Test
+ public void testPrivateConstructorAccessedThroughJavacGeneratedBridge() {
+ try {
+ @SuppressWarnings("unused") // local is needed to make ErrorProne happy
+ ConstructorReference unused = ConstructorReference.emptyThroughJavacGeneratedBridge().get();
+ fail("RuntimeException expected");
+ } catch (RuntimeException expected) {
+ assertThat(expected).hasMessage("got it!");
+ }
+ }
+
+ @Test
+ public void testExpressionMethodReference() {
+ assertThat(
+ MethodReference.stringChars(new StringBuilder().append("Larry").append("Sergey"))
+ .apply(5))
+ .isEqualTo('S');
+ }
+
+ @Test
+ public void testFieldMethodReference() {
+ MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(methodrefUse.toPredicate().test("Larry")).isTrue();
+ assertThat(methodrefUse.toPredicate().test("Sundar")).isFalse();
+ }
+
+ @Test
+ public void testConcreteFunctionWithInheritedBridgeMethods() {
+ assertThat(new ConcreteFunction().apply("1234567890987654321")).isEqualTo(1234567890987654321L);
+ assertThat(ConcreteFunction.parseAll(ImmutableList.of("5", "17"), new ConcreteFunction()))
+ .containsExactly(5L, 17L);
+ }
+
+ @Test
+ public void testLambdaWithInheritedBridgeMethods() throws Exception {
+ assertThat(ConcreteFunction.toInt().apply("123456789")).isEqualTo(123456789);
+ assertThat(ConcreteFunction.parseAll(ImmutableList.of("5", "17"), ConcreteFunction.toInt()))
+ .containsExactly(5, 17);
+ // Expect String apply(Number) and any expected bridges
+ assertThat(ConcreteFunction.toInt().getClass().getDeclaredMethods())
+ .hasLength(expectedBridgesFromSameTarget + 1);
+ // Sanity check that we only copied over methods, no fields, from the functional interface
+ try {
+ ConcreteFunction.toInt().getClass().getDeclaredField("DO_NOT_COPY_INTO_LAMBDA_CLASSES");
+ fail("NoSuchFieldException expected");
+ } catch (NoSuchFieldException expected) {}
+ assertThat(SpecializedFunction.class.getDeclaredField("DO_NOT_COPY_INTO_LAMBDA_CLASSES"))
+ .isNotNull(); // test sanity
+ }
+
+ /** Tests lambdas with bridge methods when the implemented interface is in a separate target.*/
+ @Test
+ public void testLambdaWithBridgeMethodsForInterfaceInSeparateTarget() {
+ assertThat(ConcreteFunction.isInt().test(123456789L)).isTrue();
+ assertThat(
+ ConcreteFunction.doFilter(
+ ImmutableList.of(123456789L, 1234567890987654321L),
+ ConcreteFunction.isInt()))
+ .containsExactly(123456789L);
+ // Expect test(Number) and any expected bridges
+ assertThat(ConcreteFunction.isInt().getClass().getDeclaredMethods())
+ .hasLength(expectedBridgesFromSeparateTarget + 1);
+ }
+
+ @Test
+ public void testLambdaInInterfaceStaticInitializer() {
+ assertThat(InterfaceWithLambda.DIGITS).containsExactly("0", "1").inOrder();
+ // <clinit> doesn't count but if there's a lambda method then Jacoco adds more methods
+ assertThat(InterfaceWithLambda.class.getDeclaredMethods().length != 0)
+ .isEqualTo(expectLambdaMethodsInInterfaces);
+ }
+
+ /**
+ * Sanity-checks that the resource file included in the original Jar is still there unchanged.
+ */
+ @Test
+ public void testResourcePreserved() throws Exception {
+ try (InputStream content = Lambda.class.getResource("testresource.txt").openStream()) {
+ assertThat(new String(ByteStreams.toByteArray(content), UTF_8)).isEqualTo("test");
+ }
+ }
+
+ /**
+ * Test for b/62456849. After desugar, the method {@code lambda$mult$0} should still be in the
+ * class.
+ */
+ @Test
+ public void testCallMethodWithLambdaNamingConvention()
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ Method method = Lambda.class.getDeclaredMethod("lambda$mult$0");
+ Object value = method.invoke(null);
+ assertThat(value).isInstanceOf(Integer.class);
+ assertThat((Integer) value).isEqualTo(0);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8FunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8FunctionalTest.java
new file mode 100644
index 0000000000..8321d75350
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8FunctionalTest.java
@@ -0,0 +1,397 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.android.desugar.testdata.java8.AnnotationsOfDefaultMethodsShouldBeKept.AnnotatedInterface;
+import com.google.devtools.build.android.desugar.testdata.java8.AnnotationsOfDefaultMethodsShouldBeKept.SomeAnnotation;
+import com.google.devtools.build.android.desugar.testdata.java8.ConcreteDefaultInterfaceWithLambda;
+import com.google.devtools.build.android.desugar.testdata.java8.ConcreteOverridesDefaultWithLambda;
+import com.google.devtools.build.android.desugar.testdata.java8.DefaultInterfaceMethodWithStaticInitializer;
+import com.google.devtools.build.android.desugar.testdata.java8.DefaultInterfaceWithBridges;
+import com.google.devtools.build.android.desugar.testdata.java8.FunctionWithDefaultMethod;
+import com.google.devtools.build.android.desugar.testdata.java8.FunctionalInterfaceWithInitializerAndDefaultMethods;
+import com.google.devtools.build.android.desugar.testdata.java8.GenericDefaultInterfaceWithLambda;
+import com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod;
+import com.google.devtools.build.android.desugar.testdata.java8.InterfaceWithDefaultMethod;
+import com.google.devtools.build.android.desugar.testdata.java8.InterfaceWithDuplicateMethods.ClassWithDuplicateMethods;
+import com.google.devtools.build.android.desugar.testdata.java8.Java7InterfaceWithBridges;
+import com.google.devtools.build.android.desugar.testdata.java8.Named;
+import com.google.devtools.build.android.desugar.testdata.java8.TwoInheritedDefaultMethods;
+import com.google.devtools.build.android.desugar.testdata.java8.VisibilityTestClass;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test that exercises classes in the {@code testdata_java8} package. This is meant to be run
+ * against a desugared version of those classes, which in turn exercise various desugaring features.
+ */
+@RunWith(JUnit4.class)
+public class DesugarJava8FunctionalTest extends DesugarFunctionalTest {
+
+ public DesugarJava8FunctionalTest() {
+ this(true, true);
+ }
+
+ protected DesugarJava8FunctionalTest(
+ boolean expectBridgesFromSeparateTarget, boolean expectDefaultMethods) {
+ super(expectBridgesFromSeparateTarget, expectDefaultMethods);
+ }
+
+ @Test
+ public void testLambdaInDefaultMethod() {
+ assertThat(new ConcreteDefaultInterfaceWithLambda().defaultWithLambda())
+ .containsExactly("0", "1")
+ .inOrder();
+ }
+
+ @Test
+ public void testLambdaInDefaultCallsInterfaceMethod() {
+ assertThat(new ConcreteDefaultInterfaceWithLambda().defaultCallsInterfaceMethod())
+ .containsExactly("1", "2")
+ .inOrder();
+ }
+
+ @Test
+ public void testOverrideLambdaInDefault() {
+ assertThat(new ConcreteOverridesDefaultWithLambda().defaultWithLambda())
+ .containsExactly("2", "3")
+ .inOrder();
+ }
+
+ @Test
+ public void testLambdaInDefaultCallsOverrideMethod() {
+ assertThat(new ConcreteOverridesDefaultWithLambda().defaultCallsInterfaceMethod())
+ .containsExactly("3", "4")
+ .inOrder();
+ }
+
+ @Test
+ public void testDefaultInterfaceMethodReference() {
+ InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
+ List<String> dest =
+ methodrefUse.defaultMethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(dest).containsExactly("Sergey");
+ }
+
+ @Test
+ public void testStaticInterfaceMethodReference() {
+ InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
+ List<String> dest =
+ methodrefUse.staticMethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(dest).containsExactly("Alex");
+ }
+
+ @Test
+ public void testLambdaCallsDefaultMethod() {
+ InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
+ List<String> dest =
+ methodrefUse.lambdaCallsDefaultMethod(ImmutableList.of("Sergey", "Larry", "Alex"));
+ assertThat(dest).containsExactly("Sergey");
+ }
+
+ @Test
+ public void testStaticMethodsInInterface_explicitAndLambdaBody() {
+ List<Long> result = FunctionWithDefaultMethod.DoubleInts.add(ImmutableList.of(7, 39, 8), 3);
+ assertThat(result).containsExactly(10L, 42L, 11L).inOrder();
+ }
+
+ @Test
+ public void testOverriddenDefaultMethod_inHandwrittenClass() {
+ FunctionWithDefaultMethod<Integer> doubler = new FunctionWithDefaultMethod.DoubleInts();
+ assertThat(doubler.apply(7)).isEqualTo(14);
+ assertThat(doubler.twice(7)).isEqualTo(35);
+ }
+
+ @Test
+ public void testOverriddenDefaultMethod_inHandwrittenSuperclass() {
+ FunctionWithDefaultMethod<Integer> doubler = new FunctionWithDefaultMethod.DoubleInts2();
+ assertThat(doubler.apply(7)).isEqualTo(14);
+ assertThat(doubler.twice(7)).isEqualTo(35);
+ }
+
+ @Test
+ public void testInheritedDefaultMethod_inLambda() {
+ FunctionWithDefaultMethod<Integer> doubler =
+ FunctionWithDefaultMethod.DoubleInts.doubleLambda();
+ assertThat(doubler.apply(7)).isEqualTo(14);
+ assertThat(doubler.twice(7)).isEqualTo(28);
+ }
+
+ @Test
+ public void testDefaultMethodReference_onLambda() {
+ FunctionWithDefaultMethod<Integer> plus6 = FunctionWithDefaultMethod.DoubleInts.incTwice(3);
+ assertThat(plus6.apply(18)).isEqualTo(24);
+ assertThat(plus6.twice(18)).isEqualTo(30);
+ }
+
+ @Test
+ public void testDefaultMethodReference_onHandwrittenClass() {
+ FunctionWithDefaultMethod<Integer> times5 = FunctionWithDefaultMethod.DoubleInts.times5();
+ assertThat(times5.apply(6)).isEqualTo(30);
+ assertThat(times5.twice(6)).isEqualTo(150); // Irrelevant that DoubleInts overrides twice()
+ }
+
+ @Test
+ public void testStaticInterfaceMethodReferenceReturned() {
+ Function<Integer, FunctionWithDefaultMethod<Integer>> factory =
+ FunctionWithDefaultMethod.DoubleInts.incFactory();
+ assertThat(factory.apply(6).apply(7)).isEqualTo(13);
+ assertThat(factory.apply(6).twice(7)).isEqualTo(19);
+ }
+
+ @Test
+ public void testSuperDefaultMethodInvocation() {
+ assertThat(new TwoInheritedDefaultMethods().name()).isEqualTo("One:Two");
+ assertThat(new Named.DefaultName().name()).isEqualTo("DefaultName-once");
+ assertThat(new Named.DefaultNameSubclass().name()).isEqualTo("DefaultNameSubclass-once-twice");
+ }
+
+ @Test
+ public void testInheritedPreferredOverDefault() throws Exception {
+ assertThat(new Named.ExplicitName("hello").name()).isEqualTo("hello");
+ // Make sure AbstractName remains abstract, despite default method from implemented interface
+ assertThat(Modifier.isAbstract(Named.AbstractName.class.getMethod("name").getModifiers()))
+ .isTrue();
+ }
+
+ @Test
+ public void testRedefinedDefaultMethod() throws Exception {
+ assertThat(new InterfaceWithDefaultMethod.Version2().version()).isEqualTo(2);
+ }
+
+ @Test
+ public void testDefaultMethodRedefinedInSubclass() throws Exception {
+ assertThat(new InterfaceWithDefaultMethod.AlsoVersion2().version()).isEqualTo(2);
+ }
+
+ @Test
+ public void testDefaultMethodVisibility() {
+ assertThat(new VisibilityTestClass().m()).isEqualTo(42);
+ }
+
+ /** Test for b/38302860 */
+ @Test
+ public void testAnnotationsOfDefaultMethodsAreKept() throws Exception {
+ {
+ Annotation[] annotations = AnnotatedInterface.class.getAnnotations();
+ assertThat(annotations).hasLength(1);
+ assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
+ assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(1);
+ }
+ {
+ Annotation[] annotations =
+ AnnotatedInterface.class.getMethod("annotatedAbstractMethod").getAnnotations();
+ assertThat(annotations).hasLength(1);
+ assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
+ assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(2);
+ }
+ {
+ Annotation[] annotations =
+ AnnotatedInterface.class.getMethod("annotatedDefaultMethod").getAnnotations();
+ assertThat(annotations).hasLength(1);
+ assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
+ assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(3);
+ }
+ }
+ /** Test for b/38308515 */
+ @Test
+ public void testDefaultAndStaticMethodNameClash() {
+ final ClassWithDuplicateMethods instance = new ClassWithDuplicateMethods();
+ assertThat(instance.getZero()).isEqualTo(0);
+ assertThat(instance.getZeroFromStaticInterfaceMethod()).isEqualTo(1);
+ }
+
+ /**
+ * Test for b/38257037
+ *
+ * <p>Note that, we intentionally suppress unchecked warnings, because we expect some
+ * ClassCastException to test bridge methods.
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testBridgeAndDefaultMethods() {
+ {
+ DefaultInterfaceWithBridges object = new DefaultInterfaceWithBridges();
+ Integer one = 1;
+ assertThat(object.copy(one)).isEqualTo(one);
+ assertThat(object.copy((Number) one)).isEqualTo(one);
+ assertThrows(ClassCastException.class, () -> object.copy(Double.valueOf(1)));
+
+ assertThat(object.getNumber()).isInstanceOf(Double.class);
+ assertThat(object.getNumber()).isEqualTo(Double.valueOf(2.3d));
+ assertThat(object.getDouble()).isEqualTo(Double.valueOf(2.3d));
+ }
+ {
+ Java7InterfaceWithBridges.ClassAddTwo testObject =
+ new Java7InterfaceWithBridges.ClassAddTwo();
+ assertThat(testObject.add(Integer.valueOf(2))).isEqualTo(4);
+
+ @SuppressWarnings("rawtypes")
+ Java7InterfaceWithBridges top = testObject;
+ assertThat(top.add(Integer.valueOf(2))).isEqualTo(4);
+ assertThrows(ClassCastException.class, () -> top.add(new Object()));
+ assertThrows(ClassCastException.class, () -> top.add(Double.valueOf(1)));
+ assertThrows(ClassCastException.class, () -> top.add(Long.valueOf(1)));
+
+ @SuppressWarnings("rawtypes")
+ Java7InterfaceWithBridges.LevelOne levelOne = testObject;
+ assertThat(levelOne.add(Integer.valueOf(2))).isEqualTo(4);
+ assertThrows(ClassCastException.class, () -> top.add(new Object()));
+ assertThrows(ClassCastException.class, () -> top.add(Double.valueOf(1)));
+ assertThrows(ClassCastException.class, () -> top.add(Long.valueOf(1)));
+
+ @SuppressWarnings("rawtypes")
+ Java7InterfaceWithBridges.LevelOne levelTwo = testObject;
+ assertThat(levelTwo.add(Integer.valueOf(2))).isEqualTo(4);
+ assertThrows(ClassCastException.class, () -> levelTwo.add(Double.valueOf(1)));
+ assertThrows(ClassCastException.class, () -> levelTwo.add(Long.valueOf(1)));
+ }
+ {
+ GenericDefaultInterfaceWithLambda.ClassTwo testObject =
+ new GenericDefaultInterfaceWithLambda.ClassTwo();
+
+ assertThat(testObject.increment(Integer.valueOf(0))).isEqualTo(1);
+ assertThat(testObject.toString(Integer.valueOf(0))).isEqualTo("0");
+ assertThat(testObject.getBaseValue()).isEqualTo(Integer.valueOf(0));
+
+ assertThat(testObject.toList(0)).isEmpty();
+ assertThat(testObject.toList(1)).containsExactly(0).inOrder();
+ assertThat(testObject.toList(2)).containsExactly(0, 1).inOrder();
+
+ assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(0))
+ .isEmpty();
+ assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(1))
+ .containsExactly(0)
+ .inOrder();
+ assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(2))
+ .containsExactly(0, 1)
+ .inOrder();
+
+ assertThat(testObject.convertToStringList(ImmutableList.of(0)))
+ .containsExactly("0")
+ .inOrder();
+ assertThat(testObject.convertToStringList(ImmutableList.of(0, 1)))
+ .containsExactly("0", "1")
+ .inOrder();
+
+ @SuppressWarnings("rawtypes")
+ GenericDefaultInterfaceWithLambda top = testObject;
+ assertThrows(ClassCastException.class, () -> top.increment(Long.valueOf(1)));
+ assertThrows(ClassCastException.class, () -> top.toString(Long.valueOf(1)));
+ assertThat(top.increment(Integer.valueOf(0))).isEqualTo(1);
+ assertThat(top.toString(Integer.valueOf(0))).isEqualTo("0");
+ assertThat(top.getBaseValue()).isEqualTo(Integer.valueOf(0));
+
+ assertThat(top.toList(0)).isEmpty();
+ assertThat(top.toList(1)).containsExactly(0).inOrder();
+ assertThat(top.toList(2)).containsExactly(0, 1).inOrder();
+
+ assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(0)).isEmpty();
+ assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(1))
+ .containsExactly(0)
+ .inOrder();
+ assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(2))
+ .containsExactly(0, 1)
+ .inOrder();
+
+ assertThat(top.convertToStringList(ImmutableList.of(0))).containsExactly("0").inOrder();
+ assertThat(top.convertToStringList(ImmutableList.of(0, 1)))
+ .containsExactly("0", "1")
+ .inOrder();
+ }
+ {
+ @SuppressWarnings("rawtypes")
+ GenericDefaultInterfaceWithLambda testObject =
+ new GenericDefaultInterfaceWithLambda.ClassThree();
+ assertThat(testObject.getBaseValue()).isEqualTo(Long.valueOf(0));
+ assertThat(testObject.increment(Long.valueOf(0))).isEqualTo(Long.valueOf(0 + 1));
+ assertThat(testObject.toString(Long.valueOf(0))).isEqualTo(Long.valueOf(0).toString());
+ assertThrows(ClassCastException.class, () -> testObject.increment(Integer.valueOf(0)));
+ assertThrows(ClassCastException.class, () -> testObject.toString(Integer.valueOf(0)));
+ assertThat(testObject.toList(2)).containsExactly(Long.valueOf(0), Long.valueOf(1)).inOrder();
+ assertThat(testObject.convertToStringList(testObject.toList(1))).containsExactly("0");
+ assertThat(((Function<Integer, ArrayList<Long>>) testObject.toListSupplier()).apply(2))
+ .containsExactly(Long.valueOf(0), Long.valueOf(1));
+ }
+ }
+
+ /**
+ * Test for b/62047432.
+ *
+ * <p>When desugaring a functional interface with an executable clinit and default methods, we
+ * erase the body of clinit to avoid executing it during desugaring. This test makes sure that all
+ * the constants defined in the interface are still there after desugaring.
+ */
+ @Test
+ public void testFunctionalInterfaceWithExecutableClinitStillWorkAfterDesugar() {
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CONSTANT.length("").convert())
+ .isEqualTo(0);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CONSTANT.length("1").convert())
+ .isEqualTo(1);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.BOOLEAN).isFalse();
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CHAR).isEqualTo('h');
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.BYTE).isEqualTo(0);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.SHORT).isEqualTo(0);
+
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.INT).isEqualTo(0);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.FLOAT).isEqualTo(0f);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.LONG).isEqualTo(0);
+ assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.DOUBLE).isEqualTo(0d);
+ }
+
+ /** Test for b/38255926. */
+ @Test
+ public void testDefaultMethodInitializationOrder() {
+ {
+ assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne.C().sum())
+ .isEqualTo(11); // To trigger loading the class C and its super interfaces.
+ assertThat(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne
+ .getRealInitializationOrder())
+ .isEqualTo(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne
+ .getExpectedInitializationOrder());
+ }
+ {
+ assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo.C().sum())
+ .isEqualTo(3);
+ assertThat(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo
+ .getRealInitializationOrder())
+ .isEqualTo(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo
+ .getExpectedInitializationOrder());
+ }
+ {
+ assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree.C().sum())
+ .isEqualTo(11);
+ assertThat(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree
+ .getRealInitializationOrder())
+ .isEqualTo(
+ DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree
+ .getExpectedInitializationOrder());
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8LikeAndroidStudioFunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8LikeAndroidStudioFunctionalTest.java
new file mode 100644
index 0000000000..13edc57980
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarJava8LikeAndroidStudioFunctionalTest.java
@@ -0,0 +1,31 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Variant of {@link DesugarJava8FunctionalTest} that doesn't expect any bridge methods already
+ * present on functional interfaces to be also present on generated classes, even where functional
+ * interfaces are defined in other compilations, which requires compiling against regular jar files
+ * instead of a classpath of -hjars.
+ */
+@RunWith(JUnit4.class)
+public final class DesugarJava8LikeAndroidStudioFunctionalTest extends DesugarJava8FunctionalTest {
+
+ public DesugarJava8LikeAndroidStudioFunctionalTest() {
+ super(/*expectBridgesFromSeparateTarget*/ false, /*expectDefaultMethods*/ true);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarLongCompareTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarLongCompareTest.java
new file mode 100644
index 0000000000..708fc8e666
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarLongCompareTest.java
@@ -0,0 +1,135 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+
+import com.google.devtools.build.android.desugar.testdata.ClassCallingLongCompare;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/** The test case for the rewriter rewriting a call of Long.compare(long, long) to lcmp. */
+@RunWith(JUnit4.class)
+public class DesugarLongCompareTest {
+
+ @Test
+ public void testClassCallingLongCompareHasNoReferenceToLong_compare() {
+ try {
+ ClassReader reader = new ClassReader(ClassCallingLongCompare.class.getName());
+
+ AtomicInteger counter = new AtomicInteger(0);
+
+ reader.accept(
+ new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ return new MethodVisitor(api) {
+ @Override
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String desc, boolean itf) {
+ if (opcode == INVOKESTATIC
+ && owner.equals("java/lang/Long")
+ && name.equals("compare")
+ && desc.equals("(JJ)I")) {
+ counter.incrementAndGet();
+ }
+ }
+ };
+ }
+ },
+ 0);
+ assertThat(counter.get()).isEqualTo(0);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void testCompareLongWithLambda() {
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(1, 0)).isEqualTo(1);
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(1, 1)).isEqualTo(0);
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(1, 2)).isEqualTo(-1);
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(Long.MAX_VALUE, Long.MIN_VALUE))
+ .isEqualTo(1);
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(Long.MAX_VALUE, Long.MAX_VALUE))
+ .isEqualTo(0);
+ assertThat(ClassCallingLongCompare.compareLongWithLambda(Long.MIN_VALUE, Long.MAX_VALUE))
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void testCompareLongWithMethodReference() {
+ assertThat(ClassCallingLongCompare.compareLongWithMethodReference(1, 0)).isEqualTo(1);
+ assertThat(ClassCallingLongCompare.compareLongWithMethodReference(1, 1)).isEqualTo(0);
+ assertThat(ClassCallingLongCompare.compareLongWithMethodReference(1, 2)).isEqualTo(-1);
+ assertThat(
+ ClassCallingLongCompare.compareLongWithMethodReference(Long.MAX_VALUE, Long.MIN_VALUE))
+ .isEqualTo(1);
+ assertThat(
+ ClassCallingLongCompare.compareLongWithMethodReference(Long.MAX_VALUE, Long.MAX_VALUE))
+ .isEqualTo(0);
+ assertThat(
+ ClassCallingLongCompare.compareLongWithMethodReference(Long.MIN_VALUE, Long.MAX_VALUE))
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void testcompareLongByCallingLong_compare() {
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare(1, 0)).isEqualTo(1);
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare(1, 1)).isEqualTo(0);
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare(1, 2)).isEqualTo(-1);
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare(
+ Long.MAX_VALUE, Long.MIN_VALUE))
+ .isEqualTo(1);
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare(
+ Long.MAX_VALUE, Long.MAX_VALUE))
+ .isEqualTo(0);
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare(
+ Long.MIN_VALUE, Long.MAX_VALUE))
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void testcompareLongByCallingLong_compare2() {
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare2(1, 0)).isEqualTo("g");
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare2(1, 1)).isEqualTo("e");
+ assertThat(ClassCallingLongCompare.compareLongByCallingLong_compare2(0, 1)).isEqualTo("l");
+
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare2(
+ Long.MAX_VALUE, Long.MIN_VALUE))
+ .isEqualTo("g");
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare2(
+ Long.MAX_VALUE, Long.MAX_VALUE))
+ .isEqualTo("e");
+ assertThat(
+ ClassCallingLongCompare.compareLongByCallingLong_compare2(
+ Long.MIN_VALUE, Long.MAX_VALUE))
+ .isEqualTo("l");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarMainClassTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarMainClassTest.java
new file mode 100644
index 0000000000..039201282e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarMainClassTest.java
@@ -0,0 +1,82 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.LambdaClassMaker.LAMBDA_METAFACTORY_DUMPER_PROPERTY;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Strings;
+import java.io.IOError;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Supplier;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link Desugar} */
+@RunWith(JUnit4.class)
+public class DesugarMainClassTest {
+
+ @Test
+ public void testVerifyLambdaDumpDirectoryRegistration() throws Exception {
+ if (Strings.isNullOrEmpty(System.getProperty(LAMBDA_METAFACTORY_DUMPER_PROPERTY))) {
+ testLambdaDumpDirSpecifiedInProgramFail();
+ } else {
+ testLambdaDumpDirPassSpecifiedInCmdPass();
+ }
+ }
+
+ private void testLambdaDumpDirSpecifiedInProgramFail() throws Exception {
+ // This lambda will fail the dump directory registration, which is intended.
+ Supplier<Path> supplier =
+ () -> {
+ Path path = Paths.get(".").toAbsolutePath();
+ System.setProperty(LAMBDA_METAFACTORY_DUMPER_PROPERTY, path.toString());
+ return path;
+ };
+ try {
+ Desugar.verifyLambdaDumpDirectoryRegistered(supplier.get());
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * Test the LambdaMetafactory can be correctly set up by specifying the system property {@code
+ * LAMBDA_METAFACTORY_DUMPER_PROPERTY} in the command line.
+ */
+ private void testLambdaDumpDirPassSpecifiedInCmdPass() throws IOException {
+ // The following lambda ensures that the LambdaMetafactory is loaded at the beggining of this
+ // test, so that the dump directory can be registered.
+ Supplier<Path> supplier =
+ () -> {
+ try {
+ return Desugar.createAndRegisterLambdaDumpDirectory();
+ } catch (IOException e) {
+ throw new IOError(e);
+ }
+ };
+ Path dumpDirectory = supplier.get();
+ assertThat(dumpDirectory.toAbsolutePath().toString())
+ .isEqualTo(
+ Paths.get(System.getProperty(LAMBDA_METAFACTORY_DUMPER_PROPERTY))
+ .toAbsolutePath()
+ .toString());
+ Desugar.verifyLambdaDumpDirectoryRegistered(dumpDirectory);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarObjectsRequireNonNullTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarObjectsRequireNonNullTest.java
new file mode 100644
index 0000000000..6f3be3c0aa
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarObjectsRequireNonNullTest.java
@@ -0,0 +1,153 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+
+import com.google.devtools.build.android.desugar.testdata.ClassCallingRequireNonNull;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This test case tests the desugaring feature for Objects.requireNonNull. This feature replaces any
+ * call to this method with o.getClass() to check whether 'o' is null.
+ */
+@RunWith(JUnit4.class)
+public class DesugarObjectsRequireNonNullTest {
+
+ @Test
+ public void testClassCallingRequireNonNullHasNoReferenceToRequiresNonNull() {
+ try {
+ ClassReader reader = new ClassReader(ClassCallingRequireNonNull.class.getName());
+
+ AtomicInteger counterForSingleArgument = new AtomicInteger(0);
+ AtomicInteger counterForString = new AtomicInteger(0);
+ AtomicInteger counterForSupplier = new AtomicInteger(0);
+
+ reader.accept(
+ new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ return new MethodVisitor(api) {
+ @Override
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String desc, boolean itf) {
+ if (opcode == INVOKESTATIC
+ && owner.equals("java/util/Objects")
+ && name.equals("requireNonNull")) {
+ switch (desc) {
+ case "(Ljava/lang/Object;)Ljava/lang/Object;":
+ counterForSingleArgument.incrementAndGet();
+ break;
+ case "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;":
+ counterForString.incrementAndGet();
+ break;
+ case "(Ljava/lang/Object;Ljava/util/function/Supplier;)Ljava/lang/Object;":
+ counterForSupplier.incrementAndGet();
+ break;
+ default:
+ fail("Unknown overloaded requireNonNull is found: " + desc);
+ }
+ }
+ }
+ };
+ }
+ },
+ 0);
+ assertThat(counterForSingleArgument.get()).isEqualTo(0);
+ // we do not desugar requireNonNull(Object, String) or requireNonNull(Object, Supplier)
+ assertThat(counterForString.get()).isEqualTo(1);
+ assertThat(counterForSupplier.get()).isEqualTo(1);
+ } catch (IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void testInliningImplicitCallToObjectsRequireNonNull() {
+ try {
+ ClassCallingRequireNonNull.getStringLengthWithMethodReference(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ assertThat(ClassCallingRequireNonNull.getStringLengthWithMethodReference("")).isEqualTo(0);
+ assertThat(ClassCallingRequireNonNull.getStringLengthWithMethodReference("1")).isEqualTo(1);
+
+ try {
+ ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ assertThat(
+ ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull(""))
+ .isEqualTo(0);
+ assertThat(
+ ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull(
+ "1"))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void testInliningExplicitCallToObjectsRequireNonNull() {
+ try {
+ ClassCallingRequireNonNull.getFirstCharVersionOne(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ try {
+ ClassCallingRequireNonNull.getFirstCharVersionTwo(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ try {
+ ClassCallingRequireNonNull.callRequireNonNullWithArgumentString(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ try {
+ ClassCallingRequireNonNull.callRequireNonNullWithArgumentSupplier(null);
+ fail ("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ assertThat(ClassCallingRequireNonNull.getFirstCharVersionOne("hello")).isEqualTo('h');
+ assertThat(ClassCallingRequireNonNull.getFirstCharVersionTwo("hello")).isEqualTo('h');
+
+ assertThat(ClassCallingRequireNonNull.callRequireNonNullWithArgumentString("hello"))
+ .isEqualTo('h');
+ assertThat(ClassCallingRequireNonNull.callRequireNonNullWithArgumentSupplier("hello"))
+ .isEqualTo('h');
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarTryWithResourcesFunctionalTest.java b/src/test/java/com/google/devtools/build/android/desugar/DesugarTryWithResourcesFunctionalTest.java
new file mode 100644
index 0000000000..38df9e33a4
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DesugarTryWithResourcesFunctionalTest.java
@@ -0,0 +1,99 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.getStrategyClassName;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.getTwrStrategyClassNameSpecifiedInSystemProperty;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isMimicStrategy;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isNullStrategy;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isReuseStrategy;
+import static org.junit.Assert.fail;
+
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension;
+import com.google.devtools.build.android.desugar.testdata.ClassUsingTryWithResources;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** The functional test for desugaring try-with-resources. */
+@RunWith(JUnit4.class)
+public class DesugarTryWithResourcesFunctionalTest {
+
+ @Test
+ public void testCheckSuppressedExceptionsReturningEmptySuppressedExceptions() {
+ Throwable[] suppressed = ClassUsingTryWithResources.checkSuppressedExceptions(false);
+ assertThat(suppressed).isEmpty();
+ }
+
+ @Test
+ public void testPrintStackTraceOfCaughtException() {
+ String trace = ClassUsingTryWithResources.printStackTraceOfCaughtException();
+ if (isMimicStrategy()) {
+ assertThat(trace.toLowerCase()).contains("suppressed");
+ } else if (isReuseStrategy()) {
+ assertThat(trace.toLowerCase()).contains("suppressed");
+ } else if (isNullStrategy()) {
+ assertThat(trace.toLowerCase()).doesNotContain("suppressed");
+ } else {
+ fail("unexpected desugaring strategy " + ThrowableExtension.getStrategy());
+ }
+ }
+
+ @Test
+ public void testCheckSuppressedExceptionReturningOneSuppressedException() {
+ Throwable[] suppressed = ClassUsingTryWithResources.checkSuppressedExceptions(true);
+
+ if (isMimicStrategy()) {
+ assertThat(suppressed).hasLength(1);
+ } else if (isReuseStrategy()) {
+ assertThat(suppressed).hasLength(1);
+ } else if (isNullStrategy()) {
+ assertThat(suppressed).isEmpty();
+ } else {
+ fail("unexpected desugaring strategy " + ThrowableExtension.getStrategy());
+ }
+ }
+
+ @Test
+ public void testSimpleTryWithResources() {
+
+ try {
+ ClassUsingTryWithResources.simpleTryWithResources();
+ fail("Expected RuntimeException");
+ } catch (Exception expected) {
+ assertThat(expected.getClass()).isEqualTo(RuntimeException.class);
+
+ String expectedStrategyName = getTwrStrategyClassNameSpecifiedInSystemProperty();
+ assertThat(getStrategyClassName()).isEqualTo(expectedStrategyName);
+ if (isMimicStrategy()) {
+ assertThat(expected.getSuppressed()).isEmpty();
+ assertThat(ThrowableExtension.getSuppressed(expected)).hasLength(1);
+ assertThat(ThrowableExtension.getSuppressed(expected)[0].getClass())
+ .isEqualTo(IOException.class);
+ } else if (isReuseStrategy()) {
+ assertThat(expected.getSuppressed()).hasLength(1);
+ assertThat(expected.getSuppressed()[0].getClass()).isEqualTo(IOException.class);
+ assertThat(ThrowableExtension.getSuppressed(expected)[0].getClass())
+ .isEqualTo(IOException.class);
+ } else if (isNullStrategy()) {
+ assertThat(expected.getSuppressed()).isEmpty();
+ assertThat(ThrowableExtension.getSuppressed(expected)).isEmpty();
+ } else {
+ fail("unexpected desugaring strategy " + getStrategyClassName());
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/FieldInfoTest.java b/src/test/java/com/google/devtools/build/android/desugar/FieldInfoTest.java
new file mode 100644
index 0000000000..afb2beacbd
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/FieldInfoTest.java
@@ -0,0 +1,33 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link FieldInfo} */
+@RunWith(JUnit4.class)
+public class FieldInfoTest {
+
+ @Test
+ public void testFieldsAreCorrectlySet() {
+ FieldInfo info = FieldInfo.create("owner", "name", "desc");
+ assertThat(info.owner()).isEqualTo("owner");
+ assertThat(info.name()).isEqualTo("name");
+ assertThat(info.desc()).isEqualTo("desc");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/IndexedInputsTest.java b/src/test/java/com/google/devtools/build/android/desugar/IndexedInputsTest.java
new file mode 100644
index 0000000000..bac3fc92cd
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/IndexedInputsTest.java
@@ -0,0 +1,136 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test that exercises the behavior of the IndexedInputs class.
+ */
+@RunWith(JUnit4.class)
+public final class IndexedInputsTest {
+
+ private static File lib1;
+
+ private static String lib1Name;
+
+ private static File lib2;
+
+ private static String lib2Name;
+
+ private static InputFileProvider lib1InputFileProvider;
+
+ private static InputFileProvider lib2InputFileProvider;
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ lib1 = File.createTempFile("lib1", ".jar");
+ lib1Name = lib1.getName();
+ try (ZipOutputStream zos1 = new ZipOutputStream(new FileOutputStream(lib1))) {
+ zos1.putNextEntry(new ZipEntry("a/b/C.class"));
+ zos1.putNextEntry(new ZipEntry("a/b/D.class"));
+ zos1.closeEntry();
+ }
+
+ lib2 = File.createTempFile("lib2", ".jar");
+ lib2Name = lib2.getName();
+ try (ZipOutputStream zos2 = new ZipOutputStream(new FileOutputStream(lib2))) {
+ zos2.putNextEntry(new ZipEntry("a/b/C.class"));
+ zos2.putNextEntry(new ZipEntry("a/b/E.class"));
+ zos2.closeEntry();
+ }
+ }
+
+ @Before
+ public void createProviders() throws Exception {
+ lib1InputFileProvider = new ZipInputFileProvider(lib1.toPath());
+ lib2InputFileProvider = new ZipInputFileProvider(lib2.toPath());
+ }
+
+ @After
+ public void closeProviders() throws Exception {
+ lib1InputFileProvider.close();
+ lib2InputFileProvider.close();
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ lib1.delete();
+ lib2.delete();
+ }
+
+ @Test
+ public void testClassFoundWithParentLibrary() throws Exception {
+ IndexedInputs indexedLib2 = new IndexedInputs(ImmutableList.of(lib2InputFileProvider));
+ IndexedInputs indexedLib1 = new IndexedInputs(ImmutableList.of(lib1InputFileProvider));
+ IndexedInputs indexedLib2AndLib1 = indexedLib1.withParent(indexedLib2);
+ assertThat(indexedLib2AndLib1.getInputFileProvider("a/b/C.class").toString())
+ .isEqualTo(lib2Name);
+ assertThat(indexedLib2AndLib1.getInputFileProvider("a/b/D.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(indexedLib2AndLib1.getInputFileProvider("a/b/E.class").toString())
+ .isEqualTo(lib2Name);
+
+ indexedLib2 = new IndexedInputs(ImmutableList.of(lib2InputFileProvider));
+ indexedLib1 = new IndexedInputs(ImmutableList.of(lib1InputFileProvider));
+ IndexedInputs indexedLib1AndLib2 = indexedLib2.withParent(indexedLib1);
+ assertThat(indexedLib1AndLib2.getInputFileProvider("a/b/C.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(indexedLib1AndLib2.getInputFileProvider("a/b/D.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(indexedLib1AndLib2.getInputFileProvider("a/b/E.class").toString())
+ .isEqualTo(lib2Name);
+ }
+
+ @Test
+ public void testClassFoundWithoutParentLibrary() throws Exception {
+ IndexedInputs ijLib1Lib2 =
+ new IndexedInputs(ImmutableList.of(lib1InputFileProvider, lib2InputFileProvider));
+ assertThat(ijLib1Lib2.getInputFileProvider("a/b/C.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(ijLib1Lib2.getInputFileProvider("a/b/D.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(ijLib1Lib2.getInputFileProvider("a/b/E.class").toString())
+ .isEqualTo(lib2Name);
+
+ IndexedInputs ijLib2Lib1 =
+ new IndexedInputs(ImmutableList.of(lib2InputFileProvider, lib1InputFileProvider));
+ assertThat(ijLib2Lib1.getInputFileProvider("a/b/C.class").toString())
+ .isEqualTo(lib2Name);
+ assertThat(ijLib2Lib1.getInputFileProvider("a/b/D.class").toString())
+ .isEqualTo(lib1Name);
+ assertThat(ijLib2Lib1.getInputFileProvider("a/b/E.class").toString())
+ .isEqualTo(lib2Name);
+ }
+
+ @Test
+ public void testClassNotFound() throws Exception {
+ IndexedInputs ijLib1Lib2 =
+ new IndexedInputs(ImmutableList.of(lib1InputFileProvider, lib2InputFileProvider));
+ assertThat(ijLib1Lib2.getInputFileProvider("a/b/F.class")).isNull();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/Java7CompatibilityTest.java b/src/test/java/com/google/devtools/build/android/desugar/Java7CompatibilityTest.java
new file mode 100644
index 0000000000..b8c8b542e7
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/Java7CompatibilityTest.java
@@ -0,0 +1,122 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(JUnit4.class)
+public class Java7CompatibilityTest {
+
+ @Test
+ public void testJava7CompatibleInterface() throws Exception {
+ ClassReader reader = new ClassReader(ExtendsDefault.class.getName());
+ ClassTester tester = new ClassTester();
+ reader.accept(new Java7Compatibility(tester, null), 0);
+ assertThat(tester.version).isEqualTo(Opcodes.V1_7);
+ assertThat(tester.bridgeMethods).isEqualTo(0); // make sure we strip bridge methods
+ assertThat(tester.clinitMethods).isEqualTo(1); // make sure we don't strip <clinit>
+ }
+
+ @Test
+ public void testDefaultMethodFails() throws Exception {
+ ClassReader reader = new ClassReader(WithDefault.class.getName());
+ try {
+ reader.accept(new Java7Compatibility(null, null), 0);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException expected) {
+ assertThat(expected).hasMessageThat().contains("getVersion()I");
+ }
+ }
+
+ /**
+ * Tests that a class implementing interfaces with bridge methods redeclares those bridges.
+ * This is behavior of javac that we rely on.
+ */
+ @Test
+ public void testConcreteClassRedeclaresBridges() throws Exception {
+ ClassReader reader = new ClassReader(Impl.class.getName());
+ ClassTester tester = new ClassTester();
+ reader.accept(new Java7Compatibility(tester, null), 0);
+ assertThat(tester.version).isEqualTo(Opcodes.V1_7);
+ assertThat(tester.bridgeMethods).isEqualTo(2);
+ }
+
+ private static class ClassTester extends ClassVisitor {
+
+ int version;
+ int bridgeMethods;
+ int clinitMethods;
+
+ private ClassTester() {
+ super(Opcodes.ASM5, null);
+ }
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ this.version = version;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ if (BitFlags.isSet(access, Opcodes.ACC_BRIDGE)) {
+ ++bridgeMethods;
+ }
+ if ("<clinit>".equals(name)) {
+ ++clinitMethods;
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+ }
+
+ interface WithDefault<T> {
+ default int getVersion() {
+ return 18;
+ }
+ T get();
+ }
+
+ // Javac will generate a default bridge method "Object get()" that Java7Compatibility will remove
+ interface ExtendsDefault<T extends Number> extends WithDefault<T> {
+ public static final Integer X = Integer.valueOf(37);
+ String name();
+ @Override T get();
+ }
+
+ // Javac will generate 2 bridge methods that we *don't* want to remove
+ static class Impl implements ExtendsDefault<Integer> {
+ @Override public Integer get() {
+ return X;
+ }
+ @Override public String name() {
+ return "test";
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/MethodInfoTest.java b/src/test/java/com/google/devtools/build/android/desugar/MethodInfoTest.java
new file mode 100644
index 0000000000..ebe9ba6d24
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/MethodInfoTest.java
@@ -0,0 +1,33 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link MethodInfo} */
+@RunWith(JUnit4.class)
+public class MethodInfoTest {
+
+ @Test
+ public void testMethodInfoAreCorrectlySet() {
+ MethodInfo method = MethodInfo.create("owner", "name", "desc");
+ assertThat(method.owner()).isEqualTo("owner");
+ assertThat(method.name()).isEqualTo("name");
+ assertThat(method.desc()).isEqualTo("desc");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/StackMapBugTest.java b/src/test/java/com/google/devtools/build/android/desugar/StackMapBugTest.java
new file mode 100644
index 0000000000..26aa52821b
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/StackMapBugTest.java
@@ -0,0 +1,45 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.util.TestClassForStackMapFrame;
+
+/** This test case is for testing the fix for b/36654936. */
+@RunWith(JUnit4.class)
+public class StackMapBugTest {
+
+ /** This is a regression test for b/36654936 (external ASM bug 317785) */
+ @Test
+ public void testAsmBug317785() {
+ int result = TestClassForStackMapFrame.testInputForAsmBug317785();
+ assertThat(result).isEqualTo(20);
+ }
+
+ /**
+ * This is a regression test for b/36654936 (external ASM bug 317785). The first attempted fix
+ * cl/152199391 caused stack map frame corruption, which caused the following test to fail.
+ */
+ @Test
+ public void testStackMapFrameCorrectness() {
+ TestClassForStackMapFrame testObject = new TestClassForStackMapFrame();
+ assertThat(testObject.joinIntegers(0)).isEmpty();
+ assertThat(testObject.joinIntegers(1)).isEqualTo("0=Even");
+ assertThat(testObject.joinIntegers(2)).isEqualTo("0=Even,1=Odd");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java b/src/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java
new file mode 100644
index 0000000000..587d4f7b8b
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/TryWithResourcesRewriterTest.java
@@ -0,0 +1,414 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.getStrategyClassName;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.getTwrStrategyClassNameSpecifiedInSystemProperty;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isMimicStrategy;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isNullStrategy;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isReuseStrategy;
+import static org.junit.Assert.fail;
+import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
+import static org.objectweb.asm.Opcodes.ASM5;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension;
+import com.google.devtools.build.android.desugar.testdata.ClassUsingTryWithResources;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is the unit test for {@link TryWithResourcesRewriter} */
+@RunWith(JUnit4.class)
+public class TryWithResourcesRewriterTest {
+
+ private final DesugaringClassLoader classLoader =
+ new DesugaringClassLoader(ClassUsingTryWithResources.class.getName());
+ private Class<?> desugaredClass;
+
+ @Before
+ public void setup() {
+ try {
+ desugaredClass = classLoader.findClass(ClassUsingTryWithResources.class.getName());
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Test
+ public void testMethodsAreDesugared() {
+ // verify whether the desugared class is indeed desugared.
+ DesugaredThrowableMethodCallCounter origCounter =
+ countDesugaredThrowableMethodCalls(ClassUsingTryWithResources.class);
+ DesugaredThrowableMethodCallCounter desugaredCounter =
+ countDesugaredThrowableMethodCalls(classLoader.classContent, classLoader);
+ /**
+ * In java9, javac creates a helper method {@code $closeResource(Throwable, AutoCloseable)
+ * to close resources. So, the following number 3 is highly dependant on the version of javac.
+ */
+ assertThat(hasAutoCloseable(classLoader.classContent)).isFalse();
+ assertThat(classLoader.numOfTryWithResourcesInvoked.intValue()).isAtLeast(2);
+ assertThat(classLoader.visitedExceptionTypes)
+ .containsExactly(
+ "java/lang/Exception", "java/lang/Throwable", "java/io/UnsupportedEncodingException");
+ assertDesugaringBehavior(origCounter, desugaredCounter);
+ }
+
+ @Test
+ public void testCheckSuppressedExceptionsReturningEmptySuppressedExceptions() {
+ {
+ Throwable[] suppressed = ClassUsingTryWithResources.checkSuppressedExceptions(false);
+ assertThat(suppressed).isEmpty();
+ }
+ try {
+ Throwable[] suppressed =
+ (Throwable[])
+ desugaredClass
+ .getMethod("checkSuppressedExceptions", boolean.class)
+ .invoke(null, Boolean.FALSE);
+ assertThat(suppressed).isEmpty();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AssertionError(e);
+ }
+ }
+
+ @Test
+ public void testPrintStackTraceOfCaughtException() {
+ {
+ String trace = ClassUsingTryWithResources.printStackTraceOfCaughtException();
+ assertThat(trace.toLowerCase()).contains("suppressed");
+ }
+ try {
+ String trace =
+ (String) desugaredClass.getMethod("printStackTraceOfCaughtException").invoke(null);
+
+ if (isMimicStrategy()) {
+ assertThat(trace.toLowerCase()).contains("suppressed");
+ } else if (isReuseStrategy()) {
+ assertThat(trace.toLowerCase()).contains("suppressed");
+ } else if (isNullStrategy()) {
+ assertThat(trace.toLowerCase()).doesNotContain("suppressed");
+ } else {
+ fail("unexpected desugaring strategy " + ThrowableExtension.getStrategy());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AssertionError(e);
+ }
+ }
+
+ @Test
+ public void testCheckSuppressedExceptionReturningOneSuppressedException() {
+ {
+ Throwable[] suppressed = ClassUsingTryWithResources.checkSuppressedExceptions(true);
+ assertThat(suppressed).hasLength(1);
+ }
+ try {
+ Throwable[] suppressed =
+ (Throwable[])
+ desugaredClass
+ .getMethod("checkSuppressedExceptions", boolean.class)
+ .invoke(null, Boolean.TRUE);
+
+ if (isMimicStrategy()) {
+ assertThat(suppressed).hasLength(1);
+ } else if (isReuseStrategy()) {
+ assertThat(suppressed).hasLength(1);
+ } else if (isNullStrategy()) {
+ assertThat(suppressed).isEmpty();
+ } else {
+ fail("unexpected desugaring strategy " + ThrowableExtension.getStrategy());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AssertionError(e);
+ }
+ }
+
+ @Test
+ public void testSimpleTryWithResources() throws Throwable {
+ {
+ try {
+ ClassUsingTryWithResources.simpleTryWithResources();
+ fail("Expected RuntimeException");
+ } catch (RuntimeException expected) {
+ assertThat(expected.getClass()).isEqualTo(RuntimeException.class);
+ assertThat(expected.getSuppressed()).hasLength(1);
+ assertThat(expected.getSuppressed()[0].getClass()).isEqualTo(IOException.class);
+ }
+ }
+
+ try {
+ try {
+ desugaredClass.getMethod("simpleTryWithResources").invoke(null);
+ fail("Expected RuntimeException");
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ } catch (RuntimeException expected) {
+ String expectedStrategyName = getTwrStrategyClassNameSpecifiedInSystemProperty();
+ assertThat(getStrategyClassName()).isEqualTo(expectedStrategyName);
+ if (isMimicStrategy()) {
+ assertThat(expected.getSuppressed()).isEmpty();
+ assertThat(ThrowableExtension.getSuppressed(expected)).hasLength(1);
+ assertThat(ThrowableExtension.getSuppressed(expected)[0].getClass())
+ .isEqualTo(IOException.class);
+ } else if (isReuseStrategy()) {
+ assertThat(expected.getSuppressed()).hasLength(1);
+ assertThat(expected.getSuppressed()[0].getClass()).isEqualTo(IOException.class);
+ assertThat(ThrowableExtension.getSuppressed(expected)[0].getClass())
+ .isEqualTo(IOException.class);
+ } else if (isNullStrategy()) {
+ assertThat(expected.getSuppressed()).isEmpty();
+ assertThat(ThrowableExtension.getSuppressed(expected)).isEmpty();
+ } else {
+ fail("unexpected desugaring strategy " + ThrowableExtension.getStrategy());
+ }
+ }
+ }
+
+ private static void assertDesugaringBehavior(
+ DesugaredThrowableMethodCallCounter orig, DesugaredThrowableMethodCallCounter desugared) {
+ assertThat(desugared.countThrowableGetSuppressed()).isEqualTo(orig.countExtGetSuppressed());
+ assertThat(desugared.countThrowableAddSuppressed()).isEqualTo(orig.countExtAddSuppressed());
+ assertThat(desugared.countThrowablePrintStackTrace()).isEqualTo(orig.countExtPrintStackTrace());
+ assertThat(desugared.countThrowablePrintStackTracePrintStream())
+ .isEqualTo(orig.countExtPrintStackTracePrintStream());
+ assertThat(desugared.countThrowablePrintStackTracePrintWriter())
+ .isEqualTo(orig.countExtPrintStackTracePrintWriter());
+
+ assertThat(orig.countThrowableGetSuppressed()).isEqualTo(desugared.countExtGetSuppressed());
+ // $closeResource is rewritten to ThrowableExtension.closeResource, so addSuppressed() is called
+ // in the runtime library now.
+ assertThat(orig.countThrowableAddSuppressed())
+ .isAtLeast(desugared.countThrowableAddSuppressed());
+ assertThat(orig.countThrowablePrintStackTrace()).isEqualTo(desugared.countExtPrintStackTrace());
+ assertThat(orig.countThrowablePrintStackTracePrintStream())
+ .isEqualTo(desugared.countExtPrintStackTracePrintStream());
+ assertThat(orig.countThrowablePrintStackTracePrintWriter())
+ .isEqualTo(desugared.countExtPrintStackTracePrintWriter());
+
+ assertThat(desugared.countThrowablePrintStackTracePrintStream()).isEqualTo(0);
+ assertThat(desugared.countThrowablePrintStackTracePrintStream()).isEqualTo(0);
+ assertThat(desugared.countThrowablePrintStackTracePrintWriter()).isEqualTo(0);
+ assertThat(desugared.countThrowableAddSuppressed()).isEqualTo(0);
+ assertThat(desugared.countThrowableGetSuppressed()).isEqualTo(0);
+ }
+
+ private static DesugaredThrowableMethodCallCounter countDesugaredThrowableMethodCalls(
+ Class<?> klass) {
+ try {
+ ClassReader reader = new ClassReader(klass.getName());
+ DesugaredThrowableMethodCallCounter counter =
+ new DesugaredThrowableMethodCallCounter(klass.getClassLoader());
+ reader.accept(counter, 0);
+ return counter;
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.toString());
+ return null;
+ }
+ }
+
+ private static DesugaredThrowableMethodCallCounter countDesugaredThrowableMethodCalls(
+ byte[] content, ClassLoader loader) {
+ ClassReader reader = new ClassReader(content);
+ DesugaredThrowableMethodCallCounter counter = new DesugaredThrowableMethodCallCounter(loader);
+ reader.accept(counter, 0);
+ return counter;
+ }
+
+ /** Check whether java.lang.AutoCloseable is used as arguments of any method. */
+ private static boolean hasAutoCloseable(byte[] classContent) {
+ ClassReader reader = new ClassReader(classContent);
+ final AtomicInteger counter = new AtomicInteger();
+ ClassVisitor visitor =
+ new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ for (Type argumentType : Type.getArgumentTypes(desc)) {
+ if ("Ljava/lang/AutoCloseable;".equals(argumentType.getDescriptor())) {
+ counter.incrementAndGet();
+ }
+ }
+ return null;
+ }
+ };
+ reader.accept(visitor, 0);
+ return counter.get() > 0;
+ }
+
+ private static class DesugaredThrowableMethodCallCounter extends ClassVisitor {
+ private final ClassLoader classLoader;
+ private final Map<String, AtomicInteger> counterMap;
+
+ public DesugaredThrowableMethodCallCounter(ClassLoader loader) {
+ super(ASM5);
+ classLoader = loader;
+ counterMap = new HashMap<>();
+ TryWithResourcesRewriter.TARGET_METHODS
+ .entries()
+ .forEach(entry -> counterMap.put(entry.getKey() + entry.getValue(), new AtomicInteger()));
+ TryWithResourcesRewriter.TARGET_METHODS
+ .entries()
+ .forEach(
+ entry ->
+ counterMap.put(
+ entry.getKey()
+ + TryWithResourcesRewriter.METHOD_DESC_MAP.get(entry.getValue()),
+ new AtomicInteger()));
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ return new InvokeCounter();
+ }
+
+ private class InvokeCounter extends MethodVisitor {
+
+ public InvokeCounter() {
+ super(ASM5);
+ }
+
+ private boolean isAssignableToThrowable(String owner) {
+ try {
+ Class<?> ownerClass = classLoader.loadClass(owner.replace('/', '.'));
+ return Throwable.class.isAssignableFrom(ownerClass);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ String signature = name + desc;
+ if ((opcode == INVOKEVIRTUAL && isAssignableToThrowable(owner))
+ || (opcode == INVOKESTATIC
+ && Type.getInternalName(ThrowableExtension.class).equals(owner))) {
+ AtomicInteger counter = counterMap.get(signature);
+ if (counter == null) {
+ return;
+ }
+ counter.incrementAndGet();
+ }
+ }
+ }
+
+ public int countThrowableAddSuppressed() {
+ return counterMap.get("addSuppressed(Ljava/lang/Throwable;)V").get();
+ }
+
+ public int countThrowableGetSuppressed() {
+ return counterMap.get("getSuppressed()[Ljava/lang/Throwable;").get();
+ }
+
+ public int countThrowablePrintStackTrace() {
+ return counterMap.get("printStackTrace()V").get();
+ }
+
+ public int countThrowablePrintStackTracePrintStream() {
+ return counterMap.get("printStackTrace(Ljava/io/PrintStream;)V").get();
+ }
+
+ public int countThrowablePrintStackTracePrintWriter() {
+ return counterMap.get("printStackTrace(Ljava/io/PrintWriter;)V").get();
+ }
+
+ public int countExtAddSuppressed() {
+ return counterMap.get("addSuppressed(Ljava/lang/Throwable;Ljava/lang/Throwable;)V").get();
+ }
+
+ public int countExtGetSuppressed() {
+ return counterMap.get("getSuppressed(Ljava/lang/Throwable;)[Ljava/lang/Throwable;").get();
+ }
+
+ public int countExtPrintStackTrace() {
+ return counterMap.get("printStackTrace(Ljava/lang/Throwable;)V").get();
+ }
+
+ public int countExtPrintStackTracePrintStream() {
+ return counterMap.get("printStackTrace(Ljava/lang/Throwable;Ljava/io/PrintStream;)V").get();
+ }
+
+ public int countExtPrintStackTracePrintWriter() {
+ return counterMap.get("printStackTrace(Ljava/lang/Throwable;Ljava/io/PrintWriter;)V").get();
+ }
+ }
+
+ private static class DesugaringClassLoader extends ClassLoader {
+
+ private final String targetedClassName;
+ private Class<?> klass;
+ private byte[] classContent;
+ private final Set<String> visitedExceptionTypes = new HashSet<>();
+ private final AtomicInteger numOfTryWithResourcesInvoked = new AtomicInteger();
+
+ public DesugaringClassLoader(String targetedClassName) {
+ super(DesugaringClassLoader.class.getClassLoader());
+ this.targetedClassName = targetedClassName;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals(targetedClassName)) {
+ if (klass != null) {
+ return klass;
+ }
+ // desugar the class, and return the desugared one.
+ classContent = desugarTryWithResources(name);
+ klass = defineClass(name, classContent, 0, classContent.length);
+ return klass;
+ } else {
+ return super.findClass(name);
+ }
+ }
+
+ private byte[] desugarTryWithResources(String className) {
+ try {
+ ClassReader reader = new ClassReader(className);
+ ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS);
+ TryWithResourcesRewriter rewriter =
+ new TryWithResourcesRewriter(
+ writer,
+ TryWithResourcesRewriterTest.class.getClassLoader(),
+ visitedExceptionTypes,
+ numOfTryWithResourcesInvoked);
+ reader.accept(rewriter, 0);
+ return writer.toByteArray();
+ } catch (IOException e) {
+ fail(e.toString());
+ return null; // suppress compiler error.
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/capture_lambda_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/capture_lambda_disassembled_golden.txt
new file mode 100644
index 0000000000..752dad6c8e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/capture_lambda_disassembled_golden.txt
@@ -0,0 +1,21 @@
+final class com.google.devtools.build.android.desugar.testdata.CaptureLambda$$Lambda$0 implements java.util.function.Predicate {
+ private final java.lang.String arg$1;
+
+ com.google.devtools.build.android.desugar.testdata.CaptureLambda$$Lambda$0(java.lang.String);
+ Code:
+ 0: aload_0
+ 1: invokespecial #13 // Method java/lang/Object."<init>":()V
+ 4: aload_0
+ 5: aload_1
+ 6: putfield #15 // Field arg$1:Ljava/lang/String;
+ 9: return
+
+ public boolean test(java.lang.Object);
+ Code:
+ 0: aload_0
+ 1: getfield #15 // Field arg$1:Ljava/lang/String;
+ 4: aload_1
+ 5: checkcast #19 // class java/lang/String
+ 8: invokestatic #25 // Method com/google/devtools/build/android/desugar/testdata/CaptureLambda.lambda$prefixed$0$CaptureLambda:(Ljava/lang/String;Ljava/lang/String;)Z
+ 11: ireturn
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/class_with_inherited_abstract_method_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/class_with_inherited_abstract_method_disassembled_golden.txt
new file mode 100644
index 0000000000..9ab9eb720d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/class_with_inherited_abstract_method_disassembled_golden.txt
@@ -0,0 +1,4 @@
+Compiled from "Named.java"
+public abstract class com.google.devtools.build.android.desugar.testdata.java8.Named$AbstractName extends com.google.devtools.build.android.desugar.testdata.java8.Named$AbstractNameBase implements com.google.devtools.build.android.desugar.testdata.java8.Named {
+ public com.google.devtools.build.android.desugar.testdata.java8.Named$AbstractName();
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/class_with_lambdas_in_implemented_interface_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/class_with_lambdas_in_implemented_interface_disassembled_golden.txt
new file mode 100644
index 0000000000..48a863299d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/class_with_lambdas_in_implemented_interface_disassembled_golden.txt
@@ -0,0 +1,8 @@
+Compiled from "InterfaceMethod.java"
+public class com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod$Concrete implements com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod {
+ public com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod$Concrete();
+ public java.util.List defaultMethodReference(java.util.List);
+ public java.util.List staticMethodReference(java.util.List);
+ public java.util.List lambdaCallsDefaultMethod(java.util.List);
+ public boolean startsWithS(java.lang.String);
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/diff.sh b/src/test/java/com/google/devtools/build/android/desugar/diff.sh
new file mode 100755
index 0000000000..afe2d96f7d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/diff.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2016 The Bazel Authors. 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.
+diff "$1" "$2"
diff --git a/src/test/java/com/google/devtools/build/android/desugar/interface_with_desugared_method_bodies_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/interface_with_desugared_method_bodies_disassembled_golden.txt
new file mode 100644
index 0000000000..828cee4d97
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/interface_with_desugared_method_bodies_disassembled_golden.txt
@@ -0,0 +1,7 @@
+Compiled from "InterfaceMethod.java"
+public interface com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod {
+ public abstract java.util.List<java.lang.String> defaultMethodReference(java.util.List<java.lang.String>);
+ public abstract java.util.List<java.lang.String> staticMethodReference(java.util.List<java.lang.String>);
+ public abstract java.util.List<java.lang.String> lambdaCallsDefaultMethod(java.util.List<java.lang.String>);
+ public abstract boolean startsWithS(java.lang.String);
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/jacoco_0_7_5_default_method.jar b/src/test/java/com/google/devtools/build/android/desugar/jacoco_0_7_5_default_method.jar
new file mode 100644
index 0000000000..1e0deca5a8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/jacoco_0_7_5_default_method.jar
Binary files differ
diff --git a/src/test/java/com/google/devtools/build/android/desugar/jacoco_legacy_default_method_companion_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/jacoco_legacy_default_method_companion_disassembled_golden.txt
new file mode 100644
index 0000000000..0eb51c13ec
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/jacoco_legacy_default_method_companion_disassembled_golden.txt
@@ -0,0 +1,37 @@
+public abstract class com.example.gavra.java8coverage.Defaults$$CC {
+ public static boolean[] $jacocoData;
+
+ public static void foo(com.example.gavra.java8coverage.Defaults);
+ Code:
+ 0: invokestatic #12 // Method $jacocoInit$$STATIC$$:()[Z
+ 3: astore_1
+ 4: aload_1
+ 5: iconst_0
+ 6: iconst_1
+ 7: bastore
+ 8: return
+
+ public static void baz$$STATIC$$();
+ Code:
+ 0: invokestatic #12 // Method $jacocoInit$$STATIC$$:()[Z
+ 3: astore_0
+ 4: aload_0
+ 5: iconst_1
+ 6: iconst_1
+ 7: bastore
+ 8: return
+
+ static boolean[] $jacocoInit$$STATIC$$();
+ Code:
+ 0: getstatic #18 // Field $jacocoData:[Z
+ 3: dup
+ 4: ifnonnull 21
+ 7: pop
+ 8: ldc2_w #19 // long -7447229029980688604l
+ 11: ldc #22 // String com/example/gavra/java8coverage/Defaults
+ 13: iconst_2
+ 14: invokestatic #28 // Method org/jacoco/agent/rt/internal_773e439/Offline.getProbes:(JLjava/lang/String;I)[Z
+ 17: dup
+ 18: putstatic #18 // Field $jacocoData:[Z
+ 21: areturn
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/mocked_android_framework/android/os/Build.java b/src/test/java/com/google/devtools/build/android/desugar/mocked_android_framework/android/os/Build.java
new file mode 100644
index 0000000000..43d2f7df08
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/mocked_android_framework/android/os/Build.java
@@ -0,0 +1,31 @@
+// Copyright 2017 The Bazel Authors. 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 android.os;
+
+/** This class is a standin for android.os.Build for tests running in a JVM */
+public final class Build {
+
+ public static final String SYSTEM_PROPERTY_NAME = "fortest.simulated.android.sdk_int";
+
+ /** A simple mock for the real android.os.Build.VERSION */
+ public static final class VERSION {
+
+ public static final int SDK_INT;
+
+ static {
+ String sdkInt = System.getProperty(SYSTEM_PROPERTY_NAME, "0");
+ SDK_INT = Integer.parseInt(sdkInt);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/runtime/BUILD b/src/test/java/com/google/devtools/build/android/desugar/runtime/BUILD
new file mode 100644
index 0000000000..d6f03e0655
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/runtime/BUILD
@@ -0,0 +1,98 @@
+# Description:
+# Tests for the extension classes for desugaring try-with-resources for Android.
+package(
+ default_testonly = 1,
+ default_visibility = ["//src/test/java/com/google/devtools/build/android/desugar:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ testonly = 0,
+ srcs = glob(["*"]),
+)
+
+java_library(
+ name = "throwable_extension_test_utility",
+ srcs = ["ThrowableExtensionTestUtility.java"],
+ deps = [
+ "//third_party:guava",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "ThrowableExtensionTestWithMimicDesugaringStrategy",
+ size = "small",
+ srcs = ["ThrowableExtensionTest.java"],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$MimicDesugaringStrategy'",
+ ],
+ test_class = "com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTest",
+ deps = [
+ ":throwable_extension_test_utility",
+ "//src/test/java/com/google/devtools/build/android/desugar:mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "ThrowableExtensionTestWithNullDesugaringStrategy",
+ size = "small",
+ srcs = ["ThrowableExtensionTest.java"],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=18",
+ "-Dcom.google.devtools.build.android.desugar.runtime.twr_disable_mimic=true",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$NullDesugaringStrategy'",
+ ],
+ test_class = "com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTest",
+ deps = [
+ ":throwable_extension_test_utility",
+ "//src/test/java/com/google/devtools/build/android/desugar:mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "ThrowableExtensionTestWithReuseDesugaringStrategy",
+ size = "small",
+ srcs = ["ThrowableExtensionTest.java"],
+ jvm_flags = [
+ "-Dfortest.simulated.android.sdk_int=19",
+ "'-Dexpected.strategy=com.google.devtools.build.android.desugar.runtime.ThrowableExtension$$ReuseDesugaringStrategy'",
+ ],
+ test_class = "com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTest",
+ deps = [
+ ":throwable_extension_test_utility",
+ "//src/test/java/com/google/devtools/build/android/desugar:mocked_android_os_sdk_for_testing",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
+ name = "ConcurrentWeakIdentityHashMapTest",
+ timeout = "long", # multi-threaded and rely on GC, so it could take long.
+ srcs = ["ConcurrentWeakIdentityHashMapTest.java"],
+ test_class = "com.google.devtools.build.android.desugar.runtime.ConcurrentWeakIdentityHashMapTest",
+ deps = [
+ "//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension",
+ "//third_party:guava",
+ "//third_party:guava-testlib",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/android/desugar/runtime/ConcurrentWeakIdentityHashMapTest.java b/src/test/java/com/google/devtools/build/android/desugar/runtime/ConcurrentWeakIdentityHashMapTest.java
new file mode 100644
index 0000000000..2fde7f49ae
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/runtime/ConcurrentWeakIdentityHashMapTest.java
@@ -0,0 +1,262 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.runtime;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.testing.GcFinalization;
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension.ConcurrentWeakIdentityHashMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link ConcurrentWeakIdentityHashMap}. This test uses multi-threading, and needs GC
+ * sometime to assert weak references, so it could take long.
+ */
+@RunWith(JUnit4.class)
+public class ConcurrentWeakIdentityHashMapTest {
+
+ private final Random random = new Random();
+
+ /**
+ * This method makes sure that after return, all the exceptions in the map should be garbage
+ * collected. .
+ */
+ private static ConcurrentWeakIdentityHashMap
+ testConcurrentWeakIdentityHashMapSingleThreadedHelper(CountDownLatch latch)
+ throws InterruptedException {
+ ConcurrentWeakIdentityHashMap map = new ConcurrentWeakIdentityHashMap();
+ Exception e1 = new ExceptionWithLatch("e1", latch);
+ assertThat(map.get(e1, false)).isNull();
+ assertThat(map.get(e1, true)).isNotNull();
+ assertThat(map.get(e1, true)).isEmpty();
+ assertThat(map.get(e1, false)).isNotNull();
+
+ Exception suppressed1 = new ExceptionWithLatch("suppressed1", latch);
+ map.get(e1, true).add(suppressed1);
+ assertThat(map.get(e1, true)).containsExactly(suppressed1);
+
+ Exception suppressed2 = new ExceptionWithLatch("suppressed2", latch);
+ map.get(e1, true).add(suppressed2);
+ assertThat(map.get(e1, true)).containsExactly(suppressed1, suppressed2);
+
+ assertThat(map.get(suppressed1, false)).isNull();
+ assertThat(map.get(suppressed2, false)).isNull();
+ assertThat(map.size()).isEqualTo(1);
+ assertThat(map.get(suppressed1, true)).isNotNull();
+ assertThat(map.size()).isEqualTo(2);
+ assertThat(map.get(suppressed1, true)).isNotNull();
+ assertThat(map.size()).isEqualTo(2);
+
+ Exception e2 = new ExceptionWithLatch("e2", latch);
+ assertThat(map.get(e2, true)).isNotNull();
+ Exception e3 = new ExceptionWithLatch("e3", latch);
+ assertThat(map.get(e3, true)).isNotNull();
+ assertThat(map.size()).isEqualTo(4);
+ return map;
+ }
+
+ @Test
+ public void testSingleThreadedUse() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(5);
+ ConcurrentWeakIdentityHashMap map =
+ testConcurrentWeakIdentityHashMapSingleThreadedHelper(latch);
+ for (int i = 0; i < 5; i++) {
+ map.deleteEmptyKeys();
+ GcFinalization.awaitFullGc();
+ }
+ latch.await(); // wait for e1 to be garbage collected.
+ map.deleteEmptyKeys();
+ assertThat(map.size()).isEqualTo(0);
+ }
+
+ private static Map<Throwable, List<Throwable>> createExceptionWithSuppressed(
+ int numMainExceptions, int numSuppressedPerMain, CountDownLatch latch) {
+ Map<Throwable, List<Throwable>> map = new HashMap<>();
+ for (int i = 0; i < numMainExceptions; ++i) {
+ Exception main = new ExceptionWithLatch("main-" + i, latch);
+ List<Throwable> suppressedList = new ArrayList<>();
+ assertThat(map).doesNotContainKey(main);
+ map.put(main, suppressedList);
+ for (int j = 0; j < numSuppressedPerMain; ++j) {
+ Exception suppressed = new ExceptionWithLatch("suppressed-" + j + "-main-" + i, latch);
+ suppressedList.add(suppressed);
+ }
+ }
+ return map;
+ }
+
+ private ConcurrentWeakIdentityHashMap testFunctionalCorrectnessForMultiThreadedUse(
+ int numMainExceptions, int numSuppressedPerMain, CountDownLatch latch)
+ throws InterruptedException {
+ Map<Throwable, List<Throwable>> exceptionWithSuppressed =
+ createExceptionWithSuppressed(numMainExceptions, numSuppressedPerMain, latch);
+ assertThat(exceptionWithSuppressed).hasSize(numMainExceptions);
+ List<Pair> allPairs =
+ exceptionWithSuppressed
+ .entrySet()
+ .stream()
+ .flatMap(
+ entry -> entry.getValue().stream().map(value -> new Pair(entry.getKey(), value)))
+ .collect(Collectors.toList());
+ Collections.shuffle(allPairs);
+ ConcurrentWeakIdentityHashMap map = new ConcurrentWeakIdentityHashMap();
+ List<Worker> workers =
+ IntStream.range(1, 11) // ten threads.
+ .mapToObj(i -> new Worker("worker-" + i, map))
+ .collect(Collectors.toList());
+
+ // Assign tasks to workers.
+ Iterator<Worker> workIterator = workers.iterator();
+ for (Pair pair : allPairs) {
+ if (!workIterator.hasNext()) {
+ workIterator = workers.iterator();
+ }
+ assertThat(workIterator.hasNext()).isTrue();
+ workIterator.next().exceptionList.add(pair);
+ }
+
+ // Execute all the workers.
+ ExecutorService executorService = Executors.newFixedThreadPool(workers.size());
+ workers.forEach(executorService::execute);
+ executorService.shutdown();
+ executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); // wait for completion.
+ exceptionWithSuppressed
+ .entrySet()
+ .forEach(
+ entry -> {
+ assertThat(map.get(entry.getKey(), false)).isNotNull();
+ assertThat(map.get(entry.getKey(), false))
+ .containsExactlyElementsIn(exceptionWithSuppressed.get(entry.getKey()));
+ });
+ return map;
+ }
+
+ private void testMultiThreadedUse(int numMainExceptions, int numSuppressedPerMain)
+ throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(numMainExceptions * numSuppressedPerMain);
+ ConcurrentWeakIdentityHashMap map =
+ testFunctionalCorrectnessForMultiThreadedUse(
+ numMainExceptions, numSuppressedPerMain, latch);
+ /*
+ * Calling the following methods multiple times to make sure the keys are garbage collected,
+ * and their corresponding entries are removed from the map.
+ */
+ map.deleteEmptyKeys();
+ GcFinalization.awaitFullGc();
+ map.deleteEmptyKeys();
+ GcFinalization.awaitFullGc();
+ map.deleteEmptyKeys();
+
+ assertThat(map.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testMultiThreadedUseMedium() throws InterruptedException {
+ for (int i = 0; i < 10; ++i) {
+ testMultiThreadedUse(50, 100);
+ }
+ }
+
+ @Test
+ public void testMultiThreadedUseLarge() throws InterruptedException {
+ for (int i = 0; i < 5; ++i) {
+ testMultiThreadedUse(100, 100);
+ }
+ }
+
+ @Test
+ public void testMultiThreadedUseSmall() throws InterruptedException {
+ for (int i = 0; i < 10; ++i) {
+ testMultiThreadedUse(20, 100);
+ }
+ }
+
+ private static class ExceptionWithLatch extends Exception {
+ private final CountDownLatch latch;
+
+ private ExceptionWithLatch(String message, CountDownLatch latch) {
+ super(message);
+ this.latch = latch;
+ }
+
+ @Override
+ public String toString() {
+ return this.getMessage();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ latch.countDown();
+ }
+ }
+
+ private static class Pair {
+ final Throwable throwable;
+ final Throwable suppressed;
+
+ public Pair(Throwable throwable, Throwable suppressed) {
+ this.throwable = throwable;
+ this.suppressed = suppressed;
+ }
+ }
+
+ private class Worker implements Runnable {
+ private final ConcurrentWeakIdentityHashMap map;
+ private final List<Pair> exceptionList = new ArrayList<>();
+ private final String name;
+
+ private Worker(String name, ConcurrentWeakIdentityHashMap map) {
+ this.name = name;
+ this.map = map;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void run() {
+ Iterator<Pair> iterator = exceptionList.iterator();
+ while (iterator.hasNext()) {
+ int timeToSleep = random.nextInt(3);
+ if (random.nextBoolean() && timeToSleep > 0) {
+ try {
+ Thread.sleep(timeToSleep); // add randomness to the scheduler.
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ Pair pair = iterator.next();
+ List<Throwable> suppressed = map.get(pair.throwable, true);
+ System.out.printf("add suppressed %s to %s\n", pair.suppressed, pair.throwable);
+ suppressed.add(pair.suppressed);
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTest.java b/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTest.java
new file mode 100644
index 0000000000..5ac88b89de
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTest.java
@@ -0,0 +1,453 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.runtime;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtension.MimicDesugaringStrategy.SUPPRESSED_PREFIX;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.getTwrStrategyClassNameSpecifiedInSystemProperty;
+import static com.google.devtools.build.android.desugar.runtime.ThrowableExtensionTestUtility.isNullStrategy;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.fail;
+
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension.MimicDesugaringStrategy;
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension.NullDesugaringStrategy;
+import com.google.devtools.build.android.desugar.runtime.ThrowableExtension.ReuseDesugaringStrategy;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test case for {@link ThrowableExtension} */
+@RunWith(JUnit4.class)
+public class ThrowableExtensionTest {
+
+ /**
+ * This test tests the behavior of closing resources via reflection. This is only enabled below
+ * API 19. So, if the API level is 19 or above, this test will simply skip.
+ */
+ @Test
+ public void testCloseResourceViaReflection() throws Throwable {
+ class Resource extends AbstractResource {
+ protected Resource(boolean exceptionOnClose) {
+ super(exceptionOnClose);
+ }
+
+ public void close() throws Exception {
+ super.internalClose();
+ }
+ }
+ if (ThrowableExtension.API_LEVEL >= 19) {
+ return;
+ }
+ {
+ Resource r = new Resource(false);
+ assertThat(r.isClosed()).isFalse();
+ ThrowableExtension.closeResource(null, r);
+ assertThat(r.isClosed()).isTrue();
+ }
+ {
+ Resource r = new Resource(true);
+ assertThat(r.isClosed()).isFalse();
+ assertThrows(IOException.class, () -> ThrowableExtension.closeResource(null, r));
+ }
+ {
+ Resource r = new Resource(false);
+ assertThat(r.isClosed()).isFalse();
+ ThrowableExtension.closeResource(new Exception(), r);
+ assertThat(r.isClosed()).isTrue();
+ }
+ {
+ Resource r = new Resource(true);
+ assertThat(r.isClosed()).isFalse();
+ assertThrows(Exception.class, () -> ThrowableExtension.closeResource(new Exception(), r));
+ }
+ }
+
+ /**
+ * Test the new method closeResources() in the runtime library.
+ *
+ * <p>The method is introduced to fix b/37167433.
+ */
+ @Test
+ public void testCloseResource() throws Throwable {
+
+ /**
+ * A resource implementing the interface AutoCloseable. This interface is only available since
+ * API 19.
+ */
+ class AutoCloseableResource extends AbstractResource implements AutoCloseable {
+
+ protected AutoCloseableResource(boolean exceptionOnClose) {
+ super(exceptionOnClose);
+ }
+
+ @Override
+ public void close() throws Exception {
+ internalClose();
+ }
+ }
+
+ /** A resource implementing the interface Closeable. */
+ class CloseableResource extends AbstractResource implements Closeable {
+
+ protected CloseableResource(boolean exceptionOnClose) {
+ super(exceptionOnClose);
+ }
+
+ @Override
+ public void close() throws IOException {
+ internalClose();
+ }
+ }
+
+ {
+ CloseableResource r = new CloseableResource(false);
+ assertThat(r.isClosed()).isFalse();
+ ThrowableExtension.closeResource(null, r);
+ assertThat(r.isClosed()).isTrue();
+ }
+ {
+ CloseableResource r = new CloseableResource(false);
+ assertThat(r.isClosed()).isFalse();
+ Exception suppressor = new Exception();
+ ThrowableExtension.closeResource(suppressor, r);
+ assertThat(r.isClosed()).isTrue();
+ assertThat(ThrowableExtension.getSuppressed(suppressor)).isEmpty();
+ }
+ {
+ CloseableResource r = new CloseableResource(true);
+ assertThat(r.isClosed()).isFalse();
+ assertThrows(IOException.class, () -> ThrowableExtension.closeResource(null, r));
+ assertThat(r.isClosed()).isFalse();
+ }
+ {
+ CloseableResource r = new CloseableResource(true);
+ assertThat(r.isClosed()).isFalse();
+ Exception suppressor = new Exception();
+ assertThrows(Exception.class, () -> ThrowableExtension.closeResource(suppressor, r));
+ assertThat(r.isClosed()).isFalse(); // Failed to close.
+ if (!isNullStrategy()) {
+ assertThat(ThrowableExtension.getSuppressed(suppressor)).hasLength(1);
+ assertThat(ThrowableExtension.getSuppressed(suppressor)[0].getClass())
+ .isEqualTo(IOException.class);
+ }
+ }
+ {
+ AutoCloseableResource r = new AutoCloseableResource(false);
+ assertThat(r.isClosed()).isFalse();
+ ThrowableExtension.closeResource(null, r);
+ assertThat(r.isClosed()).isTrue();
+ }
+ {
+ AutoCloseableResource r = new AutoCloseableResource(false);
+ assertThat(r.isClosed()).isFalse();
+ Exception suppressor = new Exception();
+ ThrowableExtension.closeResource(suppressor, r);
+ assertThat(r.isClosed()).isTrue();
+ assertThat(ThrowableExtension.getSuppressed(suppressor)).isEmpty();
+ }
+ {
+ AutoCloseableResource r = new AutoCloseableResource(true);
+ assertThat(r.isClosed()).isFalse();
+ assertThrows(IOException.class, () -> ThrowableExtension.closeResource(null, r));
+ assertThat(r.isClosed()).isFalse();
+ }
+ {
+ AutoCloseableResource r = new AutoCloseableResource(true);
+ assertThat(r.isClosed()).isFalse();
+ Exception suppressor = new Exception();
+ assertThrows(Exception.class, () -> ThrowableExtension.closeResource(suppressor, r));
+ assertThat(r.isClosed()).isFalse(); // Failed to close.
+ if (!isNullStrategy()) {
+ assertThat(ThrowableExtension.getSuppressed(suppressor)).hasLength(1);
+ assertThat(ThrowableExtension.getSuppressed(suppressor)[0].getClass())
+ .isEqualTo(IOException.class);
+ }
+ assertThat(r.isClosed()).isFalse();
+ }
+ }
+
+ /**
+ * LightweightStackTraceRecorder tracks the calls of various printStackTrace(*), and ensures that
+ *
+ * <p>suppressed exceptions are printed only once.
+ */
+ @Test
+ public void testLightweightStackTraceRecorder() throws IOException {
+ MimicDesugaringStrategy strategy = new MimicDesugaringStrategy();
+ ExceptionForTest receiver = new ExceptionForTest(strategy);
+ FileNotFoundException suppressed = new FileNotFoundException();
+ strategy.addSuppressed(receiver, suppressed);
+
+ String trace = printStackTraceStderrToString(() -> strategy.printStackTrace(receiver));
+ assertThat(trace).contains(SUPPRESSED_PREFIX);
+ assertThat(countOccurrences(trace, SUPPRESSED_PREFIX)).isEqualTo(1);
+ }
+
+ @Test
+ public void testMimicDesugaringStrategy() throws IOException {
+ MimicDesugaringStrategy strategy = new MimicDesugaringStrategy();
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ strategy.addSuppressed(receiver, suppressed);
+
+ assertThat(
+ printStackTracePrintStreamToString(
+ stream -> strategy.printStackTrace(receiver, stream)))
+ .contains(SUPPRESSED_PREFIX);
+
+ assertThat(
+ printStackTracePrintWriterToString(
+ writer -> strategy.printStackTrace(receiver, writer)))
+ .contains(SUPPRESSED_PREFIX);
+
+ assertThat(printStackTraceStderrToString(() -> strategy.printStackTrace(receiver)))
+ .contains(SUPPRESSED_PREFIX);
+ }
+
+ private void testThrowableExtensionWithMimicDesugaringStrategy() throws IOException {
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ ThrowableExtension.addSuppressed(receiver, suppressed);
+
+ assertThat(
+ printStackTracePrintStreamToString(
+ stream -> ThrowableExtension.printStackTrace(receiver, stream)))
+ .contains(SUPPRESSED_PREFIX);
+ assertThat(
+ printStackTracePrintWriterToString(
+ writer -> ThrowableExtension.printStackTrace(receiver, writer)))
+ .contains(SUPPRESSED_PREFIX);
+ assertThat(printStackTraceStderrToString(() -> ThrowableExtension.printStackTrace(receiver)))
+ .contains(SUPPRESSED_PREFIX);
+ }
+
+ private interface PrintStackTraceCaller {
+ void printStackTrace();
+ }
+
+ private static String printStackTraceStderrToString(PrintStackTraceCaller caller)
+ throws IOException {
+ PrintStream err = System.err;
+ try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+ PrintStream newErr = new PrintStream(stream);
+ System.setErr(newErr);
+ caller.printStackTrace();
+ newErr.flush();
+ return stream.toString();
+ } finally {
+ System.setErr(err);
+ }
+ }
+
+ private static String printStackTracePrintStreamToString(Consumer<PrintStream> caller)
+ throws IOException {
+ try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+ PrintStream printStream = new PrintStream(stream);
+ caller.accept(printStream);
+ printStream.flush();
+ return stream.toString();
+ }
+ }
+
+ private static String printStackTracePrintWriterToString(Consumer<PrintWriter> caller)
+ throws IOException {
+ try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+ PrintWriter printWriter =
+ new PrintWriter(new BufferedWriter(new OutputStreamWriter(stream, UTF_8)));
+ caller.accept(printWriter);
+ printWriter.flush();
+ return stream.toString();
+ }
+ }
+
+ @Test
+ public void testNullDesugaringStrategy() throws IOException {
+ NullDesugaringStrategy strategy = new NullDesugaringStrategy();
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ strategy.addSuppressed(receiver, suppressed);
+ assertThat(strategy.getSuppressed(receiver)).isEmpty();
+
+ strategy.addSuppressed(receiver, suppressed);
+ assertThat(strategy.getSuppressed(receiver)).isEmpty();
+
+ assertThat(printStackTracePrintStreamToString(stream -> receiver.printStackTrace(stream)))
+ .isEqualTo(
+ printStackTracePrintStreamToString(
+ stream -> strategy.printStackTrace(receiver, stream)));
+
+ assertThat(printStackTracePrintWriterToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTracePrintWriterToString(
+ writer -> strategy.printStackTrace(receiver, writer)));
+
+ assertThat(printStackTraceStderrToString(receiver::printStackTrace))
+ .isEqualTo(printStackTraceStderrToString(() -> strategy.printStackTrace(receiver)));
+ }
+
+ private void testThrowableExtensionWithNullDesugaringStrategy() throws IOException {
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ ThrowableExtension.addSuppressed(receiver, suppressed);
+ assertThat(ThrowableExtension.getSuppressed(receiver)).isEmpty();
+
+ ThrowableExtension.addSuppressed(receiver, suppressed);
+ assertThat(ThrowableExtension.getSuppressed(receiver)).isEmpty();
+
+ assertThat(printStackTracePrintStreamToString(stream -> receiver.printStackTrace(stream)))
+ .isEqualTo(
+ printStackTracePrintStreamToString(
+ stream -> ThrowableExtension.printStackTrace(receiver, stream)));
+ assertThat(printStackTracePrintWriterToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTracePrintWriterToString(
+ writer -> ThrowableExtension.printStackTrace(receiver, writer)));
+
+ assertThat(printStackTraceStderrToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTraceStderrToString(() -> ThrowableExtension.printStackTrace(receiver)));
+ }
+
+ @Test
+ public void testReuseDesugaringStrategy() throws IOException {
+ ReuseDesugaringStrategy strategy = new ReuseDesugaringStrategy();
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ strategy.addSuppressed(receiver, suppressed);
+ assertThat(strategy.getSuppressed(receiver))
+ .asList()
+ .containsExactly((Object[]) receiver.getSuppressed());
+
+ assertThat(printStackTracePrintStreamToString(stream -> receiver.printStackTrace(stream)))
+ .isEqualTo(
+ printStackTracePrintStreamToString(
+ stream -> strategy.printStackTrace(receiver, stream)));
+
+ assertThat(printStackTracePrintWriterToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTracePrintWriterToString(
+ writer -> strategy.printStackTrace(receiver, writer)));
+ assertThat(printStackTraceStderrToString(receiver::printStackTrace))
+ .isEqualTo(printStackTraceStderrToString(() -> strategy.printStackTrace(receiver)));
+ }
+
+ private void testThrowableExtensionWithReuseDesugaringStrategy() throws IOException {
+ IOException receiver = new IOException();
+ FileNotFoundException suppressed = new FileNotFoundException();
+ ThrowableExtension.addSuppressed(receiver, suppressed);
+ assertThat(ThrowableExtension.getSuppressed(receiver))
+ .asList()
+ .containsExactly((Object[]) receiver.getSuppressed());
+
+ assertThat(printStackTracePrintStreamToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTracePrintStreamToString(
+ stream -> ThrowableExtension.printStackTrace(receiver, stream)));
+
+ assertThat(printStackTracePrintWriterToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTracePrintWriterToString(
+ writer -> ThrowableExtension.printStackTrace(receiver, writer)));
+
+ assertThat(printStackTraceStderrToString(receiver::printStackTrace))
+ .isEqualTo(
+ printStackTraceStderrToString(() -> ThrowableExtension.printStackTrace(receiver)));
+ }
+
+ /** This class */
+ private static class ExceptionForTest extends Exception {
+
+ private final MimicDesugaringStrategy strategy;
+
+ public ExceptionForTest(MimicDesugaringStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ @Override
+ public void printStackTrace() {
+ this.printStackTrace(System.err);
+ }
+
+ /**
+ * This method should call this.printStackTrace(PrintWriter) directly. I deliberately change it
+ * to strategy.printStackTrace(Throwable, PrintWriter) to simulate the behavior of Desguar, that
+ * is, the direct call is intercepted and redirected to ThrowableExtension.
+ */
+ @Override
+ public void printStackTrace(PrintStream s) {
+ this.strategy.printStackTrace(
+ this, new PrintWriter(new BufferedWriter(new OutputStreamWriter(s, UTF_8))));
+ }
+ }
+
+ @Test
+ public void testStrategySelection() throws ClassNotFoundException, IOException {
+ String expectedStrategyClassName = getTwrStrategyClassNameSpecifiedInSystemProperty();
+ assertThat(expectedStrategyClassName).isNotEmpty();
+ assertThat(expectedStrategyClassName)
+ .isEqualTo(ThrowableExtension.STRATEGY.getClass().getName());
+
+ Class<?> expectedStrategyClass = Class.forName(expectedStrategyClassName);
+ if (expectedStrategyClass.equals(ReuseDesugaringStrategy.class)) {
+ testThrowableExtensionWithReuseDesugaringStrategy();
+ } else if (expectedStrategyClass.equals(MimicDesugaringStrategy.class)) {
+ testThrowableExtensionWithMimicDesugaringStrategy();
+ } else if (expectedStrategyClass.equals(NullDesugaringStrategy.class)) {
+ testThrowableExtensionWithNullDesugaringStrategy();
+ } else {
+ fail("unrecognized expected strategy class " + expectedStrategyClassName);
+ }
+ }
+
+ private static int countOccurrences(String string, String substring) {
+ int i = 0;
+ int count = 0;
+ while ((i = string.indexOf(substring, i)) >= 0) {
+ ++count;
+ i = i + string.length();
+ }
+ return count;
+ }
+
+ /** A mocked closeable class, which we can query the closedness. */
+ private abstract static class AbstractResource {
+ private final boolean exceptionOnClose;
+ private boolean closed;
+
+ protected AbstractResource(boolean exceptionOnClose) {
+ this.exceptionOnClose = exceptionOnClose;
+ }
+
+ boolean isClosed() {
+ return closed;
+ }
+
+ void internalClose() throws IOException {
+ if (exceptionOnClose) {
+ throw new IOException("intended exception");
+ }
+ closed = true;
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTestUtility.java b/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTestUtility.java
new file mode 100644
index 0000000000..b65b8bdd90
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtensionTestUtility.java
@@ -0,0 +1,64 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.runtime;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.lang.reflect.Method;
+
+/**
+ * A utility class for testing ThrowableExtension. It uses reflection to get the strategy name, so
+ * as to avoid dependency on the runtime library. This is beneficial, because we can test whether
+ * the runtime library is on the classpath.
+ */
+public class ThrowableExtensionTestUtility {
+
+ private static final String SYSTEM_PROPERTY_EXPECTED_STRATEGY = "expected.strategy";
+
+ public static String getTwrStrategyClassNameSpecifiedInSystemProperty() {
+ String className = System.getProperty(SYSTEM_PROPERTY_EXPECTED_STRATEGY);
+ assertThat(className).isNotEmpty();
+ return className;
+ }
+
+ private static final String THROWABLE_EXTENSION_CLASS_NAME =
+ "com.google.devtools.build.android.desugar.runtime.ThrowableExtension";
+
+ private static boolean isStrategyOfClass(String className) {
+ return getStrategyClassName().equals(className);
+ }
+
+ public static String getStrategyClassName() {
+ try {
+ Class<?> klass = Class.forName(THROWABLE_EXTENSION_CLASS_NAME);
+ Method method = klass.getMethod("getStrategy");
+ Object strategy = method.invoke(null);
+ return strategy.getClass().getName();
+ } catch (Throwable e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static boolean isMimicStrategy() {
+ return isStrategyOfClass(THROWABLE_EXTENSION_CLASS_NAME + "$MimicDesugaringStrategy");
+ }
+
+ public static boolean isNullStrategy() {
+ return isStrategyOfClass(THROWABLE_EXTENSION_CLASS_NAME + "$NullDesugaringStrategy");
+ }
+
+ public static boolean isReuseStrategy() {
+ return isStrategyOfClass(THROWABLE_EXTENSION_CLASS_NAME + "$ReuseDesugaringStrategy");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/simple_instance_method_reference_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/simple_instance_method_reference_disassembled_golden.txt
new file mode 100644
index 0000000000..7f26e7ef87
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/simple_instance_method_reference_disassembled_golden.txt
@@ -0,0 +1,21 @@
+final class com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass$$Lambda$0 implements java.util.function.Predicate {
+ private final com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass arg$1;
+
+ com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass$$Lambda$0(com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass);
+ Code:
+ 0: aload_0
+ 1: invokespecial #13 // Method java/lang/Object."<init>":()V
+ 4: aload_0
+ 5: aload_1
+ 6: putfield #15 // Field arg$1:Lcom/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass;
+ 9: return
+
+ public boolean test(java.lang.Object);
+ Code:
+ 0: aload_0
+ 1: getfield #15 // Field arg$1:Lcom/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass;
+ 4: aload_1
+ 5: checkcast #19 // class java/lang/String
+ 8: invokevirtual #25 // Method com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.bridge$lambda$0$MethodReferenceSuperclass:(Ljava/lang/String;)Z
+ 11: ireturn
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/stateless_lambda_disassembled_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/stateless_lambda_disassembled_golden.txt
new file mode 100644
index 0000000000..c297c0477a
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/stateless_lambda_disassembled_golden.txt
@@ -0,0 +1,24 @@
+final class com.google.devtools.build.android.desugar.testdata.Lambda$$Lambda$0 implements java.util.function.Predicate {
+ static final java.util.function.Predicate $instance;
+
+ private com.google.devtools.build.android.desugar.testdata.Lambda$$Lambda$0();
+ Code:
+ 0: aload_0
+ 1: invokespecial #10 // Method java/lang/Object."<init>":()V
+ 4: return
+
+ public boolean test(java.lang.Object);
+ Code:
+ 0: aload_1
+ 1: checkcast #14 // class java/lang/String
+ 4: invokestatic #20 // Method com/google/devtools/build/android/desugar/testdata/Lambda.lambda$as$0$Lambda:(Ljava/lang/String;)Z
+ 7: ireturn
+
+ static {};
+ Code:
+ 0: new #2 // class com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$0
+ 3: dup
+ 4: invokespecial #24 // Method "<init>":()V
+ 7: putstatic #26 // Field $instance:Ljava/util/function/Predicate;
+ 10: return
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/static_initializer_of_functional_interface_should_not_execute.sh b/src/test/java/com/google/devtools/build/android/desugar/static_initializer_of_functional_interface_should_not_execute.sh
new file mode 100755
index 0000000000..32b4c5a6b1
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/static_initializer_of_functional_interface_should_not_execute.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -e
+#
+# Copyright 2016 The Bazel Authors. 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.
+
+# Test whether Desugar runs static initializers of interfaces.
+if grep "THIS STRING IS NOT EXPECTED TO APPEAR IN THE OUTPUT OF DESUGAR!!!" "${1}" ; then
+ exit 1
+else
+ exit 0
+fi
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java
new file mode 100644
index 0000000000..6c4b6f5169
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java
@@ -0,0 +1,33 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CaptureLambda {
+
+ private final List<String> names;
+
+ public CaptureLambda(List<String> names) {
+ this.names = names;
+ }
+
+ public List<String> prefixed(String prefix) {
+ return names
+ .stream()
+ .filter(n -> n.startsWith(prefix))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java
new file mode 100644
index 0000000000..1026437b9e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java
@@ -0,0 +1,51 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+/** This class calls Long.compare(long, long) */
+public class ClassCallingLongCompare {
+
+ public static int compareLongByCallingLong_compare(long a, long b) {
+ return Long.compare(a, b);
+ }
+
+ public static String compareLongByCallingLong_compare2(long a, long b) {
+ if (Long.compare(a, b) == 0) {
+ return "e";
+ }
+ if (Long.compare(a, b) > 0) {
+ return "g";
+ }
+ if (Long.compare(a, b) < 0) {
+ return "l";
+ }
+ throw new AssertionError("unreachable");
+ }
+
+ public static int compareLongWithLambda(long a, long b) {
+ return internalCompare(a, b, (long l1, long l2) -> Long.compare(l1, l2));
+ }
+
+ public static int compareLongWithMethodReference(long a, long b) {
+ return internalCompare(a, b, Long::compare);
+ }
+
+ private static interface LongCmpFunc {
+ int compare(long a, long b);
+ }
+
+ private static int internalCompare(long a, long b, LongCmpFunc func) {
+ return func.compare(a, b);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java
new file mode 100644
index 0000000000..3823f1d774
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java
@@ -0,0 +1,53 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.Objects;
+import java.util.function.IntSupplier;
+
+/** This class is for the testing of desugaring calls to Objects.requireNonNull(Object o...) */
+public class ClassCallingRequireNonNull {
+
+ public static int getStringLengthWithMethodReference(String s) {
+ return toInt(s::length);
+ }
+
+ public static int toInt(IntSupplier function) {
+ return function.getAsInt();
+ }
+
+ public static int getStringLengthWithLambdaAndExplicitCallToRequireNonNull(final String s) {
+ return toInt(() -> Objects.requireNonNull(s).length());
+ }
+
+ public static char getFirstCharVersionOne(String string) {
+ Objects.requireNonNull(string);
+ return string.charAt(0);
+ }
+
+ public static char getFirstCharVersionTwo(String string) {
+ string = Objects.requireNonNull(string);
+ return string.charAt(0);
+ }
+
+ public static char callRequireNonNullWithArgumentString(String string) {
+ string = Objects.requireNonNull(string, "the string should not be null");
+ return string.charAt(0);
+ }
+
+ public static char callRequireNonNullWithArgumentSupplier(String string) {
+ string = Objects.requireNonNull(string, () -> "the string should not be null");
+ return string.charAt(0);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java
new file mode 100644
index 0000000000..c340c8489d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java
@@ -0,0 +1,88 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * This is a test subject for {@link
+ * com.google.devtools.build.android.desugar.TryWithResourcesRewriter}
+ */
+public class ClassUsingTryWithResources {
+
+ /**
+ * A simple resource, which always throws an exception when being closed.
+ *
+ * <p>Note that we need to implement java.io.Closeable instead of java.lang.AutoCloseable, because
+ * AutoCloseable is not available below API 19
+ *
+ * <p>java9 will emit $closeResource(Throwable, AutoCloseable) for the following class.
+ */
+ public static class SimpleResource implements Closeable {
+
+ public void call(boolean throwException) {
+ if (throwException) {
+ throw new RuntimeException("exception in call()");
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ throw new IOException("exception in close().");
+ }
+ }
+
+ /** This method will always throw {@link java.lang.Exception}. */
+ public static void simpleTryWithResources() throws Exception {
+ // Throwable.addSuppressed(Throwable) should be called in the following block.
+ try (SimpleResource resource = new SimpleResource()) {
+ resource.call(true);
+ }
+ }
+
+ public static Throwable[] checkSuppressedExceptions(boolean throwException) {
+ // Throwable.addSuppressed(Throwable) should be called in the following block.
+ try (SimpleResource resource = new SimpleResource()) {
+ resource.call(throwException);
+ } catch (Exception e) {
+ return e.getSuppressed(); // getSuppressed() is called.
+ }
+ return new Throwable[0];
+ }
+
+ public static String printStackTraceOfCaughtException() {
+ try {
+ simpleTryWithResources();
+ } catch (Exception e) {
+ PrintStream err = System.err;
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ try {
+ System.setErr(new PrintStream(stream, true, "utf-8"));
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e1) {
+ throw new AssertionError(e1);
+ } finally {
+ System.setErr(err);
+ }
+ return new String(stream.toByteArray(), UTF_8);
+ }
+ return "";
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java
new file mode 100644
index 0000000000..69bacdc6a8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java
@@ -0,0 +1,54 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import com.google.devtools.build.android.desugar.testdata.separate.SeparateInterface;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ConcreteFunction implements SpecializedFunction<String, Long> {
+ @Override
+ public Long apply(String input) {
+ return Long.valueOf(input);
+ }
+
+ // SpecializedParser makes it so we have to search multiple extended interfaces for bridge methods
+ // when desugaring the lambda returned by this method.
+ public static SpecializedParser<Integer> toInt() {
+ return (s -> Integer.valueOf(s));
+ }
+
+ public static SeparateInterface<Long> isInt() {
+ return (l -> Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE);
+ }
+
+ public static <T extends Number> List<T> parseAll(List<String> in,
+ SpecializedFunction<String, T> parser) {
+ return in.stream().map(parser).collect(Collectors.toList());
+ }
+
+ public static <T extends Number> List<T> doFilter(List<T> in, SeparateInterface<T> filter) {
+ return in.stream().filter(filter).collect(Collectors.toList());
+ }
+
+ interface Parser<T> extends Function<String, T> {
+ @Override public T apply(String in);
+ }
+
+ public interface SpecializedParser<T extends Number>
+ extends SpecializedFunction<String, T>, Parser<T> {
+ @Override public T apply(String in);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java
new file mode 100644
index 0000000000..03af2a3ea8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java
@@ -0,0 +1,56 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+public class ConstructorReference {
+
+ private final List<String> names;
+
+ private ConstructorReference(String name) {
+ names = new ArrayList<>(1);
+ names.add(name);
+ }
+
+ public ConstructorReference(List<String> names) {
+ this.names = names;
+ }
+
+ public List<Integer> toInt() {
+ return names.stream().map(Integer::new).collect(Collectors.toList());
+ }
+
+ public static Function<String, ConstructorReference> singleton() {
+ return ConstructorReference::new;
+ }
+
+ public static Supplier<ConstructorReference> emptyThroughJavacGeneratedBridge() {
+ // Because Empty is private in another (inner) class, Javac seems to generate a lambda body
+ // method in this case that calls the Empty(SentinalType) bridge constructor Javac generates.
+ return Empty::new;
+ }
+
+ private static class Empty extends ConstructorReference {
+
+ private Empty() {
+ super(new ArrayList<String>(0));
+ throw new RuntimeException("got it!");
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java
new file mode 100644
index 0000000000..4974d2561b
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java
@@ -0,0 +1,31 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+public class GuavaLambda {
+
+ private final List<String> names;
+
+ public GuavaLambda(List<String> names) {
+ this.names = names;
+ }
+
+ public Iterable<String> as() {
+ return filter(names, n -> n.startsWith("A"));
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java
new file mode 100644
index 0000000000..0fe12b9a5c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java
@@ -0,0 +1,51 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class InnerClassLambda {
+
+ protected final List<String> reference;
+
+ public InnerClassLambda(List<String> names) {
+ this.reference = names;
+ }
+
+ /**
+ * Uses a lambda that refers to a method parameter across 2 nested anonymous inner classes as well
+ * as a field in the outer scope, the former being relatively unusual as it causes javac to emit
+ * 2 getfields to pass the captured parameter directly to the generated lambda class, covering
+ * an unusual branch in how we rewrite invokedynamics.
+ */
+ public Function<List<String>, Callable<List<String>>> prefixFilter(String prefix) {
+ return new Function<List<String>, Callable<List<String>>>() {
+ @Override
+ public Callable<List<String>> apply(List<String> input) {
+ return new Callable<List<String>>() {
+ @Override
+ public List<String> call() throws Exception {
+ return input
+ .stream()
+ .filter(n -> n.startsWith(prefix) && reference.contains(n))
+ .collect(Collectors.toList());
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java
new file mode 100644
index 0000000000..47d8ab6ecd
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java
@@ -0,0 +1,25 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import com.google.common.collect.ImmutableList;
+
+public interface InterfaceWithLambda {
+ String ZERO = String.valueOf(0);
+ ImmutableList<String> DIGITS =
+ ImmutableList.of(0, 1)
+ .stream()
+ .map(i -> i == 0 ? ZERO : String.valueOf(i))
+ .collect(ImmutableList.toImmutableList());
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java
new file mode 100644
index 0000000000..48c81c8c87
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java
@@ -0,0 +1,60 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class Lambda {
+
+ private final List<String> names;
+
+ public Lambda(List<String> names) {
+ this.names = names;
+ }
+
+ public List<String> as() {
+ return names
+ .stream()
+ .filter(n -> n.startsWith("A"))
+ .collect(Collectors.toList());
+ }
+
+ public static Callable<String> hello() {
+ return (Callable<String> & java.util.RandomAccess) () -> "hello";
+ }
+
+ public static Function<Integer, Callable<Long>> mult(int x) {
+ return new Function<Integer, Callable<Long>>() {
+ @Override
+ public Callable<Long> apply(Integer y) {
+ return () -> (long) x * (long) y;
+ }
+ };
+ }
+
+ /**
+ * Test method for b/62456849. This method will first be converted to a synthetic method by {@link
+ * com.google.devtools.build.android.desugar.Bug62456849TestDataGenerator}, and then Desugar
+ * should keep it in this class without desugaring it (such as renaming).
+ *
+ * <p>Please ignore the lint error on the method name. The method name is intentionally chosen to
+ * trigger a bug in Desugar.
+ */
+ public static int lambda$mult$0() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java
new file mode 100644
index 0000000000..1f683f8788
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java
@@ -0,0 +1,35 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Test class carefully constructed so javac emits a lambda body method called lambda$filter$0,
+ * which is exactly the name used for the lambda body method generated by javac for the superclass.
+ */
+public class LambdaInOverride extends OuterReferenceLambda {
+ public LambdaInOverride(List<String> names) {
+ super(names);
+ }
+
+ public List<String> filter(List<String> names) {
+ return super
+ .filter(names)
+ .stream()
+ .filter(n -> !reference.contains(n))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java
new file mode 100644
index 0000000000..a293ceab03
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java
@@ -0,0 +1,88 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import com.google.devtools.build.android.desugar.testdata.separate.SeparateBaseClass;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class MethodReference extends SeparateBaseClass<String> {
+
+ private final List<String> names;
+
+ public MethodReference(List<String> names) {
+ super(names);
+ this.names = names;
+ }
+
+ // Class method reference
+ public void appendAll(StringBuilder dest) {
+ names.stream().forEach(dest::append);
+ }
+
+ // Interface method reference (regression test for b/33304582)
+ public List<String> transform(Transformer<String> transformer) {
+ return names.stream().map(transformer::transform).collect(Collectors.toList());
+ }
+
+ // Private method reference (regression test for b/33378312)
+ public List<String> some() {
+ return names.stream().filter(MethodReference::startsWithS).collect(Collectors.toList());
+ }
+
+ // Protected method reference in a base class of another package (regression test for b/33378312)
+ public List<String> intersect(List<String> other) {
+ return other.stream().filter(this::contains).collect(Collectors.toList());
+ }
+
+ // Contains the same method reference as intersect
+ public List<String> onlyIn(List<String> other) {
+ Predicate<String> p = this::contains;
+ return other.stream().filter(p.negate()).collect(Collectors.toList());
+ }
+
+ // Private method reference to an instance method that throws (regression test for b/33378312)
+ public Callable<String> stringer() {
+ return this::throwing;
+ }
+
+ /** Returns a method reference derived from an expression (object.toString()). */
+ public static Function<Integer, Character> stringChars(Object object) {
+ return (object == null ? "" : object.toString())::charAt;
+ }
+
+ /** Returns a method reference derived from a field */
+ public Predicate<String> toPredicate() {
+ return names::contains;
+ }
+
+ private static boolean startsWithS(String input) {
+ return input.startsWith("S");
+ }
+
+ private String throwing() throws Exception {
+ StringBuilder msg = new StringBuilder();
+ appendAll(msg);
+ throw new IOException(msg.toString());
+ }
+
+ /** Interface to create a method reference for in {@link #transform}. */
+ public interface Transformer<T> {
+ T transform(T input);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java
new file mode 100644
index 0000000000..fb1c49ece8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java
@@ -0,0 +1,37 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class MethodReferenceInSubclass extends MethodReferenceSuperclass {
+
+ public MethodReferenceInSubclass(List<String> names) {
+ super(names);
+ }
+
+ // Private method reference in subclass that causes a bridge method with the same signature as in
+ // a superclass in the same package (regression test for b/36201257). Both superclass and this
+ // class need a method reference to a private *instance* method with the same signature, and they
+ // should each only one method reference and no lambdas so any class-local counter matches, for
+ // this class to serve as a repro for b/36201257.
+ public List<String> containsE() {
+ return names.stream().filter(this::containsE).collect(Collectors.toList());
+ }
+
+ private boolean containsE(String input) {
+ return input.contains("e");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java
new file mode 100644
index 0000000000..c24cf55b81
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java
@@ -0,0 +1,39 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class MethodReferenceSuperclass {
+
+ protected final List<String> names;
+
+ public MethodReferenceSuperclass(List<String> names) {
+ this.names = names;
+ }
+
+ // Method reference that causes a simple bridge method because the referenced method is private.
+ // We want to make sure that bridge methods generated in subclasses don't clobber this one.
+ public List<String> startsWithL() {
+ return names
+ .stream()
+ .filter(this::startsWithL)
+ .collect(Collectors.toList());
+ }
+
+ private boolean startsWithL(String input) {
+ return input.startsWith("L");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java
new file mode 100644
index 0000000000..d3cf829900
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java
@@ -0,0 +1,33 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class OuterReferenceLambda {
+
+ protected final List<String> reference;
+
+ public OuterReferenceLambda(List<String> names) {
+ this.reference = names;
+ }
+
+ public List<String> filter(List<String> names) {
+ return names
+ .stream()
+ .filter(n -> reference.contains(n))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java
new file mode 100644
index 0000000000..b7616a0ae3
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java
@@ -0,0 +1,22 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata;
+
+import java.util.function.Function;
+
+public interface SpecializedFunction<S, T extends Number> extends Function<S, T> {
+ Integer DO_NOT_COPY_INTO_LAMBDA_CLASSES = Integer.valueOf(42);
+ @Override
+ public T apply(S in);
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java
new file mode 100644
index 0000000000..bdf298cce1
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java
@@ -0,0 +1,36 @@
+// Copyright 2017 The Bazel Authors. 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.
+
+// This test class is in the java.lang namespace to trigger the hardcoded JVM restrictions that
+// desugar --core_library works around
+package java.lang;
+
+/**
+ * This class will be desugared with --core_library and then functionally tested by {@code
+ * DesugarCoreLibraryFunctionalTest}
+ */
+public class AutoboxedTypes {
+ /**
+ * Dummy functional interface for autoboxedTypeLambda to return without introducing a dependency
+ * on any other java.* classes.
+ */
+ @FunctionalInterface
+ public interface Lambda {
+ String charAt(String s);
+ }
+
+ public static Lambda autoboxedTypeLambda(Integer i) {
+ return n -> n.substring(i, i + 1);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java
new file mode 100644
index 0000000000..c39d7bc3bf
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java
@@ -0,0 +1,56 @@
+// Copyright 2017 The Bazel Authors. 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 test.util;
+
+/** Test input for b/36654936 */
+public class TestClassForStackMapFrame {
+
+ /**
+ * This method caused cl/152199391 to fail due to stack map frame corruption. So it is to make
+ * sure the desugared version of this class still has correct stack map frames.
+ */
+ public String joinIntegers(int integers) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < integers; i++) {
+ if (i > 0) {
+ builder.append(",");
+ }
+ builder.append(i);
+ builder.append('=');
+ Object value = i % 2 == 0 ? "Even" : "Odd";
+ if (i % 2 == 0) {
+ builder.append(value);
+ } else {
+ builder.append(value);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * This method triggers ASM bug 317785 .
+ *
+ * @return 20
+ */
+ public static int testInputForAsmBug317785() {
+ Integer x = 0;
+ for (int i = 0; i < 10; ++i) {
+ x++;
+ }
+ for (int i = 0; i < 10; ++i) {
+ x++;
+ }
+ return x;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java
new file mode 100644
index 0000000000..eb794885c6
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java
@@ -0,0 +1,43 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Test for b/38302860. The annotations of default methods should be kept after desugaring. */
+public class AnnotationsOfDefaultMethodsShouldBeKept {
+
+ /**
+ * An interface, that has annotation, annotated abstract methods, and annotated default methods.
+ * After desugaring, all these annotations should remain in the interface.
+ */
+ @SomeAnnotation(1)
+ public interface AnnotatedInterface {
+
+ @SomeAnnotation(2)
+ void annotatedAbstractMethod();
+
+ @SomeAnnotation(3)
+ default void annotatedDefaultMethod() {}
+ }
+
+ /**
+ * A simple annotation, used for testing.
+ */
+ @Retention(value = RetentionPolicy.RUNTIME)
+ public @interface SomeAnnotation {
+ int value();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java
new file mode 100644
index 0000000000..0d9f70a76b
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java
@@ -0,0 +1,28 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import com.google.common.collect.ImmutableList;
+
+public class ConcreteDefaultInterfaceWithLambda implements DefaultInterfaceWithLambda {
+ static final String ONE = String.valueOf(1);
+
+ @Override
+ public ImmutableList<String> digits() {
+ return ImmutableList.of(0, 2)
+ .stream()
+ .map(i -> i == 0 ? ONE : String.valueOf(i))
+ .collect(ImmutableList.toImmutableList());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java
new file mode 100644
index 0000000000..cdcc5e9ce3
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java
@@ -0,0 +1,37 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import com.google.common.collect.ImmutableList;
+
+public class ConcreteOverridesDefaultWithLambda implements DefaultInterfaceWithLambda {
+ static final String TWO = String.valueOf(2);
+ static final String THREE = String.valueOf(3);
+
+ @Override
+ public ImmutableList<String> defaultWithLambda() {
+ return ImmutableList.of(0, 3)
+ .stream()
+ .map(i -> i == 0 ? TWO : String.valueOf(i))
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ @Override
+ public ImmutableList<String> digits() {
+ return ImmutableList.of(0, 4)
+ .stream()
+ .map(i -> i == 0 ? THREE : String.valueOf(i))
+ .collect(ImmutableList.toImmutableList());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java
new file mode 100644
index 0000000000..dbbf55569d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java
@@ -0,0 +1,172 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Interfaces with default methods are intialized differently from those without default methods.
+ * When we load such an interface, its static intializer will be executed.
+ *
+ * <p>However, interfaces without default methods are only initialized when their non-primitive
+ * fields are accessed.
+ *
+ * <p>Test data for b/38255926
+ */
+public class DefaultInterfaceMethodWithStaticInitializer {
+
+ final List<String> initializationOrder = new ArrayList<>();
+
+ DefaultInterfaceMethodWithStaticInitializer register(Class<?> enclosingInterfaceClass) {
+ initializationOrder.add(enclosingInterfaceClass.getSimpleName());
+ return this;
+ }
+
+ private static long getTime() {
+ return 0;
+ }
+
+ /** The simplest case: direct implementation. */
+ public static class TestInterfaceSetOne {
+
+ /**
+ * A writable field so that other interfaces can set it in their static initializers.
+ * (b/64290760)
+ */
+ static long writableStaticField;
+
+ static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
+ new DefaultInterfaceMethodWithStaticInitializer();
+
+ /** With a default method, this interface should run clinit. */
+ interface I1 {
+ long NOW = TestInterfaceSetOne.writableStaticField = getTime();
+ DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
+
+ default int defaultM1() {
+ return 1;
+ }
+ }
+
+ /** With a default method, this interface should run clinit. */
+ interface I2 {
+ long NOW = TestInterfaceSetOne.writableStaticField = getTime();
+ DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class);
+
+ default int defaultM2() {
+ return 10;
+ }
+ }
+
+ /** Class to trigger the clinit. */
+ public static class C implements I1, I2 {
+ public int sum() {
+ return defaultM1() + defaultM2();
+ }
+ }
+
+ public static ImmutableList<String> getExpectedInitializationOrder() {
+ return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName());
+ }
+
+ public static ImmutableList<String> getRealInitializationOrder() {
+ return ImmutableList.copyOf(RECORDER.initializationOrder);
+ }
+ }
+
+ /** Test for initializer execution order. */
+ public static class TestInterfaceSetTwo {
+
+ static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
+ new DefaultInterfaceMethodWithStaticInitializer();
+
+ interface I1 {
+ DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
+
+ default int defaultM1() {
+ return 1;
+ }
+ }
+
+ interface I2 extends I1 {
+ DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class);
+
+ default int defaultM2() {
+ return 2;
+ }
+ }
+
+ /**
+ * Loading this class will trigger the execution of the static initializers of I2 and I1.
+ * However, I1 will be loaded first, as I2 extends I1.
+ */
+ public static class C implements I2, I1 {
+ protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit>
+
+ public int sum() {
+ return defaultM1() + defaultM2();
+ }
+ }
+
+ public static ImmutableList<String> getExpectedInitializationOrder() {
+ return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName());
+ }
+
+ public static ImmutableList<String> getRealInitializationOrder() {
+ return ImmutableList.copyOf(RECORDER.initializationOrder);
+ }
+ }
+
+ /** Test: I2's <clinit> should not be executed. */
+ public static class TestInterfaceSetThree {
+ static final DefaultInterfaceMethodWithStaticInitializer RECORDER =
+ new DefaultInterfaceMethodWithStaticInitializer();
+
+ interface I1 {
+ DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class);
+
+ default int defaultM1() {
+ return 6;
+ }
+ }
+
+ interface I2 extends I1 {
+ default int defaultM2() {
+ return 5;
+ }
+ }
+
+ /**
+ * Loading this class will trigger the execution of the static initializers of I1. I2's will not
+ * execute.
+ */
+ public static class C implements I2, I1 {
+ protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit>
+
+ public int sum() {
+ return defaultM1() + defaultM2();
+ }
+ }
+
+ public static ImmutableList<String> getExpectedInitializationOrder() {
+ return ImmutableList.of(I1.class.getSimpleName());
+ }
+
+ public static ImmutableList<String> getRealInitializationOrder() {
+ return ImmutableList.copyOf(RECORDER.initializationOrder);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java
new file mode 100644
index 0000000000..c5fb2d35e5
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java
@@ -0,0 +1,66 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/**
+ * The base interface, which is generic, and has two default methods. These two default methods will
+ * introduce bridge methods in the child-interfaces
+ */
+interface GenericInterfaceWithDefaultMethod<T extends Number> {
+ default T copy(T t) {
+ return t;
+ }
+
+ default Number getNumber() {
+ return 1;
+ }
+}
+
+/** This interface generate two additional bridge methods */
+interface InterfaceWithDefaultAndBridgeMethods extends GenericInterfaceWithDefaultMethod<Integer> {
+ @Override
+ default Integer copy(Integer t) {
+ return GenericInterfaceWithDefaultMethod.super.copy(t);
+ }
+
+ @Override
+ default Double getNumber() {
+ return 2.3d;
+ }
+}
+
+/** A class implementing the interface. */
+class ClassWithDefaultAndBridgeMethods implements InterfaceWithDefaultAndBridgeMethods {}
+
+/** The client class that uses the interfaces and the class that implements the interfaces. */
+public class DefaultInterfaceWithBridges {
+ private final ClassWithDefaultAndBridgeMethods c = new ClassWithDefaultAndBridgeMethods();
+
+ public Integer copy(Integer i) {
+ return c.copy(i);
+ }
+
+ public Number getNumber() {
+ return ((GenericInterfaceWithDefaultMethod) c).getNumber();
+ }
+
+ public Double getDouble() {
+ return c.getNumber();
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public Number copy(Number n) {
+ return ((GenericInterfaceWithDefaultMethod) c).copy(n);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java
new file mode 100644
index 0000000000..e97cae9561
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java
@@ -0,0 +1,33 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import com.google.common.collect.ImmutableList;
+
+public interface DefaultInterfaceWithLambda {
+ String ZERO = String.valueOf(0);
+
+ public default ImmutableList<String> defaultWithLambda() {
+ return ImmutableList.of(0, 1)
+ .stream()
+ .map(i -> i == 0 ? ZERO : String.valueOf(i))
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ public default ImmutableList<String> defaultCallsInterfaceMethod() {
+ return digits();
+ }
+
+ public ImmutableList<String> digits();
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java
new file mode 100644
index 0000000000..176eacece0
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java
@@ -0,0 +1,78 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/** Desugaring test input interface that includes a default method and a static method. */
+public interface FunctionWithDefaultMethod<T extends Number> extends Function<T, T> {
+
+ @Override
+ T apply(T input);
+
+ static <T extends Number> Function<T, Long> toLong() {
+ return input -> input.longValue();
+ }
+
+ default T twice(T input) {
+ return apply(apply(input));
+ }
+
+ /** Don't call this method from tests, it won't work since Desugar moves it! */
+ static FunctionWithDefaultMethod<Integer> inc(int add) {
+ return input -> input + add;
+ }
+
+ /**
+ * Implementation of {@link FunctionWithDefaultMethod} that overrides the default method.
+ * Also declares static methods the test uses to exercise the code in this file.
+ */
+ public static class DoubleInts implements FunctionWithDefaultMethod<Integer> {
+ @Override
+ public Integer apply(Integer input) {
+ return 2 * input;
+ }
+
+ @Override
+ public Integer twice(Integer input) {
+ return 5 * input; // deliberately wrong :)
+ }
+
+ public static List<Long> add(List<Integer> ints, int add) {
+ return ints.stream().map(inc(add)).map(toLong()).collect(Collectors.toList());
+ }
+
+ public static FunctionWithDefaultMethod<Integer> doubleLambda() {
+ return input -> 2 * input;
+ }
+
+ public static FunctionWithDefaultMethod<Integer> incTwice(int add) {
+ return inc(add)::twice;
+ }
+
+ public static FunctionWithDefaultMethod<Integer> times5() {
+ return new DoubleInts2()::twice;
+ }
+
+ public static Function<Integer, FunctionWithDefaultMethod<Integer>> incFactory() {
+ return FunctionWithDefaultMethod::inc;
+ }
+ }
+
+ /** Empty subclass that explicitly implements the interface the superclass already implements. */
+ public static class DoubleInts2 extends DoubleInts implements FunctionWithDefaultMethod<Integer> {
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java
new file mode 100644
index 0000000000..cde6c7b679
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java
@@ -0,0 +1,60 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/**
+ * An interface that has a default method, and a non-empty static initializer. The initializer is
+ * NOT expected to run during desugaring.
+ */
+public interface FunctionalInterfaceWithInitializerAndDefaultMethods {
+
+ ClassWithInitializer CONSTANT = new ClassWithInitializer();
+ boolean BOOLEAN = getFalse();
+ char CHAR = "hello".charAt(0);
+ byte BYTE = Byte.parseByte("0");
+ short SHORT = Short.parseShort("0");
+ int INT = Integer.parseInt("0");
+ float FLOAT = Float.parseFloat("0");
+ long LONG = Long.parseLong("0");
+ double DOUBLE = Double.parseDouble("0");
+
+ int convert();
+
+ /**
+ * The default method ensures that the static initializer of this interface will be executed when
+ * the interface is loaded.
+ */
+ default void defaultMethod() {}
+
+ static boolean getFalse() {
+ return false;
+ }
+
+ /**
+ * A class with a static initializer that has side effects (In this class, the printing to stdout)
+ */
+ class ClassWithInitializer {
+ static {
+ System.out.println("THIS STRING IS NOT EXPECTED TO APPEAR IN THE OUTPUT OF DESUGAR!!!");
+ }
+
+ /**
+ * A lambda to trigger Desugar to load the interface {@link
+ * FunctionalInterfaceWithInitializerAndDefaultMethods}
+ */
+ public FunctionalInterfaceWithInitializerAndDefaultMethods length(String s) {
+ return s::length;
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java
new file mode 100644
index 0000000000..58396794bf
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java
@@ -0,0 +1,97 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/** An interface with default methods, lambdas, and generics */
+public interface GenericDefaultInterfaceWithLambda<T> {
+
+ T getBaseValue();
+
+ T increment(T value);
+
+ String toString(T value);
+
+ public default ArrayList<T> toList(int bound) {
+ ArrayList<T> result = new ArrayList<>();
+ if (bound == 0) {
+ return result;
+ }
+ result.add(getBaseValue());
+ for (int i = 1; i < bound; ++i) {
+ result.add(increment(result.get(i - 1)));
+ }
+ return result;
+ }
+
+ public default List<String> convertToStringList(List<T> list) {
+ return list.stream().map(this::toString).collect(Collectors.toList());
+ }
+
+ public default Function<Integer, ArrayList<T>> toListSupplier() {
+ return this::toList;
+ }
+
+ /** The type parameter is concretized to {@link Number} */
+ interface LevelOne<T extends Number> extends GenericDefaultInterfaceWithLambda<T> {}
+
+ /** The type parameter is instantiated to {@link Integer} */
+ interface LevelTwo extends LevelOne<Integer> {
+
+ @Override
+ default Integer getBaseValue() {
+ return 0;
+ }
+ }
+
+ /** An abstract class with no implementing methods. */
+ abstract static class ClassOne implements LevelTwo {}
+
+ /** A class for {@link Integer} */
+ class ClassTwo extends ClassOne {
+
+ @Override
+ public Integer increment(Integer value) {
+ return value + 1;
+ }
+
+ @Override
+ public String toString(Integer value) {
+ return value.toString();
+ }
+ }
+
+ /** A class fo {@link Long} */
+ class ClassThree implements LevelOne<Long> {
+
+ @Override
+ public Long getBaseValue() {
+ return Long.valueOf(0);
+ }
+
+ @Override
+ public Long increment(Long value) {
+ return value + 1;
+ }
+
+ @Override
+ public String toString(Long value) {
+ return value.toString();
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java
new file mode 100644
index 0000000000..622e6e51e7
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java
@@ -0,0 +1,49 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Desugar test input interface that declares lambdas and method references in default and static
+ * interface methods.
+ */
+public interface InterfaceMethod {
+ public default List<String> defaultMethodReference(List<String> names) {
+ return names.stream().filter(this::startsWithS).collect(Collectors.toList());
+ }
+
+ public default List<String> staticMethodReference(List<String> names) {
+ return names.stream().filter(InterfaceMethod::startsWithA).collect(Collectors.toList());
+ }
+
+ public default List<String> lambdaCallsDefaultMethod(List<String> names) {
+ return names.stream().filter(s -> startsWithS(s)).collect(Collectors.toList());
+ }
+
+ public static boolean startsWithA(String input) {
+ return input.startsWith("A");
+ }
+
+ public default boolean startsWithS(String input) {
+ return input.startsWith("S");
+ }
+
+ /**
+ * Empty class implementing {@link InterfaceMethod} so the test can instantiate and call default
+ * methods.
+ */
+ public static class Concrete implements InterfaceMethod {}
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java
new file mode 100644
index 0000000000..b2d1beb7cb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java
@@ -0,0 +1,41 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/** Interface for testing default methods overridden by extending interfaces. */
+public interface InterfaceWithDefaultMethod {
+ default int version() {
+ return 1;
+ }
+
+ /** Interface that overrides {@link #version}. */
+ public interface Redefine extends InterfaceWithDefaultMethod {
+ @Override
+ default int version() {
+ return 2;
+ }
+ }
+
+ /** Class that implements both interfaces, supertype before subtype. */
+ public static class Version2 implements InterfaceWithDefaultMethod, Redefine {}
+
+ /** Base class that just implements {@link Redefine}. */
+ static class Version2Base implements Redefine {}
+
+ /**
+ * Subclass that implements an interface explicitly that the superclass also implements,
+ * but the superclass implements a more specific interface that overrides a defautl method.
+ */
+ public static class AlsoVersion2 extends Version2Base implements InterfaceWithDefaultMethod {}
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java
new file mode 100644
index 0000000000..56217b8c08
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java
@@ -0,0 +1,45 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/**
+ * Test for b/38308515. This interface has one instance method {@code m()} and one static method
+ * {@code m(InterfaceWithDuplicateMethods)}, which may cause Desugar to dump a companion class with
+ * duplicate method signatures.
+ */
+public interface InterfaceWithDuplicateMethods {
+
+ /**
+ * In the companion class, this default method will be transformed to {@code int
+ * getZero(InterfaceWithDuplicateMethods)}, which has the same signature as the static interface
+ * method below.
+ */
+ @SuppressWarnings("AmbiguousMethodReference")
+ default int getZero() {
+ return 0;
+ }
+
+ /** Should not be called. Should only be called by the class {@link ClassWithDuplicateMethods} */
+ @SuppressWarnings("AmbiguousMethodReference")
+ static int getZero(InterfaceWithDuplicateMethods i) {
+ return 1;
+ }
+
+ /** This class implements the interface, and calls the static interface method. */
+ class ClassWithDuplicateMethods implements InterfaceWithDuplicateMethods {
+ public int getZeroFromStaticInterfaceMethod() {
+ return InterfaceWithDuplicateMethods.getZero(this);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java
new file mode 100644
index 0000000000..ae9ef4f765
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java
@@ -0,0 +1,56 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/**
+ * The test classes for desugaring default methods. Desugar is not expected to generate companion
+ * classes for interfaces without default methods. The bridge methods are automatically generated by
+ * javac and put in the implementing classes.
+ *
+ * <p>NOTE: There should be NO companion class generated for this class.
+ */
+public interface Java7InterfaceWithBridges<T> {
+ T add(T value);
+
+ /** Concretize T to {@link Number)} */
+ interface LevelOne<T extends Number> extends Java7InterfaceWithBridges<T> {
+ @Override
+ T add(T value);
+ }
+
+ /** Concretize to {@link Integer} */
+ interface LevelTwo extends LevelOne<Integer> {
+ @Override
+ Integer add(Integer value);
+ }
+
+ /** Empty abstract class. This class should have no bridge methods */
+ abstract static class AbstractClassOne implements LevelTwo {}
+
+ /** Implementing class. */
+ static class ClassAddOne extends AbstractClassOne {
+ @Override
+ public Integer add(Integer value) {
+ return value + 1;
+ }
+ }
+
+ /** Implementing class. */
+ static class ClassAddTwo extends AbstractClassOne implements LevelTwo {
+ @Override
+ public Integer add(Integer value) {
+ return value + 2;
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java
new file mode 100644
index 0000000000..4c44ffd611
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java
@@ -0,0 +1,72 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/** Desugar test interface to test precedence of inherited methods over default methods. */
+public interface Named {
+ default String name() {
+ return getClass().getSimpleName();
+ }
+
+ /** Base class defining {@link #name} without implementing {@link Named}. */
+ static class ExplicitNameBase {
+ private final String name;
+
+ public ExplicitNameBase(String name) {
+ this.name = name;
+ }
+
+ public String name() {
+ return name;
+ }
+ }
+
+ /** Class whose base class implementes {@link #name}. */
+ public static class ExplicitName extends ExplicitNameBase implements Named {
+ public ExplicitName(String name) {
+ super(name);
+ }
+ }
+
+ /** Class that explicitly defers to the default method in {@link Named}. */
+ public static class DefaultName extends ExplicitNameBase implements Named {
+ public DefaultName() {
+ super(null);
+ }
+
+ @Override
+ public String name() {
+ return Named.super.name() + "-once";
+ }
+ }
+
+ /** Subclass of {@link DefaultName} that uses {@code super} as well. */
+ public static class DefaultNameSubclass extends DefaultName {
+ @Override
+ public String name() {
+ return super.name() + "-twice";
+ }
+ }
+
+ /** Base class that declares {@link #name} abstract. */
+ abstract static class AbstractNameBase {
+ public abstract String name();
+ }
+
+ /**
+ * Class that inherits {@link #name} abstract so subclasses must implement it despite default
+ * method in implemented interface.
+ */
+ public abstract static class AbstractName extends AbstractNameBase implements Named {}
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java
new file mode 100644
index 0000000000..e9456ead99
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java
@@ -0,0 +1,36 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+/** Desugar test class that explicitly calls default methods from two implemented interfaces. */
+public class TwoInheritedDefaultMethods implements Name1, Name2 {
+ @Override
+ public String name() {
+ return Name1.super.name() + ":" + Name2.super.name();
+ }
+}
+
+/** Test interface for {@link TwoInheritedDefaultMethods}. */
+interface Name1 {
+ default String name() {
+ return "One";
+ }
+}
+
+/** Test interface for {@link TwoInheritedDefaultMethods}. */
+interface Name2 {
+ default String name() {
+ return "Two";
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java
new file mode 100644
index 0000000000..b6bd37997e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java
@@ -0,0 +1,23 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8;
+
+import com.google.devtools.build.android.desugar.testdata.java8.subpackage.PublicInterface;
+
+/**
+ * Class that transitively implements a package-private interface in another package. Default
+ * method desugaring will need to make the default method defined in that interface publicly
+ * accessible.
+ */
+public class VisibilityTestClass implements PublicInterface {}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java
new file mode 100644
index 0000000000..9153c12264
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java
@@ -0,0 +1,33 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8.subpackage;
+
+/** Package-private interface with default method. */
+interface PackagePrivateInterface {
+
+ /**
+ * This field makes this interface need to be initialized. With the default methods, when this
+ * interface is loaded, its initializer should also be run.
+ *
+ * <p>However, this test interface is different, as it is package-private. We need to to make sure
+ * the desugared code does not trigger IllegalAccessError.
+ *
+ * <p>See b/38255926.
+ */
+ Integer VERSION = Integer.valueOf(0);
+
+ default int m() {
+ return 42;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java
new file mode 100644
index 0000000000..c3d51db446
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java
@@ -0,0 +1,22 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.java8.subpackage;
+
+/**
+ * Public interface extending a package-private interface so classes in other packages can
+ * transitively implement a package-private interface.
+ *
+ * @see com.google.devtools.build.android.desugar.testdata.java8.VisibilityTestClass
+ */
+public interface PublicInterface extends PackagePrivateInterface {}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java
new file mode 100644
index 0000000000..a182c53329
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java
@@ -0,0 +1,32 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.separate;
+
+import java.util.List;
+
+/**
+ * Test base class for testing method references to protected methods in another compilation.
+ */
+public class SeparateBaseClass<T> {
+
+ private final List<T> list;
+
+ protected SeparateBaseClass(List<T> list) {
+ this.list = list;
+ }
+
+ protected boolean contains(T elem) {
+ return list.contains(elem);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java
new file mode 100644
index 0000000000..ce4b0584b9
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java
@@ -0,0 +1,21 @@
+// Copyright 2016 The Bazel Authors. 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 com.google.devtools.build.android.desugar.testdata.separate;
+
+import java.util.function.Predicate;
+
+public interface SeparateInterface<T extends Number> extends Predicate<T> {
+ @Override
+ boolean test(T input);
+}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt
new file mode 100644
index 0000000000..30d74d2584
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt
@@ -0,0 +1 @@
+test \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_core_library_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_core_library_jar_toc_golden.txt
new file mode 100644
index 0000000000..cb0d40c97e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_core_library_jar_toc_golden.txt
@@ -0,0 +1,18 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/testresource.txt
+java/
+java/lang/
+java/lang/AutoboxedTypes$Lambda.class
+java/lang/AutoboxedTypes.class
+test/
+test/util/
+test/util/TestClassForStackMapFrame.class
+java/lang/AutoboxedTypes$$Lambda$0.class \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt
new file mode 100644
index 0000000000..b7c3c25f38
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_disabling_twr_with_large_minsdkversion_jar_toc_golden.txt
@@ -0,0 +1,65 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/testresource.txt
+com/google/devtools/build/android/desugar/testdata/CaptureLambda.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$LongCmpFunc.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources$SimpleResource.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$Parser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$SpecializedParser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$Empty.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/Lambda.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$Transformer.class
+com/google/devtools/build/android/desugar/testdata/MethodReference.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.class
+com/google/devtools/build/android/desugar/testdata/SpecializedFunction.class
+com/google/devtools/build/android/desugar/testdata/CaptureLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$3.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$4.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$5.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$6.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$7.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda$$Lambda$0.class \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_try_with_resources_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_try_with_resources_jar_toc_golden.txt
new file mode 100644
index 0000000000..d03b121dcb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_for_try_with_resources_jar_toc_golden.txt
@@ -0,0 +1,72 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/testresource.txt
+com/google/devtools/build/android/desugar/testdata/CaptureLambda.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$LongCmpFunc.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources$SimpleResource.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$Parser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$SpecializedParser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$Empty.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/Lambda.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$Transformer.class
+com/google/devtools/build/android/desugar/testdata/MethodReference.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.class
+com/google/devtools/build/android/desugar/testdata/SpecializedFunction.class
+com/google/devtools/build/android/desugar/testdata/CaptureLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$3.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$4.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$5.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$6.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$7.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$AbstractDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ConcurrentWeakIdentityHashMap.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ConcurrentWeakIdentityHashMap$WeakKey.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$MimicDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$NullDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ReuseDesugaringStrategy.class \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_test.sh b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_test.sh
new file mode 100755
index 0000000000..7aa7d19353
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash -e
+#
+# Copyright 2016 The Bazel Authors. 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.
+
+# Test that lists the content of the desugared Jar and compares it to a golden
+# file. This makes sure that output is deterministic and the resulting Jar
+# doesn't contain any unwanted files, such as lambdas generated as part of
+# running the desugaring tool.
+
+progdir="$(dirname "$0")"
+
+if [ -d "$TEST_TMPDIR" ]; then
+ # Running as part of blaze test
+ tmpdir="$TEST_TMPDIR"
+else
+ # Manual run from command line
+ tmpdir="/tmp/test-$$"
+ mkdir "${tmpdir}"
+fi
+
+if [ -d "$TEST_UNDECLARED_OUTPUTS_DIR" ]; then
+ # Running as part of blaze test: capture test output
+ output="$TEST_UNDECLARED_OUTPUTS_DIR"
+else
+ # Manual run from command line: just write into temp dir
+ output="${tmpdir}"
+fi
+
+JAVABASE=$3
+$JAVABASE/bin/jar tf "$1" >"${output}/actual_toc.txt"
+# sorting can be removed when cl/145334839 is released
+diff <(sort "$2") <(sort "${output}/actual_toc.txt")
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_toc_golden.txt
new file mode 100644
index 0000000000..91fc415f95
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_jar_toc_golden.txt
@@ -0,0 +1,72 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/testresource.txt
+com/google/devtools/build/android/desugar/testdata/CaptureLambda.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$LongCmpFunc.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources$SimpleResource.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$Parser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$SpecializedParser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$Empty.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/Lambda.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$Transformer.class
+com/google/devtools/build/android/desugar/testdata/MethodReference.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.class
+com/google/devtools/build/android/desugar/testdata/SpecializedFunction.class
+com/google/devtools/build/android/desugar/testdata/CaptureLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$3.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$4.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$5.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$6.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$7.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$AbstractDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ConcurrentWeakIdentityHashMap.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ConcurrentWeakIdentityHashMap$WeakKey.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$MimicDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$NullDesugaringStrategy.class
+com/google/devtools/build/android/desugar/runtime/ThrowableExtension$ReuseDesugaringStrategy.class
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_java8_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_java8_jar_toc_golden.txt
new file mode 100644
index 0000000000..8664932324
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_java8_jar_toc_golden.txt
@@ -0,0 +1,145 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/testresource.txt
+com/google/devtools/build/android/desugar/testdata/CaptureLambda.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$LongCmpFunc.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources$SimpleResource.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$Parser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$SpecializedParser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$Empty.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/Lambda.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$Transformer.class
+com/google/devtools/build/android/desugar/testdata/MethodReference.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.class
+com/google/devtools/build/android/desugar/testdata/SpecializedFunction.class
+com/google/devtools/build/android/desugar/testdata/java8/
+com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept$AnnotatedInterface.class
+com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept$SomeAnnotation.class
+com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.class
+com/google/devtools/build/android/desugar/testdata/java8/ClassWithDefaultAndBridgeMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne$C.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne$I1.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne$I2.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetThree$C.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetThree$I1.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetThree$I2.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetThree.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetTwo$C.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetTwo$I1.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetTwo$I2.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetTwo.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts2.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods$ClassWithInitializer.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$ClassOne.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$ClassThree.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$ClassTwo.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$LevelOne.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$LevelTwo.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericInterfaceWithDefaultMethod.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod$Concrete.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultAndBridgeMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod$AlsoVersion2.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod$Redefine.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod$Version2.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod$Version2Base.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods$ClassWithDuplicateMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges$AbstractClassOne.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges$ClassAddOne.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges$ClassAddTwo.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges$LevelOne.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges$LevelTwo.class
+com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.class
+com/google/devtools/build/android/desugar/testdata/java8/Name1.class
+com/google/devtools/build/android/desugar/testdata/java8/Name2.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$AbstractName.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$AbstractNameBase.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$DefaultName.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$DefaultNameSubclass.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$ExplicitName.class
+com/google/devtools/build/android/desugar/testdata/java8/Named$ExplicitNameBase.class
+com/google/devtools/build/android/desugar/testdata/java8/Named.class
+com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.class
+com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.class
+com/google/devtools/build/android/desugar/testdata/java8/subpackage/
+com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.class
+com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.class
+com/google/devtools/build/android/desugar/testdata/CaptureLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/Lambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$3.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$4.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$5.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$6.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$$Lambda$7.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts$$Lambda$2.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$DoubleInts$$Lambda$3.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods$ClassWithInitializer$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod$$Lambda$0.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod$$Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod$$Lambda$2.class \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_without_lambda_desugared_jar_toc_golden.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_without_lambda_desugared_jar_toc_golden.txt
new file mode 100644
index 0000000000..256760b32e
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/testdata_desugared_without_lambda_desugared_jar_toc_golden.txt
@@ -0,0 +1,36 @@
+META-INF/
+META-INF/MANIFEST.MF
+com/
+com/google/
+com/google/devtools/
+com/google/devtools/build/
+com/google/devtools/build/android/
+com/google/devtools/build/android/desugar/
+com/google/devtools/build/android/desugar/testdata/
+com/google/devtools/build/android/desugar/testdata/CaptureLambda.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare$LongCmpFunc.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.class
+com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources$SimpleResource.class
+com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$Parser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction$SpecializedParser.class
+com/google/devtools/build/android/desugar/testdata/ConcreteFunction.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$1.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference$Empty.class
+com/google/devtools/build/android/desugar/testdata/ConstructorReference.class
+com/google/devtools/build/android/desugar/testdata/GuavaLambda.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda$1.class
+com/google/devtools/build/android/desugar/testdata/InnerClassLambda.class
+com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.class
+com/google/devtools/build/android/desugar/testdata/Lambda$1.class
+com/google/devtools/build/android/desugar/testdata/Lambda.class
+com/google/devtools/build/android/desugar/testdata/LambdaInOverride.class
+com/google/devtools/build/android/desugar/testdata/MethodReference$Transformer.class
+com/google/devtools/build/android/desugar/testdata/MethodReference.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.class
+com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.class
+com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.class
+com/google/devtools/build/android/desugar/testdata/SpecializedFunction.class
+com/google/devtools/build/android/desugar/testdata/testresource.txt \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
index 7564316d1b..0ff6314336 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
@@ -439,4 +439,37 @@ public class MoreAsserts {
assertWithMessage(events.toString()).that(foundEvents).hasSize(expectedFrequency);
return foundEvents;
}
+
+
+ /*
+ * This method will be in JUnit 4.13. Instead of patching Bazel's JUnit jar to contain the
+ * <a href="https://github.com/junit-team/junit4/commit/bdb1799">patch</a>, we define it here.
+ * Once JUnit 4.13 is released, we will switcher callers to use org.junit.Assert#assertThrows
+ * instead. See https://github.com/bazelbuild/bazel/issues/3729.
+ */
+ public static void assertThrows(
+ Class<? extends Throwable> expectedThrown, ThrowingRunnable runnable) {
+ try {
+ runnable.run();
+ } catch (Throwable actualThrown) {
+ if (expectedThrown.isInstance(actualThrown)) {
+ return;
+ } else {
+ throw new AssertionError(
+ String.format(
+ "expected %s to be thrown, but %s was thrown",
+ expectedThrown.getSimpleName(),
+ actualThrown.getClass().getSimpleName()),
+ actualThrown);
+ }
+ }
+ throw new AssertionError(
+ String.format(
+ "expected %s to be thrown, but nothing was thrown", expectedThrown.getSimpleName()));
+ }
+
+ /** A helper interface for {@link assertThrows}. */
+ public interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD b/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
index f7a5209626..eacb620843 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
@@ -13,6 +13,7 @@ java_library(
name = "desugar",
srcs = glob(["*.java"]),
visibility = [
+ "//src/test/java/com/google/devtools/build/android/desugar:__pkg__",
"//src/tools/android/java/com/google/devtools/build/android:__pkg__",
],
runtime_deps = ["//src/tools/android/java/com/google/devtools/build/android/desugar/runtime:throwable_extension"],
@@ -32,6 +33,9 @@ java_library(
java_binary(
name = "Desugar",
main_class = "com.google.devtools.build.android.desugar.Desugar",
+ visibility = [
+ "//src/test/java/com/google/devtools/build/android/desugar:__pkg__",
+ ],
runtime_deps = [":desugar"],
)
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/BUILD b/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/BUILD
index dbfd683cb8..68179ab2ac 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/BUILD
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/BUILD
@@ -1,5 +1,11 @@
# Description:
# This is the extension package to support desugaring try-with-resources statements.
+package(
+ default_visibility = [
+ "//src/test/java/com/google/devtools/build/android/desugar:__subpackages__",
+ "//src/tools/android/java/com/google/devtools/build/android/desugar:__pkg__",
+ ],
+)
java_library(
name = "throwable_extension",
@@ -9,11 +15,9 @@ java_library(
"-source 7",
"-target 7",
],
- visibility = ["//src/tools/android/java/com/google/devtools/build/android/desugar:__pkg__"],
)
filegroup(
name = "srcs",
srcs = glob(["**"]),
- visibility = ["//src/tools/android/java/com/google/devtools/build/android/desugar:__pkg__"],
)