Monday 31 March 2014

CFML: Survey follow-up (no results yet sorry): need some more input

G'day:
I realise it's not a very exciting survey, but my recent "Survey: lists in CFML, and the naming of list member functions" isn't getting an amount of attention that makes it meaningful for me to report on. I will be writing up the results - whatever they are - tomorrow anyhow, but it'd be good if you could put your oar in between now and then. If you haven't already, I mean.

The direct link to the survey is thus: "List function support as member functions in CFML".

Cheers!

--
Adam

Sunday 30 March 2014

Open Letter to site admins I might be contacting in the near future about the security of your ColdFusion site

Hi:
If you are reading this article, it's probably down to one of two reasons:
  1. you're one of my regular blog readers, in which case this will have just found its way in front of you just like anything else I write;
  2. you are a person I have successfully contacted who - hopefully - the administrator of a ColdFusion-driven website that I have noticed as having some security issues.
The article is targeted at the second group of people. If I have contacted you directly, it is vitally important you read this, and follow-up on it.

How about this for savecontent?

G'day:
The approach that CFML has taken for the CFScript implementation of <cfsavecontent> has always annoyed me, because it doesn't follow the normal syntax for doing processing and returning a result. Plus there was the need to add a new syntax construct as well. It's just occurred to me that this was not necessary. A simple function would have done the trick.


To contextualise things, let's have a look at the <cfsavecontent> tag:

<cfset days = ["Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi","Rātapu"]>
<cfsavecontent variable="contentViaTags">
<ul>
<cfloop index="day" array="#days#">
    <cfoutput><li>#day#</li></cfoutput>
</cfloop>
</ul>
</cfsavecontent>
<cfoutput>#contentViaTags#</cfoutput>

I'm just capturing the output from some simple CFML processing there, and then outputting it. It's a dumb usage of <cfsavecontent>, but it demonstrates it OK. The syntax here is entirely reasonable, and completely clear as to what's going on. It's a handy tag.

ColdFusion and Railo had already both had a go at implementing this for CFScript. And both failed (well: they came up with the same solution):

savecontent variable="contentViaScript" {
    writeOutput(days.reduce(function(previousResult, thisValue){
        return previousResult & "<li>#thisValue#</li>";
    },"<ul>") & "</ul>");
}
writeOutput(contentViaScript);

The problem here is twofold.
  1. CFML syntax for setting a variable to be the result of some processing is:
    variable = process
    Not:
    process variable="nameOfVariable"
    So it's at odds with out CFML works to approach functionality that way.
  2. We need to add this new {} syntax to enclose the code we're saving the output of. This is a new syntax construct implemented solely to emulate opening/closing tags. This is script code, so we should not be thinking in terms of opening and closing tags.
So that syntax is a loser IMO.

ColdFusion 11 has just managed to make this worse. Now we're going back to basically using tags:

cfsavecontent(variable="contentViaScriptNew") {
    writeOutput("<ul>");
    days.each(function(v){
        writeOutput("<li>#v#</li>");
    });
    writeOutput("</ul>");
}
writeOutput(contentViaScriptNew);

It also means we have two separate - and mostly the same but slightly different - constructs for doing a savecontent operation in CFScript. This is a double fail. How long will it be before we start forgetting which syntax takes the parentheses and the commas, and which just takes spaces?

But this is what's just occurred to me today. We never needed any special syntax at all to achieve savecontent in CFScript:

contentViaFunction = savecontent(function(){
    var decoratedDays = days.map(function(v){
        return "<li>#v#</li>";
    });
    writeOutput("<ul>#decoratedDays.toList('')#</ul>");
});
writeOutput(contentViaFunction);

It's just a function call. A plain old function call. We call the savecontent() function, it takes a callback which contains the code which we want to capture the output of, and returns that in its return value.

Isn't that a better approach than messing about with new syntax and weirdo ways of assigning values?

What's more... the implementation is piss-easy. It's just this:

function saveContent(required function content){
    savecontent variable="local.saved" {
        content();
    }
    return local.saved;
}

Obviously because I'm implementing this with CFML I need to reuse one of the other constructs, but it demonstrates what a simple concept to implement it is.

This is another example of what I mean that rather than taking a generic approach to implementing previously tag-only functionality in CFScript, it needs a bespoke approach. CFScript is now a first class citizen of CFML, and it deserves to have its functionality implemented carefully and thoughtfully. Not just in an automated/generic way that makes the life of the engineers and Adobe and Railo a bit easier.

I have added this suggestion as a comment on an existing Adobe ticket: 3643125;  and a new one for Railo: RAILO-3008.

--
Adam

ColdFusion 11: calling a stored procedure from script. And can we please stop wearing out our "c" and "f" keys?

G'day:
I'm not sure what's got into me today... I'm supposed to be completing a Backbone.js course @ Code School, but I keep finding things to look at in Railo / ColdFusion instead. This is the fourth article I've written this afternoon. And it's only 3pm.

I'm looking at two things in this article. Calling a stored procedure from CFScript, and how I really don't think our code needs to scream "cf" "cf" "cf" at us the whole time. We get it. It's a CFM file. It's got CFML in it. We don't also need every single line of code in it reminding us of this. But this is what we will have if Adobe get their way.

Railo: I've got to the bottom of that code I asked you to test for me

G'day:
Thanks to everyone who helped out with my challenge in this article: "Railo: help me replicate a bug I'm seeing on one of my machines". I think the reason I was seeing the difference in behaviour is twofold:
  1. I'm a dropkick;
  2. Railo's setting "Local scope mode" (which I can't find docs to link to [grumble], so I'll need to explain it).
The reason why I suspect I'm a dropkick is that I think this is all down to my machine at work having "local scope mode" set to "modern", whereas every other instance I have been looking at is set to "classic". I do not recall switching my work machine to use this setting (and I'll be switching it off as soon as I sit down at it on Monday), but it seems like this is what the difference is.

Thanks to Gert for pointing me in the direction of the various Railo "make Railo work differently from ColdFusion" settings that Railo has.

Railo: it already supports separating parameters from the SQL string

G'day:
This is a very quick  update to my previous article: "Query.cfc / queryExecute() have a good feature cfquery lacks". Railo already supports this (although it's apparently undocumented?).

Whilst raising the ticket for ColdFusion, I found an already-raised (and resolved) ticket in the Railo bugbase: RAILO-2203.

Micha has added a comment to the bottom of it: "added as hidden feature", but it is there and it does work:

<cfset params = [
    {value=URL.low},
    {value=URL.high}
]>
<cfquery name="numbersViaPositionalParams" params="#params#">
    SELECT  en AS english, mi AS maori
    FROM    colours
    WHERE   id BETWEEN ? AND ?
</cfquery>

<cfset params = {
    low=URL.low,
    high=URL.high
}>
<cfquery name="numbersViaNamedParams" params="#params#">
    SELECT  en AS english, mi AS maori
    FROM    colours
    WHERE   id BETWEEN :low AND :high
</cfquery>

Cool! Go Railo!

I shall update the ticket I raised with Adobe to encourage them to follow Railo's lead here.

--
Adam

Query.cfc / queryExecute() have a good feature <cfquery> lacks

G'day:
<cfquery> has been one of the mainstays of CFML for longer than I have been aware of CFML as a language. I presume it existed in some way, shape, or form in Cold Fusion 1.0. Up until ColdFusion 9, there was no way to perform a DB query in CFScript, unless one was to write a wrapper to do so. And I think we all had, at some stage or another.

Along came ColdFusion 9. It was during the development of ColdFusion 9 that Adobe first made the promise to implement all tag functionality in a scriptable way (note: it's taken them until CF11 to actually follow through on this promise), and when the first attempt at providing DB querying support in CFScript. I think it is astounding that it took until version 9 of the language before such a fundamental piece of functionality was available in CFScript, but there you go.

Saturday 29 March 2014

Railo: help me replicate a bug I'm seeing on one of my machines

G'day:
A few days back I raised a bug with Railo - "Bug with scoping inside iterator functions" (RAILO-3000) - which only happens on one of my Railo installs (out of six installs, on four different machines). Micha can't replicate it either. I'm trying to get to the bottom of what's going on, and what's different about my install.

Update:

I've got to the bottom of this. See "Railo: I've got to the bottom of that code I asked you to test for me"


Here's the code:

Encourage Adobe to relocate /CFIDE/scripts

G'day:
I was listening to CFHour just now - another good podcast, fellas - and Scott mentioned that ColdFusion doesn't help its case keeping itself secure/locked down because assets for CFUI tags are homed in /CFIDE/scripts, and /CFIDE really mustn't be exposed to the outside world.

Whilst there are various options to move / rehome these, I've raised a ticket to get /CFIDE/scripts to somewhere else "Isolate the /CFIDE/scripts directory from the rest of /CFIDE" (3732913), which says this:

Friday 28 March 2014

Survey: lists in CFML, and the naming of list member functions

G'day:
There's a conversation brewing on the Railo Google Group regarding string / list member functions ("String member functions and list functions"), and this touches on ColdFusion's approach to these.

TL;DR: the survey is here: "List function support as member functions in CFML"

Update:

The survey is now closed. Results are here.


The question being asked on the Railo forum is whether to bother supporting list member functions in Railo at all. And as an aside to this, some lack of uniformity in how ColdFusion 11 has implemented these has cropped-up.

Firstly, I'll "go on record" as saying that I think having a specific concept as a "list" as a (pseudo) data type in CFML is a bit rubbish. Strings aren't intended for implementing data collections, and aren't very good at doing it, so - IMO - it was a poor idea to facilitate it. If Railo and ColdFusion deprecated the concept of lists entirely, the (CFML) world would be a better place.

That said, they are in the language as a concept, so we have to acknowledge this I guess.

Adobe have added list member functions to CFML in ColdFusion 11.  Here's a table of their implementation ("Supported List member functions"):

Thursday 27 March 2014

We don't need bigots in this industry

G'day:
Bravo to the individuals at Mozilla who are requesting their new CEO steps down:



Cheers to Andy Myers for putting me on to this: 'Mozilla employees tell Brendan Eich he needs to “step down”'.

There is no place in our industry for bigots.

F*** off.

--
Adam

Sharing a conversation about clean code

G'day:
I'm being a bit lazy today. And interesting conversation cropped up on the comm log of one of the side projects I'm working on, and I thought you might be interested to read it, and perhaps add your thoughts.

We were discussing how to handle the requirement for a new API function we're adding to our localisation suite, which works similar to dayOfWeekAsString(), except the immediate requirement it to provide a localised "short version" of the day, eg: "Mon", "Tue", etc. The initial suggestion had come in as dayOfWeekShortAsString(). And the conversation started. I am "Mr Green", incidentally. I have made a few edits to clean up spelling and grammar, but I have not removed anything, or changed the context of what was said. I have added some clarification (for the purposes of this article) part-way down.

Topic:
dayOfWeekAsString() / dayOfWeekShortAsString()

Wednesday 26 March 2014

Using a sort iteration function to implement a custom ranking

G'day:
It occurred to me last night that - in all my examples of using a callback-based sort on a collection - I am always just using the natural ordering of a field; eg I sort an array of structs on a key in the struct which needs either alphabetical or numeric sorting. EG:

numbers = [
    {maori="wha", digit=4},
    {maori="toru", digit=3},
    {maori="rua", digit=2},
    {maori="tahi", digit=1}
]

dump(numbers.sort(function(v1,v2){
    return sgn(v1.digit - v2.digit)
}))


This is selling the functionality short, somewhat.

Tuesday 25 March 2014

myArray.each()... extending the array whilst iterating..?

G'day:
I dunno what to think about some behaviour I'm seeing when iterating over an array with the .each() method.

Consider (but do not run!) this code:

numbers = ["one","two","three","four"];
numbers.each(function(value,index){
    if (value=="one") {
        numbers.append("five");
    }
    writeOutput("Index: #index#; value: #value#<br>");
});
writeDump(var=numbers);


Railo adds more iteration functions: *some() and *every()

G'day:
Starting with ColdFusion 10 and some-version-or-other of Railo 4 (Railo moves so quickly I can't keep track of when features are added), CFML has been adding collection iteration functions which leverage callback functions to provided the functionality for each iteration. Examples are arraySort(), listFilter(), structEach() (the coverage in each CFML dialect for each collection data type is not fully comprehensive nor do they necessarily both implement the same functions the other does). ColdFusion added in map and reduce functions (detailed in my article "ColdFusion 11: .map() and .reduce()"), now Railo has added those in, and gone one better: now adding some() and every() functionality too. In this article I'll recap each of the sort / filter / each / map / reduce functionalities, and have a look at some() and every().This is a Railo-centric article. The code will not run on ColdFusion without modification.

Sunday 23 March 2014

CFML: Built-in functions, UDFs, methods, and function expressions... with the same name

G'day:
I have no idea what I'm playing at. It's 9pm on Saturday night and I am in a downtown Galway ("Galway, Ireland", for you Americans... there's probably a Galway in TX, MN, CA as well ;-) pub, which was nice and quiet this afternoon and good for a quiet drink and some blog research. Now it's a full on Saturday night and everyone else is just partying and I'm still typing. The alternative is sitting here by myself and drinking, looking like... I'm sitting here by myself and drinking (and it'd not be the first time. Even today!). I guess at least I would not be the only person in the place writing a blog article about CFML.

Right, so today's efforts started with the intention of looking at some new methods in Railo: .some(), .every() (there's no docs for these yet - that I can find - but there is a Jira ticket: Add closure functions ArrayMap, ArrayReduce, ArrayEvery, ArraySome functions), and rounding out at look at any other CFML iteration functions I'd not looked at yet. I've looked at some previously from a ColdFusion perspective: "ColdFusion 11: .map() and .reduce()".

But then an interesting discussion came up on the Railo Google Group and the function map() which has been added to the latest Railo BER, which breaks WireBox: "Wirebox breaking on latest Railo patch 4.2.0.006", and this absorbed me for the rest of the afternoon and evening, thinking about it, wittering on on the forum, and testing some code. There's a few concepts discussed on the thread, and it's worth reading in its entirety.

Survey results: Adobe's approach to client communications regarding security issues

G'day:
Well today's last minute push ("3") to get the survey over 50 results has worked. I've got 5679 (the number changed cos I started this on Fri, but finished it on Sun; the other responses came in during that period) now. So here're the results.

Just to remind you, the topic was:
This is just a quick survey to gauge how effective Adobe have been at communicating to their clients regarding security issues that have arisen in ColdFusion

Friday 21 March 2014

Survey: three more responses please

G'day:
I've got 47 responses to the survey I started earlier in the week "Adobe's approach to client communications regarding security issues" (direct link to survey); I'd like to get 50 before I collate the information.

So if you have a moment and an opinion, it'd be cool if you could spend that moment clicking some radio buttons for me.

Cheers.

--
Adam

Thursday 20 March 2014

An insight into the mind of a CFML developer

G'day:
I was going to respond to this on the blog I found it (the Adobe ColdFusion one), but I'll do it here instead so I'm not polluting their blog with my anguish / irritation. Be warned: this is a fairly mean-spirited article, and singles out an individual.

Wednesday 19 March 2014

Survey: Adobe's approach to client communications regarding security issues

G'day:
I haven't done a survey for a while! This is a follow-up to my earlier article "It is Adobe's fault, OK?", and just to capture the zeitgeist.

Update:

This survey is now closed. The results are here: "Survey results: Adobe's approach to client communications regarding security issues ".

So here it is: "Adobe Communications", and the description text is:

This is just a quick survey to gauge how effective Adobe have been at communicating to their clients regarding security issues that have arisen in ColdFusion
There's seven questions: all bar one can be answered via a mouseclick, and the last asks for a comment. There's other boxes for comments along the way too.

I will always remind people that I do not target a statistically meaningful demographic, nor do I gather enough results to be sensibly analysed, but it is nice to see other people's opinions on stuff sometimes.

So go fill it out if you like. I'll summarise the results when the response stream dries up.

Cheers.

--
Adam

ColdFusion 11: bug triage (and fixing?) seems to have stalled

G'day:
Ages back I wrote an article "212 untriaged ColdFusion 10 bugs", and indicated my horror at how many bugs in the current version of ColdFusion that Adobe had seen fit to simply ignore. I don't mean "not fix", I meant "just completely ignore; ie: not even acknowledge the bug had been raised".

I followed this up a coupla months later with "Bug watch: 212206 untriaged ColdFusion 10 bugs"; in that two months they had managed to triage a net of six tickets that had been raised.

Just a week later we were down to 165 untriaged bugs: "Good work Adobe ColdFusion Team!", and they had made good progress from there, getting it well below 100 untriaged bugs, and got it down to a low of 40 on Jan 22 this year. Again: good work!

Saturday 15 March 2014

ColdFusion-UI-the-Right-Way: <cfmap>

G'day:
This is a bit of a lazy one, I have to admit. I've added an example for how to use the Google Maps API directly instead of <cfmap> into the ColdFusion-UI-the-Right-Way project, but it's a very very simple example. Still: it demonstrates the code and pushes the punter in the right direction. I'll do a more interesting example when I do one for <cfmapitem>, I promise.

I've reproduced the details below:

Friday 14 March 2014

ColdFusion 11: More on this <cfinclude> thing

G'day:
I've been thinking about this new <cfinclude> security feature some more, based in no small part on the excellent reader comments on my earlier article "Is Adobe knowingly leaving exploits in ColdFusion 9 and 10 unpatched?".

Firstly I'll repeat my response to one of Sean's comments, to contextualise a baseline:

If there's a case to address, and this is a sensible way of dealing with it: no problem. However we didn't know (beyond speculation) whether either of those is true. Rupesh has now clarified there is a case to address, but I remain skeptical as to whether this is at all a sensible approach.

It comes down to communication, and Adobe's seeming inability to do it coherently. On the face of it this was just a stupid thing to do, especially when the rationale was no more developed than "because security". Part of dealing with security responsibly is to communicate the situation. Not to detail the instructions of how to implement the exploit, but at least documenting what the issue is actually addressing. Even had Adobe implemented a more even-handed solution from the outset, without explaining the situation, the community cannot make an informed decision as to whether it's a ill-conceived annoyance that might as well be disabled, or the most critical and real threat ever. I still think this one falls closer to the former than the latter.

Furthermore, without discussion and input from the community, I will never be certain (nor should any of us be) that Adobe are actually addressing the issue sensibly, or just giving it a quick hack by way of lip-service. Let's face it: they do have a habit of doing the bare-minimum amount of work necessary to be able to look themselves in the mirror (although they set a low tide mark even for that).

And also - finally - a helpful comment from Adobe's technical mouthpiece, Rupesh:

Rupesh Kumar
6:51:43AM GMT+00:00 Mar 13, 2014
As I said earlier, this basically provides a way to you to decide what you want to compile and what not, when the file is being included. This was added after we saw few cases where an application included a file and somehow the bad guys were able to write to this file being included. The file in one of the case was actually a log file where the application was logging invalid user input apart from other errors/log messages. As you would figure, the bad input was actually some CFM code which went into the log file and when this got included, the user given code got executed. The application had not expected this file to be compiled. As we understand, there are many applications which use cfinclude to include static content.

This is a good change. You are getting a control to decide what to compile. You will also get some performance improvement because your JS, HTM, CSS files would not be compiled, loaded and processed by the server. If you don't need any of this and want to compile everything, you can always use "wildcard". 

To answer whether this should be given as an update to CF 9 & 10, we would not want to break applications while applying updates in their production servers. We can add this where by default we would allow all the extensions to be compiled which then does not fix anything immediately. So how do we go about it? Do you think it needs to be made available in CF 9 & CF 10?
There are some comments following that up, and you should read them.

Thursday 13 March 2014

Do not sponsor me to go to CF.Objective()

G'day:
A coupla days ago I posted a guilty blog post "Shamelessful plug", which mentioned that Gavin was running a charity drive ("Charity Corner - Diabetes and Fly a Foul Mouthed Fusioner Fund") to try to fund me to get to CF.Objective() this year.

I am calling quits on this.

I hope I don't make any of the existing donors (thank-you!) cross, but I'm going to give the money away. Or back to you. But hopefully you let me give it away.

I just spotted this Twitter message from my long-standing mate Jared:

He needs help (details here), and more than I need a ticket to a conference, so I've instructed Gavin to give him the money gathered so far.

If any of my donors are unhappy with this decision (and I understand it'd not what you put the money in for, so that's fine), contact me privately and I'll get your money back to you.

And if you were thinking of sponsoring me: thank-you, but please sponsor Jared instead. Cheers.

Thanks for the kind thoughts & gestures everyone, but... ballocks to that: let's help our industry mate out when he needs it.

--
Adam

Testbox: using a callback as a mocked method

G'day:
John Whish hit me up the other day, wondering had I looked at a new TestBox (well: at the time it was just for MockBox) feature I'd requested and has been implemented. Rather embarrassedly I had forgotten about it, and had not looked at it. That's a bit disrespectful of Luis and/or Brad (or whoever else put the hard work in to implement it), and for that I apologise. However I have looked at it now.

The feature request is this one, MOCKBOX-8:


Luis, we discussed this briefly @ SotR.

Currently one can specify a expression to use for a $results() value, and the value of that expression is then used as the results for the mocked method.

It would be occasionally handy for some stub code to be run to provide the results when a mocked method is called. This could be effected by being able to pass a callback to $results(), which is then called to provide the results when the mocked method itself is called.

Ideally a mocked method should always be able to be fairly dumb, but sometimes in an imperfect world where the mocked method has other dependencies which cannot be mocked out, an actual usable result is necessary. We've needed to do this about... hmmm... 0.5% of the times in out unit tests I think, so this is quite edge-case-y.

Cheers.
I can't recall what exactly we were needing to do at the time, but basically we were testing one method, and that called a different method which we wanted to mock-out. However we still wanted the mocked method to produce "real" results based on its inputs (for some reason).

MockBox allows to mock a method like this:

someObject.$("methodToMock").$results(0,1,2,3,4,etc);

And each call to methodToMock() will return 0, 1, 2 [etc] for each consecutive call, for as many arguments one cares to pass to the $results() method. Once it's used all the passed-in options it cycles back to the beginning again. This is great, but didn't work for us. What we needed was for the methodToMock() to actually run a stub function when it's called. Hence the enhancement request.

The Ortus guys have implemented this, so here's an example of it in action.

Firstly a MXUnit-compat scenario, running on ColdFusion 9 (so no need for function expressions or "closures" as the TestBox docs tends to refer to them as):

// C.cfc
component {

    public struct function getStructWithUniqueKeys(required numeric iterations){
        var struct = {};
        for (var i=1; i <= iterations; i++){
            struct[getId()] = true;
        }
        return struct;

    }

    private string function getId(){
        // some convoluted way of generating a key which we don't want to test
        return ""; // doesn't matter what it is, we won't be using it
    }

}

Here we have a CFC which has a method we want to test, getStructWithUniqueKeys(). It calls getId() to get a unique ID. For whatever reason we don't want our calls to getStructWithUniqueKeys() to call the real getId() (maybe it requires a DB connection or something?), so we want to mock-out getId(). However we still need it to return unique IDs.

Here's our test CFC:


// TestMxUnitCompat.cfc
component extends="mxunit.framework.TestCase" {

    function beforeTests(){
        variables.testInstance = new C();
        new testbox.system.testing.MockBox().prepareMock(testInstance);
        testInstance.$("getId").$callback(mockedGetId);
    }

    function testGetStructWithUniqueKeys(){
        var iterations    = 10;
        var result        = testInstance.getStructWithUniqueKeys(iterations=iterations);
        assertEquals(iterations, structCount(result), "Incorrect number of struct keys created, implying non-unique results were returned from mock");
    }

    private function mockedGetId(){
        return createUuid();
    }

}

Here I'm using Mockbox to prepare my test object for mocking (which just injects a bunch of MockBox helper methods into it), and then we mock getId() so that instead of calling the real getId() method, we use mockedGetId() as a proxy for it. And mockedGetId() just uses createUuid() to return a unique key.

And, pleasingly, this all works fine:

Wednesday 12 March 2014

Testbox: investigating which method/function/callback gets called when

G'day:
I had a bit of a wrestle with working out a glitch in my TestBox code y/day, and as a result ended up with a test CFC which shows where and when everything seems to run. I'll reproduce it here in case it saves anyone some time.


// TestExecutionSequence.cfc
component extends="testbox.system.testing.BaseSpec" {

    function beforeAll(){
        writeOutput("in beforeAll()<br>");
    }
    function afterAll(){
        writeOutput("in afterAll()<br>");
    }

    function run(){
        writeOutput("top of run()<br>");

        describe("outer describe", function(){
            writeOutput("top of outer describe()'s callback<br>");

            beforeEach(function(){
                writeOutput("in outer describe()'s beforeEach()<br>");
            });

            afterEach(function(){
                writeOutput("in outer describe()'s afterEach()<br>");
            });

            describe("inner describe", function(){
                writeOutput("top of inner describe()'s callback<br>");

                beforeEach(function(){
                    writeOutput("in inner describe()'s beforeEach()<br>");
                });

                afterEach(function(){
                    writeOutput("in inner describe()'s afterEach()<br>");
                });

                it("tests the negative", function(){
                    writeOutput("top of inner describe()'s first it()'s callback<br>");
                    expect(sgn(-1)).toBeLT(0);
                    writeOutput("bottom of inner describe()'s first it()'s callback<br>");
                });

                writeOutput("bottom of inner describe()'s callback<br>");
            });

            it("tests the truth", function(){
                writeOutput("top of first it()'s callback<br>");
                expect(true).toBeTrue();
                writeOutput("bottom of first it()'s callback<br>");
            });

            it("tests falsehood", function(){
                writeOutput("top of second it()'s callback<br>");
                expect(false).notToBeTrue();
                writeOutput("bottom of second it()'s callback<br>");
            });

            writeOutput("bottom of outer describe()'s callback<br>");
        });


        describe("second outer describe", function(){
            writeOutput("top of second outer describe()'s callback<br>");

            it("tests the absolute", function(){
                writeOutput("top of second outer describe()'s first it()'s callback<br>");
                expect(abs(-1)).toBe(1);
                writeOutput("bottom of second outer describe()'s first it()'s callback<br>");
            });

            writeOutput("bottom of second outer describe()'s callback<br>");
        });

        writeOutput("bottom of run()<br>");
    }

}

And here's the output (ignoring the test results, which are immaterial here):

top of run()
   top of outer describe()'s callback
     top of inner describe()'s callback
     bottom of inner describe()'s callback
   bottom of outer describe()'s callback
   top of second outer describe()'s callback
   bottom of second outer describe()'s callback
bottom of run()
in beforeAll()
    in outer describe()'s beforeEach()
        top of first it()'s callback
   
   
bottom of first it()'s callback

    in outer describe()'s afterEach()
    in outer describe()'s beforeEach()
        top of second it()'s callback
   
   
bottom of second it()'s callback
    in outer describe()'s afterEach()
        in inner describe()'s beforeEach()
        in outer describe()'s beforeEach()
            top of inner describe()'s first it()'s callback
   
        bottom of inner describe()'s first it()'s callback
        in inner describe()'s afterEach()
    in outer describe()'s afterEach()
    top of second outer describe()'s first it()'s callback
    bottom of second outer describe()'s first it()'s callback
in afterAll()


(note the indentation is not part of the original output, I just added it to try to add clarity to what's running when. I'm not sure I successed).

There's a few things to note here.

beforeAll()

I expected this to run... before everything. Before anything at all. Not just before the first test (ie: a call to the first it()'s callback). Where it runs is convenient, but I think there should be perhaps a beforeAll() and a beforeTests(), and beforeAll() should truly run before anything else.

Same with afterAll().

beforeAll() and beforeEach()

It seems slightly odd to me that beforeAll() is just a function, whereas beforeEach() is a call to a function which takes a function expression (which is then executed). I certainly didn't guess that, and had to refer to the docs.

Nested describe()

It quite cool how one can nest describe() calls, for subcategorising test output. This makes for a good visual cue when reading the results:


Anyway. That's it. Just a FYI, really.

--
Adam

ColdFusion 11: good news... <cfhtmltopdf> will be able to run on Linux too!

G'day:
Just a short one... I figured it would be good if someone publicises this fact a bit more:


ColdFusion 11: Confusion as to why <cfhtmltopdf> is not simply an adjunct to <cfdocument>

G'day:
I had a look at <cfhtmltopdf> a week or so ago in "ColdFusion 11: <cfhtmltopdf> is pretty good!". And as I say in the article title: it works really well (other than a coupla bugs I raised). However one thing I can't work out is why we now have two tags that do the same thing: <cfdocument> and <cfhtmltopdf>.

They might - under the hood - use different mechanisms to arrive at the same goal, but surely the whole thing about having a tab abstraction layer is that the underlying mechanism ought to be irrelevant: the tags - and indeed the CFML language as a whole - is supposed to abstract the minutiae away from the developer.

A coupla things that are different about <cfhtmltopdf> are:
  1. it only works on Windows;
  2. it is enterprise only.
Both of these are a bit shitty (or a lot shitty, really), but they do not - in my mind - justify why <cfhtmltopdf> is a separate tag.

So, anyway, I asked on Twitter for some sort of explanation:

And this morning I got a response from Rakshith (well I am presuming he's still the man behind the curtain of the @ColdFusion account?)

Tuesday 11 March 2014

Shamelessful plug

G'day:
I'm not quite sure what I think about this one, and not sure how to word things. But one thing I do know how to articulate: Gavin's a nice bloke.

Sunday 9 March 2014

Is Adobe knowingly leaving exploits in ColdFusion 9 and 10 unpatched?

G'day:
I am very very much leveraging Betteridge's Law of headlines in my article headline above. The answer is - almost certainly - no. However it's perhaps a question that needs to be asked, if some conclusions I'm reading on Twitter today are to be taken seriously.

I'm trying to get some clarification on this security situation in which is "dealt with" by this addition of the allowedextforinclude (note: this was changed to compileextforinclude, by the time ColdFusion 11 was actually released) setting in neo-runtime.xml (discussed in this article: "ColdFusion 11: preventing files from being included? WTF, Adobe?"). There's a ticket in the bugbase "Either remove allowedextforinclude functionality entirely, or at least implement it so it can be disabled". The agreed-to fix here is as follows:

  • S V Pavankumar
    5:46:57 AM GMT+00:00 Feb 27, 2014
    Added the new change. 

    The new behavior will be
    1) By default only cfm files gets compiled in cfinclude tag and all other file types gets included statically. 
    2) The key allowedextforinclude now can be specified at the application as well. 
    3) Added the setting to Server settings -> settings page 
    4) If wildcard(*) is specified in the value all files will be compiled. Wildcard support is added at both server and application level.

OK, so it seems it's completely OK to disable this thing.

Saturday 8 March 2014

Unit testing: the importance of testing over assumption

G'day:
Today some code! That's better than rhetoric innit? I'm sure it won't be as popular though.

OK, so I have been too busy recently with ColdFusion 11 and various other odds 'n' sods to either continue writing about unit testing, and also I have been neglecting the CFLib.org submission queue. So today I am remedying both of those in one fell swoop.

This article is not really "TDD" or "BDD" as the code I am testing is a fait accompli, so the tests are not driving the development. However this is perhaps a good lesson in how to retrofit tests into functionality, and what sort of things to test for. There's a bit of TDD I suppose, because I end up completely refactoring the function, but first create a test bed so that that is a safe thing to do without regressions.

On CFLib there is already a function firstDayOfWeek(), but someone has just submitted a tweak to it so that it defaults to using today's date if no date is passed into it. Fair enough. Here's the updated code:

function firstDayOfWeek() {
    var dow = "";
    var dowMod = "";
    var dowMult = "";
    var firstDayOfWeek = "";
    if(arrayLen(arguments) is 0) arguments.date = now();
    date = trim(arguments.date);
    dow = dayOfWeek(date);
    dowMod = decrementValue(dow);
    dowMult = dowMod * -1;
    firstDayOfWeek = dateAdd("d", dowMult, date);

    return firstDayOfWeek;
}

Nothing earthshattering there, and I basically scanned down it going, "yep... uh-huh... oh, OK, yeah... cool... yeah that seems OK". And I was about to just approve it. Then I felt guilty and thought "ah... I really should test this. And I'll use TestBox and its BDD-style syntax to do so, and I can get a blog article out of this too.

It's just as well I did test it, because it has a bug. Can you see it?

I sat down and looked at the code, and went "right... what do I need to test?". I came up with this lot:
  • if I don't pass in a date, it returns the first day of the current week;
  • if I do pass in a date, it returns the first day of that week;
  • if I pass in the date that is the first day of the week already, it passes back that same date;
  • if I pass it "not a date", it errors predictably.
I think that about covers the testing need here? OK, so I started writing the tests:

// TestFirstDayOfWeek.cfc
component extends="testbox.system.testing.BaseSpec" {

    function beforeAll(){
        include "udfs/firstDayOfWeek.cfm";

        variables.testDate = now();
        variables.testFirstDayOfWeek = dateAdd("d", -(dayOfWeek(variables.testDate)-1), variables.testDate);
    }

    function run(){
        describe("Tests for firstDayOfWeek()", function(){

            it("returns most recent sunday for default date", function(){
                expect(
                    dateCompare(variables.testFirstDayOfWeek, firstDayOfWeek(), "d")
                ).toBe(0);
            });

            it("returns most recent sunday for current date", function(){
                expect(
                    dateCompare(variables.testFirstDayOfWeek, firstDayOfWeek(variables.testDate), "d")
                ).toBe(0);
            });
        });
    }

}

Notes:
  • I've got the UDF saved in a separate file, so just include it at the beginning of the tests;
  • I set some helper variables for using in the tests;
  • I'll get to this.
I was running the tests as I went, and here's what I got on the test round with these first two tests:

Friday 7 March 2014

Java Training

G'day:
My mate Mike Henke has passed on some good information, and said he wouldn't mind if I circulated to everyone else too.

I saw your recent post about CFML dying. Today I hit up webucator for a deal on their online java class for experienced programmers. They offered it for $1000 but I need 2 others to sign up too.

It starts April 28th 10am-5pm eastern time for 5 days..

http://www.webucator.com/java/course/java-programming-training-for-experienced-programmers.cfm

If you want to mention this in a blog post or tweet that would be awesome for CFML-ers looking to learn something else and if they are like me, needing a set, short class to ramp up fast.

Mike makes a good point that a rapid skill injection like this could be great for people who need help / opportunity to move on from CFML. I'm not necessarily be suggesting a move to Java itself would be a good idea, but there's an awful lot of good techniques to be learned from Java that a CFMLer might not necessarily acquire day to day.

Even if not moving from CFML, it's just a great opportunity to get some intense exposure to another language.

And $1000 is a bloody excellent price.

As per Mike's comment below: he can be contacted on  henke dot mike at gmail dot com.

--
Adam

Railo: small new feature I didn't catch making it into the language

G'day:
This is a minor but handy feature in Railo 4.2 that Micha just gave me a heads-up on. One can treat a string as an array:

s = "G'day world";
for (i=1; i <= s.length(); i++){
    writeOutput(s[i]);
}
writeOutput("<hr>");

charAfterApostrophe = s[find("'", s)+1];
writeOutput("charAfterApostrophe: #charAfterApostrophe#");

Output:

G'day world

charAfterApostrophe: d


Not very exciting, but makes sense, and saves a call to mid() if needing to extract characters from the string.

--
Adam

Thursday 6 March 2014

Clarification and some notes on yesterday's "CFML is dying. Let's drop it off at Dignitas" article

G'day:
I added a coupla things to the "CFML is dying. Let's drop it off at Dignitas" article this morning, after some discussions and more thoughts over night. I'll just summarise them here.

@cfmlNotifier now sending updates from the CFML Bloggers RSS feed

G'day:
Well the title pretty much sums this up: the @CfmlNotifier Twitter feed is now sending out status updates when coldfusionBloggers receives new articles:

It should be polling every hour, once I set it up to do so.

That's it.

--
Adam

Wednesday 5 March 2014

CFML is dying. Let's drop it off at Dignitas

G'day:
Yes. It's another "CFML is dying" article. We haven't had one for a while. Note that this is not "ColdFusion is dying", this is CFML in general.

TBH: the headline is slightly tongue-in-cheek, and designed to garner outraged click-throughs whilst the Daily Mail readers amongst us search for the "Comment on this article" button so they can display their mouth-froth to everyone.

This article actually isn't about CFML. And that's the point.

ColdFusion 11: Thank-you Carl, Mary-Jo, many other community members and indeed Rupesh

G'day:
Integers. We "won". Adobe have reversed their position, and they're gonna fix the isValid("integer") bug:

  • Rupesh Kumar
    9:18:35 PM GMT+00:00 Mar 4, 2014
    Wow - it is indeed incredible. Thanks Carl for digging this out. We will fix it - we would have a application setting which would bring back the old behavior in case some one needs it. I hope nobody needs to use this flag. 

    We will also roll it out in an update for the public beta and we would need your help in verifying and making sure that applications don't break. 

    Thank you everyone for raising this and providing this feedback!

Good stuff, Rupesh.

--
Adam

Tuesday 4 March 2014

ColdFusion: Of integers and indolence

G'day:

Yes, OK, I'm still banging on about integers and ColdFusion bugs. It's my blog and I can talk about whatever I like! ;-)

You might be aware that I am particularly nonplussed about Adobe's reaction to bug 3712010, which relates to integer validation via isValid(), and how it is broken.

I started by just being mildly annoyed by how ColdFusion can make such a pig's ear of something that should be simply. But the more Adobe (or, hey, let's say it: Rupesh from Adobe) squirms about the place and tries to justify why they shouldn't just bloody fix a fairly obvious bug, the more annoyed I am getting about this. I dislike having my intelligence insulted, and I also dislike the collective intelligence of the ColdFusion community insulted. Especially by someone who very clearly should not be in the business of insulting anyone's intelligence.

It's all getting a bit stupid, but one of the comments posted today on this caught my eye and made my blood boil just that bit more. I've asked Carl if I can reproduce his comment, and he has said it's fine. So here it is. I've dollied it up for formatting, but it's othewise unchanged.

Your ColdFusion bugs - visualised

G'day:
I'm stealing some of Ray's code here, and making it more general and exposing it for all to use.

Sunday 2 March 2014

ColdFusion 11: Adobe have finally started deprecating / obsoleting stuff in ColdFusion

G'day:
This article is basically gonna be a reproduction of something in the ColdFusion 11 docs, just FYI. I found an xls file buried in the docs that lists some stuff that's newly deprecated in CF11, and even some stuff they've finally obsoleted.