/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.agents.html.automators;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import com.gorillalogic.monkeytalk.Command;
import com.gorillalogic.monkeytalk.automators.AutomatorConstants;
/**
* Base automator for desktop web elements
*
* @author sstern
*
*/
public abstract class AutomatorBase implements IAutomator {
protected WebDriver driver;
protected String monkeyId;
@Override
public String play(Command command) {
String action = command.getAction();
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_NOT)) {
return verifyNot(command);
}
assertExists();
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_GET)) {
return get(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY)) {
return verify(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_REGEX)) {
return verifyRegex(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_NOT_REGEX)) {
return verifyNotRegex(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_WILDCARD)) {
return verifyWildcard(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_NOT_WILDCARD)) {
return verifyNotWildcard(command);
}
if (action.equalsIgnoreCase(AutomatorConstants.ACTION_VERIFY_IMAGE)) {
return verifyImage(command);
}
throw new IllegalArgumentException("Action '" + command.getAction()
+ "' unrecognized for component type " + command.getComponentType());
}
protected String get(Command command) {
return doGet(command);
}
protected String verify(Command command) {
return doVerify(command, false);
}
protected String verifyNot(Command command) {
return doVerify(command, true);
}
protected String verifyRegex(Command command) {
return doVerifyRegex(command, false);
}
protected String verifyNotRegex(Command command) {
return doVerifyRegex(command, true);
}
protected String verifyWildcard(Command command) {
return doVerifyWildcard(command, false);
}
protected String verifyNotWildcard(Command command) {
return doVerifyWildcard(command, true);
}
protected String verifyImage(Command command) {
return doVerifyImage(command);
}
private String doGet(Command command) {
String propName = getOptArg(command, 1);
if (propName == null) {
propName = "value";
}
String result = getProperty(propName);
return result;
}
private String doVerify(Command command, boolean not) {
String expected = getOptArg(command, 0);
if (expected == null) {
if (not) {
boolean exists = true;
try {
assertExists();
} catch (Exception e) {
exists = false;
}
if (exists) {
throw new NoSuchElementException(getComponentType() + " '" + monkeyId + "' should not be found");
}
return "true";
}
}
String propName = getOptArg(command, 1);
if (propName == null) {
propName = "value";
}
String actual = getProperty(propName);
boolean result = actual.equals(expected);
if (not) {
if (result) {
throw new java.util.NoSuchElementException("Actual value for property '" + propName
+ "' should not equal '" + actual + "'");
}
return "true";
} else {
if (!result) {
throw new java.util.NoSuchElementException("Expected '" + expected
+ "' but found '" + actual + "' for property '" + propName + "'");
}
return "true";
}
}
// Throw an exception if the associated component exists
protected void assertExists() {
}
private String doVerifyRegex(Command command, boolean not) {
String expected = getArg(command, 0);
String propName = getOptArg(command, 1);
if (propName == null) {
propName = "value";
}
String actual = getProperty(propName);
boolean result = actual.matches(expected);
if (not) {
if (result) {
throw new java.util.NoSuchElementException("Actual value '" + actual + "'for property '" + propName
+ "' should not match '" + expected + "'");
}
return "true";
} else {
if (!result) {
throw new java.util.NoSuchElementException("Expected to match '" + expected
+ "' but found '" + actual + "' for property '" + propName + "'");
}
return "true";
}
}
private String doVerifyWildcard(Command command, boolean not) {
String expected = getArg(command, 0);
String regex = wildcardToRegex(expected);
String propName = getOptArg(command, 1);
if (propName == null) {
propName = "value";
}
String actual = getProperty(propName);
boolean result = actual.matches(regex);
if (not) {
if (result) {
throw new java.util.NoSuchElementException("Actual value '" + actual + "'for property '" + propName
+ "' should not match '" + expected + "'");
}
return "true";
} else {
if (!result) {
throw new java.util.NoSuchElementException("Expected to match '" + expected
+ "' but found '" + actual + "' for property '" + propName + "'");
}
return "true";
}
}
/**
* performs the agent-side part of the verifyImage command
* take a screenshot and return it, along with the
* position and size of the target component
* @return
*/
private String doVerifyImage(Command command) {
Rect br=getBoundingRectangle();
return takeScreenshot(br.x+" "+ br.y + " " + br.w + " " + br.h);
}
private String takeScreenshot(String msg) {
if (msg == null) {
msg = "no message";
}
System.out.println("VerifyImage SCREENSHOT - " + msg + " - taking screenshot...");
//DeviceAutomator device = (DeviceAutomator) AutomationManager.findAutomatorByType("Device");
IAutomator device = this;
Command screenshotCommand
= new Command(this.getComponentType(),
this.monkeyId,
AutomatorConstants.ACTION_SCREENSHOT,
new ArrayList<String>(),
new HashMap<String, String>());
if (device != null) {
try {
String screenshot = device.play(screenshotCommand);
if (screenshot != null && screenshot.startsWith("{screenshot")) {
System.out.println("SCREENSHOT - done!");
return "{message:\"" + msg.replaceAll("\"", "'") + "\","
+ screenshot.substring(1);
}
} catch (Exception ex) {
String exMsg = ex.getMessage();
if (exMsg != null) {
exMsg = exMsg.replaceAll("\"", "'");
} else {
exMsg = ex.getClass().getName();
}
return msg + " -- " + exMsg;
}
}
return msg;
}
protected static class Rect {
int x,y,w,h;
public Rect(int x, int y, int w, int h) {this.x=x; this.y=y; this.w=w; this.h=h;}
}
protected Rect getBoundingRectangle() {
return new Rect(0,0,1,1);
}
protected String getArg(Command command, int index) {
try {
return command.getArgs().get(index);
} catch (Exception e) {
throw new IllegalArgumentException("Expected " + index + " arguments for action '"
+ command.getAction() + "' but found " + command.getArgs().size());
}
}
protected int getIndexArg(Command command, int index) {
String arg = getOptArg(command, index);
if (arg == null) {
return 1;
}
int i = 0;
try {
i = Integer.valueOf(arg);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expecting numeric value for argument " + index + 1 + " but found '" + arg + "'");
}
if (i < 1) {
throw new IllegalArgumentException("Expecting positive (> 0) value for argument " + index + 1 + " but found '" + i + "'");
}
return i;
}
protected String getOptArg(Command command, int index) {
try {
return command.getArgs().get(index);
} catch (Exception e) {
return null;
}
}
@Override
public void init(WebDriver driver, String monkeyId) {
this.driver = driver;
this.monkeyId = monkeyId;
}
/**
* The actual value of some property
*
* @param prop
* the property name
* @return the property value
*/
protected String getProperty(String prop) {
throw new IllegalArgumentException("No such property '" + prop + "' for "
+ getComponentType());
}
// Thanks - http://www.rgagnon.com/javadetails/java-0515.html
private static String wildcardToRegex(String wildcard) {
StringBuilder s = new StringBuilder(wildcard.length());
s.append('^');
for (int i = 0, is = wildcard.length(); i < is; i++) {
char c = wildcard.charAt(i);
switch (c) {
case '*':
s.append(".*");
break;
case '?':
s.append(".");
break;
// escape special regexp-characters
case '(':
case ')':
case '[':
case ']':
case '$':
case '^':
case '.':
case '{':
case '}':
case '|':
case '\\':
s.append("\\");
s.append(c);
break;
default:
s.append(c);
break;
}
}
s.append('$');
return (s.toString());
}
}