You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FlatSuiteReader.java 12KB

21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
21 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.testing.harness.bridge;
  14. import java.io.File;
  15. import java.io.IOException;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.List;
  19. import org.aspectj.bridge.AbortException;
  20. import org.aspectj.bridge.IMessage;
  21. import org.aspectj.bridge.ISourceLocation;
  22. import org.aspectj.bridge.Message;
  23. import org.aspectj.bridge.MessageUtil;
  24. import org.aspectj.bridge.SourceLocation;
  25. import org.aspectj.bridge.IMessage.Kind;
  26. import org.aspectj.testing.util.BridgeUtil;
  27. import org.aspectj.testing.util.ObjectChecker;
  28. import org.aspectj.testing.util.SFileReader;
  29. import org.aspectj.testing.util.StandardObjectChecker;
  30. import org.aspectj.testing.util.UtilLineReader;
  31. import org.aspectj.util.FileUtil;
  32. import org.aspectj.util.LangUtil;
  33. /**
  34. * SFileReader.Maker implementation to read tests
  35. * XXX supports iterative but not yet incremental compiles
  36. */
  37. public class FlatSuiteReader implements SFileReader.Maker {
  38. public static final String[] RA_String = new String[0];
  39. public static final FlatSuiteReader ME = new FlatSuiteReader();
  40. private static final SFileReader READER = new SFileReader(ME);
  41. static boolean isNumber(String s) { // XXX costly
  42. if ((null == s) || (0 == s.length())) {
  43. return false;
  44. }
  45. try {
  46. Integer.valueOf(s);
  47. return true;
  48. } catch (NumberFormatException e) {
  49. return false;
  50. }
  51. }
  52. /** if true, clean up records before returning from make */
  53. public boolean clean;
  54. private FlatSuiteReader() {
  55. }
  56. /**
  57. * @see org.aspectj.testing.harness.bridge.SFileReader.Maker#getType()
  58. */
  59. public Class getType() {
  60. return AjcTest.Spec.class;
  61. }
  62. /**
  63. * This constructs an AjcTest.Spec assuming we are at the start of a
  64. * test definition in reader and taking the parent directory of
  65. * the reader as the base directory for the test suite root.
  66. * @return the next AjcTest in reader, or null
  67. * @see org.aspectj.testing.harness.bridge.SFileReader.Maker#make(UtilLineReader)
  68. */
  69. public Object make(final UtilLineReader reader)
  70. throws AbortException, IOException {
  71. final AjcTest.Spec result = new AjcTest.Spec();
  72. boolean usingEclipse = false; // XXX
  73. /** handle read errors by throwing AbortException with context info */
  74. class R {
  75. public String read(String context) throws IOException {
  76. return read(context, true);
  77. }
  78. public String read(String context, boolean required)
  79. throws IOException {
  80. final boolean skipEmpties = false;
  81. String result = reader.nextLine(skipEmpties);
  82. if ((null != result) && (0 == result.length())) {
  83. result = null;
  84. }
  85. if ((null == result) && required) {
  86. String s = "expecting " + context + " at " + reader;
  87. throw new AbortException(s);
  88. }
  89. return result;
  90. }
  91. }
  92. final R r = new R();
  93. //final String baseDir = reader.getFile().getParent();
  94. String line;
  95. String[] words;
  96. // boolean isRequired = true;
  97. final int startLine = reader.getLineNumber() - 1;
  98. // description first - get from last line read
  99. // XXX permits exactly one blank line between test records?
  100. result.description = reader.lastLine();
  101. if (null == result.description) {
  102. throw new AbortException("expecting description at " + reader);
  103. }
  104. // next line is baseDir {option..}
  105. line = r.read("baseDir {option..}");
  106. words = LangUtil.split(line);
  107. if ((null == words) || (0 == words.length)) {
  108. throw new AbortException(
  109. "expecting dir {option..} at " + reader);
  110. }
  111. // XXX per-test (shared) root
  112. //final File sourceRoot = new File(baseDir, words[0]);
  113. result.setTestDirOffset(words[0]);
  114. String[] compileOptions = new String[words.length - 1];
  115. System.arraycopy(words, 1, compileOptions, 0, words.length - 1);
  116. // next are 1..n source lines: source...
  117. CompilerRun.Spec lastCompileSpec = null;
  118. // save last source file as default for error/warning line
  119. File lastFile = null; // XXX per-compiler-run errors
  120. while (null != (line = r.read("source.."))) {
  121. words = LangUtil.split(line);
  122. if (0 == FileUtil.sourceSuffixLength(words[0])) { // XXX
  123. break;
  124. } else {
  125. lastCompileSpec = new CompilerRun.Spec();
  126. lastCompileSpec.testSrcDirOffset = null;
  127. // srcs are in test base for old
  128. lastCompileSpec.addOptions(compileOptions);
  129. lastCompileSpec.addPaths(words);
  130. lastFile = new File(words[words.length - 1]);
  131. result.addChild(lastCompileSpec);
  132. }
  133. }
  134. if (null == lastCompileSpec) {
  135. throw new AbortException("expected sources at " + reader);
  136. }
  137. ArrayList<Message> exp = new ArrayList<>();
  138. // !compile || noerrors || className {runOption..}
  139. String first = words[0];
  140. if ("!compile".equals(first)) {
  141. //result.className = words[0];
  142. //result.runOptions = new String[words.length-1];
  143. //System.arraycopy(words, 0, result.runOptions, 0, words.length-1);
  144. } else if ("noerrors".equals(first)) {
  145. // className is null, but no errors expected
  146. // so compile succeeds but run not attempted
  147. //result.errors = Main.RA_ErrorLine;
  148. // result.runOptions = Main.RA_String;
  149. } else if (isNumber(first) || (-1 != first.indexOf(":"))) {
  150. exp.addAll(makeMessages(IMessage.ERROR, words, 0, lastFile));
  151. } else {
  152. String[] args = new String[words.length - 1];
  153. System.arraycopy(words, 0, args, 0, args.length);
  154. JavaRun.Spec spec = new JavaRun.Spec();
  155. spec.className = first;
  156. spec.addOptions(args);
  157. //XXXrun.runDir = sourceRoot;
  158. result.addChild(spec);
  159. }
  160. // optional: warnings, eclipse.warnings, eclipse.errors
  161. // XXX unable to specify error in eclipse but not ajc
  162. boolean gotErrors = false;
  163. while (null
  164. != (line =
  165. r.read(
  166. " errors, warnings, eclipse.warnings, eclipse.error",
  167. false))) {
  168. words = LangUtil.split(line);
  169. first = words[0];
  170. if ("eclipse.warnings:".equals(first)) {
  171. if (usingEclipse) {
  172. exp.addAll(
  173. makeMessages(
  174. IMessage.WARNING,
  175. words,
  176. 0,
  177. lastFile));
  178. }
  179. } else if ("eclipse.errors:".equals(first)) {
  180. if (usingEclipse) {
  181. exp.addAll(
  182. makeMessages(IMessage.ERROR, words, 0, lastFile));
  183. }
  184. } else if ("warnings:".equals(first)) {
  185. exp.addAll(
  186. makeMessages(IMessage.WARNING, words, 0, lastFile));
  187. } else if (gotErrors) {
  188. exp.addAll(
  189. makeMessages(IMessage.WARNING, words, 0, lastFile));
  190. } else {
  191. exp.addAll(
  192. makeMessages(IMessage.ERROR, words, 0, lastFile));
  193. gotErrors = true;
  194. }
  195. }
  196. lastCompileSpec.addMessages(exp);
  197. int endLine = reader.getLineNumber();
  198. File sourceFile = reader.getFile();
  199. ISourceLocation sl =
  200. new SourceLocation(sourceFile, startLine, endLine, 0);
  201. result.setSourceLocation(sl);
  202. if (clean) {
  203. cleanup(result, reader);
  204. }
  205. return result;
  206. }
  207. /** post-process result
  208. * - use file name as keyword
  209. * - clip / for dir offsets
  210. * - extract purejava keyword variants
  211. * - extract bugID
  212. * - convert test options to force-options
  213. * - detect illegal xml characters
  214. */
  215. private void cleanup(AjcTest.Spec result, UtilLineReader lineReader) {
  216. LangUtil.throwIaxIfNull(result, "result");
  217. LangUtil.throwIaxIfNull(lineReader, "lineReader");
  218. File suiteFile = lineReader.getFile();
  219. String name = suiteFile.getName();
  220. if (!name.endsWith(".txt")) {
  221. throw new Error("unexpected name: " + name);
  222. }
  223. result.addKeyword("from-" + name.substring(0,name.length()-4));
  224. final String dir = result.testDirOffset;
  225. if (dir.endsWith("/")) {
  226. result.testDirOffset = dir.substring(0,dir.length()-1);
  227. }
  228. StringBuffer description = new StringBuffer(result.description);
  229. if (strip(description, "PUREJAVA")) {
  230. result.addKeyword("purejava");
  231. }
  232. if (strip(description, "PUREJAVE")) {
  233. result.addKeyword("purejava");
  234. }
  235. if (strip(description, "[purejava]")) {
  236. result.addKeyword("purejava");
  237. }
  238. String input = description.toString();
  239. int loc = input.indexOf("PR#");
  240. if (-1 != loc) {
  241. String prefix = input.substring(0, loc).trim();
  242. String pr = input.substring(loc+3, loc+6).trim();
  243. String suffix = input.substring(loc+6).trim();
  244. description.setLength(0);
  245. description.append((prefix + " " + suffix).trim());
  246. try {
  247. result.setBugId(Integer.valueOf(pr).intValue());
  248. } catch (NumberFormatException e) {
  249. throw new Error("unable to convert " + pr + " for " + result
  250. + " at " + lineReader);
  251. }
  252. }
  253. input = description.toString();
  254. String error = null;
  255. if (-1 != input.indexOf("&")) {
  256. error = "char &";
  257. } else if (-1 != input.indexOf("<")) {
  258. error = "char <";
  259. } else if (-1 != input.indexOf(">")) {
  260. error = "char >";
  261. } else if (-1 != input.indexOf("\"")) {
  262. error = "char \"";
  263. }
  264. if (null != error) {
  265. throw new Error(error + " in " + input + " at " + lineReader);
  266. }
  267. result.description = input;
  268. ArrayList<String> newOptions = new ArrayList<>();
  269. ArrayList<String> optionsCopy = result.getOptionsList();
  270. for (String option: optionsCopy) {
  271. if (option.startsWith("-")) {
  272. newOptions.add("!" + option.substring(1));
  273. } else {
  274. throw new Error("non-flag option? " + option);
  275. }
  276. }
  277. result.setOptionsArray((String[]) newOptions.toArray(new String[0]));
  278. }
  279. private boolean strip(StringBuffer sb, String infix) {
  280. String input = sb.toString();
  281. int loc = input.indexOf(infix);
  282. if (-1 != loc) {
  283. String prefix = input.substring(0, loc);
  284. String suffix = input.substring(loc+infix.length());
  285. input = (prefix.trim() + " " + suffix.trim()).trim();
  286. sb.setLength(0);
  287. sb.append(input);
  288. return true;
  289. }
  290. return false;
  291. }
  292. /**
  293. * Generate list of expected messages of this kind.
  294. * @param kind any non-null kind, but s.b. IMessage.WARNING or ERROR
  295. * @param words
  296. * @param start index in words where to start
  297. * @param lastFile default file for source location if the input does not specify
  298. * @return List
  299. */
  300. private List<Message> makeMessages(// XXX weak - also support expected exceptions, etc.
  301. Kind kind, String[] words, int start, File lastFile) {
  302. ArrayList<Message> result = new ArrayList<>();
  303. for (int i = start; i < words.length; i++) {
  304. ISourceLocation sl =
  305. BridgeUtil.makeSourceLocation(words[i], lastFile);
  306. if (null == sl) { // XXX signalling during make
  307. // System.err.println(...);
  308. //MessageUtil.debug(handler, "not a source location: " + words[i]);
  309. } else {
  310. String text =
  311. (("" + sl.getLine()).equals(words[i]) ? "" : words[i]);
  312. result.add(new Message(text, kind, null, sl));
  313. }
  314. }
  315. return (0 == result.size() ? Collections.<Message>emptyList() : result);
  316. }
  317. /**
  318. * Read suite spec from a flat .txt file.
  319. * @throws AbortException on failure
  320. * @return AjcTest.Suite.Spec with any AjcTest.Spec as children
  321. */
  322. public AjcTest.Suite.Spec readSuite(File suiteFile) {
  323. LangUtil.throwIaxIfNull(suiteFile, "suiteFile");
  324. if (!suiteFile.isAbsolute()) {
  325. suiteFile = suiteFile.getAbsoluteFile();
  326. }
  327. final AjcTest.Suite.Spec result = new AjcTest.Suite.Spec();
  328. result.setSuiteDirFile(suiteFile.getParentFile());
  329. ObjectChecker collector = new StandardObjectChecker(IRunSpec.class) {
  330. public boolean doIsValid(Object o) {
  331. result.addChild((IRunSpec) o);
  332. return true;
  333. }
  334. };
  335. boolean abortOnError = true;
  336. try {
  337. READER.readNodes(
  338. suiteFile,
  339. collector,
  340. abortOnError,
  341. System.err);
  342. } catch (IOException e) {
  343. IMessage m = MessageUtil.fail("reading " + suiteFile, e);
  344. throw new AbortException(m);
  345. }
  346. return result;
  347. }
  348. }