/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2013, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic.html;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.xml.sax.EntityResolver;
import ch.qos.logback.classic.ClassicTestConstants;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.DummyThrowableProxy;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.testUtil.StringListAppender;
import ch.qos.logback.core.util.StatusPrinter;
public class HTMLLayoutTest {
LoggerContext lc;
Logger root;
HTMLLayout layout;
@Before
public void setUp() throws Exception {
lc = new LoggerContext();
lc.setName("default");
layout = new HTMLLayout();
layout.setThrowableRenderer(new DefaultThrowableRenderer());
layout.setContext(lc);
layout.setPattern("%level%thread%msg");
layout.start();
root = lc.getLogger(Logger.ROOT_LOGGER_NAME);
}
@After
public void tearDown() throws Exception {
lc = null;
layout = null;
}
@Test
public void testHeader() throws Exception {
String header = layout.getFileHeader();
// System.out.println(header);
Document doc = parseOutput(header + "</body></html>");
Element rootElement = doc.getRootElement();
assertNotNull(rootElement.element("body"));
}
@SuppressWarnings("unchecked")
@Test
public void testPresentationHeader() throws Exception {
String header = layout.getFileHeader();
String presentationHeader = layout.getPresentationHeader();
header = header + presentationHeader;
// System.out.println(header);
Document doc = parseOutput(header + "</table></body></html>");
Element rootElement = doc.getRootElement();
Element bodyElement = rootElement.element("body");
Element tableElement = bodyElement.element("table");
Element trElement = tableElement.element("tr");
List<Element> elementList = trElement.elements();
assertEquals("Level", elementList.get(0).getText());
assertEquals("Thread", elementList.get(1).getText());
assertEquals("Message", elementList.get(2).getText());
}
@Test
public void testAppendThrowable() throws Exception {
StringBuilder buf = new StringBuilder();
DummyThrowableProxy tp = new DummyThrowableProxy();
tp.setClassName("test1");
tp.setMessage("msg1");
StackTraceElement ste1 = new StackTraceElement("c1", "m1", "f1", 1);
StackTraceElement ste2 = new StackTraceElement("c2", "m2", "f2", 2);
StackTraceElementProxy[] stepArray = { new StackTraceElementProxy(ste1),
new StackTraceElementProxy(ste2) };
tp.setStackTraceElementProxyArray(stepArray);
DefaultThrowableRenderer renderer = (DefaultThrowableRenderer) layout
.getThrowableRenderer();
renderer.render(buf, tp);
System.out.println(buf.toString());
String[] result = buf.toString().split(CoreConstants.LINE_SEPARATOR);
System.out.println(result[0]);
assertEquals("test1: msg1", result[0]);
assertEquals(DefaultThrowableRenderer.TRACE_PREFIX + "at c1.m1(f1:1)", result[1]);
}
@Test
public void testDoLayout() throws Exception {
ILoggingEvent le = createLoggingEvent();
String result = layout.getFileHeader();
result += layout.getPresentationHeader();
result += layout.doLayout(le);
result += layout.getPresentationFooter();
result += layout.getFileFooter();
Document doc = parseOutput(result);
Element rootElement = doc.getRootElement();
rootElement.toString();
// the rest of this test is very dependent of the output generated
// by HTMLLayout. Given that the XML parser already verifies
// that the result conforms to xhtml-strict, we may want to
// skip the assertions below. However, the assertions below are another
// *independent* way to check the output format.
// head, body
assertEquals(2, rootElement.elements().size());
Element bodyElement = (Element) rootElement.elements().get(1);
Element tableElement = (Element) bodyElement.elements().get(3);
assertEquals("table", tableElement.getName());
Element trElement = (Element) tableElement.elements().get(1);
{
Element tdElement = (Element) trElement.elements().get(0);
assertEquals("DEBUG", tdElement.getText());
}
{
Element tdElement = (Element) trElement.elements().get(1);
String regex = ClassicTestConstants.NAKED_MAIN_REGEX;
System.out.println(tdElement.getText());
assertTrue(tdElement.getText().matches(regex));
}
{
Element tdElement = (Element) trElement.elements().get(2);
assertEquals("test message", tdElement.getText());
}
}
@SuppressWarnings("unchecked")
@Test
public void layoutWithException() throws Exception {
layout.setPattern("%level %thread %msg %ex");
LoggingEvent le = createLoggingEvent();
le.setThrowableProxy(new ThrowableProxy(new Exception("test Exception")));
String result = layout.doLayout(le);
String stringToParse = layout.getFileHeader();
stringToParse = stringToParse + layout.getPresentationHeader();
stringToParse += result;
stringToParse += "</table></body></html>";
// System.out.println(stringToParse);
Document doc = parseOutput(stringToParse);
Element rootElement = doc.getRootElement();
Element bodyElement = rootElement.element("body");
Element tableElement = bodyElement.element("table");
List<Element> trElementList = tableElement.elements();
Element exceptionRowElement = trElementList.get(2);
Element exceptionElement = exceptionRowElement.element("td");
assertEquals(3, tableElement.elements().size());
assertTrue(exceptionElement.getText().contains(
"java.lang.Exception: test Exception"));
}
@Test
@Ignore
public void rawLimit() throws Exception {
StringBuilder sb = new StringBuilder();
String header = layout.getFileHeader();
assertTrue(header
.startsWith("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"));
sb.append(header);
sb.append(layout.getPresentationHeader());
for (int i = 0; i < CoreConstants.TABLE_ROW_LIMIT * 3; i++) {
sb.append(layout.doLayout(new LoggingEvent(this.getClass().getName(),
root, Level.DEBUG, "test message" + i, null, null)));
}
sb.append(layout.getPresentationFooter());
sb.append(layout.getFileFooter());
// check that the output adheres to xhtml-strict.dtd
parseOutput(sb.toString());
}
private LoggingEvent createLoggingEvent() {
return new LoggingEvent(this.getClass().getName(), root,
Level.DEBUG, "test message", null, null);
}
Document parseOutput(String output) throws Exception {
EntityResolver resolver = new XHTMLEntityResolver();
SAXReader reader = new SAXReader();
reader.setValidation(true);
reader.setEntityResolver(resolver);
return reader.read(new ByteArrayInputStream(output.getBytes()));
}
void configure(String file) throws JoranException {
JoranConfigurator jc = new JoranConfigurator();
jc.setContext(lc);
jc.doConfigure(file);
}
@Test
public void testConversionRuleSupportInHtmlLayout() throws JoranException {
configure(ClassicTestConstants.JORAN_INPUT_PREFIX
+ "conversionRule/htmlLayout0.xml");
root.getAppender("LIST");
String msg = "Simon says";
root.debug(msg);
StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root
.getAppender("LIST");
assertNotNull(sla);
StatusPrinter.print(lc);
assertEquals(1, sla.strList.size());
assertFalse(sla.strList.get(0).contains("PARSER_ERROR"));
}
}