| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.log4j.spi; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.PrintWriter; |
| |
| |
| /** |
| * Unit tests for ThrowableInformation. |
| */ |
| public class ThrowableInformationTest extends TestCase { |
| /** |
| * Create ThrowableInformationTest. |
| * |
| * @param name test name. |
| */ |
| public ThrowableInformationTest(final String name) { |
| super(name); |
| } |
| |
| /** |
| * Custom throwable that only calls methods |
| * overridden by VectorWriter in log4j 1.2.14 and earlier. |
| */ |
| private static final class OverriddenThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Create new instance. |
| */ |
| public OverriddenThrowable() { |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| s.print((Object) "print(Object)"); |
| s.print("print(char[])".toCharArray()); |
| s.print("print(String)"); |
| s.println((Object) "println(Object)"); |
| s.println("println(char[])".toCharArray()); |
| s.println("println(String)"); |
| s.write("write(char[])".toCharArray()); |
| s.write("write(char[], int, int)".toCharArray(), 2, 8); |
| s.write("write(String, int, int)", 2, 8); |
| } |
| } |
| |
| /** |
| * Test capturing stack trace from a throwable that only uses the |
| * PrintWriter methods overridden in log4j 1.2.14 and earlier. |
| */ |
| public void testOverriddenBehavior() { |
| ThrowableInformation ti = new ThrowableInformation(new OverriddenThrowable()); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(4, rep.length); |
| assertEquals("print(Object)print(char[])print(String)println(Object)", rep[0]); |
| assertEquals("println(char[])", rep[1]); |
| assertEquals("println(String)", rep[2]); |
| assertEquals("write(char[])ite(charite(Stri", rep[3]); |
| } |
| |
| /** |
| * Custom throwable that calls methods |
| * not overridden by VectorWriter in log4j 1.2.14 and earlier. |
| */ |
| private static final class NotOverriddenThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Create new instance. |
| */ |
| public NotOverriddenThrowable() { |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| s.print(true); |
| s.print('a'); |
| s.print(1); |
| s.print(2L); |
| s.print(Float.MAX_VALUE); |
| s.print(Double.MIN_VALUE); |
| s.println(true); |
| s.println('a'); |
| s.println(1); |
| s.println(2L); |
| s.println(Float.MAX_VALUE); |
| s.println(Double.MIN_VALUE); |
| s.write('C'); |
| } |
| } |
| |
| /** |
| * Test capturing stack trace from a throwable that uses the |
| * PrintWriter methods not overridden in log4j 1.2.14 and earlier. |
| */ |
| public void testNotOverriddenBehavior() { |
| ThrowableInformation ti = new ThrowableInformation(new NotOverriddenThrowable()); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(7, rep.length); |
| StringBuffer buf = new StringBuffer(String.valueOf(true)); |
| buf.append('a'); |
| buf.append(String.valueOf(1)); |
| buf.append(String.valueOf(2L)); |
| buf.append(String.valueOf(Float.MAX_VALUE)); |
| buf.append(String.valueOf(Double.MIN_VALUE)); |
| buf.append(String.valueOf(true)); |
| assertEquals(buf.toString(), rep[0]); |
| assertEquals("a", rep[1]); |
| assertEquals(String.valueOf(1), rep[2]); |
| assertEquals(String.valueOf(2L), rep[3]); |
| assertEquals(String.valueOf(Float.MAX_VALUE), rep[4]); |
| assertEquals(String.valueOf(Double.MIN_VALUE), rep[5]); |
| assertEquals("C", rep[6]); |
| } |
| |
| /** |
| * Custom throwable that calls methods of VectorWriter |
| * with null. |
| */ |
| private static final class NullThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Create new instance. |
| */ |
| public NullThrowable() { |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| s.print((Object) null); |
| s.print((String) null); |
| s.println((Object) null); |
| s.println((String) null); |
| } |
| } |
| |
| /** |
| * Test capturing stack trace from a throwable that passes |
| * null to PrintWriter methods. |
| */ |
| |
| public void testNull() { |
| ThrowableInformation ti = new ThrowableInformation(new NullThrowable()); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(2, rep.length); |
| String nullStr = String.valueOf((Object) null); |
| assertEquals(nullStr + nullStr + nullStr, rep[0]); |
| assertEquals(nullStr, rep[1]); |
| } |
| |
| /** |
| * Custom throwable that does nothing in printStackTrace. |
| */ |
| private static final class EmptyThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Create new instance. |
| */ |
| public EmptyThrowable() { |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| } |
| } |
| |
| /** |
| * Test capturing stack trace from a throwable that |
| * does nothing on a call to printStackTrace. |
| */ |
| |
| public void testEmpty() { |
| ThrowableInformation ti = new ThrowableInformation(new EmptyThrowable()); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(0, rep.length); |
| } |
| |
| /** |
| * Custom throwable that emits a specified string in printStackTrace. |
| */ |
| private static final class StringThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Stack trace. |
| */ |
| private final String stackTrace; |
| /** |
| * Create new instance. |
| * @param trace stack trace. |
| */ |
| public StringThrowable(final String trace) { |
| stackTrace = trace; |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| s.print(stackTrace); |
| } |
| } |
| |
| /** |
| * Test capturing stack trace from throwable that just has a line feed. |
| */ |
| public void testLineFeed() { |
| ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\n")); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(1, rep.length); |
| assertEquals("", rep[0]); |
| } |
| |
| /** |
| * Test capturing stack trace from throwable that just has a carriage return. |
| */ |
| public void testCarriageReturn() { |
| ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\r")); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(1, rep.length); |
| assertEquals("", rep[0]); |
| } |
| |
| /** |
| * Test parsing of line breaks. |
| */ |
| public void testParsing() { |
| ThrowableInformation ti = new ThrowableInformation( |
| new StringThrowable("Line1\rLine2\nLine3\r\nLine4\n\rLine6")); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(6, rep.length); |
| assertEquals("Line1", rep[0]); |
| assertEquals("Line2", rep[1]); |
| assertEquals("Line3", rep[2]); |
| assertEquals("Line4", rep[3]); |
| assertEquals("", rep[4]); |
| assertEquals("Line6", rep[5]); |
| } |
| |
| /** |
| * Test capturing stack trace from throwable that a line feed followed by blank. |
| */ |
| public void testLineFeedBlank() { |
| ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\n ")); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals(2, rep.length); |
| assertEquals("", rep[0]); |
| assertEquals(" ", rep[1]); |
| } |
| |
| /** |
| * Test that getThrowable returns the throwable provided to the constructor. |
| */ |
| public void testGetThrowable() { |
| Throwable t = new StringThrowable("Hello, World"); |
| ThrowableInformation ti = new ThrowableInformation(t); |
| assertSame(t, ti.getThrowable()); |
| } |
| |
| /** |
| * Tests isolation of returned string representation |
| * from internal state of ThrowableInformation. |
| * log4j 1.2.15 and earlier did not isolate initial call. |
| * See bug 44032. |
| */ |
| public void testIsolation() { |
| ThrowableInformation ti = new ThrowableInformation( |
| new StringThrowable("Hello, World")); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals("Hello, World", rep[0]); |
| rep[0] = "Bonjour, Monde"; |
| String[] rep2 = ti.getThrowableStrRep(); |
| assertEquals("Hello, World", rep2[0]); |
| } |
| |
| /** |
| * Custom throwable that throws a runtime exception |
| * when printStackTrace is called. |
| */ |
| private static final class NastyThrowable extends Throwable { |
| private static final long serialVersionUID = 1L; |
| /** |
| * Create new instance. |
| */ |
| public NastyThrowable() { |
| } |
| |
| /** |
| * Print stack trace. |
| * |
| * @param s print writer. |
| */ |
| public void printStackTrace(final PrintWriter s) { |
| s.print("NastyException"); |
| throw new RuntimeException("Intentional exception"); |
| } |
| } |
| |
| /** |
| * Tests that a failure in printStackTrace |
| * does not percolate out of getThrowableStrRep(). |
| * |
| */ |
| public void testNastyException() { |
| ThrowableInformation ti = new ThrowableInformation( |
| new NastyThrowable()); |
| String[] rep = ti.getThrowableStrRep(); |
| assertEquals("NastyException", rep[0]); |
| } |
| |
| } |