Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

DeclareParentsTest.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*******************************************************************************
  2. * Copyright (c) 2004 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v 2.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  7. *
  8. * Contributors:
  9. * Andy Clement - initial implementation
  10. *******************************************************************************/
  11. package org.aspectj.ajdt.internal.compiler.batch;
  12. import java.io.File;
  13. import java.util.ArrayList;
  14. import java.util.Iterator;
  15. import java.util.List;
  16. import org.aspectj.bridge.IMessage;
  17. import org.aspectj.tools.ajc.AjcTestCase;
  18. import org.aspectj.tools.ajc.CompilationResult;
  19. /**
  20. * These tests verify the behavior of the binary implementation of declare parents. Basically we attempt a source compile with all
  21. * the classes/aspects - we get some set of errors/warnings and weaving messages out from doing this. We then compile the source
  22. * files and aspects separately and binary weave them together - we should get the same set of weaving information messages. Where
  23. * possible we also execute one of the classes after the binary weave to check it passes the verifier and executes.
  24. *
  25. * There are some notes about the implementation throughout these testcases and they are marked: 'IMPORTANT:'
  26. *
  27. *
  28. * Two things missing:
  29. *
  30. * In the case where inherited methods can't be overridden to reduce visibility, we should cope with a subclass of the decp target
  31. * also trying to do it ? We need a way once we see a type to say 'hey, watch out for this guys kids...' - this will also help us
  32. * when working with abstract classes that don't provide method implementations where their children might.
  33. *
  34. * Field inheritance? Is there something to worry about here?
  35. *
  36. * Covariance on method overrides is supported but untested because we need a Java5 compiler (so we can write easy tests)
  37. */
  38. public class DeclareParentsTest extends AjcTestCase {
  39. private static final boolean verbose = false;
  40. public static final String PROJECT_DIR = "binaryParents";
  41. private File baseDir;
  42. /**
  43. * Check the order doesn't make a difference. (order1)
  44. */
  45. public void testVerifyOrderOfProcessingIrrelevant1() {
  46. File testBase = new File(baseDir, "TestA");
  47. runSourceAndBinaryTestcase(testBase, new String[] { "Z.java", "B.java" }, new String[] { "AspectAB.aj" }, false);
  48. // runClass("B");
  49. }
  50. /**
  51. * Check the order doesn't make a difference. (order2)
  52. */
  53. public void testVerifyOrderOfProcessingIrrelevant2() {
  54. File testBase = new File(baseDir, "TestA");
  55. runSourceAndBinaryTestcase(testBase, new String[] { "B.java", "Z.java" }, new String[] { "AspectAB.aj" }, false);
  56. // runClass("B");
  57. }
  58. /**
  59. * Three classes: Top1, Middle1, Bottom1. Bottom1 extends Top1. Middle1 extends Top1. AspectX1: declares Bottom1 extends Middle1
  60. * Result: Should be OK, fits into the hierarchy no problem.
  61. */
  62. public void testSimpleDeclareParents() {
  63. File testBase = new File(baseDir, "TestA");
  64. runSourceAndBinaryTestcase(testBase, new String[] { "Top1.java", "Middle1.java", "Bottom1.java" },
  65. new String[] { "AspectX1.java" }, false);
  66. // runClass("Bottom1");
  67. }
  68. /**
  69. * Three classes: Top2, Middle2, Bottom2. Bottom2 extends Top2. Middle2 extends Top2. Bottom2 includes a call to super in a
  70. * ctor. AspectX2: declares Bottom2 extends Middle2 Result: Should be OK, fits into the hierarchy no problem. Implementation:
  71. * The super call should be modified from a Top2.<init> call to a Middle2.<init> call
  72. */
  73. public void test_SuperCtorCall() {
  74. File testBase = new File(baseDir, "TestA");
  75. runSourceAndBinaryTestcase(testBase, new String[] { "Top2.java", "Middle2.java", "Bottom2.java" },
  76. new String[] { "AspectX2.java" }, false);
  77. // runClass("Bottom2");
  78. }
  79. /**
  80. * Three classes: Top3, Middle3, Bottom3. Bottom3 extends Top3. Middle3 extends Top3. Bottom3 includes a call to a super method
  81. * in an instance method. AspectX3: declares Bottom3 extends Middle3 Result: Should be OK. Implementation: We don't modify the
  82. * call to Top3.m() that is in the Bottom3 class, we don't have to because the JVM will ensure that the m() chosen at runtime is
  83. * the one nearest the Bottom3 class - when the hierarchy has changed this will be the Middle3.m() version and so it all works.
  84. * IMPORTANT: This leaves a subtle difference in the code generated from decp application at source time and decp application at
  85. * weave time - in the source time case the call in Bottom3 will have been set to Middle3.m() during code gen, whereas in the
  86. * weave time case it will still say Top3.m() - I'm not sure this makes any practical difference though? We could easily fix it
  87. * and morph the Top3.m() call to a Middle3.m() call but it would impact peformance crawling through all the bytecodes to make
  88. * this change.
  89. */
  90. public void test_SuperMethodCall() {
  91. File testBase = new File(baseDir, "TestA");
  92. runSourceAndBinaryTestcase(testBase, new String[] { "Top3.java", "Middle3.java", "Bottom3.java" },
  93. new String[] { "AspectX3.java" }, false);
  94. // runClass("Bottom3");
  95. }
  96. /**
  97. * Three classes: Top4, Middle4, Bottom4. Bottom4 extends Top4. Middle4 extends Top4. AspectX4: declares Bottom4 extends Middle4
  98. * Result: Should fail - because Middle4 doesn't include a ctor that takes a String, which is called by Bottom4
  99. */
  100. public void test_missingCtorInIntroducedClass() {
  101. File testBase = new File(baseDir, "TestA");
  102. runSourceAndBinaryTestcase(testBase, new String[] { "Top4.java", "Middle4.java", "Bottom4.java" },
  103. new String[] { "AspectX4.java" }, true, false);
  104. }
  105. /**
  106. * If overriding an instance method, can't make it static. If overriding a static method, can't make it an instance method.
  107. *
  108. * Note: Error messages and locations for binary weaving are much better than their source counterparts !
  109. */
  110. public void test_cantMakeInheritedInstanceMethodsStatic() {
  111. runSourceAndBinaryTestcase(new File(baseDir, "TestC"), new String[] { "A1.java", "B1.java" }, new String[] { "X1.java" },
  112. true, false);
  113. }
  114. /**
  115. * Cannot extend a final class
  116. */
  117. public void xxxtest_cantExtendFinalClass() { // XXX removed test, need to discuss with andy how to repair...
  118. runSourceAndBinaryTestcase(new File(baseDir, "TestC"), new String[] { "A2.java", "B2.java" }, new String[] { "X2.java" },
  119. true, true);
  120. }
  121. /**
  122. * The Object class cannot be subject to declare parents extends
  123. *
  124. * This is tested when the aspect is compiled - so couldn't occur during binary weaving of decp.
  125. */
  126. /**
  127. * if you inherit methods you cannot override them and reduce their visibility
  128. */
  129. public void test_cantReduceVisibilityOfOverriddenMethods_1() {
  130. runSourceAndBinaryTestcase(new File(baseDir, "TestB"), new String[] { "Top1.java", "Middle1.java" },
  131. new String[] { "Aspect1.java" }, true, false);
  132. }
  133. /**
  134. * if you inherit methods you cannot override them and reduce their visibility.
  135. *
  136. * test 2 in this set checks methods from a superclass of the named new parent.
  137. */
  138. public void test_cantReduceVisibilityOfOverriddenMethods_2() {
  139. runSourceAndBinaryTestcase(new File(baseDir, "TestB"), new String[] { "TopTop6.java", "Top6.java", "Middle6.java" },
  140. new String[] { "Aspect6.java" }, true, false);
  141. }
  142. /**
  143. * If you inherit methods you cannot have incompatible return types (java1.5 will make this a little messier).
  144. */
  145. public void test_overriddenMethodsCantHaveIncompatibleReturnTypes() {
  146. runSourceAndBinaryTestcase(new File(baseDir, "TestB"),
  147. new String[] { "Top2.java", "Middle2.java", "Super.java", "Sub.java" }, new String[] { "Aspect2.java" }, true);
  148. }
  149. /**
  150. * Testing: If you inherit abstract methods and you are not abstract you need to provide an implementation.
  151. *
  152. * Test 1 in this set is simple.
  153. */
  154. public void test_inheritedAbstractMethodsMustBeImplemented_1() {
  155. runSourceAndBinaryTestcase(new File(baseDir, "TestB"),
  156. new String[] { "Top3.java", "Middle3.java", "Super.java", "Sub.java" }, new String[] { "Aspect3.java" }, true);
  157. }
  158. /**
  159. * Testing: If the decp makes you implement an interface, you must provide the implementation
  160. */
  161. public void test_interfaceMethodsImplemented() {
  162. File testBase = new File(baseDir, "TestD");
  163. runSourceAndBinaryTestcase(testBase, new String[] { "SimpleClass1.java", "SimpleIntf1.java" },
  164. new String[] { "SimpleAspect1.java" }, true);
  165. }
  166. /**
  167. * Testing: If you inherit abstract methods and you are not abstract you need to provide an implementation.
  168. *
  169. * Test 2 in this set includes methods further up the hierarchy that must be implemented.
  170. */
  171. public void test_inheritedAbstractMethodsMustBeImplemented_2() {
  172. runSourceAndBinaryTestcase(new File(baseDir, "TestB"), new String[] { "TopTop4.java", "Top4.java", "Middle4.java" },
  173. new String[] { "Aspect4.java" }, true);
  174. }
  175. /**
  176. * Testing: If you inherit abstract methods and you are not abstract you need to provide an implementation.
  177. *
  178. * Test 3 in this set includes methods further up the hierarchy that must be implemented *and* the dependencies are satisfied by
  179. * ITDs from the aspect
  180. */
  181. public void test_inheritedAbstractMethodsMustBeImplemented_3() {
  182. runSourceAndBinaryTestcase(new File(baseDir, "TestD"), new String[] { "SimpleClass2.java" },
  183. new String[] { "SimpleAspect2.java" }, true);
  184. }
  185. /**
  186. * If adding a type into a hierarchy, any missing ctor could be added via an ITDC so allow for that !
  187. */
  188. public void test_missingCtorAddedViaITD() {
  189. File testBase = new File(baseDir, "TestE");
  190. runSourceAndBinaryTestcase(testBase, new String[] { "A.java", "B.java", "C.java" }, new String[] { "X.java" }, true);
  191. }
  192. // ////////////////////////////////////////////////////////////////////////////////////////
  193. // ////////////////////////////////////////////////////////////////////////////////////////
  194. // ////////////////////////////////////////////////////////////////////////////////////////
  195. public void runSourceAndBinaryTestcase(File testBase, String[] classes, String[] aspects, boolean expectErrors) {
  196. runSourceAndBinaryTestcase(testBase, classes, aspects, expectErrors, true);
  197. }
  198. public void runSourceAndBinaryTestcase(File testBase, String[] classes, String[] aspects, boolean expectErrors,
  199. boolean compareErrors) {
  200. // Do a compile of everything together from source ...
  201. CompilationResult result = null;
  202. // Execute: "ajc <classes> <aspects> -showWeaveInfo"
  203. String[] sourceCompileCommandLine = new String[classes.length + aspects.length + 2];
  204. System.arraycopy(classes, 0, sourceCompileCommandLine, 0, classes.length);
  205. System.arraycopy(aspects, 0, sourceCompileCommandLine, classes.length, aspects.length);
  206. String[] extraOption = new String[] { "-showWeaveInfo", "-1.4"};
  207. System.arraycopy(extraOption, 0, sourceCompileCommandLine, classes.length + aspects.length, 2);
  208. result = ajc(testBase, sourceCompileCommandLine);
  209. if (!expectErrors)
  210. assertTrue("errors? \n" + result.getErrorMessages(), !result.hasErrorMessages());
  211. List<IMessage> sourceWeaveMessages = getWeaveMessages(result);
  212. int sourceWeaveMessagesCount = sourceWeaveMessages.size();
  213. List<IMessage> sourceErrorMessages = result.getErrorMessages();
  214. int sourceErrorMessagesCount = sourceErrorMessages.size();
  215. if (verbose) {
  216. System.err.println("Source Compilation: Error count = " + sourceErrorMessagesCount + "\n" + sourceErrorMessages);
  217. System.err.println("Source Compilation: Weaving count = " + sourceWeaveMessagesCount + "\n" + sourceWeaveMessages);
  218. }
  219. // Do separate compiles of the classes then the aspects then do a binary weave
  220. // Execute: "ajc <classes> -g -d classes"
  221. result = ajc(testBase, mergeOptions(classes, new String[] { "-g", "-d", "classes" }));
  222. setShouldEmptySandbox(false);
  223. // Execute: "ajc <aspects> -g -outjar aspects.jar -classpath classes -proceedOnError"
  224. result = ajc(testBase, mergeOptions(aspects, new String[] { "-g", "-outjar", "aspects.jar", "-classpath", "classes",
  225. "-proceedOnError" }));
  226. if (result.getErrorMessages().size() != 0)
  227. System.err.println("Expecting no errors from jar building but got\n" + result.getErrorMessages());
  228. assertTrue("Should get no errors for this compile, but got: " + result.getErrorMessages().size(), result.getErrorMessages()
  229. .size() == 0);
  230. // Execute: "ajc -inpath classes -showWeaveInfo -d classes2 -aspectpath aspects.jar"
  231. result = ajc(testBase, new String[] { "-inpath", "classes", "-showWeaveInfo", "-1.4", "-d", "classes2", "-aspectpath",
  232. "aspects.jar" });
  233. if (!expectErrors)
  234. assertTrue("unexpected errors? \n" + result.getErrorMessages(), !result.hasErrorMessages());
  235. List<IMessage> binaryWeaveMessages = getWeaveMessages(result);
  236. int binaryWeaveMessagesCount = binaryWeaveMessages.size();
  237. List<IMessage> binaryErrorMessages = result.getErrorMessages();
  238. int binaryErrorMessagesCount = binaryErrorMessages.size();
  239. if (verbose) {
  240. System.err.println("Binary Compilation: Error count = " + binaryErrorMessagesCount + "\n" + binaryErrorMessages);
  241. System.err.println("Binary Compilation: Weaving count = " + binaryWeaveMessagesCount + "\n" + binaryWeaveMessages);
  242. System.err.println("StandardError from final binary compile stage: " + result.getStandardError());
  243. }
  244. assertTrue("Should have same number of errors in either case: " + sourceErrorMessagesCount + "!="
  245. + binaryErrorMessagesCount, sourceErrorMessagesCount == binaryErrorMessagesCount);
  246. // ///////////////////////////////////////////////////////////////////////////
  247. // Check the error messages are comparable (allow for differing orderings)
  248. if (compareErrors) {
  249. for (IMessage binaryMessage : binaryErrorMessages) {
  250. IMessage correctSourceMessage = null;
  251. for (Iterator<IMessage> iterator = sourceErrorMessages.iterator(); iterator.hasNext() && correctSourceMessage == null; ) {
  252. IMessage sourceMessage = iterator.next();
  253. if (sourceMessage.getMessage().equals(binaryMessage.getMessage())) {
  254. correctSourceMessage = sourceMessage;
  255. }
  256. }
  257. if (correctSourceMessage == null) {
  258. fail("This error obtained during binary weaving '" + binaryMessage
  259. + "' has no equivalent in the list of messages from source compilation");
  260. }
  261. sourceErrorMessages.remove(correctSourceMessage);
  262. }
  263. if (sourceErrorMessages.size() > 0) {
  264. for (IMessage srcMsg : sourceErrorMessages) {
  265. System.err.println("This error message from source compilation '" + srcMsg
  266. + "' didn't occur during binary weaving.");
  267. }
  268. fail("Got " + sourceErrorMessages.size() + " extra error messages during source compilation");
  269. }
  270. }
  271. // //////////////////////////////////////////////////////////////////////////
  272. // Check the weaving messages are comparable
  273. if (sourceWeaveMessagesCount != binaryWeaveMessagesCount) {
  274. fail("Didn't get same number of weave info messages when source weaving and binary weaving: "
  275. + sourceWeaveMessagesCount + "!=" + binaryWeaveMessagesCount);
  276. }
  277. // Check weaving messages are comparable
  278. for (int i = 0; i < sourceWeaveMessages.size(); i++) {
  279. IMessage m1 = sourceWeaveMessages.get(i);
  280. IMessage m2 = binaryWeaveMessages.get(i);
  281. String s1 = m1.getDetails();
  282. String s2 = m2.getDetails();
  283. if (!s1.equals(s2)) {
  284. System.err.println("Source Weave Messages: #" + sourceWeaveMessages.size() + "\n" + sourceWeaveMessages);
  285. System.err.println("Binary Weave Messages: #" + binaryWeaveMessages.size() + "\n" + binaryWeaveMessages);
  286. fail("Two weaving messages aren't the same?? sourceMessage=[" + s1 + "] binaryMessage=[" + s2 + "]");
  287. }
  288. if (m1.getSourceLocation() != null || m2.getSourceLocation() != null) {
  289. if (!m1.getSourceLocation().equals(m2.getSourceLocation())) {
  290. fail("Different source locations for weaving messages? \n" + m1.getSourceLocation() + "\n"
  291. + m2.getSourceLocation());
  292. }
  293. }
  294. }
  295. // // Check the result of binary weaving !
  296. // ClassPath cp = new ClassPath(ajc.getSandboxDirectory()+File.separator+"classes2"+
  297. // File.pathSeparator+System.getProperty("sun.boot.class.path"));
  298. // System.err.println(cp);
  299. // SyntheticRepository r = SyntheticRepository.getInstance(cp);
  300. // Repository.setRepository(r);
  301. // for (int i = 0; i < classes.length; i++) {
  302. // String name = classes[i].substring(0,classes[i].lastIndexOf("."));
  303. // List verificationProblems = verify(name);
  304. // assertTrue("Did not expect any verification problems for class: "+name+": \n"+verificationProblems,verificationProblems.
  305. // size()==0);
  306. // }
  307. }
  308. public String[] mergeOptions(String[] input, String[] extras) {
  309. String[] ret = new String[input.length + extras.length];
  310. System.arraycopy(input, 0, ret, 0, input.length);
  311. System.arraycopy(extras, 0, ret, input.length, extras.length);
  312. return ret;
  313. }
  314. private List<IMessage> getWeaveMessages(CompilationResult result) {
  315. List<IMessage> infoMessages = result.getInfoMessages();
  316. List<IMessage> weaveMessages = new ArrayList<>();
  317. for (IMessage element: infoMessages) {//Iterator iter = infoMessages.iterator(); iter.hasNext();) {
  318. // IMessage element = (IMessage) iter.next();
  319. if (element.getKind() == IMessage.WEAVEINFO)
  320. weaveMessages.add(element);
  321. }
  322. return weaveMessages;
  323. }
  324. @Override
  325. protected void setUp() throws Exception {
  326. super.setUp();
  327. baseDir = new File("../org.aspectj.ajdt.core/testdata", PROJECT_DIR);
  328. }
  329. // private List verify(String name) {
  330. // List verifyProblems = new ArrayList();
  331. // System.out.println("Now verifying: " + name + "\n");
  332. //
  333. // Verifier v = VerifierFactory.getVerifier(name);
  334. // VerificationResult vr;
  335. //
  336. // vr = v.doPass1();
  337. // if (vr != VerificationResult.VR_OK)
  338. // verifyProblems.add("Pass1: " + vr.getMessage());
  339. //
  340. // vr = v.doPass2();
  341. // if (vr != VerificationResult.VR_OK)
  342. // verifyProblems.add("Pass2: " + vr.getMessage());
  343. //
  344. // if (vr == VerificationResult.VR_OK) {
  345. // JavaClass jc = Repository.lookupClass(name);
  346. // for (int i = 0; i < jc.getMethods().length; i++) {
  347. // vr = v.doPass3a(i);
  348. // if (vr != VerificationResult.VR_OK)
  349. // verifyProblems.add("Pass3a: " + jc.getMethods()[i] + " " + vr.getMessage());
  350. //
  351. // vr = v.doPass3b(i);
  352. // if (vr != VerificationResult.VR_OK)
  353. // verifyProblems.add("Pass3b: " + jc.getMethods()[i] + " " + vr.getMessage());
  354. // }
  355. // }
  356. //
  357. // System.out.println("Warnings:");
  358. // String[] warnings = v.getMessages();
  359. // if (warnings.length == 0)
  360. // System.out.println("<none>");
  361. // for (int j = 0; j < warnings.length; j++) {
  362. // System.out.println(warnings[j]);
  363. // }
  364. //
  365. // System.out.println("\n");
  366. //
  367. // // avoid swapping.
  368. // v.flush();
  369. // Repository.clearCache();
  370. // return verifyProblems;
  371. // }
  372. // private void runClass(String name) {
  373. // RunResult rr = null;
  374. // try {
  375. // rr = run(name, new String[] {}, ajc.getSandboxDirectory() + File.separator + "classes2");
  376. // } catch (VerifyError ve) {
  377. // ve.printStackTrace();
  378. // fail("Unexpected VerifyError for type upon which we declared parents");
  379. // }
  380. // // assertTrue("Didn't expect any errors from the run of "+name+", but got: "+rr.toString(),rr.get);
  381. // }
  382. }