| 1 | <!--- (see below for usage information) |
|---|
| 2 | Copyright 2007 TeraTech, Inc. http://teratech.com/ |
|---|
| 3 | |
|---|
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 5 | you may not use this file except in compliance with the License. |
|---|
| 6 | You may obtain a copy of the License at |
|---|
| 7 | |
|---|
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 9 | |
|---|
| 10 | Unless required by applicable law or agreed to in writing, software |
|---|
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
|---|
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|---|
| 13 | See the License for the specific language governing permissions and |
|---|
| 14 | limitations under the License. |
|---|
| 15 | |
|---|
| 16 | assertions plugin for Fusebox 5.x |
|---|
| 17 | |
|---|
| 18 | usage: |
|---|
| 19 | 1. declare the plugin as part of the prefuseaction and postfuseaction |
|---|
| 20 | phases in your fusebox.xml and name both declarations "assert": |
|---|
| 21 | |
|---|
| 22 | <plugins> |
|---|
| 23 | <phase name="preFuseaction"> |
|---|
| 24 | <plugin name="assert" template="assertions" /> |
|---|
| 25 | </phase> |
|---|
| 26 | <phase name="postFuseaction"> |
|---|
| 27 | <plugin name="assert" template="assertions" /> |
|---|
| 28 | </phase> |
|---|
| 29 | </plugins> |
|---|
| 30 | |
|---|
| 31 | 2. declare the assert prefix in your circuit.xml files: |
|---|
| 32 | |
|---|
| 33 | <circuit xmlns:assert="assertions"> |
|---|
| 34 | |
|---|
| 35 | 3. declare preconditions, postconditions and invariants on your |
|---|
| 36 | fuseactions: |
|---|
| 37 | |
|---|
| 38 | <fuseaction name="welcome" |
|---|
| 39 | assert:precondition="1 eq 1" |
|---|
| 40 | assert:postcondition="0 eq 0" |
|---|
| 41 | assert:invariant="new{myFusebox.thisFuseaction} eq old{myFusebox.thisFuseaction}"> |
|---|
| 42 | ... |
|---|
| 43 | </fuseaction> |
|---|
| 44 | |
|---|
| 45 | invariants: |
|---|
| 46 | old{variableName} lets an invariant refer to the value of a variable |
|---|
| 47 | as it was set at the beginning of the fuseaction |
|---|
| 48 | new{variableName} is just a synonym for variableName for symmetry |
|---|
| 49 | |
|---|
| 50 | ---> |
|---|
| 51 | <cfparam name="myFusebox.plugins[myFusebox.thisPlugin].invariants" default="#structNew()#" /> |
|---|
| 52 | <cfparam name="myFusebox.plugins[myFusebox.thisPlugin].invariants.#myFusebox.thisCircuit#$#myFusebox.thisFuseaction#" default="#structNew()#" /> |
|---|
| 53 | <cfset myFusebox.plugins[myFusebox.thisPlugin].customAttrs = |
|---|
| 54 | myFusebox.getApplication() |
|---|
| 55 | .circuits[myFusebox.thisCircuit] |
|---|
| 56 | .fuseactions[myFusebox.thisFuseaction] |
|---|
| 57 | .getCustomAttributes(myFusebox.thisPlugin) /> |
|---|
| 58 | <cfif myFusebox.thisPhase is "prefuseaction"> |
|---|
| 59 | <!--- check the precondition is true ---> |
|---|
| 60 | <cfif structKeyExists(myFusebox.plugins[myFusebox.thisPlugin].customAttrs,"precondition")> |
|---|
| 61 | <cfif not evaluate(myFusebox.plugins[myFusebox.thisPlugin].customAttrs.precondition)> |
|---|
| 62 | <cfthrow type="fusebox.failedAssertion.precondition" |
|---|
| 63 | message="Assert precondition failed" |
|---|
| 64 | detail="The precondition {#myFusebox.plugins[myFusebox.thisPlugin].customAttrs.precondition#} was false for Fuseaction #myFusebox.thisFuseaction# in Circuit #myFusebox.thisCircuit#" /> |
|---|
| 65 | </cfif> |
|---|
| 66 | </cfif> |
|---|
| 67 | <!--- parse the invariant and remember any old{variable} data ---> |
|---|
| 68 | <cfif structKeyExists(myFusebox.plugins[myFusebox.thisPlugin].customAttrs,"invariant")> |
|---|
| 69 | <!--- search for old{var} and save all those values ---> |
|---|
| 70 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = 1 /> |
|---|
| 71 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("old{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 72 | <cfloop condition="myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] neq 0"> |
|---|
| 73 | <cfset myFusebox.plugins[myFusebox.thisPlugin].old = mid(myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].match.pos[2],myFusebox.plugins[myFusebox.thisPlugin].match.len[2]) /> |
|---|
| 74 | <cfset myFusebox.plugins[myFusebox.thisPlugin].invariants["#myFusebox.thisCircuit#$#myFusebox.thisFuseaction#"][myFusebox.plugins[myFusebox.thisPlugin].old] = evaluate(myFusebox.plugins[myFusebox.thisPlugin].old) /> |
|---|
| 75 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] + myFusebox.plugins[myFusebox.thisPlugin].match.len[1] /> |
|---|
| 76 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("old{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 77 | </cfloop> |
|---|
| 78 | </cfif> |
|---|
| 79 | <cfelseif myFusebox.thisPhase is "postfuseaction"> |
|---|
| 80 | <!--- check the postcondition is true ---> |
|---|
| 81 | <cfif structKeyExists(myFusebox.plugins[myFusebox.thisPlugin].customAttrs,"postcondition")> |
|---|
| 82 | <cfif not evaluate(myFusebox.plugins[myFusebox.thisPlugin].customAttrs.postcondition)> |
|---|
| 83 | <cfthrow type="fusebox.failedAssertion.postcondition" |
|---|
| 84 | message="Assert postcondition failed" |
|---|
| 85 | detail="The postcondition {#myFusebox.plugins[myFusebox.thisPlugin].customAttrs.postcondition#} was false for Fuseaction #myFusebox.thisFuseaction# in Circuit #myFusebox.thisCircuit#" /> |
|---|
| 86 | </cfif> |
|---|
| 87 | </cfif> |
|---|
| 88 | <!--- parse the invariant and substitute any old{} / new{} values ---> |
|---|
| 89 | <cfif structKeyExists(myFusebox.plugins[myFusebox.thisPlugin].customAttrs,"invariant")> |
|---|
| 90 | <!--- search for old{var} and substitute those values ---> |
|---|
| 91 | <cfset myFusebox.plugins[myFusebox.thisPlugin].evalInvariant = myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant /> |
|---|
| 92 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = 1 /> |
|---|
| 93 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("old{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 94 | <cfloop condition="myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] neq 0"> |
|---|
| 95 | <cfset myFusebox.plugins[myFusebox.thisPlugin].old = mid(myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].match.pos[2],myFusebox.plugins[myFusebox.thisPlugin].match.len[2]) /> |
|---|
| 96 | <cfset myFusebox.plugins[myFusebox.thisPlugin].evalInvariant = replace(myFusebox.plugins[myFusebox.thisPlugin].evalInvariant,"old{#myFusebox.plugins[myFusebox.thisPlugin].old#}","myFusebox.plugins[myFusebox.thisPlugin].invariants.#myFusebox.thisCircuit#$#myFusebox.thisFuseaction#[""#myFusebox.plugins[myFusebox.thisPlugin].old#""]","one") /> |
|---|
| 97 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] + myFusebox.plugins[myFusebox.thisPlugin].match.len[1] /> |
|---|
| 98 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("old{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 99 | </cfloop> |
|---|
| 100 | <!--- search for new{var} and substitute those values ---> |
|---|
| 101 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = 1 /> |
|---|
| 102 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("new{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 103 | <cfloop condition="myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] neq 0"> |
|---|
| 104 | <cfset myFusebox.plugins[myFusebox.thisPlugin].new = mid(myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].match.pos[2],myFusebox.plugins[myFusebox.thisPlugin].match.len[2]) /> |
|---|
| 105 | <cfset myFusebox.plugins[myFusebox.thisPlugin].evalInvariant = replace(myFusebox.plugins[myFusebox.thisPlugin].evalInvariant,"new{#myFusebox.plugins[myFusebox.thisPlugin].new#}","#myFusebox.plugins[myFusebox.thisPlugin].new#","one") /> |
|---|
| 106 | <cfset myFusebox.plugins[myFusebox.thisPlugin].start = myFusebox.plugins[myFusebox.thisPlugin].match.pos[1] + myFusebox.plugins[myFusebox.thisPlugin].match.len[1] /> |
|---|
| 107 | <cfset myFusebox.plugins[myFusebox.thisPlugin].match = REFind("new{([^}]*)}",myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant,myFusebox.plugins[myFusebox.thisPlugin].start,true) /> |
|---|
| 108 | </cfloop> |
|---|
| 109 | <cfif not evaluate(myFusebox.plugins[myFusebox.thisPlugin].evalInvariant)> |
|---|
| 110 | <cfthrow type="fusebox.failedAssertion.invariant" |
|---|
| 111 | message="Assert invariant failed" |
|---|
| 112 | detail="The invariant {#myFusebox.plugins[myFusebox.thisPlugin].customAttrs.invariant#} was false for Fuseaction #myFusebox.thisFuseaction# in Circuit #myFusebox.thisCircuit#" /> |
|---|
| 113 | </cfif> |
|---|
| 114 | </cfif> |
|---|
| 115 | <cfelse> |
|---|
| 116 | <!--- no idea why the assertion plugin was invoked: ignore it ---> |
|---|
| 117 | </cfif> |
|---|