    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j;
    19
    20  import org.apache.log4j.spi.LoggingEvent;
    21  import org.w3c.dom.Document;
    22  import org.xml.sax.InputSource;
    23
    24  import javax.xml.parsers.DocumentBuilder;
    25  import javax.xml.parsers.DocumentBuilderFactory;
    26  import java.io.Reader;
    27  import java.io.StringReader;
    28  import java.util.Hashtable;
    29
    30
    31  /**
    32   * Test for HTMLLayout.
    33   *
    34   * @author Curt Arnold
    35   */
    36  public class HTMLLayoutTest extends LayoutTest {
    37    /**
    38     * Construct new instance of XMLLayoutTest.
    39     *
    40     * @param testName test name.
    41     */
    42    public HTMLLayoutTest(final String testName) {
    43      super(testName, "text/html", false, null, null);
    44    }
    45
    46    /**
    47     * @{inheritDoc}
    48     */
    49    protected Layout createLayout() {
    50      return new HTMLLayout();
    51    }
    52
    53    /**
    54     * Parses the string as the body of an XML document and returns the document element.
    55     * @param source source string.
    56     * @return document element.
    57     * @throws Exception if parser can not be constructed or source is not a valid XML document.
    58     */
    59    private Document parse(final String source) throws Exception {
    60      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    61      factory.setNamespaceAware(false);
    62      factory.setCoalescing(true);
    63
    64      DocumentBuilder builder = factory.newDocumentBuilder();
    65      Reader reader = new StringReader(source);
    66
    67      return builder.parse(new InputSource(reader));
    68    }
    69
    70    /**
    71     * Tests formatted results.
    72     * @throws Exception if unable to create parser or output is not valid XML.
    73     */
    74    public void testFormat() throws Exception {
    75      Logger logger = Logger.getLogger("org.apache.log4j.xml.HTMLLayoutTest");
    76      NDC.push("NDC goes here");
    77
    78      LoggingEvent event =
    79        new LoggingEvent(
    80          "org.apache.log4j.Logger", logger, Level.INFO, "Hello, World", null);
    81      HTMLLayout layout = (HTMLLayout) createLayout();
    82      layout.setLocationInfo(true);
    83
    84      String result = layout.format(event);
    85      NDC.pop();
    86
    87      String src =
    88        "<!DOCTYPE body [ <!ENTITY nbsp ' '>]><body>" + result + "</body>";
    89      parse(src);
    90    }
    91
    92    /**
    93     * Tests getHeader.
    94     */
    95    public void testGetHeader() {
    96      assertEquals("<!DOCTYPE", createLayout().getHeader().substring(0, 9));
    97    }
    98
    99    /**
    100    * Tests getHeader with locationInfo = true.
    101    */
    102   public void testGetHeaderWithLocation() {
    103     HTMLLayout layout = (HTMLLayout) createLayout();
    104     layout.setLocationInfo(true);
    105     assertEquals("<!DOCTYPE", layout.getHeader().substring(0, 9));
    106   }
    107
    108   /**
    109    * Tests getFooter.
    110    */
    111   public void testGetFooter() {
    112     assertEquals("</table>", createLayout().getFooter().substring(0, 8));
    113   }
    114
    115   /**
    116    * Tests getLocationInfo and setLocationInfo.
    117    */
    118   public void testGetSetLocationInfo() {
    119     HTMLLayout layout = new HTMLLayout();
    120     assertEquals(false, layout.getLocationInfo());
    121     layout.setLocationInfo(true);
    122     assertEquals(true, layout.getLocationInfo());
    123     layout.setLocationInfo(false);
    124     assertEquals(false, layout.getLocationInfo());
    125   }
    126
    127   /**
    128    * Tests activateOptions().
    129    */
    130   public void testActivateOptions() {
    131     HTMLLayout layout = new HTMLLayout();
    132     layout.activateOptions();
    133   }
    134
    135   /**
    136    * Tests getTitle and setTitle.
    137    */
    138   public void testGetSetTitle() {
    139     HTMLLayout layout = new HTMLLayout();
    140     assertEquals("Log4J Log Messages", layout.getTitle());
    141     layout.setTitle(null);
    142     assertNull(layout.getTitle());
    143
    144     String newTitle = "A treatise on messages of log persuasion";
    145     layout.setTitle(newTitle);
    146     assertEquals(newTitle, layout.getTitle());
    147   }
    148
    149   /**
    150    * Tests buffer downsizing and DEBUG and WARN colorization code paths.
    151    */
    152   public void testFormatResize() {
    153     Logger logger = Logger.getLogger("org.apache.log4j.xml.HTMLLayoutTest");
    154     NDC.clear();
    155
    156     char[] msg = new char[2000];
    157
    158     for (int i = 0; i < msg.length; i++) {
    159       msg[i] = 'A';
    160     }
    161
    162     LoggingEvent event1 =
    163       new LoggingEvent(
    164         "org.apache.log4j.Logger", logger, Level.DEBUG, new String(msg), null);
    165     HTMLLayout layout = (HTMLLayout) createLayout();
    166     layout.setLocationInfo(true);
    167
    168     String result = layout.format(event1);
    169     Exception ex = new IllegalArgumentException("'foo' is not a valid value.");
    170     LoggingEvent event2 =
    171       new LoggingEvent(
    172         "org.apache.log4j.Logger", logger, Level.WARN, "Hello, World", ex);
    173     result = layout.format(event2);
    174     assertEquals(
    175       Layout.LINE_SEP + "<tr>",
    176       result.substring(0, Layout.LINE_SEP.length() + 4));
    177   }
    178
    179
    180     /**
    181      * Level with arbitrary toString value.
    182      */
    183     private static final class ProblemLevel extends Level {
    184         private static final long serialVersionUID = 1L;
    185
    186         /**
    187          * Construct new instance.
    188          * @param levelName level name, may not be null.
    189          */
    190         public ProblemLevel(final String levelName) {
    191             super(6000, levelName, 6);
    192         }
    193     }
    194
    195     /**
    196      * Tests problematic characters in multiple fields.
    197      * @throws Exception if parser can not be constructed
    198      *  or source is not a valid XML document.
    199      */
    200     public void testProblemCharacters() throws Exception {
    201       String problemName = "com.example.bar<>&\"'";
    202       Logger logger = Logger.getLogger(problemName);
    203       Level level = new ProblemLevel(problemName);
    204       Exception ex = new IllegalArgumentException(problemName);
    205       String threadName = Thread.currentThread().getName();
    206       Thread.currentThread().setName(problemName);
    207       NDC.push(problemName);
    208       Hashtable mdcMap = MDC.getContext();
    209       if (mdcMap != null) {
    210           mdcMap.clear();
    211       }
    212       MDC.put(problemName, problemName);
    213       LoggingEvent event =
    214         new LoggingEvent(
    215           problemName, logger, level, problemName, ex);
    216       HTMLLayout layout = (HTMLLayout) createLayout();
    217       String result = layout.format(event);
    218       mdcMap = MDC.getContext();
    219       if (mdcMap != null) {
    220         mdcMap.clear();
    221       }
    222
    223       Thread.currentThread().setName(threadName);
    224
    225       //
    226       //  do a little fixup to make output XHTML
    227       //
    228       StringBuffer buf = new StringBuffer(
    229               "<!DOCTYPE table [<!ENTITY nbsp ' '>]><table>");
    230       buf.append(result);
    231       buf.append("</table>");
    232       String doc = buf.toString();
    233       for(int i = doc.lastIndexOf("<br>");
    234           i != -1;
    235           i = doc.lastIndexOf("<br>", i - 1)) {
    236           buf.replace(i, i + 4, "<br/>");
    237       }
    238
    239       parse(buf.toString());
    240     }
    241
    242 }