# HG changeset patch # User jjg # Date 1404467542 -3600 # Node ID 823512a7266029d90f04942872e30f6f2923f162 # Parent b935bc56f1e46f5cb0d762f213e71821690f3b45 8042261: Implement classfile tests for Deprecated attribute. Reviewed-by: jjg, anazarov, shurailine diff -r b935bc56f1e4 -r 823512a72660 langtools/test/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java --- a/langtools/test/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java Thu Jul 03 15:48:23 2014 -0700 +++ b/langtools/test/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java Fri Jul 04 10:52:22 2014 +0100 @@ -45,7 +45,7 @@ */ protected void compileAndTest(String sourceCode, String... classesToTest) throws Exception { - Map classes = compile(sourceCode); + Map classes = compile(sourceCode).getClasses(); String fileName = ToolBox.getJavaFileNameFromSource(sourceCode); for (String className : classesToTest) { assertAttributePresent(ClassFile.read(classes.get(className).openInputStream()), fileName); diff -r b935bc56f1e4 -r 823512a72660 langtools/test/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java Fri Jul 04 10:52:22 2014 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8042261 + * @summary Checking that deprecated attribute does not apply to classes of deprecated package. + * @library /tools/javac/lib ../lib + * @build DeprecatedPackageTest TestBase TestResult InMemoryFileManager ToolBox + * @run main DeprecatedPackageTest + */ + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Deprecated_attribute; + +public class DeprecatedPackageTest extends TestResult { + + private static final String[] sourceTest = new String[]{ + "package deprecated;\n" + + "public class notDeprecated{}", + "package deprecated;\n" + + "public interface notDeprecated{}", + "package deprecated;\n" + + "public @interface notDeprecated{}", + "package deprecated;\n" + + "public enum notDeprecated{}" + }; + + private static final String CLASS_NAME = "deprecated.notDeprecated"; + + private static final String PACKAGE_INFO = + "@Deprecated\n" + + "package deprecated;"; + + public static void main(String[] args) throws TestFailedException { + new DeprecatedPackageTest().test(); + } + + private void test() throws TestFailedException { + try { + for (String src : sourceTest) { + test(PACKAGE_INFO, src); + test(PACKAGE_INFO.replaceAll("@Deprecated", "/** @deprecated */"), src); + } + } catch (Exception e) { + addFailure(e); + } finally { + checkStatus(); + } + } + + private void test(String package_info, String src) { + addTestCase(src); + printf("Testing test case: \n%s\n", src); + try { + ClassFile cf = ClassFile.read(compile( + new String[]{"package-info.java", package_info}, + new String[]{"notDeprecated.java", src}) + .getClasses().get(CLASS_NAME).openInputStream()); + Deprecated_attribute attr = + (Deprecated_attribute) cf.getAttribute(Attribute.Deprecated); + assertNull(attr, "Class can not have deprecated attribute : " + CLASS_NAME); + } catch (Exception e) { + addFailure(e); + } + } +} diff -r b935bc56f1e4 -r 823512a72660 langtools/test/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java Fri Jul 04 10:52:22 2014 +0100 @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8042261 + * @summary Checking what attribute is generated by annotation Deprecated + * or javadoc deprecated for field, method, class(inner/local), interface. + * @library /tools/javac/lib ../lib + * @build DeprecatedTest TestBase TestResult InMemoryFileManager ToolBox + * @run main DeprecatedTest + */ + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Deprecated_attribute; +import com.sun.tools.classfile.Field; +import com.sun.tools.classfile.InnerClasses_attribute; +import com.sun.tools.classfile.InnerClasses_attribute.Info; +import com.sun.tools.classfile.Method; + +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.util.Map; + +public class DeprecatedTest extends TestResult { + + private static final String[] sources = new String[]{ + "@Deprecated public class deprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated public void deprecated() {}\n" + + "@Deprecated public int deprecated;\n" + + "public void notDeprecated() {}\n" + + "public int notDeprecated;\n" + + "public void f() {\n" + + " @Deprecated class deprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }\n" + + " class notDeprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }}\n" + + "}", + "@Deprecated public interface deprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated void deprecated01();\n" + + "void notDeprecated01();\n" + + "@Deprecated default void deprecated02() {}\n" + + "default void notDeprecated02() {}\n" + + "@Deprecated int deprecated = 0;\n" + + "int notDeprecated = 0;\n" + + "}", + "@Deprecated public enum deprecated {\n" + + "@Deprecated deprecated, notDeprecated;\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated public void deprecated() {}\n" + + "public void notDeprecated() {}\n" + + "public void f() {\n" + + " @Deprecated class deprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }\n" + + " class notDeprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }}\n" + + "}", + "@Deprecated public @interface deprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated int deprecated() default 0;\n" + + "int notDeprecated() default 0;\n" + + "@Deprecated int deprecated = 0;\n" + + "int notDeprecated = 0;\n" + + "}", + "public class notDeprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated public void deprecated() {}\n" + + "@Deprecated public int deprecated;\n" + + "public void notDeprecated() {}\n" + + "public int notDeprecated;\n" + + "public void f() {\n" + + " @Deprecated class deprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }\n" + + " class notDeprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }}\n" + + "}", + "public interface notDeprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated void deprecated01();\n" + + "void notDeprecated01();\n" + + "@Deprecated default void deprecated02() {}\n" + + "default void notDeprecated02() {}\n" + + "@Deprecated int deprecated = 0;\n" + + "int notDeprecated = 0;\n" + + "}", + "public enum notDeprecated {\n" + + "@Deprecated deprecated, notDeprecated;\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated public void deprecated() {}\n" + + "public void notDeprecated() {}\n" + + "public void f() {\n" + + " @Deprecated class deprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }\n" + + " class notDeprecatedLocal {\n" + + " @Deprecated int deprecated;\n" + + " @Deprecated void deprecated() {}\n" + + " int notDeprecated;\n" + + " void notDeprecated(){}\n" + + " }}\n" + + "}", + "public @interface notDeprecated {\n" + + "@Deprecated class deprecatedInner01 {}\n" + + "@Deprecated interface deprecatedInner02 {}\n" + + "@Deprecated enum deprecatedInner03 {}\n" + + "@Deprecated @interface deprecatedInner04 {}\n" + + "class notDeprecatedInner01 {}\n" + + "interface notDeprecatedInner02 {}\n" + + "enum notDeprecatedInner03 {}\n" + + "@interface notDeprecatedInner04 {}\n" + + "@Deprecated int deprecated() default 0;\n" + + "int notDeprecated() default 0;\n" + + "@Deprecated int deprecated = 0;\n" + + "int notDeprecated = 0;\n" + + "}"}; + + public static void main(String[] args) throws TestFailedException { + new DeprecatedTest().test(); + } + + public void test() throws TestFailedException { + try { + for (String src : sources) { + test(src); + test(src.replaceAll("@Deprecated", "/** @deprecated */")); + } + } catch (Exception e) { + addFailure(e); + } finally { + checkStatus(); + } + } + + private void test(String src) { + addTestCase(src); + printf("Testing test case :\n%s\n", src); + try { + Map classes = compile(src).getClasses(); + String outerClassName = classes.containsKey("deprecated") + ? "deprecated" + : "notDeprecated"; + echo("Testing outer class : " + outerClassName); + ClassFile cf = ClassFile.read(classes.get(outerClassName).openInputStream()); + Deprecated_attribute attr = (Deprecated_attribute) + cf.getAttribute(Attribute.Deprecated); + testAttribute(outerClassName, attr, cf); + testInnerClasses(cf, classes); + testMethods(cf); + testFields(cf); + } catch (Exception e) { + addFailure(e); + } + } + + private void testInnerClasses(ClassFile cf, Map classes) + throws ConstantPoolException, IOException { + InnerClasses_attribute innerAttr = (InnerClasses_attribute) + cf.getAttribute(Attribute.InnerClasses); + for (Info innerClass : innerAttr.classes) { + String innerClassName = cf.constant_pool. + getClassInfo(innerClass.inner_class_info_index).getName(); + echo("Testing inner class : " + innerClassName); + ClassFile innerCf = ClassFile.read(classes.get(innerClassName).openInputStream()); + Deprecated_attribute attr = (Deprecated_attribute) + innerCf.getAttribute(Attribute.Deprecated); + String innerClassSimpleName = innerClass.getInnerName(cf.constant_pool); + testAttribute(innerClassSimpleName, attr, innerCf); + if (innerClassName.contains("Local")) { + testMethods(innerCf); + testFields(innerCf); + } + } + } + + private void testMethods(ClassFile cf) + throws ConstantPoolException { + for (Method m : cf.methods) { + String methodName = cf.constant_pool.getUTF8Value(m.name_index); + echo("Testing method : " + methodName); + Deprecated_attribute attr = (Deprecated_attribute) + m.attributes.get(Attribute.Deprecated); + testAttribute(methodName, attr, cf); + } + } + + private void testFields(ClassFile cf) throws ConstantPoolException { + for (Field f : cf.fields) { + String fieldName = cf.constant_pool.getUTF8Value(f.name_index); + echo("Testing field : " + fieldName); + Deprecated_attribute attr = (Deprecated_attribute) + f.attributes.get(Attribute.Deprecated); + testAttribute(fieldName, attr, cf); + } + } + + private void testAttribute(String name, Deprecated_attribute attr, ClassFile cf) + throws ConstantPoolException { + if (name.contains("deprecated")) { + testDeprecatedAttribute(name, attr, cf); + } else { + assertNull(attr, name + " should not have deprecated attribute"); + } + } + + private void testDeprecatedAttribute(String name, Deprecated_attribute attr, ClassFile cf) + throws ConstantPoolException { + assertNotNull(attr, name + " must have deprecated attribute"); + assertEquals(0, attr.attribute_length, + "attribute_length should equal to 0"); + assertEquals("Deprecated", + cf.constant_pool.getUTF8Value(attr.attribute_name_index), + name + " attribute_name_index"); + } +} diff -r b935bc56f1e4 -r 823512a72660 langtools/test/tools/javac/classfiles/attributes/lib/TestBase.java --- a/langtools/test/tools/javac/classfiles/attributes/lib/TestBase.java Thu Jul 03 15:48:23 2014 -0700 +++ b/langtools/test/tools/javac/classfiles/attributes/lib/TestBase.java Fri Jul 04 10:52:22 2014 +0100 @@ -23,47 +23,85 @@ import java.io.File; import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.io.PrintStream; +import java.util.*; +import java.util.function.Function; import java.util.stream.Stream; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.ToolProvider; +import javax.tools.*; import static java.lang.String.format; +import static java.lang.System.lineSeparator; +import static java.util.Arrays.asList; import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; public class TestBase { - public Map compile(String... sources) throws IOException, + public static final String LINE_SEPARATOR = lineSeparator(); + + private InMemoryFileManager compile( + List options, + Function src2JavaFileObject, + List sources) + throws IOException, CompilationException { + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + List src = sources.stream() + .map(src2JavaFileObject) + .collect(toList()); + + DiagnosticCollector dc = new DiagnosticCollector<>(); + try (InMemoryFileManager fileManager + = new InMemoryFileManager(compiler.getStandardFileManager(null, null, null))) { + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, dc, options, null, src); + boolean success = task.call(); + if (!success) { + String errorMessage = dc.getDiagnostics().stream() + .map(Object::toString) + .collect(joining("\n")); + throw new CompilationException("Compilation Error\n\n" + errorMessage); + } + return fileManager; + } + } + + public InMemoryFileManager compile(String... sources) + throws IOException, CompilationException { + return compile(emptyList(), sources); + } + + /** + * @param options - compiler options + * @param sources + * @return map where key is className, value is corresponding ClassFile. + * @throws IOException + */ + public InMemoryFileManager compile(List options, String...sources) + throws IOException, CompilationException { + return compile(options, ToolBox.JavaSource::new, asList(sources)); + } + + public InMemoryFileManager compile(String[]... sources) throws IOException, CompilationException { return compile(emptyList(), sources); } /** * @param options - compiler options - * @param sources + * @param sources - sources[i][0] - name of file, sources[i][1] - sources * @return map where key is className, value is corresponding ClassFile. * @throws IOException + * @throws CompilationException */ - public Map compile(List options, String... sources) throws IOException, - CompilationException { - - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - List src = Stream.of(sources).map(ToolBox.JavaSource::new).collect(toList()); - - try (InMemoryFileManager fileManager = new InMemoryFileManager(compiler.getStandardFileManager(null, null, null))) { - boolean success = compiler.getTask(null, fileManager, null, options, null, src).call(); - if (!success) throw new CompilationException("Compilation Error"); - return fileManager.getClasses(); - } + public InMemoryFileManager compile(List options, String[]...sources) + throws IOException, CompilationException { + return compile(options, src -> new ToolBox.JavaSource(src[0], src[1]), asList(sources)); } public void assertEquals(Object actual, Object expected, String message) { if (!Objects.equals(actual, expected)) - throw new AssertionFailedException(format("%s%nGot: %s, Expected: ", message, actual, expected)); + throw new AssertionFailedException(format("%s%nGot: %s, Expected: %s", message, actual, expected)); } public void assertNull(Object actual, String message) { @@ -80,18 +118,43 @@ assertEquals(actual, true, message); } + public void assertFalse(boolean actual, String message) { + assertEquals(actual, false, message); + } + + public File getSourceDir() { + return new File(System.getProperty("test.src", ".")); + } + + public File getClassDir() { + return new File(System.getProperty("test.classes", TestBase.class.getResource(".").getPath())); + } + public File getSourceFile(String fileName) { - return new File(System.getProperty("test.src", "."), fileName); + return new File(getSourceDir(), fileName); } public File getClassFile(String fileName) { - return new File(System.getProperty("test.classes", TestBase.class.getResource(".").getPath()), fileName); + return new File(getClassDir(), fileName); } public File getClassFile(Class clazz) { return getClassFile(clazz.getName().replace(".", "/") + ".class"); } + public void echo(String message) { + System.err.println(message.replace("\n", LINE_SEPARATOR)); + } + + public void printf(String template, Object...args) { + System.err.printf(template, Stream.of(args) + .map(Objects::toString) + .map(m -> m.replace("\n", LINE_SEPARATOR)) + .collect(toList()) + .toArray()); + + } + public static class CompilationException extends Exception { public CompilationException(String message) { diff -r b935bc56f1e4 -r 823512a72660 langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java Fri Jul 04 10:52:22 2014 +0100 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; + +public class TestResult extends TestBase { + + private final List testCases; + + public TestResult() { + testCases = new ArrayList<>(); + testCases.add(new Info("Global test info")); + } + + public void addTestCase(String src) { + testCases.add(new Info(src)); + } + + public String errorMessage() { + return testCases.stream().filter(Info::isFailed) + .map(tc -> format("Failure in test case:\n%s\n%s", tc.info(), + (tc.asserts.size() > 0 ? tc.getAssertMessage() + "\n" : "") + + tc.getErrorMessage())) + .collect(joining("\n")); + } + + @Override + public void assertEquals(Object actual, Object expected, String message) { + getLastTestCase().assertEquals(actual, expected, message); + } + + @Override + public void assertNull(Object actual, String message) { + getLastTestCase().assertEquals(actual, null, message); + } + + @Override + public void assertNotNull(Object actual, String message) { + getLastTestCase().assertNotNull(actual, message); + } + + @Override + public void assertFalse(boolean actual, String message) { + getLastTestCase().assertEquals(actual, false, message); + } + + @Override + public void assertTrue(boolean actual, String message) { + getLastTestCase().assertEquals(actual, true, message); + } + + public void addFailure(Throwable th) { + getLastTestCase().addFailure(th); + } + + private Info getLastTestCase() { + if (testCases.size() == 1) { + throw new IllegalStateException("Test case should be created"); + } + return testCases.get(testCases.size() - 1); + } + + public void checkStatus() throws TestFailedException { + if (testCases.stream().anyMatch(Info::isFailed)) { + echo(errorMessage()); + throw new TestFailedException("Test failed"); + } + } + + private class Info { + + private final String info; + private final List asserts; + private final List errors; + + private Info(String info) { + this.info = info; + asserts = new ArrayList<>(); + errors = new ArrayList<>(); + } + + public String info() { + return info; + } + + public boolean isFailed() { + return !asserts.isEmpty() || !errors.isEmpty(); + } + + public void addFailure(Throwable th) { + errors.add(th); + printf("[ERROR] : %s\n", getStackTrace(th)); + } + + public void addFailure(String message) { + asserts.add(message); + printf("[ASSERT] : %s\n", message); + } + + public void assertEquals(Object actual, Object expected, String message) { + echo("Testing : " + message); + if (!Objects.equals(actual, expected)) { + addFailure(message + ": Got: " + actual + ", " + "Expected: " + expected); + } + } + + public void assertNotNull(Object actual, String message) { + echo("Testing : " + message); + if (actual == null) { + addFailure(message + " : Expected not null value"); + } + } + + public String getAssertMessage() { + return asserts.stream() + .map(failure -> "[ASSERT] : " + failure) + .collect(joining("\n")); + } + + public String getErrorMessage() { + return errors.stream() + .map(throwable -> + format("[ERROR] : %s", getStackTrace(throwable))) + .collect(joining("\n")); + } + + public String getStackTrace(Throwable throwable) { + StringWriter stringWriter = new StringWriter(); + try (PrintWriter printWriter = new PrintWriter(stringWriter)) { + throwable.printStackTrace(printWriter); + } + return stringWriter.toString(); + } + } + + public static class TestFailedException extends Exception { + public TestFailedException(String message) { + super(message); + } + } +}