Friday 20 December 2013

CFML: Using TestBox to find bugs... but not in a way I expected

G'day:
I've been off work today because I need to use up my annual leave before the end of the year, and have basically been parked in front of the computer all day. A bit of a busman's holiday, really.

So I started using TestBox today ("Unit Testing / TDD - switching off MXUnit, switching on TestBox"), and quickly found (what seems to be ~) a bug once I finished the article and started writing the code for my next article.

The details for the TestBox bug are on the the ColdBox Google group: "[Testbox v1.0.0] "Variable ISEXPECTEDEXCEPTION is undefined" on erroring test". I've got no idea what's going on: as far as I can tell their code is fine, but I've not had a chance to investigate, because since I raised that, I've been trying to work out why the hell my code doesn't run on Railo.

However I've just isolated this "bug" in Railo, and here's the details.

Here's some test code (also on GitHub @ https://github.com/daccfml/scratch/tree/master/blogExamples/railo/componentresolution):

// Application.cfc
component {

    this.mappings = {
        "/differentpackage" = getDirectoryFromPath(getCurrentTemplatePath()) & "../differentpackage"
    };

}

<cfscript>
// test.cfm
proxy = new differentpackage.proxy("LocalComponent");

localComponent = proxy.getProxiedObject();

writeDump(var=variables);
</cfscript>

// differentpackage/Proxy.cfc
component {

    public Proxy function init(required string componentName){
        variables.componentName = arguments.componentName;
        return this;
    }

    public any function getProxiedObject(){
        return createObject(variables.componentName);
    }

}

// LocalComponent.cfc
component {
    
}

What this code is doing is using a proxy to create a different CFC instance. Not complicated, and something TestBox does with this code:

<!--- runTests.cfm --->
<cfoutput>
    #new testbox.system.testing.TestBox(
        bundles="Tests"
    ).run(
        reporter="simple"
    )#
</cfoutput>

In my code, the files are organised like this (I've highlighted the locations in the code, but this is clearer):

/componentresolution/
    differentpackage/
        Proxy.cfc
    appdir/
        Application.cfc
        LocalComponent.cfc
        test.cfm

So basically test.cfm is referring to LocalComponent.cfc by its path relative to test.cfm itself: completely unqualified "LocalComponent". And then Proxy.cfc (in a "differentpackage") uses whatever string was passed to it to create the object. From Proxy.cfc's perspective, an unqualified "LocalComponent" reference is meaningless, as there's no "LocalComponent" within its "differentpackage".

And I think this is where Railo is coming from, because its reaction to all these shenanigans is:

Railo 4.1.2.005 Error (expression)
Messageinvalid component definition, can't find LocalComponent
StacktraceThe Error Occurred in
C:\webroots\railo-express-4.1.x-jre-win64\webapps\www\shared\git\blogExamples\railo\componentresolution\differentpackage\Proxy.cfc: line 10 
8: 
9: public any function getProxiedObject(){
10: return createObject(variables.componentName);
11: }
12: 

But. ColdFusion runs this code fine.

The only thing I can think of is that when ColdFusion looks up a CFC, it also includes the base template path as well as the other locations it looks for CFCs in.

TBH, I would never have expected this code to run, now that I think about it. But on ColdFusion it does, so I wonder whether it should also on Railo?

I'm not raising this as a bug yet, as I'd like to see what people think. It's bloody inconvenient for me though!

--
Adam