-
Notifications
You must be signed in to change notification settings - Fork 24
Assertions via Assert.cfc Utility
- Overview
- Before and After Examples
- Using Assertions in Mach-II Extended Components
- Assertion Methods
This new utility CFC provides assertion methods to aid in the basic validation of arguments. An assertion in this case is an expectation or assumption that something must be true at run time for the code to continue to work. A typical location to do an assertion is to check configure-time parameters in a Mach-II filter at runtime in an effort to "assert" they are valid and to thrown an exception if an assertion fails. A major advantage of doing run-time checking of parameters that when an assertion fails does occur it is detected immediately rather than later through its often obscure side-effects. It is easy to pin-point the error without time consuming debugging because if an assertion fails the developer receives an exception message (and optional details) along with the location of the failed assertion.
The Assert.cfc
that comes bundled with Mach-II offers several different types of basic assertion methods that we will look at later. However, it should be noted that the assertion utility is not designed to be used for user input validation (such as form validation), but as an utility to aid developers in performing simple checking of incoming arguments or parameters.
Here is an example of some basic validation of a configuration parameter used in the timespan cache strategy that is bundled with Mach-II.
<cfif isParameterDefined("timespan")>
<cfif getParameter("timespan") NEQ "forever" AND ListLen(getParameter("timespan")) NEQ 4>
<cfthrow type="MachII.caching.strategies.TimeSpanCache"
message="Invalid timespan of '#getParameter("timespan")#'."
detail="Timespan must be set to 'forever' or a list of 4 numbers (days, hours, minutes, seconds)." />
<cfelse>
<cfset setTimespanString(getParameter("timespan")) />
</cfif>
</cfif>
We need to validate that the incoming parameter timespan
has the value of either forever
or 0,0,10,0
. This is not the most bullet-proof validation of configuration parameters, but it is sufficient in aiding a developer if they mis-configure the timespan cache. Without throwing an exception, the developer might be faced with a strange error like Cannot get list element in position 4 (list len is 3)
and cause them to think there is an error in the code base instead of a simple configuration error (like defining the timespan as 0,0,10
and forgetting that it needs to be four list entries long).
Below is an example using an assertion that will throw an exception if the expression (the first argument of the isTrue
method) evaluates to false.
<cfif isParameterDefined("timespan")
AND getAssert().isTrue(getParameter("timespan") EQ "forever"
OR ListLen(getParameter("timespan")) EQ 4>
<cfthrow type="MachII.caching.strategies.TimeSpanCache"
message="Invalid timespan of '#getParameter("timespan")#'.",
"Timespan must be set to 'forever' or a list of 4 numbers (days, hours, minutes, seconds).")>
<cfset setTimespanString(getParameter("timespan")) />
</cfif>
As you can see, the assert code is easier to read and has more compact code.
Performing assertions on incoming parameters in Listeners, Filters, Plugins and Properties are important aspect of developing these components. The Mach-II Assert class is available in all Mach-II developer extended components and can be gotten by calling the following code in our example listener CFC:
<cfset getAssert().hasText(getParameter('someParam'), "The 'someParam' parameter needs to have some text.") />
The MachII.utils.Assert
CFC comes bundled with six basic assertion methods. Let's take a deeper look at what can be done with these methods.
The doesNotContain
method asserts that the given text does not contain the given substring (case-senstive). It the substring is found, an exception is thrown.
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset substring = "Jumps" />
<cfset assert.doesNotContain("The quick brown fox jumps over the lazy dog",
substring, "The string contains substring which it should not.") />
The above code would not generate an exception at runtime because the text does not have the substring of Jumps
(case-sensitive) in it and therefor no match is found.
Argument Name | Required | Default | Description |
---|---|---|---|
text | true | n/a | The text to check the substring against. |
substring | true | n/a | The substring to find within the text. (case-sensitive) |
message | false | [Assertion failed] - this text argument must not contain the substring '#arguments.substring#'. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |
The hasLength
method asserts that the given text is not empty (does not trim the incoming text). If the length of the text is 0, an exception is thrown.
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset howSmartAmI = "" />
<cfset assert.hasLength(howSmartAmI, "You must not be smart, because the length is 0.") />
The above code would generate an exception at runtime because the howSmartAmI
variable currently has a length of 0.
Argument Name | Required | Default | Description |
---|---|---|---|
text | true | n/a | The text to check the length. |
message | false | [Assertion failed] - this text argument must have length; it cannot be empty. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |
The hasText
method assert that the given string has valid text content; it must not be a zero length string and must contain at least one non-whitespace character.
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset text = "I seriously blushed when I sprouted that corn stalk from my cabeza." />
<cfset assert.hasText(text, "You have corn stalks in your head!?!?!") />
The above code would notthrow an exception because the text variables has at least one non-whitespace character in it.
Argument Name | Required | Default | Description |
---|---|---|---|
text | true | n/a | The text to check if there at least one non-whitespace character. |
message | false | [Assertion failed] - this text argument must contain valid text content. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |
The isNumber
method assert that the given text is a number such as a whole number (ex. 10
) or a decimal (ex. 9000.25
). This will fail if there are commas in the string (such to denote the thousands place).
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset dollarsInBankAccount = 1,101.53 />
<cfset assert.isNumber(dollarsInBankAccount , "That couldn't be the amount in your bank account!") />
The above assertion would thrown an exception because it is not a valid number (due to the comma).
Argument Name | Required | Default | Description |
---|---|---|---|
text | true | n/a | The text to check if a number (10 , 9000.25 , etc.; no commas). |
message | false | [Assertion failed] - this text argument must be numeric. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |
The isTrue
method asserts that the given expression is true.
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset a = RandRange(0, 100) />
<cfset b = RandRange(0, 100) />
<cfset assert.isTrue(a GT b, "It appears that '#a#' is less than '#b#'.") />
It is unknown whether the assert would pass or fail because the values are randomly generated, however if an exception was thrown we would be able to see what numbers were randomly generated.
Argument Name | Required | Default | Description |
---|---|---|---|
expression | true | n/a | The expression to check if not true. |
message | false | [Assertion failed] - this expression argument must be true. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |
The notEmpty
method asserts that the passed query, struct or array is not empty.
<cfset assert = CreateObject("component", "MachII.util.Assert).init() />
<cfset people = ArrayNew(1) />
<cfset assert.notEmpty(people, "It appears that there are no people!") />
The above code would generate an exception because the people variable is empty.
Argument Name | Required | Default | Description |
---|---|---|---|
object | true | n/a | The object (query, struct or array) to check if not empty. |
message | false | [Assertion failed] - this object argument cannot be an empty query, struct or array. | The message to throw if the assertion fails. |
detail | false | nothing | The detail (additional information) to throw if the assertion fails. |