Added Support for Silverlight. Added more unit tests

Support for automating Silverlight in firefox and Internet Explorer is
now supported, along with WPF and regular Win32.
This commit is contained in:
Edward Jakubowski
2014-04-08 22:40:43 -04:00
parent bc3c070ea8
commit 2389b13eb7
11 changed files with 168 additions and 61 deletions

View File

@@ -12,6 +12,7 @@ public class Config extends PropertiesSerializer {
public static String DEFAULT_PROP_FILENAME = "synthuse.properties";
public String disableWpf = "false";
public String disableFiltersWpf = "false";
public String urlList = "";
public String xpathList = "";
public String xpathHightlight = ".*process=\"([^\"]*)\".*";
@@ -28,6 +29,15 @@ public class Config extends PropertiesSerializer {
public boolean isWpfBridgeDisabled()
{
if (disableWpf == null)
return false;
return disableWpf.equals("true") || disableWpf.equals("True");
}
public boolean isFilterWpfDisabled()
{
if (disableFiltersWpf == null)
return false;
return disableFiltersWpf.equals("true") || disableFiltersWpf.equals("True");
}
}

View File

@@ -17,7 +17,7 @@ import com.sun.jna.ptr.PointerByReference;
public class WindowInfo {
public static String WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,ClassNameProperty,NameProperty";
public static String WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,ClassNameProperty,NameProperty,ValueProperty";
public HWND hwnd;
public String hwndStr = "";
@@ -25,6 +25,7 @@ public class WindowInfo {
public String parentStr = "";
public RECT rect;
public String text;
public String value;
public String className = "";
public boolean isChild = false;
public String processName = "";
@@ -69,6 +70,18 @@ public class WindowInfo {
hwndStr = Api.GetHandleAsString(hWnd);
}
public String replaceEscapedCodes(String input) {
//, is a comma ,
String result = input;
result = result.replaceAll(",", ",");
result = result.replaceAll("&lt;", "<");
result = result.replaceAll("&gt;", ">");
result = result.replaceAll("&apos;", "'");
result = result.replaceAll("&quot;", "\"");
result = result.replaceAll("&amp;", "&");
return result;
}
//support for WPF and Silverlight
public WindowInfo(String enumProperties, boolean isChild) {
//WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,ClassNameProperty,NameProperty";
@@ -84,9 +97,11 @@ public class WindowInfo {
if (spltProperties.length > 3)
this.framework = spltProperties[3];
if (spltProperties.length > 4)
this.className = spltProperties[4];
this.className = replaceEscapedCodes(spltProperties[4]);
if (spltProperties.length > 5)
this.text = spltProperties[5];
this.text = replaceEscapedCodes(spltProperties[5]);
if (spltProperties.length > 6)
this.value = replaceEscapedCodes(spltProperties[6]);
/*
this.rect = new RECT();
try {

View File

@@ -72,9 +72,11 @@ public class WindowsEnumeratedXml implements Runnable{
public static String getXml() {
final Map<String, WindowInfo> infoList = new LinkedHashMap<String, WindowInfo>();
final Map<String, String> processList = new LinkedHashMap<String, String>();
final Map<String, WindowInfo> wpfParentList = new LinkedHashMap<String, WindowInfo>();
final Map<String, String> processList = new LinkedHashMap<String, String>();
final List<String> wpfParentList = new ArrayList<String>();//HwndWrapper
final List<String> silverlightParentList = new ArrayList<String>();//MicrosoftSilverlight
int wpfCount = 0;
int silverlightCount = 0;
class ChildWindowCallback implements WinUser.WNDENUMPROC {
@Override
@@ -82,7 +84,9 @@ public class WindowsEnumeratedXml implements Runnable{
WindowInfo wi = new WindowInfo(hWnd, true);
infoList.put(wi.hwndStr, wi);
if (wi.className.startsWith("HwndWrapper"))
wpfParentList.put(wi.hwndStr, null);
wpfParentList.add(wi.hwndStr);
if (wi.className.startsWith("MicrosoftSilverlight") || wi.className.startsWith("GeckoPluginWindow"))
silverlightParentList.add(wi.hwndStr);
return true;
}
}
@@ -93,7 +97,7 @@ public class WindowsEnumeratedXml implements Runnable{
WindowInfo wi = new WindowInfo(hWnd, false);
infoList.put(wi.hwndStr, wi);
if (wi.className.startsWith("HwndWrapper"))
wpfParentList.put(wi.hwndStr, null);
wpfParentList.add(wi.hwndStr);
Api.User32.instance.EnumChildWindows(hWnd, new ChildWindowCallback(), new Pointer(0));
return true;
}
@@ -103,16 +107,16 @@ public class WindowsEnumeratedXml implements Runnable{
//Enumerate WPF windows and add to list
if (!SynthuseDlg.config.isWpfBridgeDisabled())
{
////win[starts-with(@class,'HwndWrapper')]
//WpfBridge wb = new WpfBridge();
//if (wb.countDescendantWindows() > 0)
for (String handle : wpfParentList.keySet()) {
//WindowInfo w = wpfParentList.get(handle);
//System.out.println("EnumerateWindowsWithWpfBridge: " + handle);
for (String handle : wpfParentList) {
Map<String, WindowInfo> wpfInfoList = EnumerateWindowsWithWpfBridge(handle, "WPF");
wpfCount += wpfInfoList.size();
infoList.putAll(wpfInfoList);
}
for (String handle : silverlightParentList) {
Map<String, WindowInfo> slInfoList = EnumerateWindowsWithWpfBridge(handle, "Silverlight");
silverlightCount += slInfoList.size();
infoList.putAll(slInfoList);
}
}
// convert window info list to xml dom
@@ -138,6 +142,8 @@ public class WindowsEnumeratedXml implements Runnable{
win = doc.createElement("wpf");
win.setAttribute("hwnd", w.hwndStr);
win.setAttribute("text", w.text);
if (w.value != "" && w.value != null)
win.setAttribute("value", w.value);
if (w.text != null)
win.setAttribute("TEXT", w.text.toUpperCase());
win.setAttribute("class", w.className);
@@ -179,6 +185,7 @@ public class WindowsEnumeratedXml implements Runnable{
totals.setAttribute("windowCount", infoList.size()+"");
totals.setAttribute("wpfWrapperCount", wpfParentList.size()+"");
totals.setAttribute("wpfCount", wpfCount+"");
totals.setAttribute("silverlightCount", silverlightCount+"");
totals.setAttribute("processCount", processList.size()+"");
totals.setAttribute("updatedLast", new Timestamp((new Date()).getTime()) + "");
rootElement.appendChild(totals);
@@ -196,6 +203,8 @@ public class WindowsEnumeratedXml implements Runnable{
final Map<String, WindowInfo> infoList = new LinkedHashMap<String, WindowInfo>();
WpfBridge wb = new WpfBridge();
wb.setFrameworkId(frameworkType);
if (SynthuseDlg.config.isFilterWpfDisabled())
wb.setTouchableOnly(false);
long hwnd = Long.parseLong(parentHwndStr);
//List<String> parentIds = new ArrayList<String>(Arrays.asList(wb.enumChildrenWindowIds("")));
//System.out.println("getRuntimeIdFromHandle");

View File

@@ -114,7 +114,11 @@ public class WpfBridge {
public String getWindowText(String runtimeIdValue) {
return getProperty("NameProperty", runtimeIdValue);
}
public String getWindowValue(String runtimeIdValue) {
return getProperty("ValueProperty", runtimeIdValue);
}
public String getWindowAutomationId(String runtimeIdValue) {
return getProperty("AutomationIdProperty", runtimeIdValue);
}

View File

@@ -84,18 +84,29 @@ public class XpathManager implements Runnable{
String classStr = wpf.getWindowClass(runtimeId);
//System.out.println("class: " + classStr);
String txtOrig = wpf.getWindowText(runtimeId);
String winValueOrig = wpf.getWindowValue(runtimeId);
if (classStr == null || txtOrig == null)
return "";
//System.out.println("text: " + txtOrig);
String txtStr = compareLongTextString(txtOrig);
builtXpath = "//wpf[@class='" + classStr + "' and starts-with(@text,'" + txtStr + "')]";
String valueStr = "";
if (winValueOrig != null)
if (!winValueOrig.isEmpty()) //if value attribute exists then use it too
valueStr = " and starts-with(@value,'" + compareLongTextString(winValueOrig) + "')";
builtXpath = "//wpf[@class='" + classStr + "' and starts-with(@text,'" + txtStr + "')" + valueStr + "]";
//builtXpath = "//*[@hwnd='" + runtimeId + "']";
System.out.println("evaluateXpathGetValues: " + builtXpath);
//System.out.println("evaluateXpathGetValues: " + builtXpath);
List<String> wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath);
if (wpfResultList.size() == 0)
return "";
// return builtXpath;
return builtXpath;
if (wpfResultList.size() > 0)
return builtXpath;
builtXpath = "//*[@hwnd='" + runtimeId + "']";
wpfResultList = WindowsEnumeratedXml.evaluateXpathGetValues(xml, builtXpath);
if (wpfResultList.size() > 0)
return builtXpath;
return "";
}
public String buildXpathStatement() {

View File

@@ -19,41 +19,86 @@ public class WpfBridgeTest {
}
@Test
public void countChildren() {
public void countChildrenWin32() {
WpfBridge wb = new WpfBridge();
wb.setFrameworkId("Win32");//We should find some Win32 windows, maybe not WPF
int win32Cnt = wb.countChildrenWindows();
assertTrue(win32Cnt > 0);
System.out.println("win32 countChildrenWindows: " + win32Cnt);
wb.setFrameworkId("WPF");// maybe not WPF
//System.out.println("wpf countChildrenWindows: " + wb.countChildrenWindows());
assertTrue(win32Cnt > 0);
wb.setTouchableOnly(false);//disable filter
int ufwin32Cnt = wb.countChildrenWindows();
System.out.println("win32 unfiltered countChildrenWindows: " + ufwin32Cnt);
assertTrue(ufwin32Cnt >= win32Cnt);
}
@Test
public void countChildrenWpf() {
WpfBridge wb = new WpfBridge();
wb.setFrameworkId("WPF");// maybe not WPF
wb.setTouchableOnly(true);//enable filter
System.out.println("wpf countChildrenWindows: " + wb.countChildrenWindows());
wb.setTouchableOnly(false);//disable filter
System.out.println("wpf unfiltered countChildrenWindows: " + wb.countChildrenWindows());
}
@Test
public void countDescendantsWin32() {
WpfBridge wb = new WpfBridge();
wb.setFrameworkId("Win32");//We should find some Win32 windows, maybe not WPF
int win32Cnt = wb.countDescendantWindows();
System.out.println("win32 countDescendantWindows: " + win32Cnt);
assertTrue(win32Cnt > 0);
wb.setTouchableOnly(false);//disable filter
int ufwin32Cnt = wb.countDescendantWindows();
System.out.println("win32 unfiltered countDescendantWindows: " + ufwin32Cnt);
assertTrue(ufwin32Cnt >= win32Cnt);
}
@Test
public void countDescendantsWpf() {
WpfBridge wb = new WpfBridge();
wb.setFrameworkId("WPF");// maybe not WPF
wb.setTouchableOnly(true);//enable filter
System.out.println("wpf countDescendantWindows: " + wb.countDescendantWindows());
wb.setTouchableOnly(false);//disable filter
System.out.println("wpf unfiltered countDescendantWindows: " + wb.countDescendantWindows());
}
@Test
public void getRuntimeFromHandle() {
long handle = 1639790;
//String rid = wb.getRuntimeIdFromHandle(handle);
//System.out.println("getRuntimeIdFromHandle: " + rid);
handle = 984416;
//rid = wb.getRuntimeIdFromHandle(handle);
//System.out.println("getRuntimeIdFromHandle: " + rid);
WpfBridge wb = new WpfBridge();
Api api = new Api();
wb.setFrameworkId("WPF");
WinPtr wp = new WinPtr(api.user32.FindWindow(null, "MainWindow"));//find WpfMockTestApp.exe
long handle = Long.parseLong(wp.hWndStr);
String rid = wb.getRuntimeIdFromHandle(handle);
System.out.println(wp.hWndStr + " getRuntimeIdFromHandle: " + rid);
assertTrue(rid != null);
String[] props = wb.getPropertiesAndValues(rid);
assertTrue(props != null);
//for(String p : props)
// System.out.println(p);
}
@Test
public void enumerateWindowInfo() {
WpfBridge wb = new WpfBridge();
/*
EnumerateWindowsWithWpfBridge: 1639790
getRuntimeIdFromHandle
runtimeId=42-1639790
enumDescendantWindowIds 18
EnumerateWindowsWithWpfBridge: 984416
getRuntimeIdFromHandle
runtimeId=42-984416
*/
//int count = wb.countDescendantWindows("42-984416");
String[] wInfo = wb.enumDescendantWindowInfo("42-984416", WindowInfo.WPF_PROPERTY_LIST);
if (wInfo != null)
System.out.println("enumDescendantWindowInfo: " + wInfo.length);
Api api = new Api();
wb.setFrameworkId("WPF");
wb.setTouchableOnly(false);
WinPtr wp = new WinPtr(api.user32.FindWindow(null, "MainWindow"));//find WpfMockTestApp.exe
long handle = Long.parseLong(wp.hWndStr);
String rid = wb.getRuntimeIdFromHandle(handle);
System.out.println(wp.hWndStr + " getRuntimeIdFromHandle: " + rid);
if (rid == null)
return;
String[] wInfo = wb.enumDescendantWindowInfo(rid, WindowInfo.WPF_PROPERTY_LIST);
System.out.println("enumDescendantWindowInfo length: " + wInfo.length);
System.out.println(WindowInfo.WPF_PROPERTY_LIST);
for(String w : wInfo)
System.out.println(w);
}
}