001: package org.testng.remote.strprotocol;
002:
003: import java.util.ArrayList;
004: import java.util.HashMap;
005: import java.util.List;
006: import java.util.Map;
007: import java.util.regex.Matcher;
008: import java.util.regex.Pattern;
009:
010: import org.testng.ITestResult;
011:
012: /**
013: * Marshal/unmarshal tool for <code>IStringMessage</code>s.
014: *
015: * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
016: */
017: public class MessageHelper {
018: public static final char DELIMITER = '\u0001';
019: public static final char PARAM_DELIMITER = '\u0004';
020: private static final char LINE_SEP_DELIMITER_1 = '\u0002';
021: private static final char LINE_SEP_DELIMITER_2 = '\u0003';
022:
023: public static final int GENERIC_SUITE_COUNT = 1;
024:
025: public static final int SUITE = 10;
026: public static final int SUITE_START = 11;
027: public static final int SUITE_FINISH = 12;
028:
029: public static final int TEST = 100;
030: public static final int TEST_START = 101;
031: public static final int TEST_FINISH = 102;
032:
033: public static final int TEST_RESULT = 1000;
034: public static final int PASSED_TEST = TEST_RESULT
035: + ITestResult.SUCCESS;
036: public static final int FAILED_TEST = TEST_RESULT
037: + ITestResult.FAILURE;
038: public static final int SKIPPED_TEST = TEST_RESULT
039: + ITestResult.SKIP;
040: public static final int FAILED_ON_PERCENTAGE_TEST = TEST_RESULT
041: + ITestResult.SUCCESS_PERCENTAGE_FAILURE;
042: public static final int TEST_STARTED = TEST_RESULT
043: + ITestResult.STARTED;
044:
045: public static final String STOP_MSG = ">STOP";
046: public static final String ACK_MSG = ">ACK";
047:
048: public static int getMessageType(final String message) {
049: int idx = message.indexOf(DELIMITER);
050:
051: return idx == -1 ? Integer.parseInt(message) : Integer
052: .parseInt(message.substring(0, idx));
053: }
054:
055: public static GenericMessage unmarshallGenericMessage(
056: final String message) {
057: String[] messageParts = parseMessage(message);
058: if (messageParts.length == 1) {
059: return new GenericMessage(Integer.parseInt(messageParts[0]));
060: } else {
061: Map props = new HashMap();
062:
063: for (int i = 1; i < messageParts.length; i += 2) {
064: props.put(messageParts[i], messageParts[i + 1]);
065: }
066:
067: return new GenericMessage(
068: Integer.parseInt(messageParts[0]), props);
069: }
070: }
071:
072: public static SuiteMessage createSuiteMessage(final String message) {
073: int type = getMessageType(message);
074: String[] messageParts = parseMessage(message);
075:
076: return new SuiteMessage(messageParts[1],
077: MessageHelper.SUITE_START == type, Integer
078: .parseInt(messageParts[2]));
079: }
080:
081: public static TestMessage createTestMessage(final String message) {
082: int type = getMessageType(message);
083: String[] messageParts = parseMessage(message);
084:
085: return new TestMessage(MessageHelper.TEST_START == type,
086: messageParts[1], messageParts[2], Integer
087: .parseInt(messageParts[3]), Integer
088: .parseInt(messageParts[4]), Integer
089: .parseInt(messageParts[5]), Integer
090: .parseInt(messageParts[6]), Integer
091: .parseInt(messageParts[7]));
092: }
093:
094: public static TestResultMessage unmarshallTestResultMessage(
095: final String message) {
096: String[] messageParts = parseMessage(message);
097:
098: String parametersFragment = null;
099: String startTimestampFragment = null;
100: String stopTimestampFragment = null;
101: String stackTraceFragment = null;
102: String testDescriptor = null;
103: switch (messageParts.length) {
104: case 10: {
105: parametersFragment = messageParts[5];
106: startTimestampFragment = messageParts[6];
107: stopTimestampFragment = messageParts[7];
108: stackTraceFragment = messageParts[8];
109: testDescriptor = messageParts[9];
110: }
111: break;
112: case 9: {
113: parametersFragment = messageParts[5];
114: startTimestampFragment = messageParts[6];
115: stopTimestampFragment = messageParts[7];
116: stackTraceFragment = messageParts[8];
117: }
118: break;
119: default: {
120: // HINT: old protocol without parameters
121: parametersFragment = null;
122: startTimestampFragment = messageParts[5];
123: stopTimestampFragment = messageParts[6];
124: stackTraceFragment = messageParts[7];
125: }
126: }
127: return new TestResultMessage(
128: Integer.parseInt(messageParts[0]),
129: messageParts[1],
130: messageParts[2],
131: messageParts[3],
132: messageParts[4],
133: replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(testDescriptor)),
134: parseParameters(parametersFragment),
135: Long.parseLong(startTimestampFragment),
136: Long.parseLong(stopTimestampFragment),
137: replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(stackTraceFragment)));
138: }
139:
140: public static String replaceNewLine(String message) {
141: if (null == message) {
142: return message;
143: }
144:
145: return message.replace('\n', LINE_SEP_DELIMITER_1).replace(
146: '\r', LINE_SEP_DELIMITER_2);
147: }
148:
149: public static String replaceUnicodeCharactersWithAscii(
150: String message) {
151: if (null == message) {
152: return message;
153: }
154:
155: return replace(replace(replace(replace(message, "\u0004",
156: "\\u0004"), "\u0003", "\\u0003"), "\u0002", "\\u0002"),
157: "\u0001", "\\u0001");
158: }
159:
160: public static String replaceAsciiCharactersWithUnicode(
161: String message) {
162: if (null == message) {
163: return message;
164: }
165:
166: return replace(replace(replace(replace(message, "\\u0004",
167: "\u0004"), "\\u0003", "\u0003"), "\\u0002", "\u0002"),
168: "\\u0001", "\u0001");
169: }
170:
171: public static String replaceNewLineReplacer(String message) {
172: if (null == message) {
173: return message;
174: }
175:
176: return message.replace(LINE_SEP_DELIMITER_1, '\n').replace(
177: LINE_SEP_DELIMITER_2, '\r');
178: }
179:
180: private static String[] parseParameters(final String messagePart) {
181: return tokenize(messagePart, PARAM_DELIMITER);
182: }
183:
184: private static String[] parseMessage(final String message) {
185: return tokenize(message, DELIMITER);
186: }
187:
188: private static String[] tokenize(final String message,
189: final char separator) {
190: if (null == message) {
191: return new String[0];
192: }
193:
194: List<String> tokens = new ArrayList<String>();
195: int start = 0;
196: for (int i = 0; i < message.length(); i++) {
197: if (separator == message.charAt(i)) {
198: tokens.add(message.substring(start, i));
199: start = i + 1;
200: }
201: }
202: if (start < message.length()) {
203: tokens.add(message.substring(start, message.length()));
204: }
205:
206: return tokens.toArray(new String[tokens.size()]);
207: }
208:
209: /**
210: * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
211: */
212: private static final String replace(String original,
213: CharSequence target, CharSequence replacement) {
214: return Pattern.compile(target.toString(), Pattern.LITERAL)
215: .matcher(original).replaceAll(
216: quoteReplacement(replacement.toString()));
217: }
218:
219: /**
220: * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
221: */
222: private static String quoteReplacement(String s) {
223: if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
224: return s;
225: StringBuffer sb = new StringBuffer();
226: for (int i = 0; i < s.length(); i++) {
227: char c = s.charAt(i);
228: if (c == '\\') {
229: sb.append('\\');
230: sb.append('\\');
231: } else if (c == '$') {
232: sb.append('\\');
233: sb.append('$');
234: } else {
235: sb.append(c);
236: }
237: }
238: return sb.toString();
239: }
240: }
|