aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraclement <aclement>2005-01-05 16:39:42 +0000
committeraclement <aclement>2005-01-05 16:39:42 +0000
commit7f81377868c16bb2ea666d83bd06a6651fbad60a (patch)
treeb01d4f2b07aec196b3bd8f2cf663a9ad8e53fd55
parent21dc11ccadbb301c13aae0b26a0e9b1178cd0dd5 (diff)
downloadaspectj-7f81377868c16bb2ea666d83bd06a6651fbad60a.tar.gz
aspectj-7f81377868c16bb2ea666d83bd06a6651fbad60a.zip
BWD: test cases
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/AjdtBatchTests.java1
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/DeclareParents.java494
2 files changed, 495 insertions, 0 deletions
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/AjdtBatchTests.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/AjdtBatchTests.java
index 23b1425e8..4f66539f5 100644
--- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/AjdtBatchTests.java
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/AjdtBatchTests.java
@@ -33,6 +33,7 @@ public class AjdtBatchTests extends TestCase {
suite.addTestSuite(PartiallyExposedHierarchyTestCase.class);
suite.addTestSuite(CompilerDumpTestCase.class);
suite.addTestSuite(ProceedOnErrorTestCase.class);
+ suite.addTestSuite(DeclareParents.class);
// XXX suite.addTestSuite(VerifyWeaveTestCase.class);
//suite.addTestSuite(WorkingCommandTestCase.class);
//$JUnit-END$
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/DeclareParents.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/DeclareParents.java
new file mode 100644
index 000000000..703b82585
--- /dev/null
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/DeclareParents.java
@@ -0,0 +1,494 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler.batch;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.aspectj.apache.bcel.Repository;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.verifier.VerificationResult;
+import org.aspectj.apache.bcel.verifier.Verifier;
+import org.aspectj.apache.bcel.verifier.VerifierFactory;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.tools.ajc.AjcTestCase;
+import org.aspectj.tools.ajc.CompilationResult;
+
+
+
+/**
+ * These tests verify the behavior of the binary implementation of declare parents.
+ * Basically we attempt a source compile with all the classes/aspects - we get some
+ * set of errors/warnings and weaving messages out from doing this. We then compile the
+ * source files and aspects separately and binary weave them together - we should
+ * get the same set of weaving information messages. Where possible we also execute one of the
+ * classes after the binary weave to check it passes the verifier and executes.
+ *
+ * There are some notes about the implementation throughout these testcases and they
+ * are marked: 'IMPORTANT:'
+ *
+ *
+ * Two things missing:
+
+ * In the case where inherited methods can't be overridden to reduce visibility, we should cope
+ * with a subclass of the decp target 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 when working with abstract
+ * classes that don't provide method implementations where their children might.
+
+ * Field inheritance? Is there something to worry about here?
+
+ * Covariance on method overrides is supported but untested because we need a Java5 compiler (so we can write easy tests)
+
+ */
+public class DeclareParents extends AjcTestCase {
+
+ private static final boolean verbose = false;
+
+ public static final String PROJECT_DIR = "binaryParents";
+
+ private File baseDir;
+
+
+ /**
+ * Check the order doesn't make a difference. (order1)
+ */
+ public void testVerifyOrderOfProcessingIrrelevant1() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"Z.java","B.java"},
+ new String[]{"AspectAB.aj"},false);
+ runClass("B");
+ }
+
+
+ /**
+ * Check the order doesn't make a difference. (order2)
+ */
+ public void testVerifyOrderOfProcessingIrrelevant2() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"B.java","Z.java"},
+ new String[]{"AspectAB.aj"},false);
+ runClass("B");
+ }
+
+
+ /**
+ * Three classes:
+ * Top1, Middle1, Bottom1. Bottom1 extends Top1. Middle1 extends Top1.
+ * AspectX1: declares Bottom1 extends Middle1
+ * Result:
+ * Should be OK, fits into the hierarchy no problem.
+ */
+ public void testSimpleDeclareParents() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"Top1.java","Middle1.java","Bottom1.java"},
+ new String[]{"AspectX1.java"},false);
+ runClass("Bottom1");
+ }
+
+
+ /**
+ * Three classes:
+ * Top2, Middle2, Bottom2. Bottom2 extends Top2. Middle2 extends Top2.
+ * Bottom2 includes a call to super in a ctor.
+ * AspectX2: declares Bottom2 extends Middle2
+ * Result:
+ * Should be OK, fits into the hierarchy no problem.
+ * Implementation:
+ * The super call should be modified from a Top2.<init> call to a Middle2.<init> call
+ */
+ public void test_SuperCtorCall() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"Top2.java","Middle2.java","Bottom2.java"},
+ new String[]{"AspectX2.java"},false);
+ runClass("Bottom2");
+ }
+
+
+ /**
+ * Three classes:
+ * Top3, Middle3, Bottom3. Bottom3 extends Top3. Middle3 extends Top3.
+ * Bottom3 includes a call to a super method in an instance method.
+ * AspectX3: declares Bottom3 extends Middle3
+ * Result: Should be OK.
+ * Implementation:
+ * We don't modify the 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 the one nearest the Bottom3 class -
+ * when the hierarchy has changed this will be the Middle3.m() version and so it all works.
+ * IMPORTANT:
+ * This leaves a subtle difference in the code generated from decp application at source time
+ * and decp application at weave time - in the source time case the call in Bottom3 will have
+ * been set to Middle3.m() during code gen, whereas in the weave time case it will still
+ * say Top3.m() - I'm not sure this makes any practical difference though? We could easily
+ * fix it and morph the Top3.m() call to a Middle3.m() call but it would impact peformance
+ * crawling through all the bytecodes to make this change.
+ */
+ public void test_SuperMethodCall() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"Top3.java","Middle3.java","Bottom3.java"},
+ new String[]{"AspectX3.java"},false);
+ runClass("Bottom3");
+ }
+
+
+ /**
+ * Three classes:
+ * Top4, Middle4, Bottom4. Bottom4 extends Top4. Middle4 extends Top4.
+ * AspectX4: declares Bottom4 extends Middle4
+ * Result: Should fail - because Middle4 doesn't include a ctor that takes a String, which is called by Bottom4
+ */
+ public void test_missingCtorInIntroducedClass() {
+ File testBase = new File(baseDir,"TestA");
+ runSourceAndBinaryTestcase(testBase,new String[]{"Top4.java","Middle4.java","Bottom4.java"},
+ new String[]{"AspectX4.java"},true,false);
+ }
+
+
+ /**
+ * If overriding an instance method, can't make it static.
+ * If overriding a static method, can't make it an instance method.
+ *
+ * Note: Error messages and locations for binary weaving are much better than their source counterparts !
+ */
+ public void test_cantMakeInheritedInstanceMethodsStatic() {
+ File testBase = new File(baseDir,"TestC");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestC"),
+ new String[]{"A1.java","B1.java"},
+ new String[]{"X1.java"},true,false);
+ }
+
+ /**
+ * Cannot extend a final class
+ */
+ public void test_cantExtendFinalClass() {
+ File testBase = new File(baseDir,"TestC");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestC"),
+ new String[]{"A2.java","B2.java"},
+ new String[]{"X2.java"},true,true);
+ }
+
+ /**
+ * The Object class cannot be subject to declare parents extends
+ *
+ * This is tested when the aspect is compiled - so couldn't occur during binary weaving of decp.
+ */
+
+
+ /**
+ * if you inherit methods you cannot override them and reduce their visibility
+ */
+ public void test_cantReduceVisibilityOfOverriddenMethods_1() {
+ File testBase = new File(baseDir,"TestB");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestB"),
+ new String[]{"Top1.java","Middle1.java"},
+ new String[]{"Aspect1.java"},true,false);
+ }
+
+ /**
+ * if you inherit methods you cannot override them and reduce their visibility.
+ *
+ * test 2 in this set checks methods from a superclass of the named new parent.
+ */
+ public void test_cantReduceVisibilityOfOverriddenMethods_2() {
+ File testBase = new File(baseDir,"TestB");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestB"),
+ new String[]{"TopTop6.java","Top6.java","Middle6.java"},
+ new String[]{"Aspect6.java"},true,false);
+ }
+
+
+
+ /**
+ * If you inherit methods you cannot have incompatible return types (java1.5 will
+ * make this a little messier).
+ */
+ public void test_overriddenMethodsCantHaveIncompatibleReturnTypes() {
+ File testBase = new File(baseDir,"TestB");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestB"),
+ new String[]{"Top2.java","Middle2.java","Super.java","Sub.java"},
+ new String[]{"Aspect2.java"},true);
+ }
+
+
+ /**
+ * Testing: If you inherit abstract methods and you are not abstract you need to provide
+ * an implementation.
+ *
+ * Test 1 in this set is simple.
+ */
+ public void test_inheritedAbstractMethodsMustBeImplemented_1() {
+ File testBase = new File(baseDir,"TestB");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestB"),
+ new String[]{"Top3.java","Middle3.java","Super.java","Sub.java"},
+ new String[]{"Aspect3.java"},true);
+ }
+
+ /**
+ * Testing: If the decp makes you implement an interface, you must provide the implementation
+ */
+ public void test_interfaceMethodsImplemented() {
+ File testBase = new File(baseDir,"TestD");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(testBase,
+ new String[]{"SimpleClass1.java","SimpleIntf1.java"},
+ new String[]{"SimpleAspect1.java"},true);
+ }
+
+ /**
+ * Testing: If you inherit abstract methods and you are not abstract you need to provide
+ * an implementation.
+ *
+ * Test 2 in this set includes methods further up the hierarchy that must be
+ * implemented.
+ */
+ public void test_inheritedAbstractMethodsMustBeImplemented_2() {
+ File testBase = new File(baseDir,"TestB");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestB"),
+ new String[]{"TopTop4.java","Top4.java","Middle4.java"},
+ new String[]{"Aspect4.java"},true);
+ }
+
+
+ /**
+ * Testing: If you inherit abstract methods and you are not abstract you need to provide
+ * an implementation.
+ *
+ * Test 3 in this set includes methods further up the hierarchy that must be
+ * implemented *and* the dependencies are satisfied by ITDs from the aspect
+ */
+ public void test_inheritedAbstractMethodsMustBeImplemented_3() {
+ File testBase = new File(baseDir,"TestD");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(new File(baseDir,"TestD"),
+ new String[]{"SimpleClass2.java"},
+ new String[]{"SimpleAspect2.java"},true);
+ }
+
+ /**
+ * If adding a type into a hierarchy, any missing ctor could be added via an ITDC so allow for
+ * that !
+ */
+ public void test_missingCtorAddedViaITD() {
+ File testBase = new File(baseDir,"TestE");
+ CompilationResult result = null;
+ runSourceAndBinaryTestcase(testBase,
+ new String[]{"A.java","B.java","C.java"},
+ new String[]{"X.java"},true);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ public void runSourceAndBinaryTestcase(File testBase,String[] classes,String[] aspects,boolean expectErrors) {
+ runSourceAndBinaryTestcase(testBase,classes,aspects,expectErrors,true);
+ }
+
+ public void runSourceAndBinaryTestcase(File testBase,String[] classes,String[] aspects,boolean expectErrors,boolean compareErrors) {
+ // Do a compile of everything together from source ...
+ CompilationResult result = null;
+
+ // Execute: "ajc <classes> <aspects> -showWeaveInfo"
+ String[] sourceCompileCommandLine = new String[classes.length+aspects.length+1];
+ System.arraycopy(classes,0,sourceCompileCommandLine,0,classes.length);
+ System.arraycopy(aspects,0,sourceCompileCommandLine,classes.length,aspects.length);
+ String[] extraOption = new String[]{"-showWeaveInfo"};
+ System.arraycopy(extraOption,0,sourceCompileCommandLine,classes.length+aspects.length,1);
+ result = ajc(testBase,sourceCompileCommandLine);
+ if (!expectErrors) assertTrue("errors? \n"+result.getErrorMessages(),!result.hasErrorMessages());
+ List sourceWeaveMessages = getWeaveMessages(result);
+ int sourceWeaveMessagesCount = sourceWeaveMessages.size();
+ List sourceErrorMessages = result.getErrorMessages();
+ int sourceErrorMessagesCount = sourceErrorMessages.size();
+
+ if (verbose) {
+ System.err.println("Source Compilation: Error count = "+sourceErrorMessagesCount+"\n"+sourceErrorMessages);
+ System.err.println("Source Compilation: Weaving count = "+sourceWeaveMessagesCount+"\n"+sourceWeaveMessages);
+ }
+
+ // Do separate compiles of the classes then the aspects then do a binary weave
+
+ // Execute: "ajc <classes> -g -d classes"
+ result = ajc(testBase,mergeOptions(classes,new String[]{"-g","-d","classes"}));
+ setShouldEmptySandbox(false);
+ // Execute: "ajc <aspects> -g -outjar aspects.jar -classpath classes -proceedOnError"
+ result = ajc(testBase,mergeOptions(aspects,new String[]{"-g","-outjar","aspects.jar","-classpath","classes","-proceedOnError"}));
+ if (result.getErrorMessages().size()!=0) System.err.println("Errors from jar building\n"+result.getErrorMessages());
+ assertTrue("Shouldn't get errors for this compile, but got: "+result.getErrorMessages().size(),result.getErrorMessages().size()==0);
+ // Execute: "ajc -inpath classes -showWeaveInfo -d classes2 -aspectpath aspects.jar"
+ result = ajc(testBase,new String[]{"-inpath","classes","-showWeaveInfo","-d","classes2","-aspectpath","aspects.jar"});
+
+ if (!expectErrors) assertTrue("unexpected errors? \n"+result.getErrorMessages(),!result.hasErrorMessages());
+
+ List binaryWeaveMessages = getWeaveMessages(result);
+ int binaryWeaveMessagesCount = binaryWeaveMessages.size();
+ List binaryErrorMessages = result.getErrorMessages();
+ int binaryErrorMessagesCount = binaryErrorMessages.size();
+
+ if (verbose) {
+ System.err.println("Binary Compilation: Error count = "+binaryErrorMessagesCount+"\n"+binaryErrorMessages);
+ System.err.println("Binary Compilation: Weaving count = "+binaryWeaveMessagesCount+"\n"+binaryWeaveMessages);
+ System.err.println("StandardError from final binary compile stage: "+result.getStandardError());
+ }
+
+ assertTrue("Should have same number of errors in either case: "+sourceErrorMessagesCount+"!="+binaryErrorMessagesCount,
+ sourceErrorMessagesCount==binaryErrorMessagesCount);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Check the error messages are comparable (allow for differing orderings)
+ if (compareErrors) {
+ for (Iterator iter = binaryErrorMessages.iterator(); iter.hasNext();) {
+ IMessage binaryMessage = (IMessage) iter.next();
+ IMessage correctSourceMessage = null;
+ for (Iterator iterator = sourceErrorMessages.iterator(); iterator.hasNext() && correctSourceMessage==null;) {
+ IMessage sourceMessage = (IMessage) iterator.next();
+
+ if (sourceMessage.getMessage().equals(binaryMessage.getMessage())) {
+ correctSourceMessage = sourceMessage;
+ }
+ }
+ if (correctSourceMessage == null) {
+ fail("This error obtained during binary weaving '"+binaryMessage+"' has no equivalent in the list of messages from source compilation");
+ }
+ sourceErrorMessages.remove(correctSourceMessage);
+ }
+ if (sourceErrorMessages.size()>0) {
+ for (Iterator iter = sourceErrorMessages.iterator(); iter.hasNext();) {
+ IMessage srcMsg = (IMessage) iter.next();
+ System.err.println("This error message from source compilation '"+srcMsg+"' didn't occur during binary weaving.");
+ }
+ fail("Got "+sourceErrorMessages.size()+" extra error messages during source compilation");
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Check the weaving messages are comparable
+ if (sourceWeaveMessagesCount!=binaryWeaveMessagesCount) {
+ fail("Didn't get same number of weave info messages when source weaving and binary weaving: "+sourceWeaveMessagesCount+"!="+binaryWeaveMessagesCount);
+ }
+
+ // Check weaving messages are comparable
+ for (int i=0; i<sourceWeaveMessages.size(); i++) {
+ IMessage m1 = (IMessage)sourceWeaveMessages.get(i);
+ IMessage m2 = (IMessage)binaryWeaveMessages.get(i);
+ String s1 = m1.getDetails();
+ String s2 = m2.getDetails();
+
+ if (!s1.equals(s2)) {
+ System.err.println("Source Weave Messages: #"+sourceWeaveMessages.size()+"\n"+sourceWeaveMessages);
+ System.err.println("Binary Weave Messages: #"+binaryWeaveMessages.size()+"\n"+binaryWeaveMessages);
+ fail("Two weaving messages aren't the same?? sourceMessage=["+s1+"] binaryMessage=["+s2+"]");
+ }
+ if (m1.getSourceLocation()!=null || m2.getSourceLocation()!=null) {
+ if (!m1.getSourceLocation().equals(m2.getSourceLocation())) {
+ fail("Different source locations for weaving messages? \n"+m1.getSourceLocation()+"\n"+m2.getSourceLocation()) ;
+ }
+ }
+ }
+
+// // Check the result of binary weaving !
+// ClassPath cp = new ClassPath(ajc.getSandboxDirectory()+File.separator+"classes2"+
+// File.pathSeparator+System.getProperty("sun.boot.class.path"));
+// System.err.println(cp);
+// SyntheticRepository r = SyntheticRepository.getInstance(cp);
+// Repository.setRepository(r);
+// for (int i = 0; i < classes.length; i++) {
+// String name = classes[i].substring(0,classes[i].lastIndexOf("."));
+// List verificationProblems = verify(name);
+// assertTrue("Did not expect any verification problems for class: "+name+": \n"+verificationProblems,verificationProblems.size()==0);
+// }
+ }
+
+ public String[] mergeOptions(String[] input,String[] extras) {
+ String[] ret = new String[input.length+extras.length];
+ System.arraycopy(input,0,ret,0,input.length);
+ System.arraycopy(extras,0,ret,input.length,extras.length);
+ return ret;
+ }
+
+
+
+
+ private List getWeaveMessages(CompilationResult result) {
+ List infoMessages = result.getInfoMessages();
+ List weaveMessages = new ArrayList();
+ for (Iterator iter = infoMessages.iterator(); iter.hasNext();) {
+ IMessage element = (IMessage) iter.next();
+ if (element.getKind()== IMessage.WEAVEINFO) weaveMessages.add(element);
+ }
+ return weaveMessages;
+ }
+
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ baseDir = new File("../org.aspectj.ajdt.core/testdata",PROJECT_DIR);
+ }
+
+ private List verify(String name) {
+ List verifyProblems = new ArrayList();
+ System.out.println("Now verifying: "+name+"\n");
+
+ Verifier v = VerifierFactory.getVerifier(name);
+ VerificationResult vr;
+
+ vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK) verifyProblems.add("Pass1: "+vr.getMessage());
+
+ vr = v.doPass2();
+ if (vr != VerificationResult.VR_OK) verifyProblems.add("Pass2: "+vr.getMessage());
+
+ if (vr == VerificationResult.VR_OK){
+ JavaClass jc = Repository.lookupClass(name);
+ for (int i=0; i<jc.getMethods().length; i++){
+ vr = v.doPass3a(i);
+ if (vr != VerificationResult.VR_OK) verifyProblems.add("Pass3a: "+jc.getMethods()[i]+" "+vr.getMessage());
+
+ vr = v.doPass3b(i);
+ if (vr != VerificationResult.VR_OK) verifyProblems.add("Pass3b: "+jc.getMethods()[i]+" "+vr.getMessage());
+ }
+ }
+
+ System.out.println("Warnings:");
+ String[] warnings = v.getMessages();
+ if (warnings.length == 0) System.out.println("<none>");
+ for (int j=0; j<warnings.length; j++){
+ System.out.println(warnings[j]);
+ }
+
+ System.out.println("\n");
+
+ // avoid swapping.
+ v.flush();
+ Repository.clearCache();
+ return verifyProblems;
+ }
+
+ private void runClass(String name) {
+ RunResult rr = null;
+ try {
+ rr = run(name,new String[]{},ajc.getSandboxDirectory()+File.separator+"classes2");
+ } catch (VerifyError ve) {
+ ve.printStackTrace();
+ fail("Unexpected VerifyError for type upon which we declared parents");
+ }
+ //assertTrue("Didn't expect any errors from the run of "+name+", but got: "+rr.toString(),rr.get);
+ }
+
+}