• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.testng.remote.strprotocol;
2 
3 
4 import org.testng.ITestResult;
5 import org.testng.collections.Lists;
6 
7 import java.util.List;
8 import java.util.regex.Pattern;
9 
10 
11 /**
12  * Marshal/unmarshal tool for <code>IStringMessage</code>s.
13  *
14  * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
15  */
16 public class MessageHelper {
17   public static final char DELIMITER = '\u0001';
18   public static final char PARAM_DELIMITER = '\u0004';
19   private static final char LINE_SEP_DELIMITER_1 = '\u0002';
20   private static final char LINE_SEP_DELIMITER_2 = '\u0003';
21 
22   public static final int GENERIC_SUITE_COUNT = 1;
23 
24   public static final int SUITE = 10;
25   public static final int SUITE_START = 11;
26   public static final int SUITE_FINISH = 12;
27 
28   public static final int TEST = 100;
29   public static final int TEST_START = 101;
30   public static final int TEST_FINISH = 102;
31 
32   public static final int TEST_RESULT = 1000;
33   public static final int PASSED_TEST = TEST_RESULT + ITestResult.SUCCESS;
34   public static final int FAILED_TEST = TEST_RESULT + ITestResult.FAILURE;
35   public static final int SKIPPED_TEST = TEST_RESULT + ITestResult.SKIP;
36   public static final int FAILED_ON_PERCENTAGE_TEST = TEST_RESULT + ITestResult.SUCCESS_PERCENTAGE_FAILURE;
37   public static final int TEST_STARTED = TEST_RESULT + ITestResult.STARTED;
38 
39   public static final String STOP_MSG = ">STOP";
40   public static final String ACK_MSG = ">ACK";
41 
getMessageType(final String message)42   public static int getMessageType(final String message) {
43     int idx = message.indexOf(DELIMITER);
44 
45     return idx == -1 ? Integer.parseInt(message) : Integer.parseInt(message.substring(0, idx));
46   }
47 
unmarshallGenericMessage(final String message)48   public static GenericMessage unmarshallGenericMessage(final String message) {
49     String[] messageParts = parseMessage(message);
50     if(messageParts.length == 1) {
51       return new GenericMessage(Integer.parseInt(messageParts[0]));
52     }
53     else {
54       GenericMessage result = new GenericMessage(Integer.parseInt(messageParts[0]));
55 
56       for(int i = 1; i < messageParts.length; i+=2) {
57         if ("testCount".equals(messageParts[i])) {
58           result.setTestCount(Integer.parseInt(messageParts[i + 1]));
59         } else if ("suiteCount".equals(messageParts[i])) {
60           result.setSuiteCount(Integer.parseInt(messageParts[i + 1]));
61         }
62       }
63 
64       return result;
65     }
66   }
67 
createSuiteMessage(final String message)68   public static SuiteMessage createSuiteMessage(final String message) {
69     int type = getMessageType(message);
70     String[] messageParts = parseMessage(message);
71 
72     SuiteMessage result = new SuiteMessage(messageParts[1],
73                             MessageHelper.SUITE_START == type,
74                             Integer.parseInt(messageParts[2]));
75     // Any excluded methods?
76     if (messageParts.length > 3) {
77       int count = Integer.parseInt(messageParts[3]);
78       if (count > 0) {
79         List<String> methods = Lists.newArrayList();
80         int i = 4;
81         while (count-- > 0) {
82           methods.add(messageParts[i++]);
83         }
84         result.setExcludedMethods(methods);
85       }
86     }
87 
88     return result;
89   }
90 
createTestMessage(final String message)91   public static TestMessage createTestMessage(final String message) {
92     int type = getMessageType(message);
93     String[] messageParts = parseMessage(message);
94 
95     return new TestMessage(MessageHelper.TEST_START == type,
96                            messageParts[1],
97                            messageParts[2],
98                            Integer.parseInt(messageParts[3]),
99                            Integer.parseInt(messageParts[4]),
100                            Integer.parseInt(messageParts[5]),
101                            Integer.parseInt(messageParts[6]),
102                            Integer.parseInt(messageParts[7]));
103   }
104 
unmarshallTestResultMessage(final String message)105   public static TestResultMessage unmarshallTestResultMessage(final String message) {
106     String[] messageParts = parseMessage(message);
107 
108     String parametersFragment= null;
109     String startTimestampFragment= null;
110     String stopTimestampFragment= null;
111     String stackTraceFragment= null;
112     String testDescriptor= null;
113     switch(messageParts.length) {
114       case 10:
115       {
116         parametersFragment= messageParts[5];
117         startTimestampFragment= messageParts[6];
118         stopTimestampFragment= messageParts[7];
119         stackTraceFragment= messageParts[8];
120         testDescriptor= messageParts[9];
121       }
122       break;
123       case 9:
124       {
125         parametersFragment= messageParts[5];
126         startTimestampFragment= messageParts[6];
127         stopTimestampFragment= messageParts[7];
128         stackTraceFragment= messageParts[8];
129       }
130       break;
131       default:
132       {
133         // HINT: old protocol without parameters
134         parametersFragment= null;
135         startTimestampFragment= messageParts[5];
136         stopTimestampFragment= messageParts[6];
137         stackTraceFragment= messageParts[7];
138       }
139     }
140     return new TestResultMessage(Integer.parseInt(messageParts[0]),
141                                  messageParts[1],
142                                  messageParts[2],
143                                  messageParts[3],
144                                  messageParts[4],
145                                  replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(testDescriptor)),
146                                  replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(testDescriptor)),
147                                  parseParameters(parametersFragment),
148                                  Long.parseLong(startTimestampFragment),
149                                  Long.parseLong(stopTimestampFragment),
150                                  replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(stackTraceFragment)),
151                                  0, 0 /* invocation counts not supported by this protocol */
152             );
153   }
154 
replaceNewLine(String message)155   public static String replaceNewLine(String message) {
156     if(null == message) {
157       return message;
158     }
159 
160     return message.replace('\n', LINE_SEP_DELIMITER_1).replace('\r', LINE_SEP_DELIMITER_2);
161   }
162 
replaceUnicodeCharactersWithAscii(String message)163   public static String replaceUnicodeCharactersWithAscii(String message) {
164     if(null == message) {
165       return message;
166     }
167 
168     return replace(
169               replace(
170                   replace(
171                     replace(message, "\u0004", "\\u0004"),
172                   "\u0003", "\\u0003"),
173               "\u0002", "\\u0002"),
174            "\u0001", "\\u0001");
175   }
176 
replaceAsciiCharactersWithUnicode(String message)177   public static String replaceAsciiCharactersWithUnicode(String message) {
178     if(null == message) {
179       return message;
180     }
181 
182     return replace(
183             replace(
184                 replace(
185                     replace(message, "\\u0004", "\u0004"),
186                     "\\u0003", "\u0003"),
187                 "\\u0002", "\u0002"),
188             "\\u0001", "\u0001");
189   }
190 
replaceNewLineReplacer(String message)191   public static String replaceNewLineReplacer(String message) {
192     if(null == message) {
193       return message;
194     }
195 
196     return message.replace(LINE_SEP_DELIMITER_1, '\n').replace(LINE_SEP_DELIMITER_2, '\r');
197   }
198 
parseParameters(final String messagePart)199   private static String[] parseParameters(final String messagePart) {
200     return tokenize(messagePart, PARAM_DELIMITER);
201   }
202 
parseMessage(final String message)203   private static String[] parseMessage(final String message) {
204     return tokenize(message, DELIMITER);
205   }
206 
tokenize(final String message, final char separator)207   private static String[] tokenize(final String message, final char separator) {
208     if(null == message) {
209       return new String[0];
210     }
211 
212     List<String> tokens = Lists.newArrayList();
213     int start = 0;
214     for(int i = 0; i < message.length(); i++) {
215       if(separator == message.charAt(i)) {
216         tokens.add(message.substring(start, i));
217         start = i + 1;
218       }
219     }
220     if(start < message.length()) {
221       tokens.add(message.substring(start, message.length()));
222     }
223 
224     return tokens.toArray(new String[tokens.size()]);
225   }
226 
227   /**
228    * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
229    */
replace(String original, CharSequence target, CharSequence replacement)230   private static final String replace(String original, CharSequence target, CharSequence replacement) {
231       return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(original)
232           .replaceAll(quoteReplacement(replacement.toString()));
233   }
234 
235   /**
236    * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
237    */
quoteReplacement(String s)238   private static String quoteReplacement(String s) {
239       if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1)) {
240         return s;
241       }
242       StringBuffer sb = new StringBuffer();
243       for (int i=0; i<s.length(); i++) {
244           char c = s.charAt(i);
245           if (c == '\\') {
246               sb.append('\\'); sb.append('\\');
247           } else if (c == '$') {
248               sb.append('\\'); sb.append('$');
249           } else {
250               sb.append(c);
251           }
252       }
253       return sb.toString();
254   }
255 }
256