diff options
author | aclement <aclement> | 2005-01-05 16:39:42 +0000 |
---|---|---|
committer | aclement <aclement> | 2005-01-05 16:39:42 +0000 |
commit | 7f81377868c16bb2ea666d83bd06a6651fbad60a (patch) | |
tree | b01d4f2b07aec196b3bd8f2cf663a9ad8e53fd55 | |
parent | 21dc11ccadbb301c13aae0b26a0e9b1178cd0dd5 (diff) | |
download | aspectj-7f81377868c16bb2ea666d83bd06a6651fbad60a.tar.gz aspectj-7f81377868c16bb2ea666d83bd06a6651fbad60a.zip |
BWD: test cases
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); + } + +} |