// Copyright � 2004-2005 ASERT. Released under the Canoo Webtest license. package com.canoo.webtest.extension; import java.util.StringTokenizer; import org.apache.log4j.Logger; import com.canoo.webtest.steps.store.BaseStoreStep; import com.canoo.webtest.util.ConversionUtil; /** * Stores a random value (number, string or token) into a property.<p> * <p/> * Either ant or dynamic properties are supported. The random values can * be used when invoking subsequent steps and checking responses. * * @author Paul King, ASERT * @webtest.step category="Extension" * name="storeRandom" * description="Provides the ability to store a random number, string or token value for later processing. Useful to avoid setting (and maintaining) large numbers of properties containing test data when specific test values aren't important." */ public final class StoreRandom extends BaseStoreStep { private static final Logger LOG = Logger.getLogger(StoreRandom.class); private static final int MODE_NUMBER = 1; private static final int MODE_STRING = 2; private static final int MODE_CHOICE = 3; private static final String DEFAULT_CHARS = " abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 "; private String fFrom; private String fTo; private String fLength; private String fChars; private String fChoice; private int fMode; public String getFrom() { return fFrom; } /** * @webtest.parameter required="yes/no" * description="Used when storing a random number. The random number stored will be greater than or equal to this number. Required if <em>to</em> is set. Parameters <em>length</em> and <em>choice</em> must be empty." */ public void setFrom(String from) { fFrom = from; } public String getTo() { return fTo; } /** * @webtest.parameter required="yes/no" * description="Used when storing a random number. The random number stored will be less than or equal to this number. Required if <em>from</em> is set. Parameters <em>length</em> and <em>choice</em> must be empty." */ public void setTo(final String to) { fTo = to; } public String getLength() { return fLength; } /** * @webtest.parameter required="yes/no" * description="Used when storing a random string. The length of the random string to store (i.e. the number of characters to randomly select). Parameters <em>from</em>, <em>to</em> and <em>choice</em> must be empty." */ public void setLength(final String length) { fLength = length; } public String getChars() { return fChars; } /** * @webtest.parameter required="no" * description="Used when storing a random string. The set of characters to choose from when creating the random string. Ignored unless <em>length</em> is set." * default="the upper and lowercase alphabets plus numbers plus spaces" */ public void setChars(final String chars) { fChars = chars; } public String getChoice() { return fChoice; } /** * @webtest.parameter required="yes/no" * description="Used when storing a random token. The comma delimited choice of tokens to randomly select between. Parameters <em>from</em>, <em>to</em> and <em>length</em> must be empty." */ public void setChoice(final String choice) { fChoice = choice; } public void doExecute() { String randString; switch (fMode) { case MODE_NUMBER: int fromInt = ConversionUtil.convertToInt(getFrom(), -1); int toInt = ConversionUtil.convertToInt(getTo(), -1); paramCheck(fromInt >= toInt, "Parameter \"from\" must be less than parameter \"to\"!"); randString = generateRandomNumber(fromInt, toInt); break; case MODE_CHOICE: StringTokenizer st = new StringTokenizer(getChoice(), ","); paramCheck(st.countTokens() < 1, "Parameter \"choice\" must have some comma-delimited choices!"); randString = generateRandomToken(st); break; default: // MODE_STRING int numChars = ConversionUtil.convertToInt(getLength(), 0); if (getChars() == null) { randString = generateRandomChars(numChars, DEFAULT_CHARS); } else { randString = generateRandomChars(numChars, getChars()); } break; } storeProperty(randString); } private static String generateRandomToken(final StringTokenizer st) { String randString = ""; for (int pos = (int) (Math.random() * st.countTokens()) + 1; pos-- > 0;) { randString = st.nextToken(); } return randString; } private static String generateRandomNumber(int fromInt, int toInt) { int randValue = fromInt + (int) (Math.random() * (toInt - fromInt + 1)); return Integer.toString(randValue); } private static String generateRandomChars(int numChars, final String chars) { StringBuffer randBuf = new StringBuffer(); int l = chars.length(); for (int i = 0; i < numChars; i++) { int pos = (int) (l * Math.random()); randBuf.append(chars.charAt(pos)); } return randBuf.toString(); } /** * Verifies the parameters */ protected void verifyParameters() { super.verifyParameters(); nullParamCheck(getProperty(), "property"); fMode = 0; if (isOnlyLengthSet()) { fMode = MODE_STRING; integerParamCheck(getLength(), "length", true); LOG.debug("Mode = MODE_STRING"); } else if (isOnlyFromAndToSet()) { fMode = MODE_NUMBER; integerParamCheck(getFrom(), "from", true); integerParamCheck(getTo(), "to", true); LOG.debug("Mode = MODE_NUMBER"); } else if (isOnlyChoiceSet()) { fMode = MODE_CHOICE; LOG.debug("Mode = MODE_CHOICE"); } paramCheck(fMode == 0, "Required parameter(s) not set correctly! Need (\"from\" and \"to\") or \"length\" or \"choice\"."); } private boolean isOnlyChoiceSet() { return getChoice() != null && getLength() == null && getFrom() == null && getTo() == null; } private boolean isOnlyFromAndToSet() { return getFrom() != null && getTo() != null && getChoice() == null && getLength() == null; } private boolean isOnlyLengthSet() { return getFrom() == null && getTo() == null && getChoice() == null && getLength() != null; } }