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

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.IMessage.Kind;
  22. import org.aspectj.bridge.ISourceLocation;
  23. import org.aspectj.bridge.Message;
  24. import org.aspectj.bridge.MessageUtil;
  25. import org.aspectj.bridge.SourceLocation;
  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) || (first.contains(":"))) {
  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 (input.contains("&")) {
  256. error = "char &";
  257. } else if (input.contains("<")) {
  258. error = "char <";
  259. } else if (input.contains(">")) {
  260. error = "char >";
  261. } else if (input.contains("\"")) {
  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. }