aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Damien Martin-Guillerez <dmarting@google.com>2015-03-10 12:32:21 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-03-10 16:13:29 +0100
commitc513e114a0a5f97891433b80bf442c5e9acaf22b (patch)
treed3c1bb107bd3e7900f328235d0451bf87af990a7
parenta5a11203aa75729bd0b3a29a22a63977ee2267a0 (diff)
Open-source ijar's tests
-- MOS_MIGRATED_REVID=88210083
-rw-r--r--src/java_tools/buildjar/BUILD4
-rw-r--r--third_party/BUILD5
-rw-r--r--third_party/README.md7
-rw-r--r--third_party/asm/LICENSE31
-rw-r--r--third_party/asm/asm-5.0.3.jarbin0 -> 241639 bytes
-rw-r--r--third_party/ijar/BUILD8
-rw-r--r--third_party/ijar/test/A.java71
-rw-r--r--third_party/ijar/test/AnnotatedClass.java38
-rw-r--r--third_party/ijar/test/Annotations.java38
-rw-r--r--third_party/ijar/test/B.java51
-rw-r--r--third_party/ijar/test/BUILD105
-rw-r--r--third_party/ijar/test/DeprecatedParts.java93
-rw-r--r--third_party/ijar/test/DumbClass.java24
-rw-r--r--third_party/ijar/test/EnclosingMethod.java39
-rw-r--r--third_party/ijar/test/IjarTests.java194
-rw-r--r--third_party/ijar/test/Object.java18
-rw-r--r--third_party/ijar/test/PrivateMembersClass.java51
-rw-r--r--third_party/ijar/test/PrivateNestedClass.java20
-rw-r--r--third_party/ijar/test/StripVerifyingVisitor.java223
-rw-r--r--third_party/ijar/test/TypeAnnotationTest2.java19
-rw-r--r--third_party/ijar/test/UseDeprecatedParts.java48
-rw-r--r--third_party/ijar/test/UseRestrictedAnnotation.java22
-rw-r--r--third_party/ijar/test/WellCompressed1.java505
-rw-r--r--third_party/ijar/test/WellCompressed2.java316
-rwxr-xr-xthird_party/ijar/test/ijar_test.sh417
-rw-r--r--third_party/ijar/test/invokedynamic/ClassWithLambda.java31
-rw-r--r--third_party/ijar/test/libwrongcentraldir.jarbin0 -> 2027 bytes
-rw-r--r--third_party/ijar/test/package-info.java15
-rw-r--r--third_party/ijar/test/typeannotations2/NonNull.java23
-rw-r--r--third_party/ijar/test/typeannotations2/Nullable.java23
-rw-r--r--third_party/ijar/test/typeannotations2/Util.java19
-rw-r--r--third_party/ijar/test/typeannotations2/java/lang/annotation/ElementType.java21
32 files changed, 2478 insertions, 1 deletions
diff --git a/src/java_tools/buildjar/BUILD b/src/java_tools/buildjar/BUILD
index d467e66bf9..4384cdd45b 100644
--- a/src/java_tools/buildjar/BUILD
+++ b/src/java_tools/buildjar/BUILD
@@ -117,6 +117,10 @@ java_library(
name = "BazelJavaCompiler",
srcs = ["java/com/google/devtools/build/java/bazel/BazelJavaCompiler.java"],
data = ["//tools/defaults:java_langtools"],
+ visibility = [
+ "//src:__subpackages__",
+ "//third_party/ijar:__subpackages__",
+ ],
deps = [
":JavaBuilderConfig",
":JavaLangtools",
diff --git a/third_party/BUILD b/third_party/BUILD
index ae72fdcd4d..86d6b28c36 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -120,6 +120,11 @@ java_import(
],
)
+java_import(
+ name = "asm",
+ jars = ["asm/asm-5.0.3.jar"],
+)
+
config_setting(
name = "windows_mingw",
values = {"compiler": "windows_mingw"},
diff --git a/third_party/README.md b/third_party/README.md
index c1e992df26..9bdd67147b 100644
--- a/third_party/README.md
+++ b/third_party/README.md
@@ -136,3 +136,10 @@ Testing
* Version: 1.3
* License: New BSD License
+
+[asm](https://asm.ow2.org)
+-----
+
+* Version: 5.0.3
+* License: 3-clause revised BSD
+
diff --git a/third_party/asm/LICENSE b/third_party/asm/LICENSE
new file mode 100644
index 0000000000..23ea440b63
--- /dev/null
+++ b/third_party/asm/LICENSE
@@ -0,0 +1,31 @@
+*******************************************************************************
+* ASM: a very small and fast Java bytecode manipulation framework
+* Copyright (c) 2000-2011 INRIA, France Telecom
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holders nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+* THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+
+This directory contains the documentation of the product.
diff --git a/third_party/asm/asm-5.0.3.jar b/third_party/asm/asm-5.0.3.jar
new file mode 100644
index 0000000000..da5b23e156
--- /dev/null
+++ b/third_party/asm/asm-5.0.3.jar
Binary files differ
diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD
index 6f6659f0d4..3c1e141403 100644
--- a/third_party/ijar/BUILD
+++ b/third_party/ijar/BUILD
@@ -1,4 +1,10 @@
-package(default_visibility = ["//src:__pkg__"])
+package(
+ default_visibility = [
+ "//src:__pkg__",
+ "//third_party/ijar:__subpackages__",
+ ],
+)
+
licenses(["notice"]) # Apache 2.0
cc_binary(
diff --git a/third_party/ijar/test/A.java b/third_party/ijar/test/A.java
new file mode 100644
index 0000000000..45c6b8fe13
--- /dev/null
+++ b/third_party/ijar/test/A.java
@@ -0,0 +1,71 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+import java.io.IOException;
+import java.lang.annotation.*;
+
+class A {
+
+ // Exercise removal of class initializers:
+ static { }
+
+ // Exercise removal of private members:
+ private String privateField;
+
+ protected int protectedField;
+
+ // Exercise ConstantValue annotation
+ public static final long L1 = 123L;
+
+ // Exercise removal of private members:
+ private void privateMethod() {
+ System.err.println("foofoofoofoo");
+ }
+
+ // Exercise Signature annotation:
+ protected <T> T protectedMethod(T t) { return t; }
+
+ // Exercise Deprecated annotation:
+ @Deprecated
+ // Exercise Exceptions annotation:
+ public void deprecatedMethod() throws IOException {}
+
+ // Exercise retention of private inner classes:
+ private class PrivateInner {}
+
+ // Exercise InnerClasses attribute:
+ public class PublicInner {}
+
+ public @interface MyAnnotation {
+ // Exercise BaseTypeElementValue:
+ String a() default "foo";
+
+ // Exercise EnumTypeElementValue:
+ ElementType b() default ElementType.METHOD;
+
+ // Exercise ClassTypeElementValue:
+ Class<?> c() default String.class;
+
+ // Exercise ArrayTypeElementValue:
+ String[] d() default { "foo", "bar" };
+
+ // Exercise AnnotationTypeElementValue:
+ Deprecated e() default @Deprecated;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface RuntimeAnnotation {}
+
+}
diff --git a/third_party/ijar/test/AnnotatedClass.java b/third_party/ijar/test/AnnotatedClass.java
new file mode 100644
index 0000000000..2a1535708c
--- /dev/null
+++ b/third_party/ijar/test/AnnotatedClass.java
@@ -0,0 +1,38 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * A heavily annotated class used for testing.
+ */
+@Annotations.RuntimeInvisible
+@Annotations.RuntimeVisible
+final class AnnotatedClass {
+ @Annotations.RuntimeInvisible
+ @Annotations.RuntimeVisible
+ String field;
+
+ @Annotations.RuntimeInvisible
+ @Annotations.RuntimeVisible
+ private AnnotatedClass() {}
+
+ @Annotations.RuntimeInvisible
+ @Annotations.RuntimeVisible
+ public static void publicStaticMethod(
+ @Annotations.RuntimeInvisible @Annotations.RuntimeVisible String param) {
+ @Annotations.RuntimeInvisible
+ @Annotations.RuntimeVisible
+ String local = "Hello " + param + "!";
+ System.out.println(local);
+ }
+}
diff --git a/third_party/ijar/test/Annotations.java b/third_party/ijar/test/Annotations.java
new file mode 100644
index 0000000000..a4fff58fc7
--- /dev/null
+++ b/third_party/ijar/test/Annotations.java
@@ -0,0 +1,38 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotations used for testing.
+ */
+final class Annotations {
+ private Annotations() {}
+
+ @Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD,
+ ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
+ @interface RuntimeInvisible {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD,
+ ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
+ @interface RuntimeVisible {}
+
+ @Target(ElementType.PARAMETER)
+ public @interface ParametersOnlyAnnotation {
+ }
+}
diff --git a/third_party/ijar/test/B.java b/third_party/ijar/test/B.java
new file mode 100644
index 0000000000..c1a946016f
--- /dev/null
+++ b/third_party/ijar/test/B.java
@@ -0,0 +1,51 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+import java.io.IOException;
+
+public class B extends A {
+
+ B() {
+ // Will trigger compile error if Signature attr is missing.
+ String str = protectedMethod("foo");
+
+ try {
+ deprecatedMethod(); // <-- triggers deprecation warning; checked by
+ // .sh script.
+ } catch (IOException e) { // Will trigger compile error if Exceptions
+ // annotation is discarded.
+ }
+
+ l(A.L1); // <-- should be a compile-time ConstantValue; checked by .sh.
+
+ new PublicInner();
+ }
+
+ @MyAnnotation
+ void l(long l) {}
+
+ @RuntimeAnnotation
+ public int k;
+
+ public static void main(String[] args) throws Exception {
+ // Regression test for bug #1210750.
+ if (!Class.forName("B").getField("k").isAnnotationPresent(RuntimeAnnotation.class)) {
+ throw new AssertionError("RuntimeAnnotation got lost!");
+ }
+
+ System.err.println("B.main() OK");
+ }
+
+}
diff --git a/third_party/ijar/test/BUILD b/third_party/ijar/test/BUILD
new file mode 100644
index 0000000000..cb17830fc8
--- /dev/null
+++ b/third_party/ijar/test/BUILD
@@ -0,0 +1,105 @@
+package(default_visibility = ["//visibility:__pkg__"])
+
+licenses(["notice"]) # Apache License 2.0
+
+exports_files(["LICENSE"])
+
+sh_test(
+ name = "ijar_test",
+ size = "large",
+ srcs = ["ijar_test.sh"],
+ args = [
+ "$(JAVAC)",
+ "$(JAVA)",
+ "$(JAVABASE)/bin/jar",
+ "$(JAVABASE)/bin/javap",
+ "$(location //third_party/ijar)",
+ "$(location //tools/jdk:langtools)",
+ # We assume unzip and zip to be on the path
+ "unzip",
+ "zip",
+ ],
+ data = [
+ "//third_party/ijar",
+ "A.java",
+ "B.java",
+ "Object.java",
+ "WellCompressed1.java",
+ "WellCompressed2.java",
+ ":libtypeannotations2.jar",
+ "TypeAnnotationTest2.java",
+ # invokedynamic/ClassWithLambda.java, compiled with javac8
+ ":libinvokedynamic.jar",
+ # Intentionally bad test JAR: file count in central directory
+ # wrong.
+ "libwrongcentraldir.jar",
+ "//tools/defaults:jdk",
+ "//tools/jdk:langtools",
+ ],
+)
+
+java_library(
+ name = "invokedynamic",
+ testonly = 1,
+ srcs = ["invokedynamic/ClassWithLambda.java"],
+ javacopts = ["-source 8 -target 8"],
+)
+
+# For testing purposes: a class which exposes a private nested class in
+# public API, classes with annotations and a class with different forms of
+# deprecations markers
+java_library(
+ name = "ijar_testlib",
+ srcs = [
+ "AnnotatedClass.java",
+ "Annotations.java",
+ "DeprecatedParts.java",
+ "DumbClass.java",
+ "EnclosingMethod.java",
+ "PrivateMembersClass.java",
+ ],
+)
+
+# For testing purposes: an interface jar (ijar) which includes the
+# interface view of the various test class from above.
+genrule(
+ name = "interface_ijar_testlib",
+ srcs = [":ijar_testlib"],
+ outs = ["interface_ijar_testlib.jar"],
+ cmd = "$(location //third_party/ijar) $< $@",
+ tools = ["//third_party/ijar"],
+)
+
+java_library(
+ name = "typeannotations2",
+ srcs = glob(["typeannotations2/**/*.java"]),
+ javacopts = ["-source 8 -target 8"],
+)
+
+java_test(
+ name = "IjarTests",
+ size = "small",
+ srcs = [
+ "IjarTests.java",
+ "StripVerifyingVisitor.java",
+ ],
+ args = ["IjarTests"],
+ data = [
+ "PrivateNestedClass.java",
+ "UseDeprecatedParts.java",
+ "UseRestrictedAnnotation.java",
+ "package-info.java",
+ ":interface_ijar_testlib",
+ ],
+ deps = [
+ "//src/java_tools/buildjar:BazelJavaCompiler",
+ "//third_party:asm",
+ "//third_party:junit4",
+ ],
+)
+
+test_suite(
+ name = "all_tests",
+ testonly = 1,
+ visibility = ["//visibility:public"],
+)
diff --git a/third_party/ijar/test/DeprecatedParts.java b/third_party/ijar/test/DeprecatedParts.java
new file mode 100644
index 0000000000..1cbed27835
--- /dev/null
+++ b/third_party/ijar/test/DeprecatedParts.java
@@ -0,0 +1,93 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * A class with various deprecated parts used for testing.
+ */
+@SuppressWarnings("dep-ann")
+final class DeprecatedParts {
+ @Deprecated
+ public static String deprecatedViaAnnotationStaticField = "hi";
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public static String deprecatedViaJavadocStaticField = "hi";
+
+ @Deprecated
+ public String deprecatedViaAnnotationField = "hi";
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public String deprecatedViaJavadocField = "hi";
+
+ @Deprecated
+ public void deprecatedViaAnnotationMethod() {
+ }
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public void deprecatedViaJavadocMethod() {
+ }
+
+ // Note: @Deprecated can be applied to parameters, but the compiler doesn't seem to use it
+
+ @Deprecated
+ public static void deprecatedViaAnnotationStaticMethod() {
+ }
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public static void deprecatedViaJavadocStaticMethod() {
+ }
+
+ @Deprecated
+ public @interface DeprecatedViaAnnotationAnnotation {}
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public @interface DeprecatedViaJavadocAnnotation {}
+
+ @Deprecated
+ public static class DeprecatedViaAnnotationClass {}
+
+ /**
+ * @deprecated Marked deprecated to exercise preservation of deprecation.
+ */
+ public static class DeprecatedViaJavadocClass {}
+
+ public static class DeprecatedViaAnnotationConstructor {
+ @Deprecated
+ public DeprecatedViaAnnotationConstructor() {}
+ }
+
+ public static class DeprecatedViaJavadocConstructor {
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public DeprecatedViaJavadocConstructor() {}
+ }
+
+ @Deprecated
+ public interface DeprecatedViaAnnotationInterface {}
+
+ /**
+ * @deprecated Marked deprecated for test.
+ */
+ public interface DeprecatedViaJavadocInterface {}
+}
diff --git a/third_party/ijar/test/DumbClass.java b/third_party/ijar/test/DumbClass.java
new file mode 100644
index 0000000000..4b685f943d
--- /dev/null
+++ b/third_party/ijar/test/DumbClass.java
@@ -0,0 +1,24 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * For testing purposes: a "dumb" class in that it exposes a private
+ * inner class in public API.
+ */
+class DumbClass<V> {
+ public Inner inner;
+ private class Inner {
+ V v;
+ }
+}
diff --git a/third_party/ijar/test/EnclosingMethod.java b/third_party/ijar/test/EnclosingMethod.java
new file mode 100644
index 0000000000..1684d7a3bf
--- /dev/null
+++ b/third_party/ijar/test/EnclosingMethod.java
@@ -0,0 +1,39 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.util.concurrent.Callable;
+
+/**
+ * For testing purposes, an anonymous inner class that requires an
+ * EnclosingMethod attribute in its class file.
+ */
+class EnclosingMethod {
+ class Inner {
+ public <T> T run(Callable<T> callable) {
+ try {
+ return callable.call();
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+ private <T> Callable<T> asCallable(final Callable<T> callableToWrap) {
+ return new Callable<T>() {
+ @Override public T call() throws Exception {
+ return Inner.this.run(callableToWrap);
+ }
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/third_party/ijar/test/IjarTests.java b/third_party/ijar/test/IjarTests.java
new file mode 100644
index 0000000000..0448b33b71
--- /dev/null
+++ b/third_party/ijar/test/IjarTests.java
@@ -0,0 +1,194 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.google.devtools.build.java.bazel.BazelJavaCompiler;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.objectweb.asm.ClassReader;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+/**
+ * JUnit tests for ijar tool.
+ */
+@RunWith(JUnit4.class)
+public class IjarTests {
+
+ private static File getTmpDir() {
+ String tmpdir = System.getenv("TEST_TMPDIR");
+ if (tmpdir == null) {
+ // Fall back on the system temporary directory
+ tmpdir = System.getProperty("java.io.tmpdir");
+ }
+ if (tmpdir == null) {
+ fail("TEST_TMPDIR environment variable is not set!");
+ }
+ return new File(tmpdir);
+ }
+
+ DiagnosticCollector<JavaFileObject> diagnostics;
+
+ private JavaCompiler.CompilationTask makeCompilationTask(String... files) throws IOException {
+ JavaCompiler compiler = BazelJavaCompiler.newInstance();
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+ fileManager.setLocation(StandardLocation.CLASS_PATH,
+ Arrays.asList(new File("third_party/ijar/test/interface_ijar_testlib.jar")));
+ fileManager.setLocation(StandardLocation.CLASS_OUTPUT,
+ Arrays.asList(getTmpDir()));
+ diagnostics = new DiagnosticCollector<JavaFileObject>();
+ return compiler.getTask(null,
+ fileManager,
+ diagnostics,
+ Arrays.asList("-Xlint:deprecation"), // used for deprecation tests
+ null,
+ fileManager.getJavaFileObjects(files));
+ }
+
+ /**
+ * Test that the ijar tool preserves private nested classes as they
+ * may be exposed through public API. This test relies on an
+ * interface jar provided through the build rule
+ * :interface_ijar_testlib and the Java source file
+ * PrivateNestedClass.java.
+ */
+ @Test
+ public void testPrivateNestedClass() throws IOException {
+ if (!makeCompilationTask("third_party/ijar/test/PrivateNestedClass.java").call()) {
+ fail(getFailedCompilationMessage());
+ }
+ }
+
+ /**
+ * Test that the ijar tool preserves annotations, especially @Target
+ * meta-annotation.
+ */
+ @Test
+ public void testRestrictedAnnotations() throws IOException {
+ assertFalse(makeCompilationTask("third_party/ijar/test/UseRestrictedAnnotation.java").call());
+ }
+
+ /**
+ * Test that the ijar tool preserves private nested classes as they
+ * may be exposed through public API. This test relies on an
+ * interface jar provided through the build rule
+ * :interface_ijar_testlib and the Java source file
+ * PrivateNestedClass.java.
+ */
+ @Test
+ public void testDeprecatedParts() throws IOException {
+ if (!makeCompilationTask("third_party/ijar/test/UseDeprecatedParts.java").call()) {
+ fail(getFailedCompilationMessage());
+ }
+ int deprecatedWarningCount = 0;
+ for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
+ if ((diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING) &&
+ // Java 6:
+ (diagnostic.getMessage(Locale.ENGLISH).startsWith("[deprecation]") ||
+ // Java 7:
+ diagnostic.getMessage(Locale.ENGLISH).contains("has been deprecated"))) {
+ deprecatedWarningCount++;
+ }
+ }
+ assertEquals(16, deprecatedWarningCount);
+ }
+
+ /**
+ * Test that the ijar tool preserves EnclosingMethod attributes and doesn't
+ * prevent annotation processors from accessing all the elements in a package.
+ */
+ @Test
+ public void testEnclosingMethod() throws IOException {
+ JavaCompiler.CompilationTask task = makeCompilationTask("third_party/ijar/test/package-info.java");
+ task.setProcessors(Arrays.asList(new AbstractProcessor() {
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return Collections.singleton("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ roundEnv.getElementsAnnotatedWith(java.lang.Override.class);
+ return true;
+ }
+ }));
+ if (!task.call()) {
+ fail(getFailedCompilationMessage());
+ }
+ }
+
+ @Test
+ public void testVerifyStripping() throws Exception {
+ ZipFile zip = new ZipFile("third_party/ijar/test/interface_ijar_testlib.jar");
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ ClassReader reader = new ClassReader(zip.getInputStream(entry));
+ StripVerifyingVisitor verifier = new StripVerifyingVisitor();
+
+ reader.accept(verifier, 0);
+
+ if (verifier.errors.size() > 0) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Verification of ");
+ builder.append(entry.getName());
+ builder.append(" failed: ");
+ for (String msg : verifier.errors) {
+ builder.append(msg);
+ builder.append("\t");
+ }
+ fail(builder.toString());
+ }
+ }
+ }
+
+ private String getFailedCompilationMessage() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Build failed unexpectedly");
+ for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
+ builder.append(String.format(
+ "\t%s line %d column %d: %s",
+ diagnostic.getKind().toString(),
+ diagnostic.getLineNumber(),
+ diagnostic.getColumnNumber(),
+ diagnostic.getMessage(Locale.ENGLISH)));
+ }
+ return builder.toString();
+ }
+}
diff --git a/third_party/ijar/test/Object.java b/third_party/ijar/test/Object.java
new file mode 100644
index 0000000000..93b508886a
--- /dev/null
+++ b/third_party/ijar/test/Object.java
@@ -0,0 +1,18 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java.lang;
+
+class Object {
+}
diff --git a/third_party/ijar/test/PrivateMembersClass.java b/third_party/ijar/test/PrivateMembersClass.java
new file mode 100644
index 0000000000..0f4ecaf71d
--- /dev/null
+++ b/third_party/ijar/test/PrivateMembersClass.java
@@ -0,0 +1,51 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * A class with many private parts. Used for testing.
+ */
+final class PrivateMembersClass {
+ private String privateField;
+
+ private PrivateMembersClass() {}
+
+ public static void main() {
+ privateStaticMethod();
+ }
+
+ private static void privateStaticMethod() {
+ new PrivateMembersClass().privateMethod();
+ }
+
+ private void privateMethod() {
+ new PrivateInnerClass().print();
+ new PrivateStaticInnerClass().print();
+ }
+
+ private class PrivateInnerClass {
+ void print() {
+ System.out.println("private inner");
+ }
+ }
+
+ private static class PrivateStaticInnerClass {
+ void print() {
+ System.out.println("private static inner");
+ }
+ }
+
+ private interface PrivateInnerInterface {}
+
+ private @interface PrivateInnerAnnotation {}
+}
diff --git a/third_party/ijar/test/PrivateNestedClass.java b/third_party/ijar/test/PrivateNestedClass.java
new file mode 100644
index 0000000000..4459d5cd5f
--- /dev/null
+++ b/third_party/ijar/test/PrivateNestedClass.java
@@ -0,0 +1,20 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * For testing purposes: a client of DumbClass.
+ */
+class PrivateNestedClass {
+ static { Object o = new DumbClass<String>().inner; }
+}
diff --git a/third_party/ijar/test/StripVerifyingVisitor.java b/third_party/ijar/test/StripVerifyingVisitor.java
new file mode 100644
index 0000000000..0045018625
--- /dev/null
+++ b/third_party/ijar/test/StripVerifyingVisitor.java
@@ -0,0 +1,223 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@code ClassVisitor} that checks that ijar did its job.
+ */
+final class StripVerifyingVisitor extends ClassVisitor {
+ public List<String> errors = new ArrayList<String>();
+ private String className;
+
+ public StripVerifyingVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ className = name;
+ if ((access & Opcodes.ACC_PRIVATE) != 0) {
+ errors.add(String.format("Private class found %s", className));
+ }
+ }
+
+ @Override public void visitSource(String source, String debug) {
+ errors.add(String.format("Source entry found %s %s", source, debug));
+ }
+
+ @Override public void visitOuterClass(String owner, String name, String desc) {
+ // Always okay.
+ }
+
+ @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // Always okay.
+ return null;
+ }
+
+ @Override public void visitAttribute(Attribute attr) {
+ // Just assume this is okay.
+ }
+
+ @Override public void visitInnerClass(
+ String name,
+ String outerName,
+ String innerName,
+ int access) {
+ // Always okay
+ // TODO(bazel-team): verify removal of leftover inner classes once implemented
+ // TODO(bazel-team): verify removal of private inner classes once implemented
+ }
+
+ @Override public FieldVisitor visitField(
+ int access,
+ String name,
+ String desc,
+ String signature,
+ Object value) {
+ if ((access & Opcodes.ACC_PRIVATE) != 0) {
+ errors.add(String.format("Private field %s found in %s", name, className));
+ }
+ // We need to go deeper.
+ return new StripVerifyingFieldVisitor(errors, className, name);
+ }
+
+ @Override public MethodVisitor visitMethod(
+ int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ if ((access & Opcodes.ACC_PRIVATE) != 0) {
+ errors.add(String.format("Private method %s found in %s", name, className));
+ }
+ // We need to go deeper.
+ return new StripVerifyingMethodVisitor(errors, className, name);
+ }
+
+ @Override public void visitEnd() {
+ // Always okay.
+ }
+
+ private static class StripVerifyingFieldVisitor extends FieldVisitor {
+ private final List<String> errors;
+ private final String className;
+ private final String fieldName;
+
+ StripVerifyingFieldVisitor(List<String> errors, String className, String fieldName) {
+ super(Opcodes.ASM4);
+ this.errors = errors;
+ this.className = className;
+ this.fieldName = fieldName;
+ }
+
+ @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // Always okay.
+ return null;
+ }
+
+ @Override public void visitAttribute(Attribute attr) {
+ // Just assume this is okay.
+ }
+
+ @Override public void visitEnd() {
+ // Always okay.
+ }
+ }
+
+ private static class StripVerifyingMethodVisitor extends MethodVisitor {
+ private final List<String> errors;
+ private final String className;
+ private final String methodName;
+
+ StripVerifyingMethodVisitor(List<String> errors, String className, String methodName) {
+ super(Opcodes.ASM4);
+ this.errors = errors;
+ this.className = className;
+ this.methodName = methodName;
+ }
+
+ @Override public AnnotationVisitor visitAnnotationDefault() {
+ // Always okay.
+ return null;
+ }
+
+ @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // Always okay.
+ return null;
+ }
+
+ @Override public AnnotationVisitor visitParameterAnnotation(
+ int parameter,
+ String desc,
+ boolean visible) {
+ // Always okay.
+ return null;
+ }
+
+ @Override public void visitAttribute(Attribute attr) {
+ // Just assume this is okay.
+ }
+
+ @Override public void visitCode() {
+ errors.add(String.format("Code found for method %s of %s", methodName, className));
+ }
+
+ @Override public void visitEnd() {}
+
+ // We ignore all details about code segments. Presumably we already logged an error about code
+ // existing at all.
+
+ @Override public void visitFrame(
+ int type,
+ int nLocal,
+ Object[] local,
+ int nStack,
+ Object[] stack) {}
+
+ @Override public void visitInsn(int opcode) {}
+
+ @Override public void visitIntInsn(int opcode, int operand) {}
+
+ @Override public void visitVarInsn(int opcode, int var) {}
+
+ @Override public void visitTypeInsn(int opcode, String type) {}
+
+ @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) {}
+
+ @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) {}
+
+ @Override public void visitJumpInsn(int opcode, Label label) {}
+
+ @Override public void visitLabel(Label label) {}
+
+ @Override public void visitLdcInsn(Object cst) {}
+
+ @Override public void visitIincInsn(int var, int increment) {}
+
+ @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {}
+
+ @Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {}
+
+ @Override public void visitMultiANewArrayInsn(String desc, int dims) {}
+
+ @Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {}
+
+ @Override public void visitLocalVariable(
+ String name,
+ String desc,
+ String signature,
+ Label start,
+ Label end,
+ int index) {}
+
+ @Override public void visitLineNumber(int line, Label start) {}
+
+ @Override public void visitMaxs(int maxStack, int maxLocals) {}
+ }
+}
diff --git a/third_party/ijar/test/TypeAnnotationTest2.java b/third_party/ijar/test/TypeAnnotationTest2.java
new file mode 100644
index 0000000000..a539790085
--- /dev/null
+++ b/third_party/ijar/test/TypeAnnotationTest2.java
@@ -0,0 +1,19 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+public class TypeAnnotationTest2 {
+ void m(Object o) {
+ Util.castNullable(null);
+ }
+}
diff --git a/third_party/ijar/test/UseDeprecatedParts.java b/third_party/ijar/test/UseDeprecatedParts.java
new file mode 100644
index 0000000000..024a5816c0
--- /dev/null
+++ b/third_party/ijar/test/UseDeprecatedParts.java
@@ -0,0 +1,48 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * A class that uses deprecated things for testing.
+ */
+final class UseDeprecatedParts {
+ @DeprecatedParts.DeprecatedViaAnnotationAnnotation String annotatedField1;
+ @DeprecatedParts.DeprecatedViaJavadocAnnotation String annotatedField2;
+
+ static final DeprecatedParts.DeprecatedViaAnnotationConstructor dummyField1 =
+ new DeprecatedParts.DeprecatedViaAnnotationConstructor();
+ static final DeprecatedParts.DeprecatedViaJavadocConstructor dummyField2 =
+ new DeprecatedParts.DeprecatedViaJavadocConstructor ();
+
+ public static void dummyMethod() {
+ System.out.println(DeprecatedParts.deprecatedViaAnnotationStaticField);
+ System.out.println(DeprecatedParts.deprecatedViaJavadocStaticField);
+
+ System.out.println(new DeprecatedParts().deprecatedViaAnnotationField);
+ System.out.println(new DeprecatedParts().deprecatedViaJavadocField);
+
+ new DeprecatedParts().deprecatedViaAnnotationMethod();
+ new DeprecatedParts().deprecatedViaJavadocMethod();
+
+ DeprecatedParts.deprecatedViaAnnotationStaticMethod();
+ DeprecatedParts.deprecatedViaJavadocStaticMethod();
+ }
+
+ class Class1 extends DeprecatedParts.DeprecatedViaAnnotationClass {}
+
+ class Class2 extends DeprecatedParts.DeprecatedViaJavadocClass {}
+
+ interface Interface1 extends DeprecatedParts.DeprecatedViaAnnotationInterface {}
+
+ interface Interface2 extends DeprecatedParts.DeprecatedViaJavadocInterface {}
+}
diff --git a/third_party/ijar/test/UseRestrictedAnnotation.java b/third_party/ijar/test/UseRestrictedAnnotation.java
new file mode 100644
index 0000000000..fcdb83ad2d
--- /dev/null
+++ b/third_party/ijar/test/UseRestrictedAnnotation.java
@@ -0,0 +1,22 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * Incorrect use of RestrictedAnnotation. Used for testing.
+ */
+public class UseRestrictedAnnotation {
+ @Annotations.ParametersOnlyAnnotation
+ public void m() {
+ }
+}
diff --git a/third_party/ijar/test/WellCompressed1.java b/third_party/ijar/test/WellCompressed1.java
new file mode 100644
index 0000000000..7fc90f7556
--- /dev/null
+++ b/third_party/ijar/test/WellCompressed1.java
@@ -0,0 +1,505 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * For testing purposes: a class that can be really well compressed.
+ *
+ * This class should be at least one page (4K) longer when uncompressed than
+ * when compressed to trigger "ijar segmentation fault" bug.
+ */
+class WellCompressed1 {
+ private WellCompressed1() {}
+ public static final String DATA = " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " "
+ + " ";
+}
diff --git a/third_party/ijar/test/WellCompressed2.java b/third_party/ijar/test/WellCompressed2.java
new file mode 100644
index 0000000000..ffb292f049
--- /dev/null
+++ b/third_party/ijar/test/WellCompressed2.java
@@ -0,0 +1,316 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+public class WellCompressed2 {
+ public final static String DATA_001 = " "
+ + " "
+ + " ";
+ public final static String DATA_002 = " "
+ + " "
+ + " ";
+ public final static String DATA_003 = " "
+ + " "
+ + " ";
+ public final static String DATA_004 = " "
+ + " "
+ + " ";
+ public final static String DATA_005 = " "
+ + " "
+ + " ";
+ public final static String DATA_006 = " "
+ + " "
+ + " ";
+ public final static String DATA_007 = " "
+ + " "
+ + " ";
+ public final static String DATA_008 = " "
+ + " "
+ + " ";
+ public final static String DATA_009 = " "
+ + " "
+ + " ";
+ public final static String DATA_010 = " "
+ + " "
+ + " ";
+ public final static String DATA_011 = " "
+ + " "
+ + " ";
+ public final static String DATA_012 = " "
+ + " "
+ + " ";
+ public final static String DATA_013 = " "
+ + " "
+ + " ";
+ public final static String DATA_014 = " "
+ + " "
+ + " ";
+ public final static String DATA_015 = " "
+ + " "
+ + " ";
+ public final static String DATA_016 = " "
+ + " "
+ + " ";
+ public final static String DATA_017 = " "
+ + " "
+ + " ";
+ public final static String DATA_018 = " "
+ + " "
+ + " ";
+ public final static String DATA_019 = " "
+ + " "
+ + " ";
+ public final static String DATA_020 = " "
+ + " "
+ + " ";
+ public final static String DATA_021 = " "
+ + " "
+ + " ";
+ public final static String DATA_022 = " "
+ + " "
+ + " ";
+ public final static String DATA_023 = " "
+ + " "
+ + " ";
+ public final static String DATA_024 = " "
+ + " "
+ + " ";
+ public final static String DATA_025 = " "
+ + " "
+ + " ";
+ public final static String DATA_026 = " "
+ + " "
+ + " ";
+ public final static String DATA_027 = " "
+ + " "
+ + " ";
+ public final static String DATA_028 = " "
+ + " "
+ + " ";
+ public final static String DATA_029 = " "
+ + " "
+ + " ";
+ public final static String DATA_030 = " "
+ + " "
+ + " ";
+ public final static String DATA_031 = " "
+ + " "
+ + " ";
+ public final static String DATA_032 = " "
+ + " "
+ + " ";
+ public final static String DATA_033 = " "
+ + " "
+ + " ";
+ public final static String DATA_034 = " "
+ + " "
+ + " ";
+ public final static String DATA_035 = " "
+ + " "
+ + " ";
+ public final static String DATA_036 = " "
+ + " "
+ + " ";
+ public final static String DATA_037 = " "
+ + " "
+ + " ";
+ public final static String DATA_038 = " "
+ + " "
+ + " ";
+ public final static String DATA_039 = " "
+ + " "
+ + " ";
+ public final static String DATA_040 = " "
+ + " "
+ + " ";
+ public final static String DATA_041 = " "
+ + " "
+ + " ";
+ public final static String DATA_042 = " "
+ + " "
+ + " ";
+ public final static String DATA_043 = " "
+ + " "
+ + " ";
+ public final static String DATA_044 = " "
+ + " "
+ + " ";
+ public final static String DATA_045 = " "
+ + " "
+ + " ";
+ public final static String DATA_046 = " "
+ + " "
+ + " ";
+ public final static String DATA_047 = " "
+ + " "
+ + " ";
+ public final static String DATA_048 = " "
+ + " "
+ + " ";
+ public final static String DATA_049 = " "
+ + " "
+ + " ";
+ public final static String DATA_050 = " "
+ + " "
+ + " ";
+ public final static String DATA_051 = " "
+ + " "
+ + " ";
+ public final static String DATA_052 = " "
+ + " "
+ + " ";
+ public final static String DATA_053 = " "
+ + " "
+ + " ";
+ public final static String DATA_054 = " "
+ + " "
+ + " ";
+ public final static String DATA_055 = " "
+ + " "
+ + " ";
+ public final static String DATA_056 = " "
+ + " "
+ + " ";
+ public final static String DATA_057 = " "
+ + " "
+ + " ";
+ public final static String DATA_058 = " "
+ + " "
+ + " ";
+ public final static String DATA_059 = " "
+ + " "
+ + " ";
+ public final static String DATA_060 = " "
+ + " "
+ + " ";
+ public final static String DATA_061 = " "
+ + " "
+ + " ";
+ public final static String DATA_062 = " "
+ + " "
+ + " ";
+ public final static String DATA_063 = " "
+ + " "
+ + " ";
+ public final static String DATA_064 = " "
+ + " "
+ + " ";
+ public final static String DATA_065 = " "
+ + " "
+ + " ";
+ public final static String DATA_066 = " "
+ + " "
+ + " ";
+ public final static String DATA_067 = " "
+ + " "
+ + " ";
+ public final static String DATA_068 = " "
+ + " "
+ + " ";
+ public final static String DATA_069 = " "
+ + " "
+ + " ";
+ public final static String DATA_070 = " "
+ + " "
+ + " ";
+ public final static String DATA_071 = " "
+ + " "
+ + " ";
+ public final static String DATA_072 = " "
+ + " "
+ + " ";
+ public final static String DATA_073 = " "
+ + " "
+ + " ";
+ public final static String DATA_074 = " "
+ + " "
+ + " ";
+ public final static String DATA_075 = " "
+ + " "
+ + " ";
+ public final static String DATA_076 = " "
+ + " "
+ + " ";
+ public final static String DATA_077 = " "
+ + " "
+ + " ";
+ public final static String DATA_078 = " "
+ + " "
+ + " ";
+ public final static String DATA_079 = " "
+ + " "
+ + " ";
+ public final static String DATA_080 = " "
+ + " "
+ + " ";
+ public final static String DATA_081 = " "
+ + " "
+ + " ";
+ public final static String DATA_082 = " "
+ + " "
+ + " ";
+ public final static String DATA_083 = " "
+ + " "
+ + " ";
+ public final static String DATA_084 = " "
+ + " "
+ + " ";
+ public final static String DATA_085 = " "
+ + " "
+ + " ";
+ public final static String DATA_086 = " "
+ + " "
+ + " ";
+ public final static String DATA_087 = " "
+ + " "
+ + " ";
+ public final static String DATA_088 = " "
+ + " "
+ + " ";
+ public final static String DATA_089 = " "
+ + " "
+ + " ";
+ public final static String DATA_090 = " "
+ + " "
+ + " ";
+ public final static String DATA_091 = " "
+ + " "
+ + " ";
+ public final static String DATA_092 = " "
+ + " "
+ + " ";
+ public final static String DATA_093 = " "
+ + " "
+ + " ";
+ public final static String DATA_094 = " "
+ + " "
+ + " ";
+ public final static String DATA_095 = " "
+ + " "
+ + " ";
+ public final static String DATA_096 = " "
+ + " "
+ + " ";
+ public final static String DATA_097 = " "
+ + " "
+ + " ";
+ public final static String DATA_098 = " "
+ + " "
+ + " ";
+ public final static String DATA_099 = " "
+ + " "
+ + " ";
+ public final static String DATA_100 = " "
+ + " "
+ + " ";
+}
diff --git a/third_party/ijar/test/ijar_test.sh b/third_party/ijar/test/ijar_test.sh
new file mode 100755
index 0000000000..9869969adf
--- /dev/null
+++ b/third_party/ijar/test/ijar_test.sh
@@ -0,0 +1,417 @@
+#!/bin/bash -eu
+#
+# Copyright 2015 Google Inc. All rights reserved.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+
+# TODO(bazel-team): this file is bloated, we should factor it.
+
+#### Inputs
+
+## TEST_TMPDIR
+if [ -z "${TEST_TMPDIR:-}" ]; then
+ TEST_TMPDIR="$(mktemp -d ${TMPDIR:-/tmp}/ijar-test.XXXXXXXX)"
+ trap "rm -fr ${TEST_TMPDIR}" EXIT
+fi
+
+## Mac OS X stat and MD5
+PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
+if [[ "$PLATFORM" = "darwin" ]]; then
+ function statfmt() {
+ stat -f "%z" $1
+ }
+ MD5SUM=/sbin/md5
+else
+ function statfmt() {
+ stat -c "%s" $1
+ }
+ MD5SUM=md5sum
+fi
+
+## Tools
+JAVAC=$1
+JAVA=$2
+JAR=$3
+JAVAP=$4
+IJAR=$TEST_SRCDIR/$5
+LANGTOOLS8=$TEST_SRCDIR/$6
+UNZIP=$7
+ZIP=$8
+
+IJAR_SRCDIR=$(dirname ${IJAR})
+A_JAR=$TEST_TMPDIR/A.jar
+A_INTERFACE_JAR=$TEST_TMPDIR/A-interface.jar
+A_ZIP_JAR=$TEST_TMPDIR/A_zip.jar
+A_ZIP_INTERFACE_JAR=$TEST_TMPDIR/A_zip-interface.jar
+W_JAR=$TEST_TMPDIR/W.jar
+BOTTLES_JAR=$TEST_TMPDIR/bottles.jar
+JAR_WRONG_CENTRAL_DIR=$IJAR_SRCDIR/test/libwrongcentraldir.jar
+IJAR_WRONG_CENTRAL_DIR=$TEST_TMPDIR/wrongcentraldir_interface.jar
+OBJECT_JAVA=$IJAR_SRCDIR/test/Object.java
+OBJECT_JAR=$TEST_TMPDIR/object.jar
+OBJECT_IJAR=$TEST_TMPDIR/object_interface.jar
+TYPEANN2_JAR=$IJAR_SRCDIR/test/libtypeannotations2.jar
+TYPEANN2_IJAR=$TEST_TMPDIR/typeannotations2_interface.jar
+TYPEANN2_JAVA=$IJAR_SRCDIR/test/TypeAnnotationTest2.java
+INVOKEDYNAMIC_JAR=$IJAR_SRCDIR/test/libinvokedynamic.jar
+INVOKEDYNAMIC_IJAR=$TEST_TMPDIR/invokedynamic_interface.jar
+
+#### Testing framework
+# Print message in "$1" then exit with status "$2"
+die () {
+ # second argument is optional, defaulting to 1
+ local status_code=${2:-1}
+ # Stop capturing stdout/stderr, and dump captured output
+ if [ "$CAPTURED_STD_ERR" -ne 0 ]; then
+ restore_outputs
+ cat "${TEST_TMPDIR}/captured.err" 1>&2
+ fi
+
+ if [ -n "${1-}" ] ; then
+ echo "$1" 1>&2
+ fi
+ if [ x"$status_code" != x -a x"$status_code" != x"0" ]; then
+ exit "$status_code"
+ else
+ exit 1
+ fi
+}
+
+# Die if "$1" == "$2", print $3 as death reason
+check_ne () {
+ if [ "$1" = "$2" ]; then
+ die "Check failed: '$1' != '$2' ${3:+ ($3)}"
+ fi
+}
+
+# Die if "$1" != "$2", print $3 as death reason
+check_eq () {
+ if [ ! "$1" = "$2" ]; then
+ die "Check failed: '$1' = '$2' ${3:+ ($3)}"
+ fi
+}
+
+CAPTURED_STD_ERR="${CAPTURED_STD_ERR:-0}"
+
+capture_test_stderr () {
+ exec 6>&2 # Save stderr as fd 6
+ exec 7>"${TEST_TMPDIR}/captured.err"
+ exec 2>&7
+ CAPTURED_STD_ERR=1
+}
+
+restore_outputs () {
+ if [ "$CAPTURED_STD_ERR" -ne 0 ] ; then
+ exec 2>&6
+ fi
+}
+
+recapture_outputs () {
+ if [ "$CAPTURED_STD_ERR" -ne 0 ] ; then
+ exec 2>&7
+ fi
+}
+
+#### Setup
+
+# set_file_length FILE SIZE
+#
+# Sets the file size for FILE, truncating if necessary, creating a
+# sparse file if possible, preserving original contents if they fit.
+function set_file_length() {
+ perl -e 'open(FH, ">>$ARGV[0]") && truncate(FH, $ARGV[1]) or die $!' "$@" &&
+ [[ "$(statfmt $1)" == "$2" ]] ||
+ die "set_file_length failed"
+}
+
+# grep_test_stderr STRING MESSAGE
+#
+# Greps the captured stderr text for STRING. If not found, fails with MESSAGE.
+grep_test_stderr() {
+ restore_outputs
+ [ "$CAPTURED_STD_ERR" -ne 0 ] || \
+ die "Must call capture_test_stderr before grep_test_stderr"
+ grep -c "$1" ${TEST_TMPDIR}/captured.err >/dev/null || \
+ die "Check failed: grep -c '$1' ${TEST_TMPDIR}/captured.err ${2:+ ($2)}"
+ CAPTURED_STD_ERR=0
+ recapture_outputs
+}
+
+# check_consistent_file_contents FILE
+#
+# Checks that all files created with the given filename have identical contents.
+expected_output=""
+function check_consistent_file_contents() {
+ local actual="$(cat $1 | ${MD5SUM} | awk '{ print $1; }')"
+ local filename="$(echo $1 | ${MD5SUM} | awk '{ print $1; }')"
+ local expected="$actual"
+ if $(echo "${expected_output}" | grep -q "^${filename} "); then
+ echo "${expected_output}" | grep -q "^${filename} ${actual}$" || {
+ ls -l "$1"
+ die "output file contents differ"
+ }
+ else
+ expected_output="$expected_output$filename $actual
+"
+ fi
+}
+
+# Tests that ijar does not crash when output ijar is bigger than the input jar
+rm -fr $TEST_TMPDIR/classes
+mkdir -p $TEST_TMPDIR/classes || die "mkdir $TEST_TMPDIR/classes failed"
+$JAVAC -g -d $TEST_TMPDIR/classes \
+ $IJAR_SRCDIR/test/WellCompressed*.java ||
+ die "javac failed"
+$JAR cf $W_JAR -C $TEST_TMPDIR/classes . || die "jar failed"
+
+W_INTERFACE_JAR=$TEST_TMPDIR/W-interface.jar
+$IJAR $W_JAR $W_INTERFACE_JAR || die "ijar failed"
+
+mkdir -p $TEST_TMPDIR/java/lang
+cp $OBJECT_JAVA $TEST_TMPDIR/java/lang/.
+$JAVAC $TEST_TMPDIR/java/lang/Object.java || die "javac failed"
+$JAR cf $OBJECT_JAR -C $TEST_TMPDIR java/lang/Object.class || die "jar failed"
+
+# Tests that ijar can handle class bodies longer than 64K
+rm -fr $TEST_TMPDIR/classes
+mkdir -p $TEST_TMPDIR/classes || die "mkdir $TEST_TMPDIR/classes failed"
+# First, generate the input file
+BOTTLES_JAVA=$TEST_TMPDIR/BottlesOnTheWall.java
+echo "public class BottlesOnTheWall {" > $BOTTLES_JAVA
+for i in $(seq 1 16384); do
+ echo " public int getBottleOnTheWall${i}() { return ${i}; }" >> $BOTTLES_JAVA
+done
+
+echo "}" >> $BOTTLES_JAVA
+
+$JAVAC -g -d $TEST_TMPDIR/classes $BOTTLES_JAVA || die "javac failed"
+BOTTLES_INTERFACE_JAR=$TEST_TMPDIR/bottles-interface.jar
+
+for flag0 in '' '0'; do
+ $JAR c"${flag0}"f $BOTTLES_JAR -C $TEST_TMPDIR/classes . || die "jar failed"
+ $IJAR $BOTTLES_JAR $BOTTLES_INTERFACE_JAR || die "ijar failed"
+ check_consistent_file_contents $BOTTLES_INTERFACE_JAR
+done
+
+# Compiles A.java, builds A.jar and A-interface.jar
+rm -fr $TEST_TMPDIR/classes
+mkdir -p $TEST_TMPDIR/classes || die "mkdir $TEST_TMPDIR/classes failed"
+$JAVAC -g -d $TEST_TMPDIR/classes $IJAR_SRCDIR/test/A.java ||
+ die "javac failed"
+
+for flag0 in '' '0'; do
+# Ensure input files larger than INITIAL_BUFFER_SIZE work.
+# TODO(martinrb): remove maximum .class file size limit (MAX_BUFFER_SIZE)
+for size in '' $((1024*1024)) $((15*1024*1024)); do
+ if [[ -n "$size" ]]; then
+ for file in $(find $TEST_TMPDIR/classes -name '*.class'); do
+ set_file_length "$file" "$size"
+ done
+ fi
+ $JAR c"${flag0}"f $A_JAR -C $TEST_TMPDIR/classes . || die "jar failed"
+ $IJAR $A_JAR $A_INTERFACE_JAR || die "ijar failed."
+ check_consistent_file_contents $A_INTERFACE_JAR
+ done
+done
+
+# Creates a huge (3Gb) input jar to test "large file" correctness
+set_file_length $TEST_TMPDIR/zeroes.data $((3*1024*1024*1024))
+for flag0 in '' '0'; do
+ $JAR c"${flag0}"f $A_JAR -C $TEST_TMPDIR zeroes.data -C $TEST_TMPDIR/classes . || die "jar failed"
+ $IJAR $A_JAR $A_INTERFACE_JAR || die "ijar failed."
+ check_consistent_file_contents $A_INTERFACE_JAR
+done
+
+# Create an output jar with upper bound on size > 2GB
+DIR=$TEST_TMPDIR/ManyLargeClasses
+mkdir -p $DIR/classes
+for i in $(seq 200); do
+ printf "class C${i} {}\n" > $DIR/C${i}.java
+done
+([[ "$JAVAC" =~ ^/ ]] || JAVAC="$PWD/$JAVAC"; cd $DIR && $JAVAC -d classes *.java)
+for i in $(seq 200); do
+ set_file_length $DIR/classes/C${i}.class $((15*1024*1024))
+done
+$JAR cf $DIR/ManyLargeClasses.jar -C $DIR/classes . || die "jar failed"
+$IJAR $DIR/ManyLargeClasses.jar $DIR/ManyLargeClasses.ijar || die "ijar failed."
+
+#### Checks
+
+# Check that ijar can produce class files with a body longer than 64K by
+# calling ijar itself on the output file to make sure that it is valid
+BOTTLES_INTERFACE_INTERFACE_JAR=$TEST_TMPDIR/bottles-interface-interface.jar
+$IJAR $BOTTLES_INTERFACE_JAR $BOTTLES_INTERFACE_INTERFACE_JAR ||
+ die "ijar cannot produce class files with body longer than 64K"
+
+# Check that the interface jar is bigger than the original jar.
+W_JAR_SIZE=$(statfmt $W_JAR)
+W_INTERFACE_JAR_SIZE=$(statfmt $W_INTERFACE_JAR)
+[[ $W_INTERFACE_JAR_SIZE -gt $W_JAR_SIZE ]] || die "interface jar should be bigger"
+
+# Check that the number of entries is 5:
+# A, A.PrivateInner, A.PublicInner, A.MyAnnotation,
+# A.RuntimeAnnotation
+# (Note: even private inner classes are retained, so we don't need to change
+# the types of members.)
+lines=$($JAR tvf $A_INTERFACE_JAR | wc -l)
+expected=5
+check_eq $expected $lines "Interface jar should have $expected entries!"
+
+
+# Check that no private class members are found:
+lines=$($JAVAP -private -classpath $A_JAR A | grep priv | wc -l)
+check_eq 2 $lines "Input jar should have 2 private members!"
+lines=$($JAVAP -private -classpath $A_INTERFACE_JAR A | grep priv | wc -l)
+check_eq 0 $lines "Interface jar should have no private members!"
+lines=$($JAVAP -private -classpath $A_INTERFACE_JAR A | grep clinit | wc -l)
+check_eq 0 $lines "Interface jar should have no class initializers!"
+
+
+# Check that no code is found:
+lines=$($JAVAP -c -private -classpath $A_JAR A | grep Code: | wc -l)
+check_eq 5 $lines "Input jar should have 5 method bodies!"
+lines=$($JAVAP -c -private -classpath $A_INTERFACE_JAR A | grep Code: | wc -l)
+check_eq 0 $lines "Interface jar should have no method bodies!"
+
+
+# Check that constants from code are no longer present:
+$JAVAP -c -private -classpath $A_JAR A | grep -sq foofoofoofoo ||
+ die "Input jar should have code constants!"
+$JAVAP -c -private -classpath $A_INTERFACE_JAR A | grep -sq foofoofoofoo &&
+ die "Interface jar should have no code constants!"
+
+
+# Check (important, this!) that the interface jar is still sufficient
+# for compiling:
+$JAVAC -Xlint -classpath $A_INTERFACE_JAR -g -d $TEST_TMPDIR/classes \
+ $IJAR_SRCDIR/test/B.java 2>$TEST_TMPDIR/B.javac.err ||
+ { cat $TEST_TMPDIR/B.javac.err >&2; die "Can't compile B!"; }
+
+
+# Test compilation of B yielded deprecation message:
+grep -sq 'deprecatedMethod.*in A has been deprecated' \
+ $TEST_TMPDIR/B.javac.err || die "ijar has lost @Deprecated annotation!"
+
+
+# Check idempotence of ijar transformation:
+A_INTERFACE_INTERFACE_JAR=$TEST_TMPDIR/A-interface-interface.jar
+$IJAR $A_INTERFACE_JAR $A_INTERFACE_INTERFACE_JAR || die "ijar failed."
+cmp $A_INTERFACE_JAR $A_INTERFACE_INTERFACE_JAR ||
+ die "ijar transformation is not idempotent"
+
+
+# Check that -interface.jar contains nothing but .class files:
+check_eq 0 $($JAR tf $A_INTERFACE_JAR | grep -v \\.class$ | wc -l) \
+ "Interface jar should contain only .class files!"
+
+
+# Check that -interface.jar timestamps are all zeros:
+check_eq 0 $(TZ=UTC $JAR tvf $A_INTERFACE_JAR |
+ grep -v 'Fri Nov 30 00:00:00 UTC 1979' | wc -l) \
+ "Interface jar contained non-zero timestamps!"
+
+
+# Check that compile-time constants in A are still annotated as such in ijar:
+$JAVAP -classpath $TEST_TMPDIR/classes -c B | grep -sq ldc2_w.*123 ||
+ die "ConstantValue not propagated to class B!"
+
+# Regression test for jar file without classes (javac doesn't like an empty ijar).
+>$TEST_TMPDIR/empty
+$ZIP $TEST_TMPDIR/noclasses.jar $TEST_TMPDIR/empty >/dev/null 2>&1
+$IJAR $TEST_TMPDIR/noclasses.jar || die "ijar failed"
+$UNZIP -qql $TEST_TMPDIR/noclasses-interface.jar 2>/dev/null | grep -q . ||
+ die "noclasses-interface.jar is completely empty!"
+ $JAVAC -classpath $TEST_TMPDIR/noclasses-interface.jar \
+ -d $TEST_TMPDIR/classes \
+ $IJAR_SRCDIR/test/A.java ||
+ die "javac noclasses-interface.jar failed"
+rm $TEST_TMPDIR/{empty,noclasses.jar,noclasses-interface.jar}
+
+
+# Run the dynamic checks in B.main().
+$JAVA -classpath $TEST_TMPDIR/classes B || exit 1
+
+# TODO(bazel-team) test that modifying the source in a non-interface
+# changing way results in the same -interface.jar.
+
+# Check that a jar compressed with zip results in the same interface jar as a
+# jar compressed with jar
+rm -fr $TEST_TMPDIR/classes
+mkdir -p $TEST_TMPDIR/classes || die "mkdir $TEST_TMPDIR/classes failed"
+$JAVAC -g -d $TEST_TMPDIR/classes $IJAR_SRCDIR/test/A.java ||
+ die "javac failed"
+$JAR cf $A_JAR $TEST_TMPDIR/classes/A.class || die "jar failed"
+$ZIP $A_ZIP_JAR $TEST_TMPDIR/classes/A.class || die "zip failed"
+
+$IJAR $A_JAR $A_INTERFACE_JAR || die "ijar failed"
+$IJAR $A_ZIP_JAR $A_ZIP_INTERFACE_JAR || die "ijar failed"
+cmp $A_INTERFACE_JAR $A_ZIP_INTERFACE_JAR || \
+ die "ijars from jar and zip are different"
+
+
+# Check that a JAR file can be parsed even if the central directory file count
+# is wrong
+$IJAR $JAR_WRONG_CENTRAL_DIR $IJAR_WRONG_CENTRAL_DIR || die "ijar failed"
+IJAR_FILES=$($UNZIP -qql $IJAR_WRONG_CENTRAL_DIR | wc -l | xargs echo)
+if [[ $IJAR_FILES != 2 ]]; then
+ die "ijar removed files"
+fi
+
+# Check that constant pool references used by JSR308 type annotations are
+# preserved
+$IJAR $TYPEANN2_JAR $TYPEANN2_IJAR || die "ijar failed"
+$JAVAP -classpath $TYPEANN2_IJAR -v Util |
+ grep -sq RuntimeVisibleTypeAnnotations ||
+ die "RuntimeVisibleTypeAnnotations not preserved!"
+set -x
+cp $TYPEANN2_JAVA $TEST_TMPDIR/TypeAnnotationTest2.java
+$JAVAC -J-Xbootclasspath/p:$LANGTOOLS8 $TEST_TMPDIR/TypeAnnotationTest2.java -cp $TYPEANN2_IJAR ||
+ die "javac failed"
+set +x
+
+# Check that ijar works on classes with invokedynamic
+$IJAR $INVOKEDYNAMIC_JAR $INVOKEDYNAMIC_IJAR || die "ijar failed"
+lines=$($JAVAP -c -private -classpath $INVOKEDYNAMIC_JAR ClassWithLambda | grep Code: | wc -l)
+check_eq 4 $lines "Input jar should have 4 method bodies!"
+lines=$($JAVAP -c -private -classpath $INVOKEDYNAMIC_IJAR ClassWithLambda | grep Code: | wc -l)
+check_eq 0 $lines "Interface jar should have no method bodies!"
+
+# Check that Object.class can be processed
+$IJAR $OBJECT_JAR $OBJECT_IJAR || die "ijar failed"
+
+# Check that the tool detects and reports a corrupted end of central directory
+# record condition
+CORRUPTED_JAR=$TEST_TMPDIR/corrupted.jar
+# First make the jar one byte longer
+cp $JAR_WRONG_CENTRAL_DIR $CORRUPTED_JAR
+chmod +w $CORRUPTED_JAR
+echo >> $CORRUPTED_JAR
+set +e
+capture_test_stderr
+$IJAR $CORRUPTED_JAR && die "ijar should have failed"
+status=$?
+set -e
+check_ne 0 $status
+grep_test_stderr "missing end of central directory record"
+restore_outputs
+# Then make the jar one byte shorter than the original one
+let "NEW_SIZE = `statfmt $CORRUPTED_JAR` - 2"
+set_file_length $CORRUPTED_JAR $NEW_SIZE
+set +e
+capture_test_stderr
+$IJAR $CORRUPTED_JAR && die "ijar should have failed"
+status=$?
+set -e
+check_ne 0 $status
+grep_test_stderr "missing end of central directory record"
+restore_outputs
+
+echo "PASS"
diff --git a/third_party/ijar/test/invokedynamic/ClassWithLambda.java b/third_party/ijar/test/invokedynamic/ClassWithLambda.java
new file mode 100644
index 0000000000..f2f71059e4
--- /dev/null
+++ b/third_party/ijar/test/invokedynamic/ClassWithLambda.java
@@ -0,0 +1,31 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.util.function.Function;
+
+class ClassWithLambda {
+ interface Rec extends Function<Rec, Rec> {}
+
+ private static final String HELLO = "Hello World";
+
+ int hash(Function<String, Integer> hashFunc) {
+ return hashFunc.apply(HELLO);
+ }
+
+ void m() {
+ Rec f = x -> x.apply(x);
+
+ int x = hash(String::hashCode);
+ }
+}
diff --git a/third_party/ijar/test/libwrongcentraldir.jar b/third_party/ijar/test/libwrongcentraldir.jar
new file mode 100644
index 0000000000..0d86817afe
--- /dev/null
+++ b/third_party/ijar/test/libwrongcentraldir.jar
Binary files differ
diff --git a/third_party/ijar/test/package-info.java b/third_party/ijar/test/package-info.java
new file mode 100644
index 0000000000..3e122fc5f1
--- /dev/null
+++ b/third_party/ijar/test/package-info.java
@@ -0,0 +1,15 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/** Empty package-info */ \ No newline at end of file
diff --git a/third_party/ijar/test/typeannotations2/NonNull.java b/third_party/ijar/test/typeannotations2/NonNull.java
new file mode 100644
index 0000000000..089e70c5e7
--- /dev/null
+++ b/third_party/ijar/test/typeannotations2/NonNull.java
@@ -0,0 +1,23 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
+public @interface NonNull {
+}
diff --git a/third_party/ijar/test/typeannotations2/Nullable.java b/third_party/ijar/test/typeannotations2/Nullable.java
new file mode 100644
index 0000000000..2f341c00ad
--- /dev/null
+++ b/third_party/ijar/test/typeannotations2/Nullable.java
@@ -0,0 +1,23 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
+public @interface Nullable {
+}
diff --git a/third_party/ijar/test/typeannotations2/Util.java b/third_party/ijar/test/typeannotations2/Util.java
new file mode 100644
index 0000000000..baaff4d96a
--- /dev/null
+++ b/third_party/ijar/test/typeannotations2/Util.java
@@ -0,0 +1,19 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+public class Util {
+ public static <T extends @Nullable Object> @NonNull T castNullable(T value) {
+ return (@NonNull T) value;
+ }
+}
diff --git a/third_party/ijar/test/typeannotations2/java/lang/annotation/ElementType.java b/third_party/ijar/test/typeannotations2/java/lang/annotation/ElementType.java
new file mode 100644
index 0000000000..001b8c707a
--- /dev/null
+++ b/third_party/ijar/test/typeannotations2/java/lang/annotation/ElementType.java
@@ -0,0 +1,21 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java.lang.annotation;
+
+/**
+ * This is stub for the jdk8 ElementType. It allows the test to compile with a
+ * jdk7 javabase.
+ */
+public enum ElementType { TYPE_USE, TYPE_PARAMETER; }