001: // Copyright © 2002-2007 Canoo Engineering AG, Switzerland.
002: package com.canoo.webtest.steps.control;
003:
004: import org.apache.commons.lang.StringUtils;
005: import org.apache.log4j.Logger;
006: import org.apache.tools.ant.BuildException;
007:
008: import com.canoo.webtest.engine.StepFailedException;
009: import com.canoo.webtest.steps.AbstractStepContainer;
010: import com.canoo.webtest.util.ConversionUtil;
011:
012: /**
013: * @author Carsten Seibert
014: * @author Aatish Arora
015: * @author Jeanie Graham
016: * @author Paul King
017: * @author Gerald Klopp
018: * @webtest.step category="Extension"
019: * name="ifStep"
020: * description="Step which allows conditional execution of inner steps."
021: */
022: public class IfStep extends AbstractStepContainer {
023: private static final Logger LOG = Logger.getLogger(IfStep.class);
024:
025: private String fTest;
026: private String fUnless;
027: private GroupStep fCondition;
028: private GroupStep fThen;
029: private GroupStep fElse;
030:
031: /**
032: * @param test
033: * @webtest.parameter required="yes/no"
034: * description="Expression which if <em>true</em> should cause inner steps to be executed. One of <em>test</em> or <em>unless</em> should be set unless nested <em>condition</em> is used."
035: */
036: public void setTest(final String test) {
037: fTest = test;
038: }
039:
040: public String getTest() {
041: return fTest;
042: }
043:
044: /**
045: * @param unless
046: * @webtest.parameter required="yes/no"
047: * description="Expression which if <em>true</em> should cause inner steps NOT to be executed. One of <em>test</em> or <em>unless</em> should be set unless nested <em>condition</em> is used."
048: */
049: public void setUnless(final String unless) {
050: fUnless = unless;
051: }
052:
053: public String getUnless() {
054: return fUnless;
055: }
056:
057: /**
058: * Handles the nested 'condition' tag.<p>
059: *
060: * If all the steps contained in the 'condition' tag succeed, the 'ifStep' tag inner steps are executed
061: *
062: * @param condition The group of steps to execute to evaluate the test condition
063: * @webtest.nested.parameter required="yes/no"
064: * description="Group of steps which if <em>successful</em> should cause inner steps to be executed. Use instead of <em>test</em> or <em>unless</em> for more complex conditions."
065: */
066: public void addCondition(final GroupStep condition) {
067: fCondition = condition;
068: }
069:
070: public GroupStep getCondition() {
071: return fCondition;
072: }
073:
074: /**
075: * Handles the nested 'then' tag.<p>
076: *
077: * If the 'ifStep' condition passes, execute all the steps in the 'then' inner group.
078: *
079: * @param then The group of steps to execute if the condition passes
080: * @webtest.nested.parameter required="no"
081: * description="Group of steps which execute if the 'ifStep' condition passes. If neither 'then' or 'else' are explicitly set, any inner steps are treated as if they were in an implicit 'then' step."
082: */
083: public void addThen(final GroupStep then) {
084: paramCheck(fThen != null,
085: "Only one nested 'then' step is supported.");
086: fThen = then;
087: }
088:
089: public GroupStep getThen() {
090: return fThen;
091: }
092:
093: /**
094: * Handles the nested 'else' tag.<p>
095: *
096: * If the 'ifStep' condition fails, execute all the steps in the 'else' inner group.
097: *
098: * @param elseStep The group of steps to execute if the condition fails
099: * @webtest.nested.parameter required="no"
100: * description="Group of steps which execute if the 'ifStep' condition fails. If neither 'then' or 'else' are explicitly set, any inner steps are treated as if they were in an implicit 'then' step."
101: */
102: public void addElse(final GroupStep elseStep) {
103: paramCheck(fElse != null,
104: "Only one nested 'else/otherwise' step is supported.");
105: fElse = elseStep;
106: }
107:
108: public GroupStep getElse() {
109: return fElse;
110: }
111:
112: /**
113: * Handles the nested 'otherwise' tag.<p>
114: *
115: * If the 'ifStep' condition fails, execute all the steps in the 'otherwise' inner group.
116: * An alias for 'else'; sometimes more convenient name when used from scripting languages,
117: * e.g. Groovy, where else is a keyword and must otherwise have single quotes around it.
118: *
119: * @param otherwiseStep The group of steps to execute if the condition fails
120: * @webtest.nested.parameter required="no"
121: * description="Alias for else step."
122: */
123: public void addOtherwise(final GroupStep otherwiseStep) {
124: addElse(otherwiseStep);
125: }
126:
127: public GroupStep getOtherwise() {
128: return fElse;
129: }
130:
131: /**
132: * Execute all of the nested steps according to some condition.<p>
133: *
134: * The nested steps will be executed only if one of these conditions is true:<br/>
135: * The 'test' property evaluates to true<br/>
136: * All the steps contained in the nested 'test' tag succeed<br/>
137: * The 'unless' property evaluates to false<br/>
138: * One of the steps contained in the nested 'unless' tag fails<br/>
139: * specifically:
140: * <p/>
141: * <table>
142: * <tr><th>'test' property</th><th>'unless' property</th><th>nested 'condition' tag</th><th>execute?</th></tr>
143: * <tr><td>true</td> <td>missing</td> <td>missing</td> <td>yes</td></tr>
144: * <tr><td>false</td> <td>missing</td> <td>missing</td> <td>no</td></tr>
145: * <tr><td>missing</td> <td>missing</td> <td>all tests succeed</td> <td>yes</td></tr>
146: * <tr><td>missing</td> <td>missing</td> <td>one test fails</td> <td>no</td></tr>
147: * <tr><td>missing</td> <td>true</td> <td>missing</td> <td>no</td></tr>
148: * <tr><td>missing</td> <td>false</td> <td>missing</td> <td>yes</td></tr>
149: * </table>
150: * In other cases, an error occurs
151: *
152: * @throws com.canoo.webtest.engine.StepFailedException
153: * Raises this exception if one of the wrapped steps fails
154: */
155: public void doExecute() throws CloneNotSupportedException {
156: boolean shouldRunSteps = runNestedTests();
157: if (!shouldRunSteps) {
158: if (getElse() != null) {
159: executeContainedStep(getElse());
160: }
161: return;
162: }
163: if (getThen() != null) {
164: executeContainedStep(getThen());
165: } else if (getElse() == null) {
166: executeContainedSteps();
167: }
168: }
169:
170: protected void verifyParameters() {
171: super .verifyParameters();
172: int testParamsNr = 0;
173: if (StringUtils.isNotEmpty(getTest())) {
174: testParamsNr++;
175: }
176: if (StringUtils.isNotEmpty(getUnless())) {
177: testParamsNr++;
178: }
179: if (getCondition() != null) {
180: testParamsNr++;
181: }
182:
183: paramCheck(testParamsNr == 0,
184: "One of the 'test' or the 'unless' attributes or nested tags is required.");
185: paramCheck(testParamsNr > 1,
186: "Only one of the 'test' or the 'unless' attributes or nested tags allowed.");
187: if (fThen != null || fElse != null) {
188: paramCheck(
189: getSteps().size() > 0,
190: "When using 'then' and 'else/otherwise', nested steps most only be grouped inside the 'then' or 'else/otherwise' steps.");
191: }
192: }
193:
194: protected boolean runNestedTests() {
195: if (StringUtils.isNotEmpty(getTest())) {
196: return ConversionUtil.convertToBoolean(getTest(), false);
197: }
198: if (StringUtils.isNotEmpty(getUnless())) {
199: return !ConversionUtil.convertToBoolean(getUnless(), false);
200: }
201: try {
202: executeContainedStep(getCondition());
203: } catch (final BuildException e) {
204: if (StepFailedException.isCausedByStepFailedException(e)) {
205: LOG.debug("test failed");
206: return false;
207: } else {
208: LOG
209: .debug("BuildException not caused by a StepFailedException. Rethrowing.");
210: throw e;
211: }
212: }
213:
214: return true;
215: }
216:
217: }
|