PointcutRewriterTest.java
/* *******************************************************************
* Copyright (c) 2004 IBM Corporation.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* ******************************************************************/
package org.aspectj.weaver.patterns;
import java.util.Set;
import junit.framework.TestCase;
import org.aspectj.weaver.Shadow;
import static org.aspectj.weaver.patterns.LogicalPointcutStructure.*;
/**
* Testing the pointcut rewriter.
*
* @author Adrian Colyer
* @author Andy Clement
* @author Alexander Kriegisch
*/
public class PointcutRewriterTest extends TestCase {
private PointcutRewriter prw;
public void testComplexRewrite1() {
Pointcut p = getPointcut("(persingleton(org.eclipse.ajdt.internal.ui.ras.UIFFDC) && ((handler(java.lang.Throwable+) && args(arg1)) && ((within(org.eclipse.ajdt..*) && (!within(org.eclipse.ajdt.internal.ui.lazystart..*) && (!within(org.eclipse.ajdt.internal.ui.dialogs.OpenTypeSelectionDialog2) && !(within(org.eclipse.ajdt.internal.ui.editor.AspectJBreakpointRulerAction) && handler(org.eclipse.jface.text.BadLocationException))))) && (!(within(org.eclipse.ajdt.core.ras.FFDC+) || handler(org.eclipse.core.runtime.OperationCanceledException)) && !this(java.lang.Object)))))");
checkMultipleRewrite(p);
p = getPointcut("((((((((((!within(org.eclipse.ajdt.internal.ui.lazystart..*) && !within(org.eclipse.ajdt.internal.ui.dialogs.OpenTypeSelectionDialog2)) && !within(org.eclipse.ajdt.core.ras.FFDC+)) && within(org.eclipse.ajdt..*)) && !within(org.eclipse.ajdt.internal.ui.editor.AspectJBreakpointRulerAction)) && handler(java.lang.Throwable+)) && !handler(org.eclipse.core.runtime.OperationCanceledException)) && !this(java.lang.Object)) && args(arg1)) && persingleton(org.eclipse.ajdt.internal.ui.ras.UIFFDC)) || (((((((((!within(org.eclipse.ajdt.internal.ui.lazystart..*) && !within(org.eclipse.ajdt.internal.ui.dialogs.OpenTypeSelectionDialog2)) && !within(org.eclipse.ajdt.core.ras.FFDC+)) && within(org.eclipse.ajdt..*)) && !handler(org.eclipse.jface.text.BadLocationException)) && handler(java.lang.Throwable+)) && !handler(org.eclipse.core.runtime.OperationCanceledException)) && !this(java.lang.Object)) && args(arg1)) && persingleton(org.eclipse.ajdt.internal.ui.ras.UIFFDC)))");
checkMultipleRewrite(p);
p = getPointcut("(persingleton(Oranges) && ((handler(Apples+) && args(arg1)) && ((within(foo..*) && (!within(org.eclipse.ajdt.internal.ui.lazystart..*) && (!within(org.eclipse.ajdt.internal.ui.dialogs.OpenTypeSelectionDialog2) && !(within(org.eclipse.ajdt.internal.ui.editor.AspectJBreakpointRulerAction) && handler(org.eclipse.jface.text.BadLocationException))))) && (!(within(org.eclipse.ajdt.core.ras.FFDC+) || handler(org.eclipse.core.runtime.OperationCanceledException)) && !this(java.lang.Object)))))");
checkMultipleRewrite(p);
p = getPointcut("(((handler(Apples+)) && ((within(foo..*) && (!within(org.eclipse.ajdt.internal.ui.lazystart..*) && (!within(org.eclipse.ajdt.internal.ui.dialogs.OpenTypeSelectionDialog2) && !(within(org.eclipse.ajdt.internal.ui.editor.AspectJBreakpointRulerAction) && handler(org.eclipse.jface.text.BadLocationException))))) && (!(within(org.eclipse.ajdt.core.ras.FFDC+) || handler(org.eclipse.core.runtime.OperationCanceledException)) && !this(java.lang.Object)))))");
checkMultipleRewrite(p);
p = getPointcut("within(xxx..*) && within(XXY) && within(org.eclipse.AspectJBreakpoint)");
checkMultipleRewrite(p);
}
/**
* Rewrites a pointcut twice and checks the format is stable
*/
private void checkMultipleRewrite(Pointcut p) {
Pointcut rewrittenPointcut = prw.rewrite(p, false);
String rewrite = rewrittenPointcut.toString();
Pointcut rewriteOfRewrittenPointcut = prw.rewrite(rewrittenPointcut, false);
String rewriteOfRewritten = rewriteOfRewrittenPointcut.toString();
assertEquals(rewrite, rewriteOfRewritten);
}
public void testDistributeNot() {
Pointcut plain = getPointcut("this(Foo)");
assertEquals("Unchanged", plain, prw.rewrite(plain));
Pointcut not = getPointcut("!this(Foo)");
assertEquals("Unchanged", not, prw.rewrite(not));
Pointcut notNot = getPointcut("!!this(Foo)");
assertEquals("this(Foo)", prw.rewrite(notNot).toString());
Pointcut notNotNOT = getPointcut("!!!this(Foo)");
assertEquals("!this(Foo)", prw.rewrite(notNotNOT).toString());
Pointcut and = getPointcut("!(this(Foo) && this(Goo))");
assertEquals(OR(NOT("this(Foo)"), NOT("this(Goo)")), fromPointcut(prw.rewrite(and, true)));
Pointcut or = getPointcut("!(this(Foo) || this(Goo))");
assertEquals(AND(NOT("this(Foo)"), NOT("this(Goo)")), fromPointcut(prw.rewrite(or, true)));
Pointcut nestedNot = getPointcut("!(this(Foo) && !this(Goo))");
assertEquals(OR(NOT("this(Foo)"), "this(Goo)"), fromPointcut(prw.rewrite(nestedNot, true)));
}
public void testPullUpDisjunctions() {
assertEquals(
AND("this(Foo)", "this(Goo)"),
fromPointcut(prw.rewrite(getPointcut("this(Foo) && this(Goo)")))
);
assertEquals(
OR("this(Foo)", "this(Moo)"),
fromPointcut(prw.rewrite(getPointcut("this(Foo) || this(Moo)")))
);
assertEquals(
OR("this(Foo)", AND("this(Goo)", "this(Boo)")),
fromPointcut(prw.rewrite(getPointcut("this(Foo) || (this(Goo) && this(Boo))")))
);
assertEquals(
OR(AND("this(Goo)", "this(Boo)"), "this(Foo)"),
fromPointcut(prw.rewrite(getPointcut("(this(Goo) && this(Boo)) || this(Foo)")))
);
// The previous two are semantically identical
assertEquals(
fromPointcut(prw.rewrite(getPointcut("this(Foo) || (this(Goo) && this(Boo))"))),
fromPointcut(prw.rewrite(getPointcut("(this(Goo) && this(Boo)) || this(Foo)")))
);
assertEquals(
OR(AND("this(Foo)", "this(Goo)"), AND("this(Foo)", "this(Boo)")),
fromPointcut(prw.rewrite(getPointcut("this(Foo) && (this(Goo) || this(Boo))")))
);
assertEquals(
OR(AND("this(Foo)", "this(Goo)"), AND("this(Foo)", "this(Boo)")),
fromPointcut(prw.rewrite(getPointcut("(this(Goo) || this(Boo)) && this(Foo)")))
);
// The previous two are semantically identical
assertEquals(
fromPointcut(prw.rewrite(getPointcut("this(Foo) && (this(Goo) || this(Boo))"))),
fromPointcut(prw.rewrite(getPointcut("(this(Goo) || this(Boo)) && this(Foo)")))
);
assertEquals(
OR("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Foo) || this(Goo) || this(Boo)")))
);
assertEquals(
OR("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Boo) || this(Goo) || this(Foo)")))
);
assertEquals(
OR("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Boo) || this(Foo) || this(Goo)")))
);
assertEquals(
AND("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Foo) && this(Goo) && this(Boo)")))
);
assertEquals(
AND("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Boo) && this(Goo) && this(Foo)")))
);
assertEquals(
AND("this(Foo)", "this(Goo)", "this(Boo)"),
fromPointcut(prw.rewrite(getPointcut("this(Boo) && this(Foo) && this(Goo)")))
);
assertEquals(
OR(AND("this(Foo)", "this(Boo)", "this(Moo)"), AND("this(Foo)", "this(Boo)", "this(Goo)")),
fromPointcut(prw.rewrite(getPointcut("(this(Foo) && (this(Boo) && (this(Goo) || this(Moo))))")))
);
}
/*
public void testSplitOutWithins() {
Pointcut simpleExecution = getPointcut("execution(* *.*(..))");
assertEquals("Unchanged", simpleExecution, prw.rewrite(simpleExecution));
Pointcut simpleWithinCode = getPointcut("withincode(* *.*(..))");
assertEquals("Unchanged", simpleWithinCode, prw.rewrite(simpleWithinCode));
Pointcut execution = getPointcut("execution(@Foo Foo (@Goo org.xyz..*).m*(Foo,Boo))");
assertEquals("(within((@(Goo) org.xyz..*)) && execution(@(Foo) Foo m*(Foo, Boo)))", prw.rewrite(execution).toString());
Pointcut withincode = getPointcut("withincode(@Foo Foo (@Goo org.xyz..*).m*(Foo,Boo))");
assertEquals("(within((@(Goo) org.xyz..*)) && withincode(@(Foo) Foo m*(Foo, Boo)))", prw.rewrite(withincode).toString());
Pointcut notExecution = getPointcut("!execution(Foo BankAccount+.*(..))");
assertEquals("(!within(BankAccount+) || !execution(Foo *(..)))", prw.rewrite(notExecution).toString());
Pointcut andWithincode = getPointcut("withincode(Foo.new(..)) && this(Foo)");
assertEquals("((within(Foo) && withincode(new(..))) && this(Foo))", prw.rewrite(andWithincode).toString());
Pointcut orExecution = getPointcut("this(Foo) || execution(Goo Foo.moo(Baa))");
assertEquals("((within(Foo) && execution(Goo moo(Baa))) || this(Foo))", prw.rewrite(orExecution).toString());
}
*/
public void testRemoveDuplicatesInAnd() {
Pointcut dupAnd = getPointcut("this(Foo) && this(Foo)");
assertEquals("this(Foo)", prw.rewrite(dupAnd).toString());
Pointcut splitdupAnd = getPointcut("(this(Foo) && target(Boo)) && this(Foo)");
assertEquals(AND("target(Boo)", "this(Foo)"), fromPointcut(prw.rewrite(splitdupAnd)));
}
public void testNotRemoveNearlyDuplicatesInAnd() {
Pointcut toAndto = getPointcut("this(Object+) && this(Object)");
assertEquals(AND("this(Object+)", "this(Object)"), fromPointcut(prw.rewrite(toAndto)));
}
public void testAAndNotAinAnd() {
Pointcut aAndNota = getPointcut("this(Foo)&& !this(Foo)");
assertEquals("Matches nothing", "", prw.rewrite(aAndNota).toString());
Pointcut aAndBAndNota = getPointcut("this(Foo) && execution(* *.*(..)) && !this(Foo)");
assertEquals("Matches nothing", "", prw.rewrite(aAndBAndNota).toString());
}
public void testIfFalseInAnd() {
Pointcut ifFalse = IfPointcut.makeIfFalsePointcut(Pointcut.CONCRETE);
Pointcut p = getPointcut("this(A)");
assertEquals("Matches nothing", "", prw.rewrite(new AndPointcut(ifFalse, p)).toString());
}
public void testMatchesNothinginAnd() {
Pointcut nothing = Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
Pointcut p = getPointcut("this(A)");
assertEquals("Matches nothing", "", prw.rewrite(new AndPointcut(nothing, p)).toString());
}
public void testMixedKindsInAnd() {
Pointcut mixedKinds = getPointcut("call(* *(..)) && execution(* *(..))");
assertEquals("Matches nothing", "", prw.rewrite(mixedKinds).toString());
Pointcut ok = getPointcut("this(Foo) && call(* *(..))");
assertEquals(ok, prw.rewrite(ok));
}
public void testDetermineKindSetOfAnd() {
Pointcut oneKind = getPointcut("execution(* foo(..)) && this(Boo)");
AndPointcut rewritten = (AndPointcut) prw.rewrite(oneKind);
assertEquals("Only one kind", 1, Shadow.howMany(rewritten.couldMatchKinds()));
assertTrue("It's Shadow.MethodExecution", Shadow.MethodExecution.isSet(rewritten.couldMatchKinds()));
}
public void testKindSetOfExecution() {
Pointcut p = getPointcut("execution(* foo(..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.MethodExecution", Shadow.MethodExecution.isSet(p.couldMatchKinds()));
p = getPointcut("execution(new(..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.ConstructorExecution", Shadow.ConstructorExecution.isSet(p.couldMatchKinds()));
}
public void testKindSetOfCall() {
Pointcut p = getPointcut("call(* foo(..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.MethodCall", Shadow.MethodCall.isSet(p.couldMatchKinds()));
p = getPointcut("call(new(..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.ConstructorCall", Shadow.ConstructorCall.isSet(p.couldMatchKinds()));
}
public void testKindSetOfAdviceExecution() {
Pointcut p = getPointcut("adviceexecution()");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.AdviceExecution", Shadow.AdviceExecution.isSet(p.couldMatchKinds()));
}
public void testKindSetOfGet() {
Pointcut p = getPointcut("get(* *)");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.FieldGet", Shadow.FieldGet.isSet(p.couldMatchKinds()));
}
public void testKindSetOfSet() {
Pointcut p = getPointcut("set(* *)");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.FieldSet", Shadow.FieldSet.isSet(p.couldMatchKinds()));
}
public void testKindSetOfHandler() {
Pointcut p = getPointcut("handler(*)");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.ExceptionHandler", Shadow.ExceptionHandler.isSet(p.couldMatchKinds()));
}
public void testKindSetOfInitialization() {
Pointcut p = getPointcut("initialization(new (..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.Initialization", Shadow.Initialization.isSet(p.couldMatchKinds()));
}
public void testKindSetOfPreInitialization() {
Pointcut p = getPointcut("preinitialization(new (..))");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.PreInitialization", Shadow.PreInitialization.isSet(p.couldMatchKinds()));
}
public void testKindSetOfStaticInitialization() {
Pointcut p = getPointcut("staticinitialization(*)");
assertEquals("Only one kind", 1, Shadow.howMany(p.couldMatchKinds()));
assertTrue("It's Shadow.StaticInitialization", Shadow.StaticInitialization.isSet(p.couldMatchKinds()));
}
public void testKindSetOfThis() {
Pointcut p = getPointcut("this(Foo)");
Set<Shadow.Kind> matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind o : matches) {
assertFalse("No kinds that don't have a this", o.neverHasThis());
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].neverHasThis()) {
assertTrue("All kinds that do have this", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
// + @
p = getPointcut("@this(Foo)");
matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind match : matches) {
assertFalse("No kinds that don't have a this", match.neverHasThis());
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].neverHasThis()) {
assertTrue("All kinds that do have this", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
}
public void testKindSetOfTarget() {
Pointcut p = getPointcut("target(Foo)");
Set<Shadow.Kind> matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind o : matches) {
assertFalse("No kinds that don't have a target", o.neverHasTarget());
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].neverHasTarget()) {
assertTrue("All kinds that do have target", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
// + @
p = getPointcut("@target(Foo)");
matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind match : matches) {
assertFalse("No kinds that don't have a target", match.neverHasTarget());
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].neverHasTarget()) {
assertTrue("All kinds that do have target", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
}
public void testKindSetOfArgs() {
Pointcut p = getPointcut("args(..)");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
// + @
p = getPointcut("@args(..)");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
}
public void testKindSetOfAnnotation() {
Pointcut p = getPointcut("@annotation(Foo)");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
}
public void testKindSetOfWithin() {
Pointcut p = getPointcut("within(*)");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
// + @
p = getPointcut("@within(Foo)");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
}
public void testKindSetOfWithinCode() {
Pointcut p = getPointcut("withincode(* foo(..))");
Set<Shadow.Kind> matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind o : matches) {
assertFalse("No kinds that are themselves enclosing",
(o.isEnclosingKind() && o != Shadow.ConstructorExecution && o != Shadow.Initialization));
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
assertTrue("All kinds that are not enclosing", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
assertTrue("Need cons-exe for inlined field inits", matches.contains(Shadow.ConstructorExecution));
assertTrue("Need init for inlined field inits", matches.contains(Shadow.Initialization));
// + @
p = getPointcut("@withincode(Foo)");
matches = Shadow.toSet(p.couldMatchKinds());
for (Shadow.Kind match : matches) {
assertFalse("No kinds that are themselves enclosing", match.isEnclosingKind());
}
for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
if (!Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
assertTrue("All kinds that are not enclosing", matches.contains(Shadow.SHADOW_KINDS[i]));
}
}
}
public void testKindSetOfIf() {
Pointcut p = new IfPointcut(null, 0);
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
p = IfPointcut.makeIfTruePointcut(Pointcut.CONCRETE);
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
p = IfPointcut.makeIfFalsePointcut(Pointcut.CONCRETE);
assertEquals("Nothing", p.couldMatchKinds(), Shadow.NO_SHADOW_KINDS_BITS);
}
public void testKindSetOfCflow() {
Pointcut p = getPointcut("cflow(this(Foo))");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
// [below]
p = getPointcut("cflowbelow(this(Foo))");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
}
public void testKindSetInNegation() {
Pointcut p = getPointcut("!execution(new(..))");
assertEquals("All kinds", p.couldMatchKinds(), Shadow.ALL_SHADOW_KINDS_BITS);
}
public void testKindSetOfOr() {
Pointcut p = getPointcut("execution(new(..)) || get(* *)");
Set<Shadow.Kind> matches = Shadow.toSet(p.couldMatchKinds());
assertEquals("2 kinds", 2, matches.size());
assertTrue("ConstructorExecution", matches.contains(Shadow.ConstructorExecution));
assertTrue("FieldGet", matches.contains(Shadow.FieldGet));
}
public void testOrderingInAnd() {
Pointcut bigLongPC = getPointcut("cflow(this(Foo)) && @args(X) && args(X) && @this(Foo) && @target(Boo) && this(Moo) && target(Boo) && @annotation(Moo) && @withincode(Boo) && withincode(new(..)) && set(* *) && @within(Foo) && within(Foo)");
checkMultipleRewrite(bigLongPC);
assertEquals(
AND("cflow(this(Foo))", "@args(X)", "args(X)", "@target(Boo)", "@this(Foo)", "@annotation(Moo)", "this(Moo)", "target(Boo)", "@withincode(Boo)", "withincode(new(..))", "set(* *)", "@within(Foo)", "within(Foo)"),
fromPointcut(prw.rewrite(bigLongPC))
);
}
public void testOrderingInSimpleOr() {
OrPointcut opc = (OrPointcut) getPointcut("execution(new(..)) || get(* *)");
assertEquals("reordered", "(get(* *) || execution(new(..)))", prw.rewrite(opc).toString());
}
public void testOrderingInNestedOrs() {
OrPointcut opc = (OrPointcut) getPointcut("(execution(new(..)) || get(* *)) || within(abc)");
assertEquals("reordered", "((within(abc) || get(* *)) || execution(new(..)))", prw.rewrite(opc).toString());
}
public void testOrderingInOrsWithNestedAnds() {
OrPointcut opc = (OrPointcut) getPointcut("get(* *) || (execution(new(..)) && within(abc))");
assertEquals("reordered", "((within(abc) && execution(new(..))) || get(* *))", prw.rewrite(opc).toString());
}
private Pointcut getPointcut(String s) {
return new PatternParser(s).parsePointcut();
}
/*
* @see TestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
prw = new PointcutRewriter();
}
}