• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.testng;
2 
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.Vector;
7 
8 import org.testng.collections.Lists;
9 import org.testng.collections.Maps;
10 import org.testng.util.Strings;
11 
12 /**
13  * This class is used for test methods to log messages that will be
14  * included in the HTML reports generated by TestNG.
15  * <br>
16  * <br>
17  * <b>Implementation details.</b>
18  * <br>
19  * <br>
20  * The reporter keeps a combined output of strings (in m_output) and also
21  * a record of which method output which line.  In order to do this, callers
22  * specify what the current method is with setCurrentTestResult() and the
23  * Reporter maintains a mapping of each test result with a list of integers.
24  * These integers are indices in the combined output (avoids duplicating
25  * the output).
26  *
27  * Created on Nov 2, 2005
28  * @author cbeust
29  */
30 public class Reporter {
31   // when tests are run in parallel, each thread may be working with different
32   // 'current test result'. Also, this value should be inherited if the test code
33   // spawns its own thread.
34   private static ThreadLocal<ITestResult> m_currentTestResult = new InheritableThreadLocal<>();
35 
36   /**
37    * All output logged in a sequential order.
38    */
39   private static List<String> m_output = new Vector<>();
40 
41   /** The key is the hashCode of the ITestResult */
42   private static Map<Integer, List<Integer>> m_methodOutputMap = Maps.newHashMap();
43 
44   private static boolean m_escapeHtml = false;
45   //This variable is responsible for persisting all output that is yet to be associated with any
46   //valid TestResult objects.
47   private static ThreadLocal<List<String>> m_orphanedOutput = new InheritableThreadLocal<>();
48 
setCurrentTestResult(ITestResult m)49   public static void setCurrentTestResult(ITestResult m) {
50     m_currentTestResult.set(m);
51   }
52 
getOutput()53   public static List<String> getOutput() {
54     return m_output;
55   }
56 
57   /**
58    * Erase the content of all the output generated so far.
59    */
clear()60   public static void clear() {
61     m_methodOutputMap.clear();
62     m_output.clear();
63   }
64 
65   /**
66    * @param escapeHtml If true, use HTML entities for special HTML characters (<, >, &, ...).
67    */
setEscapeHtml(boolean escapeHtml)68   public static void setEscapeHtml(boolean escapeHtml) {
69     m_escapeHtml = escapeHtml;
70   }
71 
log(String s, ITestResult m)72   private static synchronized void log(String s, ITestResult m) {
73     // Escape for the HTML reports
74     if (m_escapeHtml) {
75       s = Strings.escapeHtml(s);
76     }
77 
78     if (m == null) {
79       //Persist the output temporarily into a Threadlocal String list.
80       if (m_orphanedOutput.get() == null) {
81         m_orphanedOutput.set(new ArrayList<String>());
82       }
83       m_orphanedOutput.get().add(s);
84       return;
85     }
86 
87     // synchronization needed to ensure the line number and m_output are updated atomically
88     int n = getOutput().size();
89 
90     List<Integer> lines = m_methodOutputMap.get(m.hashCode());
91     if (lines == null) {
92       lines = Lists.newArrayList();
93       m_methodOutputMap.put(m.hashCode(), lines);
94     }
95 
96     // Check if there was already some orphaned output for the current thread.
97     if (m_orphanedOutput.get() != null) {
98       n = n + m_orphanedOutput.get().size();
99       getOutput().addAll(m_orphanedOutput.get());
100       // Since we have already added all of the orphaned output to the current
101       // TestResult, lets clear it off
102       m_orphanedOutput.remove();
103     }
104     lines.add(n);
105     getOutput().add(s);
106   }
107 
108   /**
109    * Log the passed string to the HTML reports
110    * @param s The message to log
111    */
log(String s)112   public static void log(String s) {
113     log(s, getCurrentTestResult());
114   }
115 
116   /**
117    * Log the passed string to the HTML reports if the current verbosity
118    * is equal or greater than the one passed in parameter. If logToStandardOut
119    * is true, the string will also be printed on standard out.
120    *
121    * @param s The message to log
122    * @param level The verbosity of this message
123    * @param logToStandardOut Whether to print this string on standard
124    * out too
125    */
log(String s, int level, boolean logToStandardOut)126   public static void log(String s, int level, boolean logToStandardOut) {
127     if (TestRunner.getVerbose() >= level) {
128       log(s, getCurrentTestResult());
129       if (logToStandardOut) {
130         System.out.println(s);
131       }
132     }
133   }
134 
135   /**
136    * Log the passed string to the HTML reports.  If logToStandardOut
137    * is true, the string will also be printed on standard out.
138    *
139    * @param s The message to log
140    * @param logToStandardOut Whether to print this string on standard
141    * out too
142    */
log(String s, boolean logToStandardOut)143   public static void log(String s, boolean logToStandardOut) {
144     log(s, getCurrentTestResult());
145     if (logToStandardOut) {
146       System.out.println(s);
147     }
148   }
149   /**
150    * Log the passed string to the HTML reports if the current verbosity
151    * is equal or greater than the one passed in parameter
152    *
153    * @param s The message to log
154    * @param level The verbosity of this message
155    */
log(String s, int level)156   public static void log(String s, int level) {
157     if (TestRunner.getVerbose() >= level) {
158       log(s, getCurrentTestResult());
159     }
160   }
161 
162   /**
163    * @return the current test result.
164    */
getCurrentTestResult()165   public static ITestResult getCurrentTestResult() {
166     return m_currentTestResult.get();
167   }
168 
getOutput(ITestResult tr)169   public static synchronized List<String> getOutput(ITestResult tr) {
170     List<String> result = Lists.newArrayList();
171     if (tr == null) {
172       //guard against a possible NPE in scenarios wherein the test result object itself could be a null value.
173       return result;
174     }
175     List<Integer> lines = m_methodOutputMap.get(tr.hashCode());
176     if (lines != null) {
177       for (Integer n : lines) {
178         result.add(getOutput().get(n));
179       }
180     }
181 
182     return result;
183   }
184 }
185