Skip to content

Commit

Permalink
Fix for #518 (#519)
Browse files Browse the repository at this point in the history
* Adding TestBox tests for issue 518

* Updating aop.getAliases function to use dottedPath instead of beanName.

* Updating ioc.variables.beanInfo to not include the beanName, if there are 2 different beans with the same name.

* Removing duplicate beans from beanNames array.

* Removing whitespace changes in file with only whitespace changes.
  • Loading branch information
LordBrom authored Jul 21, 2020
1 parent 9e4394d commit ef81c47
Show file tree
Hide file tree
Showing 18 changed files with 632 additions and 26 deletions.
30 changes: 12 additions & 18 deletions framework/aop.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ component extends="framework.ioc" {
{
// build the interceptor array:
var beanName = listLast(arguments.dottedPath, ".");
var beanNames = getAliases(beanName);
var beanNames = getAliases(arguments.dottedPath);
var beanTypes = "";
var interceptDefinition = "";
var interceptedBeanName = "";
Expand All @@ -128,6 +128,8 @@ component extends="framework.ioc" {

arrayPrepend(beanNames, beanName);

// Removing duplicate beanNames
beanNames = listToArray(listRemoveDuplicates(arrayToList(beanNames),",",true) );

// Grab all name based interceptors that match.
for (interceptedBeanName in beanNames)
Expand Down Expand Up @@ -185,7 +187,7 @@ component extends="framework.ioc" {
var interceptedBeanName = "";
var interceptorDefinition = {};
var beanName = listLast(arguments.dottedPath, ".");
var beanNames = getAliases(beanName);
var beanNames = getAliases(arguments.dottedPath);
var beanTypes = "";


Expand Down Expand Up @@ -234,29 +236,21 @@ component extends="framework.ioc" {
}


/** Finds all aliases for the given beanName. */
private array function getAliases(string beanName)
/** Finds all aliases for the given dottedPath. */
private array function getAliases(string dottedPath)
{
var aliases = [];
var beanData = "";
var key = "";


if (structKeyExists(variables.beanInfo, arguments.beanName))
for (key in variables.beanInfo)
{
beanData = variables.beanInfo[arguments.beanName];

for (key in variables.beanInfo)
// Same cfc dotted path, must be an alias.
if (
structKeyExists(variables.beanInfo[key], "cfc") &&
variables.beanInfo[key].cfc == arguments.dottedPath)
{
// Same cfc dotted path, must be an alias.
if (
key != arguments.beanName &&
structKeyExists(variables.beanInfo[key], "cfc") &&
structKeyExists(variables.beanInfo[arguments.beanName], "cfc") &&
variables.beanInfo[key].cfc == variables.beanInfo[arguments.beanName].cfc)
{
arrayAppend(aliases, key);
}
arrayAppend(aliases, key);
}
}

Expand Down
25 changes: 17 additions & 8 deletions framework/ioc.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ component {
} catch ( any e ) {
// assume bad path - ignore it, cfcs is empty list
}
local.beansWithDuplicates = "";
for ( var cfcOSPath in cfcs ) {
var cfcPath = replace( cfcOSPath, chr(92), '/', 'all' );
// watch out for excluded paths:
Expand All @@ -561,18 +562,26 @@ component {
if ( structKeyExists( metadata.metadata, "type" ) && metadata.metadata.type == "interface" ) {
continue;
}
if ( structKeyExists( variables.beanInfo, beanName ) ) {
if ( variables.config.omitDirectoryAliases ) {
throw '#beanName# is not unique (and omitDirectoryAliases is true)';

if ( variables.config.omitDirectoryAliases ) {
if ( structKeyExists( variables.beanInfo, beanName ) ) {
throw '#beanName# is not unique';
}
structDelete( variables.beanInfo, beanName );
variables.beanInfo[ beanName & singleDir ] = metadata;
} else {
variables.beanInfo[ beanName ] = metadata;
if ( !variables.config.omitDirectoryAliases ) {
variables.beanInfo[ beanName & singleDir ] = metadata;
} else {
if ( listFindNoCase(local.beansWithDuplicates, beanName) ) {}
else if ( structKeyExists( variables.beanInfo, beanName ) ) {
structDelete( variables.beanInfo, beanName );
local.beansWithDuplicates = listAppend(local.beansWithDuplicates, beanName);
} else {
variables.beanInfo[ beanName ] = metadata;
}
if ( structKeyExists( variables.beanInfo, beanName & singleDir ) ) {
throw '#beanName & singleDir# is not unique';
}
variables.beanInfo[ beanName & singleDir ] = metadata;
}

} catch ( any e ) {
// wrap the exception so we can add bean name for debugging
// this trades off any stack trace information for the bean name but
Expand Down
289 changes: 289 additions & 0 deletions tests/CombinedInterceptorsTestIssue518.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
component extends="mxunit.framework.TestCase" {

function TestBeforeAroundAfterInterception() {
//Putting it all together What happens when you call all of them?
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});
//add an Interceptor

bf.intercept("ReverseService", "BeforeInterceptor");
bf.intercept("ReverseService", "AroundInterceptor");
bf.intercept("ReverseService", "AfterInterceptor");

rs = bf.getBean("ReverseService");
result = rs.doReverse("Hello!");


AssertEquals("around," & Reverse("beforeHello!") & ",around", result);
AssertEquals(4, arrayLen(request.callstack));
AssertEquals("before,around,doReverse,after", arrayToList(request.callstack));
}


function TestInitMethods() {
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {initMethod = "configure"});

bf.intercept("advReverse", "BeforeInterceptor");

rs = bf.getBean("advReverseService");
result = rs.doWrap("Hello!");

// First test does not intercept the (init, set..., or initMethod) methods.
AssertEquals(9, arrayLen(request.callstack));
AssertEquals( "init,setStackLog,configure,before,dowrap,before,dofront,before,dorear",
arrayToList(request.callstack),
"This test shows that the (init, set..., and configure) methods are by default ignored.");


request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {initMethod = "configure"});

bf.intercept("advReverse", "BeforeInterceptor", "init,configure,setStackLog,doWrap");

rs = bf.getBean("advReverseService");
result = rs.doWrap("Hello!");

// Explicitly intercept the (init, set..., or initMethod) methods.
AssertEquals(10, arrayLen(request.callstack));
AssertEquals( "before,init,before,setStackLog,before,configure,before,dowrap,dofront,dorear",
arrayToList(request.callstack),
"This test shows that the (init, set..., and configure) methods can be explicitly intercepted.");
}


function TestInterceptOnRegex() {
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {initMethod = "configure"});

//add an Interceptor
bf.intercept("/^reverse.*$/", "BeforeInterceptor");

ars = bf.getBean("advReverseService");
rs = bf.getBean("reverse");
as = bf.getBean("array");


result = ars.doWrap("Hello!");
result2 = rs.doReverse("Hello!");
result3 = as.doListToArray("dog,cat,mouse");


AssertEquals("front-Hello!-rear", result);
AssertEquals("!olleHerofeb", result2);
AssertTrue(isArray(result3));
AssertEquals("dog,cat,mouse", arrayToList(result3));

AssertEquals(9, arrayLen(request.callstack));
AssertEquals("init,setStackLog,configure,doWrap,doFront,doRear,before,doReverse,doListToArray", arrayToList(request.callstack));
}


function TestInterceptOnType() {
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {initMethod = "configure"});

//add an Interceptor
bf.interceptByType("string", "BeforeInterceptor", "doReverse,doForward,doWrap");

ars = bf.getBean("advReverseService");
rs = bf.getBean("reverse");
as = bf.getBean("array");


result = ars.doWrap("Hello!");
result2 = rs.doReverse("Hello!");
result3 = as.doListToArray("dog,cat,mouse");


AssertEquals("front-beforeHello!-rear", result);
AssertEquals("!olleHerofeb", result2);
AssertTrue(isArray(result3));
AssertEquals("dog,cat,mouse", arrayToList(result3));

AssertEquals(10, arrayLen(request.callstack));
AssertEquals("init,setStackLog,configure,before,doWrap,doFront,doRear,before,doReverse,doListToArray", arrayToList(request.callstack));
}


function TestMultipleBeforeInterceptions() {
//Multiple Before Advisors
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});

//Need to create different Before interceptors
bf.declareBean("BeforeInterceptorA", "tests.issue518.interceptors.aop.BeforeInterceptor", true, {name = "beforeA"});
bf.declareBean("BeforeInterceptorB", "tests.issue518.interceptors.aop.BeforeInterceptor", true, {name = "beforeB"});
bf.declareBean("BeforeInterceptorC", "tests.issue518.interceptors.aop.BeforeInterceptor", true, {name = "beforeC"});

bf.intercept("ReverseService", "BeforeInterceptorA");
bf.intercept("ReverseService", "BeforeInterceptorB");
bf.intercept("ReverseService", "BeforeInterceptorC");

rs = bf.getBean("ReverseService");
result = rs.doReverse("Hello!");

AssertEquals(reverse("beforebeforebeforeHello!"), result);
AssertEquals(4, arrayLen(request.callstack));
AssertEquals("beforeA,beforeB,beforeC,doReverse", arrayToList(request.callstack));
}


function TestMultipleAfterInterceptors() {
//Multiple After Advisors
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});

//Need to create different After interceptors
bf.declareBean("AfterInterceptorA", "tests.issue518.interceptors.aop.AfterInterceptor", true, {name = "afterA"});
bf.declareBean("AfterInterceptorB", "tests.issue518.interceptors.aop.AfterInterceptor", true, {name = "afterAlterResultB"});
bf.declareBean("AfterInterceptorC", "tests.issue518.interceptors.aop.AfterInterceptor", true, {name = "afterC"});


bf.intercept("ReverseService", "AfterInterceptorA");
bf.intercept("ReverseService", "AfterInterceptorB");
bf.intercept("ReverseService", "AfterInterceptorC");


rs = bf.getBean("ReverseService");
result = rs.doReverse("Hello!");

AssertEquals(reverse("Hello!") & ",afterAlterResultB", result);
AssertEquals(4, arrayLen(request.callstack));
AssertEquals("doReverse,afterA,afterAlterResultB,afterC", arrayToList(request.callstack));
}


function TestMultipleAroundInterceptors() {
//Multiple Around Advisors
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});


//Need to create different After interceptors
bf.declareBean("AroundInterceptorA", "tests.issue518.interceptors.aop.AroundInterceptor", true, {name = "aroundA"});
bf.declareBean("AroundInterceptorB", "tests.issue518.interceptors.aop.AroundInterceptor", true, {name = "aroundB"});
bf.declareBean("AroundInterceptorC", "tests.issue518.interceptors.aop.AroundInterceptor", true, {name = "aroundC"});


bf.intercept("ReverseService", "AroundInterceptorA");
bf.intercept("ReverseService", "AroundInterceptorB");
bf.intercept("ReverseService", "AroundInterceptorC");
rs = bf.getBean("ReverseService");

result = rs.doReverse("Hello!");

AssertEquals("aroundA,aroundB,aroundC," & reverse("Hello!") & ",aroundC,aroundB,aroundA", result);
AssertEquals(4, arrayLen(request.callstack));
AssertEquals("aroundA,aroundB,aroundC,doReverse", arrayToList(request.callstack));
}


function TestMethodMatches() {
bf = new framework.ioc('/tests/issue518', {});
rs = bf.getBean("Reverse");

proxy = new framework.beanProxy(rs, [], {});
makePublic( proxy, "methodMatches" );

AssertFalse(proxy.methodMatches("doForward", "doReverse"));
AssertTrue(proxy.methodMatches("doForward", ""));
AssertTrue(proxy.methodMatches("doForward", "*"));
AssertFalse(proxy.methodMatches("doForward", "doReverse,"));
AssertTrue(proxy.methodMatches("doForward", "doReverse,doForward"));
}


function TestNamedMethodInterceptions() {
//Named Method Interceptions

request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});
//add an Interceptor
bf.intercept("ReverseService", "BeforeInterceptor", "doReverse");

rs = bf.getBean("ReverseService");

// This should be intercepted.
result = rs.doReverse("Hello!");

// This shoud not be intercepted.
result2 = rs.doForward("Hello!");


// This should be intercepted.
result3 = rs.doReverse("Hello!");

AssertEquals(reverse("beforeHello!"), result);
AssertEquals("hello!", result2);
AssertEquals(reverse("beforeHello!"), result3);
AssertEquals(5, arrayLen(request.callstack));
AssertEquals("before,doReverse,doForward,before,doReverse", arrayToList(request.callstack));
}


function TestOnErrorInterceptors() {
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});
rs = bf.getBean("ReverseService");
result2 = rs.doForward("Hello!");


AssertEquals("Hello!", result2);
AssertEquals(1, arrayLen(request.callstack));
AssertEquals("doForward", arrayToList(request.callstack));


request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});
//add an Interceptor
bf.intercept("ReverseService", "ErrorInterceptor", "throwError");

rs = bf.getBean("ReverseService");
rs.throwError();

AssertEquals(2, arrayLen(request.callstack));
AssertEquals("throwError,onError", arrayToList(request.callstack));
}


function TestPrivateMethodInterceptors() {
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {initMethod = "configure"});

//add an Interceptor
bf.intercept("advReverseService", "BeforeInterceptor", "doFront");

rs = bf.getBean("advReverseService");

result = rs.doWrap("Hello!");

AssertEquals("front-beforeHello!-rear", result);
AssertEquals(7, arrayLen(request.callstack));
AssertEquals("init,setStackLog,configure,doWrap,before,doFront,doRear", arrayToList(request.callstack));
}


function TestSingleInterceptorOnMultipleObjects() {
//Multiple Around Advisors
request.callstack = []; //reset
bf = new framework.aop('/tests/issue518', {});


//Need to create different After interceptors
bf.declareBean("AroundInterceptorA", "tests.issue518.interceptors.aop.AroundInterceptor", true, {name = "aroundA"});


bf.intercept("advReverse", "AroundInterceptorA", "doWrap");
bf.intercept("ReverseService", "AroundInterceptorA", "doReverse");

rs = bf.getBean("ReverseService");
ars = bf.getBean("advReverseService");

result = ars.doWrap(rs.doReverse("Hello!"));

AssertEquals("aroundA,front-aroundA," & reverse("Hello!") & ",aroundA-rear,aroundA", result);
AssertEquals(8, arrayLen(request.callstack));
AssertEquals("init,setStackLog,aroundA,doReverse,aroundA,doWrap,doFront,doRear", arrayToList(request.callstack));
}
}
Loading

0 comments on commit ef81c47

Please sign in to comment.