Bug 701076 - core robocop toolchain (1.03) a=tfair; r=gbrown,blassey

This commit is contained in:
Joel Maher 2011-12-22 09:09:41 -05:00
parent 157c7f8bcb
commit 0eb9ac4812
11 changed files with 1237 additions and 0 deletions

View File

@ -0,0 +1,60 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
import java.util.List;
public interface Actions {
public enum SpecialKey {
DOWN, UP, LEFT, RIGHT, ENTER
}
/**
* Waits for a gecko event to be sent from the Gecko instance.
*
* @param geckoEvent The geckoEvent JSONObject's type
*/
void waitForGeckoEvent(String geckoEvent);
// Send the string kewsToSend to the application
void sendKeys(String keysToSend);
//Send any of the above keys to the element
void sendSpecialKey(SpecialKey button);
void drag(int startingX, int endingX, int startingY, int endingY);
}

View File

@ -0,0 +1,19 @@
#filter substitution
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.roboexample.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="@ANDROID_PACKAGE_NAME@" />
<application
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>

View File

@ -0,0 +1,78 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
import java.util.List;
public interface Driver {
/**
* Find the first Element using the given method.
*
* @param name The name of the element
* @return The first matching element on the current context
* @throws RoboCopException If no matching elements are found
*/
Element findElement(String name);
/**
* Sets up scroll handling so that data is received from the extension.
*/
void setupScrollHandling();
int getPageHeight();
int getScrollHeight();
int getHeight();
int getGeckoTop();
int getGeckoLeft();
int getGeckoWidth();
int getGeckoHeight();
void startFrameRecording();
int stopFrameRecording();
void dumpLog(String message);
void setLogFile(String filename);
void ok(boolean condition, String name, String diag);
void is(Object a, Object b, String name);
void isnot(Object a, Object b, String name);
void todo(boolean condition, String name, String diag);
void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name);
void info(String name, String message);
}

View File

@ -0,0 +1,49 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
public interface Element {
//Click on the element
void click();
//Returns true if the element is currently displayed
boolean isDisplayed();
//Returns the text currently displayed on the element.
String getText();
}

View File

@ -0,0 +1,197 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.List;
import java.lang.Class;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.Long;
import android.app.Activity;
import android.app.Instrumentation;
import android.util.Log;
import android.view.View;
import android.view.KeyEvent;
import java.util.concurrent.SynchronousQueue;
import org.json.*;
import com.jayway.android.robotium.solo.Solo;
public class FennecNativeActions implements Actions {
// Map of IDs to element names.
private Solo solo;
private Instrumentation instr;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
// If waiting for an event.
private SynchronousQueue waitqueue = new SynchronousQueue<Boolean>();
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
this.solo = robocop;
this.instr = instrumentation;
// Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = gel;
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
class wakeInvocationHandler implements InvocationHandler {
public wakeInvocationHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
//Depending on the method, return a completely different type.
if(methodName.equals("toString")) {
return "wakeInvocationHandler";
}
if(methodName.equals("equals")) {
return this == args[0];
}
if(methodName.equals("clone")) {
return this;
}
if(methodName.equals("hashCode")) {
return 314;
}
Log.i("Robocop", "Waking up on "+methodName);
waitqueue.offer(new Boolean(true));
return null;
}
}
public void waitForGeckoEvent(String geckoEvent) {
Log.i("Robocop", "waiting for "+geckoEvent);
try {
Class [] interfaces = new Class[1];
interfaces[0] = gel;
Object[] finalParams = new Object[2];
finalParams[0] = geckoEvent;
wakeInvocationHandler wIH = new wakeInvocationHandler();
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, wIH);
finalParams[1] = proxy;
registerGEL.invoke(null, finalParams);
waitqueue.take();
unregisterGEL.invoke(null, finalParams);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Robocop", "wait ends for: "+geckoEvent);
}
public void sendSpecialKey(SpecialKey button) {
switch( button) {
case DOWN:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
break;
case UP:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
break;
case LEFT:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
break;
case RIGHT:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
break;
case ENTER:
instr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
break;
default:
break;
}
}
@Override
public void sendKeys(String input) {
instr.sendStringSync(input);
}
public void drag(int startingX, int endingX, int startingY, int endingY) {
solo.drag(startingX, endingX, startingY, endingY, 10);
}
}

View File

@ -0,0 +1,425 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.List;
import java.lang.Class;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.Long;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import org.json.*;
import com.jayway.android.robotium.solo.Solo;
public class FennecNativeDriver implements Driver {
// Map of IDs to element names.
private HashMap locators = null;
private Activity activity;
private Solo solo;
private String logFile;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
private Method _startFrameRecording;
private Method _stopFrameRecording;
private LinkedList<testInfo> testList = new LinkedList<testInfo>();
public FennecNativeDriver(Activity activity, Solo robocop){
this.activity = activity;
this.solo = robocop;
// Set up table of fennec_ids.
locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
// Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = gel;
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
//Information on the location of the Gecko Frame.
private boolean geckoInfo = false;
private int geckoTop = 100;
private int geckoLeft = 0;
private int geckoHeight= 700;
private int geckoWidth = 1024;
private void getGeckoInfo() {
View geckoLayout = activity.findViewById(Integer.decode((String)locators.get("gecko_layout")));
if (geckoLayout != null) {
geckoTop = geckoLayout.getTop();
geckoLeft = geckoLayout.getLeft();
geckoWidth = geckoLayout.getWidth();
geckoHeight = geckoLayout.getHeight();
geckoInfo = true;
}
}
public int getGeckoTop() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoTop;
}
public int getGeckoLeft() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoLeft;
}
public int getGeckoHeight() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoHeight;
}
public int getGeckoWidth() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoWidth;
}
@Override
public Element findElement(String name) {
if (name == null)
throw new IllegalArgumentException("Can not findElements when passed a null");
if (locators.containsKey(name)){
return new FennecNativeElement(Integer.decode((String)locators.get(name)), activity, solo);
}
throw new RoboCopException("Element does not exist in the list");
}
public void startFrameRecording() {
try {
Object [] params = null;
_startFrameRecording.invoke(null, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public int stopFrameRecording() {
Class [] parameters = new Class[1];
parameters[0] = null;
List frames;
try {
Object [] params = null;
frames = (List)_stopFrameRecording.invoke(null, params);
Object [] framearray = frames.toArray();
Long last = new Long(0);
Long threshold = new Long(17);
int numDelays = 0;
for (int i=0; i < framearray.length; i++) {
Long val = (Long)framearray[i];
if ((val - last) > threshold) {
numDelays++;
}
last = val;
}
return numDelays;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {
try{
//Disect the JSON object into the appropriate variables
JSONObject jo = ((JSONObject)args[1]);
scrollHeight = jo.getInt("y");
height = jo.getInt("cheight");
//We don't want a height of 0. That means it's a bad response.
if( height > 0) {
pageHeight = jo.getInt("height");
}
} catch( Throwable e) {
Log.i("Robocop", "WARNING: ScrollReceived, but read wrong!");
}
return null;
}
}
public int getScrollHeight() {
return scrollHeight;
}
public int getPageHeight() {
return pageHeight;
}
public int getHeight() {
return height;
}
public int height=0;
public int scrollHeight=0;
public int pageHeight=10;
public void setupScrollHandling() {
//Setup scrollHandler to catch "robocop:scroll" events.
try {
Class [] interfaces = new Class[1];
interfaces[0] = gel;
Object[] finalParams = new Object[2];
finalParams[0] = "robocop:scroll";
finalParams[1] = Proxy.newProxyInstance(classLoader, interfaces, new scrollHandler());
registerGEL.invoke(null, finalParams);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//Takes a filename, loads the file,
// and returns a string version of the entire file.
public static String getFile(String filename)
{
File file = new File(filename);
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
} catch(IOException e) {
e.printStackTrace();
}
return text.toString();
}
// Write information to a logfile and logcat
public void dumpLog(String message)
{
File file = new File(logFile);
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(logFile, true));
bw.write(message);
bw.newLine();
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Log.i("Robocop", message);
}
// Set the filename used for dumpLog.
public void setLogFile(String filename)
{
logFile = filename;
}
// Takes a string of "key=value" pairs split by \n and creates a hash table.
public static HashMap convertTextToTable(String data)
{
HashMap retVal = new HashMap();
String[] lines = data.split("\n");
for (int i = 0; i < lines.length; i++) {
String[] parts = lines[i].split("=");
retVal.put(parts[0].trim(), parts[1].trim());
}
return retVal;
}
class testInfo {
public boolean result;
public String name;
public String diag;
public boolean todo;
public testInfo(boolean r, String n, String d, boolean t) {
result = r;
name = n;
diag = d;
todo = t;
}
}
private void _logResult(testInfo test, String passString, String failString)
{
boolean isError = true;
String resultString = failString;
if(test.result || test.todo){
isError = false;
}
if(test.result)
{
resultString = passString;
}
String diag= test.name;
if(test.diag!=null) diag+= " - " + test.diag;
String message = resultString + " | " + "ROBOCOP" + " | " + diag;
if(isError) {
dumpLog(message);
}
else {
dumpLog(message);
}
}
public void ok(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, false);
_logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
testList.add(test);
}
public void is(Object a, Object b, String name) {
boolean pass = a.equals(b);
String diag = "got " + a.toString() + ", expected " + b.toString();
if(pass) {
diag = a.toString() + " should equal " + b.toString();
}
ok(pass, name, diag);
}
public void isnot(Object a, Object b, String name) {
boolean pass = !a.equals(b);
String diag = "didn't expect " + a.toString() + ", but got it";
if(pass) {
diag = a.toString() + " should not equal " + b.toString();
}
ok(pass, name, diag);
}
public void todo(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, true);
_logResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
testList.add(test);
}
public void todo_is(Object a, Object b, String name) {
boolean pass = a.equals(b);
String diag = "got " + a.toString() + ", expected " + b.toString();
if(pass) {
diag = a.toString() + " should equal " + b.toString();
}
todo(pass, name, diag);
}
public void todo_isnot(Object a, Object b, String name) {
boolean pass = !a.equals(b);
String diag = "didn't expect " + a.toString() + ", but got it";
if(pass) {
diag = a.toString() + " should not equal " + b.toString();
}
todo(pass, name, diag);
}
public void info(String name, String message) {
testInfo test = new testInfo(true, name, message, false);
_logResult(test, "TEST-INFO", "INFO FAILED?");
}
}

View File

@ -0,0 +1,149 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
import java.util.List;
import android.app.Activity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextSwitcher;
import android.app.Instrumentation;
import android.util.Log;
import com.jayway.android.robotium.solo.Solo;
import java.util.concurrent.SynchronousQueue;
public class FennecNativeElement implements Element {
private Integer id;
private Activity currentActivity;
private Solo robocop;
public FennecNativeElement(Integer id, Activity activity, Solo solo){
this.id = id;
robocop = solo;
currentActivity = activity;
}
public Integer getId() {
return id;
}
@Override
public void click() {
final SynchronousQueue syncQueue = new SynchronousQueue();
currentActivity = robocop.getCurrentActivity();
currentActivity.runOnUiThread(
new Runnable() {
public void run() {
View view = (View)currentActivity.findViewById(id);
if(view != null) {
view.performClick();
} else {
throw new RoboCopException("click: unable to find view "+id);
}
syncQueue.offer(new Object());
}
});
try {
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Object text;
private Activity elementActivity;
@Override
public String getText() {
elementActivity = robocop.getCurrentActivity();
final SynchronousQueue syncQueue = new SynchronousQueue();
elementActivity.runOnUiThread(
new Runnable() {
public void run() {
View v = elementActivity.findViewById(id);
if(v instanceof EditText) {
EditText et = (EditText)v;
text = et.getEditableText();
}else if(v instanceof TextSwitcher) {
TextSwitcher ts = (TextSwitcher)v;
ts.getNextView();
text = ((TextView)ts.getCurrentView()).getText();
}else if(v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup)v;
for(int i = 0; i < vg.getChildCount(); i++) {
if(vg.getChildAt(i) instanceof TextView) {
text = ((TextView)vg.getChildAt(i)).getText();
}
} //end of for
} else if(v instanceof TextView) {
text = ((TextView)v).getText();
} else if(v == null) {
throw new RoboCopException("getText: unable to find view "+id);
} else {
throw new RoboCopException("getText: unhandled type for view "+id);
}
syncQueue.offer(new Object());
} // end of run() method definition
} // end of anonymous Runnable object instantiation
);
try {
//Wait for the UiThread code to finish running
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(text == null) {
throw new RoboCopException("getText: Text is null for view "+id);
}
return text.toString();
}
@Override
public boolean isDisplayed() {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -0,0 +1,136 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Android sutagent for testing.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
TESTPATH = $(topsrcdir)/mobile/android/base/tests
include $(DEPTH)/config/autoconf.mk
MODULE = robocop
ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.0.jar
JAVAFILES = \
R.java \
_JAVA_HARNESS = \
Driver.java \
Element.java \
Actions.java \
FennecNativeElement.java \
RoboCopException.java \
FennecNativeDriver.java \
FennecNativeActions.java \
_JAVA_TESTS = $(patsubst $(TESTPATH)/%.in,%,$(wildcard $(TESTPATH)/*.java.in))
_ROBOCOP_TOOLS = \
$(TESTPATH)/robocop.ini \
parse_ids.py \
$(NULL)
GARBAGE += \
AndroidManifest.xml \
_JAVA_TESTS \
_JAVA_HARNESS \
classes.dex \
robocop.apk \
robocop.ap_ \
robocop-unsigned-unaligned.apk \
robocop-unaligned.apk \
$(NULL)
DEFINES += \
-DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
$(NULL)
GARBAGE_DIRS += res
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(ROBOTIUM_PATH)
include $(topsrcdir)/config/rules.mk
# Override rules.mk java flags with the android specific ones
include $(topsrcdir)/config/android-common.mk
$(_JAVA_HARNESS): % : %.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
AndroidManifest.xml: % : %.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
$(_JAVA_TESTS): % : $(TESTPATH)/%.in
$(NSINSTALL) -D $(DEPTH)/mobile/android/base/tests
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $(DEPTH)/mobile/android/base/tests/$@
$(_ROBOCOP_TOOLS):
cp $(TESTPATH)/robocop.ini robocop.ini
cp $(srcdir)/parse_ids.txt parse_ids.txt
tools:: robocop.apk
classes.dex: robocop.ap_
classes.dex: $(_ROBOCOP_TOOLS)
classes.dex: $(_JAVA_HARNESS)
classes.dex: $(_JAVA_TESTS)
classes.dex: $(TEST_FILES)
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(addprefix $(DEPTH)/mobile/android/base/tests/,$(_JAVA_TESTS))
$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH)
robocop.ap_: AndroidManifest.xml
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -I . -S res -F $@ -J ./
robocop-unsigned-unaligned.apk: robocop.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
robocop-unaligned.apk: robocop-unsigned-unaligned.apk
cp robocop-unsigned-unaligned.apk $@
jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android $@ androiddebugkey
robocop.apk: robocop-unaligned.apk
$(ZIPALIGN) -f -v 4 robocop-unaligned.apk $@
cp $(TESTPATH)/robocop.ini robocop.ini
cp $(srcdir)/parse_ids.py parse_ids.py
export::
$(NSINSTALL) -D res
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/robocop/res && tar -xf -)

View File

@ -0,0 +1,59 @@
#filter substitution
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Firefox Mobile Test Framework.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Trevor Fairey <tnfairey@gmail.com>
* David Burns <dburns@mozilla.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package @ANDROID_PACKAGE_NAME@;
public class RoboCopException extends RuntimeException {
public RoboCopException(){
super();
}
public RoboCopException(String message){
super(message);
}
public RoboCopException(Throwable cause){
super(cause);
}
public RoboCopException(String message, Throwable cause){
super(message, cause);
}
}

View File

@ -0,0 +1,60 @@
import re
import os
import sys
import optparse
def getFile(filename):
fHandle = open(filename, 'r')
data = fHandle.read()
fHandle.close()
return data
def findIDs(data):
start_function = False
reID = re.compile('.*public static final class id {.*')
reEnd = re.compile('.*}.*')
idlist = []
for line in data.split('\n'):
if reEnd.match(line):
start_function = False
if start_function:
id_value = line.split(' ')[-1]
idlist.append(id_value.split(';')[0].split('='))
if reID.match(line):
start_function = True
return idlist
def printIDs(outputFile, idlist):
fOutput = open(outputFile, 'w')
for item in idlist:
fOutput.write("%s=%s\n" % (item[0], item[1]))
fOutput.close()
def main(args=sys.argv[1:]):
parser = optparse.OptionParser()
parser.add_option('-o', '--output', dest='outputFile', default='',
help="output file with the id=value pairs")
parser.add_option('-i', '--input', dest='inputFile', default='',
help="filename of the input R.java file")
options, args = parser.parse_args(args)
if options.inputFile == '':
print "Error: please provide input file: -i <filename>"
sys.exit(1)
if options.outputFile == '':
print "Error: please provide output file: -o <filename>"
sys.exit(1)
data = getFile(os.path.abspath(options.inputFile));
idlist = findIDs(data)
printIDs(os.path.abspath(options.outputFile), idlist)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Roboexample</string>
</resources>