/// <summary> /// Tries to find the target ah repeatedly for the "Wait" period /// </summary> /// <param name="ah"></param> /// <param name="gpath"></param> private void ClickPathUntilFound(AccessibilityHelper ah, GuiPath gpath) { string badPath = ""; if (DoingOnce()) { badPath = ClickPath(ah, gpath); } else { // act as if it's being done once //IntPtr handle = (IntPtr)ah.HWnd; // get an updated ah based on its window handle bool done = false; while (!done && !m_finished) { //ah = new AccessibilityHelper((handle)); // refresh the context ah ah = new AccessibilityHelper(ah); // refresh the context ah if (ah == null) { m_log.paragraph(makeNameTag() + "ClickPathUntilFound on " + gpath + " handled a null context"); } if (ah != null) { badPath = ClickPath(ah, gpath); } done = Utilities.NumTicks(m_ExecuteTickCount, System.Environment.TickCount) > m_until; System.Threading.Thread.Sleep(500); // try every half second } // if not clicked, it waited a long time on a bad path if (!m_finished) { m_log.fail(makeNameTag() + badPath); } } }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being appended to m_path more than once. public override void Execute() { base.Execute(); PassFailInContext(m_onPass, m_onFail, out m_onPass, out m_onFail); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, "Glimpse must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, "Glimpse context not accessible"); m_path = Utilities.evalExpr(m_path); m_expect = Utilities.evalExpr(m_expect); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { m_path = SelectToPath(con, m_select) + m_path; // process m_select m_doneOnce = true; } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, "attribute path='" + m_path + "' not parsed"); GlimpsePath(ah, gpath, m_expect); } else { fail("attribute 'path' or 'select' must be set."); } Logger.getOnly().result(this); }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being appended to m_path more than once. public override void Execute() { base.Execute(); PassFailInContext(m_onPass,m_onFail,out m_onPass,out m_onFail); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con,"Glimpse must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah,"Glimpse context not accessible"); m_path = Utilities.evalExpr(m_path); m_expect = Utilities.evalExpr(m_expect); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { m_path = SelectToPath(con, m_select) + m_path; // process m_select m_doneOnce = true; } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath,"attribute path='"+m_path+"' not parsed"); GlimpsePath(ah, gpath, m_expect); } else fail("attribute 'path' or 'select' must be set."); Logger.getOnly().result(this); }
/// <summary> /// Execute a click, creating and executing more for @select and /// creating and executing child instructions. /// When used in a do-once instruction, this call is repeated. /// </summary> public override void Execute() { // Increase the wait time if the rest time is greater // This gives the script writer some control over how // long to try the click. base.Execute(); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, makeNameTag() + " must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, makeNameTag() + " context is not accessible"); m_path = Utilities.evalExpr(m_path); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { m_path = SelectToPath(con, m_select) + m_path; // process m_select m_doneOnce = true; } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, makeNameTag() + " path='" + m_path + "' not parsed"); ClickPathUntilFound(ah, gpath); } else { fail(makeNameTag() + "attribute 'path' or 'select' must be set or evaluate properly."); } }
public override void Execute() { base.Execute(); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, "Hover-over must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, "The hover-over context is not accessible"); m_path = Utilities.evalExpr(m_path); // Use the path if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, "attribute path='" + m_path + "' not parsed"); string BadPath = HoverPath(ah, gpath); if (BadPath != "") { fail(BadPath); } } else { fail("attribute 'path' must be set."); } Finished = true; // tell do-once it's done }
/// <summary> /// Glimpse one gui-path and return the result. If the expected value is not found, /// an assertion is raised. /// </summary> /// <param name="ah">Context accessibility helper, taken as the starting place for gpath.</param> /// <param name="gpath">The path through the GUI to the control.</param> /// <param name="expect">The expected value of the property for the control.</param> /// <returns></returns> bool GlimpsePath(AccessibilityHelper ah, GuiPath gpath, string expect) { m_Result = true; m_got = null; IPathVisitor visitor = null; ah = gpath.FindInGui(ah, visitor); m_Result = GlimpseGUI(ah, expect); if (m_Result) { base.Finished = true; // teminates do-once } if ((m_onPass == "assert" && m_Result == true) || (m_onFail == "assert" && m_Result == false)) { if (m_message != null && m_message.HasContent()) { fail(m_message.Read()); } else { string image = "Property [" + m_prop + "] was [" + m_got + "] expecting [" + m_expect + "] Result = '" + m_Result + "', on-pass='******', on-fail='" + m_onFail + "'"; if (gpath != null) { fail(image + " on gPath = " + gpath.toString()); } else { fail(image); } } } return(m_Result); }
/// <summary> /// A linked list node that represents one step in a GUI path. /// A step in the typedPath is represented by this node. /// Following steps generate subsequent GuiPath nodes recursively. /// </summary> /// <param name="typedPath">a typed path</param> public GuiPath(string typedPath) { // remove the first step from the typedPath and process it int last = 0; string step = Utilities.GetFirstStep(typedPath, out last); Utilities.SplitTypedToken(step, out m_name, out m_type); if (m_type == "value" && (m_name == null || m_name == "")) { m_name = ""; // want it to be empty } else if (m_name == null || m_name == "") { m_name = "NAMELESS"; } try { int roleValue = Convert.ToInt32(m_type); m_role = (AccessibleRole)roleValue; } catch (Exception) { m_role = Utilities.TypeToRole(m_type); } // Parse the name string name; string varId; m_Nth = parseIndex(m_name, out name, out varId); if (m_name == name) { m_Nth = 1; } m_name = name; m_varId = varId; if (m_type == "para" || m_type == "line") { try { m_Nth = Convert.ToInt32(m_name); } catch (System.FormatException) { Assert.Fail(m_type + ": needs to be followed by an integer, not " + m_name); } if (m_type == "para") { m_name = "Paragraph"; } if (m_type == "line") { m_name = "Srting"; } } // if not consumed, split off the end of the path as a child path if (1 + last < typedPath.Length) { m_child = new GuiPath(typedPath.Substring(last + 1)); m_child.m_parent = this; } }
public void ParseStarTest() { Assert.IsTrue(GuiPath.parseIndexTesting("stuf[*]f", "stuf", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[*]", "stuff", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff3[*i]", "stuff3", 0, "i")); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[*id]", "stuff", 0, "id")); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[**id*]", "stuff", 0, "*id*")); }
/// <summary> /// checkNextLevel follows the GUI model 'level' nodes as indicated via the level path, lpath, /// to create a FW views navigation array to the string to be selected. /// If lpath does not contain a symbol for the current level, the first encountered in the /// GUI model is used. /// The last level of the GUI model must be specified to obtain a string. /// If not, an interop error is raised. This needs further investigation. /// Information from the model populates the SelLevInfo array as recursions return. /// </summary> /// <param name="viewRoot">The a GUI model view or level XML node.</param> /// <param name="lpath">Level path array</param> /// <param name="passes">The recursion count.</param> /// <param name="rgvsli">The FW views system navigation array.</param> /// <param name="clevels">Number of levels in the FW views system navigation array.</param> private void checkNextLevel(XmlNode viewRoot, GuiPath lpath, int passes, out SelLevInfo[] rgvsli, out int clevels) { XmlNodeList nLevelList = viewRoot.SelectNodes("level"); isNotNull(nLevelList, "found no levels in Gui Model view."); XmlNode xLevel = nLevelList[0]; lpath = lpath.Next; // if lpath = null, then set fisrt level only. if (lpath == null) { // end recursion if (passes == 0) { clevels = 1; } else { clevels = passes; } rgvsli = new SelLevInfo[clevels]; if (passes == 0) { // create at least the first level rgvsli[0].ihvo = 0; rgvsli[0].tag = Convert.ToInt32(xLevel.Attributes["flid"].Value); rgvsli[0].cpropPrevious = 0; } return; } string num = "0"; //ihvo // Does the lpath type match a level symbol? // Try to get more specific by matching the user's symbol IEnumerator eLevel = nLevelList.GetEnumerator(); bool OK = eLevel.MoveNext(); while (OK && !((XmlNode)eLevel.Current).Attributes["symbol"].Value.Equals(lpath.Type)) { OK = eLevel.MoveNext(); } if (OK) { // got a match: use the level obtained xLevel = (XmlNode)eLevel.Current; num = lpath.Name; // ihvo } checkNextLevel(xLevel, lpath, passes + 1, out rgvsli, out clevels); // set the rgvsli array on the way out (post recurive) if (num == null) { num = "0"; } int indx = clevels - passes - 1; // the array elements are reversed rgvsli[indx].ihvo = Convert.ToInt32(num); rgvsli[indx].tag = Convert.ToInt32(xLevel.Attributes["flid"].Value); rgvsli[indx].cpropPrevious = 0; }
public void ParseGuiPathTest() { GuiPath gpath = new GuiPath("menu:View/menu:Filters/button:Configure..."); Assert.AreEqual("View", gpath.Name, "ParseGuiPath name 0 is '" + gpath.Name + "' not 'View'"); Assert.AreEqual("MenuItem", gpath.Role.ToString(), "ParseGuiPath role 0 is '" + gpath.Role.ToString() + "' not 'MenuItem'"); Assert.AreEqual("Filters", gpath.Next.Name, "ParseGuiPath name 1 is '" + gpath.Next.Name + "' not 'Filters'"); Assert.AreEqual("MenuItem", gpath.Next.Role.ToString(), "ParseGuiPath role 1 is '" + gpath.Next.Role.ToString() + "' not 'MenuItem'"); Assert.AreEqual("Configure...", gpath.Next.Next.Name, "ParseGuiPath name 2 is '" + gpath.Next.Next.Name + "' not 'Configure...'"); Assert.AreEqual("PushButton", gpath.Next.Next.Role.ToString(), "ParseGuiPath role 2 is '" + gpath.Next.Next.Role.ToString() + "' not 'PushButton'"); }
public void ParseNameOnlyGuiPathTest() { GuiPath gpath = new GuiPath("View/Filters/Configure..."); Assert.AreEqual("View", gpath.Name, "ParseGuiPath name 0 is '" + gpath.Name + "' not 'View'"); Assert.AreEqual("None", gpath.Role.ToString(), "ParseGuiPath role 0 is '" + gpath.Role.ToString() + "' not 'None'"); Assert.AreEqual("Filters", gpath.Next.Name, "ParseGuiPath name 1 is '" + gpath.Next.Name + "' not 'Filters'"); Assert.AreEqual("None", gpath.Next.Role.ToString(), "ParseGuiPath role 1 is '" + gpath.Next.Role.ToString() + "' not 'None'"); Assert.AreEqual("Configure...", gpath.Next.Next.Name, "ParseGuiPath name 2 is '" + gpath.Next.Next.Name + "' not 'Configure...'"); Assert.AreEqual("None", gpath.Next.Next.Role.ToString(), "ParseGuiPath role 2 is '" + gpath.Next.Next.Role.ToString() + "' not 'None'"); }
public void ParseIndexTest() { Assert.IsTrue(GuiPath.parseIndexTesting("stuff", "stuff", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[3]", "stuff", 3, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff3[43]", "stuff3", 43, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[-4]", "stuff", -4, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[-654]", "stuff", -654, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[3", "stuff[3", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff3]", "stuff3]", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[*3]", "stuff", 0, "3")); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[3*]", "stuff[3*]", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("s[tu]ff[3]", "s[tu]ff", 3, null)); Assert.IsTrue(GuiPath.parseIndexTesting("[-98]", "", -98, null)); }
public void ParseVarTest() { TestState ts = TestState.getOnly("LT"); ts.Script = "UtilitiesTest.xml"; Var ins2 = new Var(); ts.AddNamedInstruction("one", ins2); ins2.Set = "4"; ins2.Execute(); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[$hi]", "stuff[$hi]", 0, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[$one]", "stuff", 4, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff3[$one;3]", "stuff3", 43, null)); Assert.IsTrue(GuiPath.parseIndexTesting("stuff[3$one]", "stuff[3$one]", 0, null)); }
/// <summary> /// Execute a click, creating and executing more for @select and /// creating and executing child instructions. /// When used in a do-once instruction, this call is repeated. /// </summary> public override void Execute() { // Increase the wait time if the rest time is greater // This gives the script writer some control over how // long to try the click. base.Execute(); Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, makeNameTag() + " must occur in some context"); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, makeNameTag() + " context is not accessible"); m_path = Utilities.evalExpr(m_path); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { XmlPath node = SelectToPath(con, m_select); // process m_select m_path = node.Path + m_path; m_dx = getOffset(m_dx, k_offset, node.ModelNode, "dx"); m_dy = getOffset(m_dy, k_offset, node.ModelNode, "dy"); if (m_dx != k_offset || m_dy != k_offset) { m_log.paragraph(makeNameTag() + "dx = " + m_dx + ", dy = " + m_dy); } m_doneOnce = true; // avoid adding to m_path again on subsequent do-once iterations } if (Application != null) { try { Application.Process.WaitForInputIdle(); } catch (Win32Exception e) { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); } } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(gpath, makeNameTag() + " path='" + m_path + "' not parsed"); ClickPathUntilFound(ah, gpath); } else { m_log.fail(makeNameTag() + "attribute 'path' or 'select' must be set or evaluate properly."); } }
/// <summary> /// A linked list node that represents one step in a GUI path. /// A step in the typedPath is represented by this node. /// Following steps generate subsequent GuiPath nodes recursively. /// </summary> /// <param name="typedPath">a typed path</param> public GuiPath(string typedPath) { // remove the first step from the typedPath and process it int last = 0; string step = Utilities.GetFirstStep(typedPath, out last); Utilities.SplitTypedToken(step, out m_name, out m_type); if (m_type == "value" && (m_name == null || m_name == "")) m_name = ""; // want it to be empty else if (m_name == null || m_name == "") m_name = "NAMELESS"; try { int roleValue = Convert.ToInt32(m_type); m_role = (AccessibleRole)roleValue; } catch (Exception) { m_role = Utilities.TypeToRole(m_type); } // Parse the name string name; string varId; m_Nth = parseIndex(m_name, out name, out varId); if (m_name == name) m_Nth = 1; m_name = name; m_varId = varId; if (m_type == "para" || m_type == "line") { try { m_Nth = Convert.ToInt32(m_name); } catch (System.FormatException) { Assert.Fail(m_type + ": needs to be followed by an integer, not " + m_name); } if (m_type == "para") m_name = "Paragraph"; if (m_type == "line") m_name = "Srting"; } // if not consumed, split off the end of the path as a child path if (1 + last < typedPath.Length) { m_child = new GuiPath(typedPath.Substring(last + 1)); m_child.m_parent = this; } }
public override void Execute() { base.Execute(); bool exists = false; isNotNull(m_path, "attribute 'path' must be set"); m_path = Utilities.evalExpr(m_path); GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, "attribute path='" + m_path + "' not parsed"); GuiPath lpath = null; if (m_loc != null) // if it's null, get the whole string content { lpath = new GuiPath(m_loc); isNotNull(lpath, "attribute path='" + m_loc + "' not parsed"); } Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, "Select-text must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, "Select-text context not accessible"); // The model names are needed in selectText. IPathVisitor visitor = null; ah = gpath.FindInGui(ah, visitor); isNotNull(ah, "context not accessible from path"); if (ah != null) { if (m_loc == null) { exists = getStrValue(ah); } else { exists = selectText(lpath, ah); } } Logger.getOnly().result(this); Finished = true; // tell do-once it's done }
private string ClickPath(AccessibilityHelper ah, GuiPath gpath) { //bool forAll = false; //bool clickParent = false; //AccessibilityHelper child; //if (m_for != null && "all" == (string)m_for) forAll = true; if (1 == m_logLevel) { m_log.paragraph(makeNameTag() + "Click starting path from "" + ah.Role + ":" + ah.Name + """); } ah = gpath.FindInGui(ah, this); if (ah != null) { if (1 == m_logLevel) { m_log.paragraph(makeNameTag() + "Clicking last pair in path"); } int j; for (j = 0; j < m_repeat; j++) { // click 10 pixels from the left edge - see below if (m_side == "right") { ah.SimulateRightClickRelative(m_dx, m_dy); } else { ah.SimulateClickRelative(m_dx, m_dy); } // when @wait="no" don't wait at all between repeated clicks if (m_wait) { Thread.Sleep(400); // wait a while eg. let menus open, etc. } } m_finished = true; // tell do-once it's done } else { return(m_message); } return(""); }
/// <summary> /// Gets the GUI Model root node and finds the model of the view to select text from. /// The model view is recursively followed using the symbols in the level path /// array. Information from the model populates the SelLevInfo array as recursions return. /// </summary> /// <param name="lpath">Level path array.</param> /// <param name="rgvsli">The FW views system navigation array.</param> /// <param name="clevels">Number of levels in the FW views system navigation array.</param> /// <returns>True if the navigation array is filled. False if something goes wrong.</returns> private bool DrillToContent(GuiPath lpath, out SelLevInfo[] rgvsli, out int clevels) { bool status = true; clevels = 0; rgvsli = null; XmlElement root = null; // Application.GuiModelRoot; status = root != null; if (status) { // Use lpath to get to the right place in the gui model string xPath = "//" + lpath.Type + "[@name='" + lpath.Name + "']"; XmlNode viewRoot = root.SelectSingleNode(xPath); isNotNull(viewRoot, "could not find " + m_loc + " in the GUI Model"); int passes = 0; // count the levels checkNextLevel(viewRoot, lpath, passes, out rgvsli, out clevels); } return(status); }
public override void Execute() { base.Execute(); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con,"Hover-over must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah,"The hover-over context is not accessible"); m_path = Utilities.evalExpr(m_path); // Use the path if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath,"attribute path='"+m_path+"' not parsed"); string BadPath = HoverPath(ah, gpath); if (BadPath != "") fail(BadPath); } else fail("attribute 'path' must be set."); Finished = true; // tell do-once it's done }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being appended to m_path more than once. public override void Execute() { base.Execute(); PassFailInContext(m_onPass, m_onFail, out m_onPass, out m_onFail); Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, makeNameTag() + "Glimpse must occur in some context"); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, makeNameTag() + "Glimpse context not accessible"); m_path = Utilities.evalExpr(m_path); m_expect = Utilities.evalExpr(m_expect); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { XmlPath node = SelectToPath(con, m_select); // process m_select m_path = node.Path + m_path; m_doneOnce = true; // avoid adding to m_path again on subsequent do-once iterations } try { Application.Process.WaitForInputIdle(); } catch (Win32Exception e) { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(makeNameTag() + gpath, "attribute path='" + m_path + "' not parsed"); GlimpsePath(ah, gpath); } else { m_log.fail(makeNameTag() + "attribute 'path' or 'select' must be set."); } Logger.getOnly().result(this); }
public void findInGui() { Process m_proc = Process.Start(@"C:\WINDOWS\NOTEPAD.EXE"); AccessibilityHelper m_ah; m_proc.WaitForInputIdle(); while (Process.GetProcessById(m_proc.Id).MainWindowHandle == IntPtr.Zero) { Thread.Sleep(100); } m_proc.WaitForInputIdle(); SIL.FieldWorks.Common.Utils. Win32.SetForegroundWindow(m_proc.MainWindowHandle); m_ah = new AccessibilityHelper(m_proc.MainWindowHandle); AccessibilityHelper ah = null; GuiPath gpath = new GuiPath("menu:Help/menu:Help Topics"); ah = gpath.FindInGui(m_ah, null); Assert.IsNotNull(ah, "'menu:Help/menu:Help Topics' Accessibility Helper not found"); Assert.AreEqual("Help Topics", ah.Name, "'menu:Help/menu:Help Topics' menu item not found"); Assert.AreEqual(AccessibleRole.MenuItem, ah.Role, "'menu:Help/menu:Help Topics' menu item role not found"); try { m_proc.WaitForInputIdle(); Win32.SetForegroundWindow(m_proc.MainWindowHandle); SendKeys.SendWait("%{F4}"); m_proc.WaitForInputIdle(); m_proc.WaitForExit(); } catch { } }
// when all the instructions pass, do-once passes // otherwise it fails public override void Execute() { // Don't call the base execute method! - want control.. // base.Execute(); if (Number == -1) { Number = TestState.getOnly().IncInstructionCount; } m_log.mark(this); m_ExecuteTickCount = System.Environment.TickCount; PrepareChildren(); // base method to build child instructions // remove all wait times in this context, but only at the child level this.RemoveWaitTime(); foreach (Instruction ins in m_instructions) { ins.RemoveWaitTime(); } PassFailInContext(OnPass, OnFail, out m_onPass, out m_onFail); AccessibilityHelper m_ah = Accessibility; if (1 == m_logLevel) { m_log.paragraph(makeNameTag() + "Context is "" + m_ah.Role + ":" + m_ah.Name + """); } if (m_waitingFor != null && m_waitingFor != "") { m_waitingFor = Utilities.evalExpr(m_waitingFor); } int startTick = System.Environment.TickCount; m_log.paragraph(image()); bool done = false; bool lastPass = false; // used to allow 1 last pass over instructions after time is up while (!done) { CheckForErrorDialogs(true); // see if there are any cmds not finished done = true; // start as if they're all done foreach (Instruction ins in m_instructions) { if (!ins.Finished) // not already finished { // Don't assert onFail until it's the last pass (time is up) ins.DeferAssert = !lastPass; ins.Execute(); if (!ins.Finished) // still not finished { done = false; } } } m_Result = done; AccessibilityHelper ah = null; string title = null; if (m_waitingFor != null && m_waitingFor != "") { m_Result = false; // fail if the window is not found IntPtr foundHwndPtr = FindWindow(null, m_waitingFor); if ((int)foundHwndPtr != 0) { ah = new AccessibilityHelper(foundHwndPtr); // The ah constructor gets the topWindow if our window isn't found // Don't want that // ah = new AccessibilityHelper(m_waitingFor); // get the title, the ah.Name can be different. GuiPath path = new GuiPath("titlebar:NAMELESS"); AccessibilityHelper ah1 = ah.SearchPath(path, null); if (ah1 != null) { title = ah1.Value; } } } if (ah != null) { m_log.paragraph(makeNameTag() + "do-once found window:" + ah.Name); } if (title != null) { m_log.paragraph(makeNameTag() + "do-once found title:" + title); } if (lastPass) { done = true; } if (title != null && title == m_waitingFor) { lastPass = true; // A window may appear a bit later m_Result = true; } // once time is up, allow finial pass over instructions allowing asserts as needed if (!lastPass) { lastPass = Utilities.NumTicks(startTick, System.Environment.TickCount) > m_waitTicks; } } // end of while loop Logger.getOnly().result(this); Finished = true; // tell do-once it's done if (m_onPass == "assert" && m_Result == true) { m_log.fail(makeNameTag() + "do-once accomplished its task(s) but was not supposed to."); } if (m_onFail == "assert" && m_Result == false) { m_log.fail(makeNameTag() + "do-once did not accomplish all of its tasks."); } }
/// <summary> /// checkNextLevel follows the GUI model 'level' nodes as indicated via the level path, lpath, /// to create a FW views navigation array to the string to be selected. /// If lpath does not contain a symbol for the current level, the first encountered in the /// GUI model is used. /// The last level of the GUI model must be specified to obtain a string. /// If not, an interop error is raised. This needs further investigation. /// Information from the model populates the SelLevInfo array as recursions return. /// </summary> /// <param name="viewRoot">The a GUI model view or level XML node.</param> /// <param name="lpath">Level path array</param> /// <param name="passes">The recursion count.</param> /// <param name="rgvsli">The FW views system navigation array.</param> /// <param name="clevels">Number of levels in the FW views system navigation array.</param> private void checkNextLevel(XmlNode viewRoot, GuiPath lpath, int passes, out SelLevInfo[] rgvsli, out int clevels) { XmlNodeList nLevelList = viewRoot.SelectNodes("level"); isNotNull(nLevelList,"found no levels in Gui Model view."); XmlNode xLevel = nLevelList[0]; lpath = lpath.Next; // if lpath = null, then set fisrt level only. if (lpath == null) { // end recursion if (passes == 0) clevels = 1; else clevels = passes; rgvsli = new SelLevInfo[clevels]; if (passes == 0) { // create at least the first level rgvsli[0].ihvo = 0; rgvsli[0].tag = Convert.ToInt32(xLevel.Attributes["flid"].Value); rgvsli[0].cpropPrevious = 0; } return; } string num = "0"; //ihvo // Does the lpath type match a level symbol? // Try to get more specific by matching the user's symbol IEnumerator eLevel = nLevelList.GetEnumerator(); bool OK = eLevel.MoveNext(); while (OK && !((XmlNode)eLevel.Current).Attributes["symbol"].Value.Equals(lpath.Type)) OK = eLevel.MoveNext(); if (OK) { // got a match: use the level obtained xLevel = (XmlNode)eLevel.Current; num = lpath.Name; // ihvo } checkNextLevel(xLevel, lpath, passes+1, out rgvsli, out clevels); // set the rgvsli array on the way out (post recurive) if (num == null) num = "0"; int indx = clevels-passes-1; // the array elements are reversed rgvsli[indx].ihvo = Convert.ToInt32(num); rgvsli[indx].tag = Convert.ToInt32(xLevel.Attributes["flid"].Value); rgvsli[indx].cpropPrevious = 0; }
/// <summary> /// Gets the GUI Model root node and finds the model of the view to select text from. /// The model view is recursively followed using the symbols in the level path /// array. Information from the model populates the SelLevInfo array as recursions return. /// </summary> /// <param name="lpath">Level path array.</param> /// <param name="rgvsli">The FW views system navigation array.</param> /// <param name="clevels">Number of levels in the FW views system navigation array.</param> /// <returns>True if the navigation array is filled. False if something goes wrong.</returns> private bool DrillToContent(GuiPath lpath, out SelLevInfo[] rgvsli, out int clevels) { bool status = true; clevels = 0; rgvsli = null; XmlElement root = null; // Application.GuiModelRoot; status = root != null; if (status) { // Use lpath to get to the right place in the gui model string xPath = "//" + lpath.Type + "[@name='" + lpath.Name + "']"; XmlNode viewRoot = root.SelectSingleNode(xPath); isNotNull(viewRoot,"could not find "+m_loc+" in the GUI Model"); int passes = 0; // count the levels checkNextLevel(viewRoot, lpath, passes, out rgvsli, out clevels); } return status; }
/// <summary> /// Given the GUI control or view ah, find and highlight the text indicated /// via the location (level) path. /// </summary> /// <param name="lpath">Level path array.</param> /// <param name="ah">Accessibility helper from the GUI control or view</param> /// <returns>true if the selected string was retrieved.</returns> private bool selectText(GuiPath lpath, AccessibilityHelper ah) { IVwRootBox rbox = ah.RootBox(); isNotNull(rbox,"view rootbox not found"); IVwSelection sel = null; // returned selection // create a SelLevInfo[] array to the content using the model view levels. int clevels = 0; SelLevInfo[] rgvsli; if (DrillToContent(lpath, out rgvsli, out clevels)) { int ihvoRoot = 0; // first rootbox int tagTextProp = 16002; // kflidStTxtPara_Contents int cpropPrevious = 0; int ichAnchor = m_at; // starting character number int ichEnd = m_at + m_run; // ending character number in rgvsli[0].ihvo or ihvoEnd if it is not -1 int ws = 0; bool fAssocPrev = false; int ihvoEnd = -1; // paragraph # to end at, if it doesn't exist, get unspecified interop error ITsTextProps ttpIns = null; bool fInstall = true; // make it the view's default selection //int iHeight = rbox.get_Height(); int iHeight = rbox.Height; sel = rbox.MakeTextSelection (ihvoRoot, clevels, rgvsli, tagTextProp, cpropPrevious, ichAnchor, ichEnd, ws, fAssocPrev, ihvoEnd, ttpIns, fInstall); isNotNull(sel,"failed to select text"); //areEqual(true, sel.get_IsValid(), "selection is not valid"); areEqual(true, sel.IsValid, "selection is not valid"); ITsTextProps ttp = spyOnSelection(sel); if(ttp != null) spyOnTextProps(ttp); } string strSeparator = "|"; ITsString tssFromApp; sel.GetSelectionString(out tssFromApp, strSeparator); ITsStreamWrapper tsw = TsStreamWrapperClass.Create(); //UCOMIStream strm = tsw.get_Stream(); System.Runtime.InteropServices.ComTypes.IStream strm = tsw.Stream; // Copy the string to our address space. ITsStrBldr bldr = TsStrBldrClass.Create(); bldr.ReplaceTsString(0,0, tssFromApp); ITsString tss = bldr.GetString(); int icchIndent = 2; int iws = 0; bool fWriteObjData = true; //tsw.WriteTssAsXml(tss2, icchIndent, iws, fWriteObjData); //ISilDataAccess da = rbox.get_DataAccess(); ISilDataAccess da = rbox.DataAccess; //ILgWritingSystemFactory wsf = da.get_WritingSystemFactory(); ILgWritingSystemFactory wsf = da.WritingSystemFactory; tss.WriteAsXml(strm, wsf, icchIndent, iws, fWriteObjData); //m_text = tsw.get_Contents(); // XML formatted string m_text = tsw.Contents; // XML formatted string return m_text != null; }
/// <summary> /// Method to apply when a path node is not found. /// No path above it and none below will call this method; /// only the one not found. /// </summary> /// <param name="path">The path step last tried.</param> public void notFound(GuiPath path) { m_message = "Item '" + path.Role + ":" + path.Name + "' not found to click"; }
/// <summary> /// Finds the accessible object at the end of the path with optional place and varId from /// which it creates a variable object to hold the sibling number of the object found. /// An optional path visitor allows the caller to do something with intermediate steps /// along the path for debugging or interface control. /// The value of a node can be specified via a path step like "value:whatever the value is". /// When place is greater than 0, the search is breadth-first. /// Generally, clients need not be included in the "path". /// When place is 0, a value must be the leaf node of the path /// as there is typically some repeated structure /// like a table, row and cell with value. The structure is /// traversed repeatedly until the leaf node with the value is found. /// When place is negative, depth-first search is used. It tends to be /// the slowest way to search the Accessibility tree. /// </summary> /// <param name="path">The path to search. Each step in the path contains an /// Accessibility name and Accessibility role of the matching gui object.</param> /// <param name="visitor">null or the object providing methods that are called when steps are found.</param> /// <returns>A new <see cref="AccessibilityHelper"/> object that wraps the object found at the end of the path.</returns> public AccessibilityHelper SearchPath(GuiPath path, IPathVisitor visitor) { if (path == null) return null; // three cases based on Nth if (path.Nth > 0) { // psuedo breadth-first return this.SearchPathByBreadth(path, visitor); } if (path.Nth == 0) { // loop over FindChildBreadth to find a sibling index to set a var with varId return this.SearchPathForIndex(path, visitor); } else if (path.Nth < 0) { // depth-first return this.SearchPathByDepth(path, visitor); } return null; }
/// <summary> /// Method to apply when a path node is not found. /// No path above it and none below will call this method; /// only the one not found. /// </summary> /// <param name="path">The path step last tried.</param> public void notFound(GuiPath path) { m_message = "Item '" + path.Role + ":" + path.Name + "' not found for hover"; }
/// <summary> /// Given the GUI control or view ah, find and highlight the text indicated /// via the location (level) path. /// </summary> /// <param name="lpath">Level path array.</param> /// <param name="ah">Accessibility helper from the GUI control or view</param> /// <returns>true if the selected string was retrieved.</returns> private bool selectText(GuiPath lpath, AccessibilityHelper ah) { IVwRootBox rbox = ah.RootBox(); isNotNull(rbox, "view rootbox not found"); IVwSelection sel = null; // returned selection // create a SelLevInfo[] array to the content using the model view levels. int clevels = 0; SelLevInfo[] rgvsli; if (DrillToContent(lpath, out rgvsli, out clevels)) { int ihvoRoot = 0; // first rootbox int tagTextProp = 16002; // kflidStTxtPara_Contents int cpropPrevious = 0; int ichAnchor = m_at; // starting character number int ichEnd = m_at + m_run; // ending character number in rgvsli[0].ihvo or ihvoEnd if it is not -1 int ws = 0; bool fAssocPrev = false; int ihvoEnd = -1; // paragraph # to end at, if it doesn't exist, get unspecified interop error ITsTextProps ttpIns = null; bool fInstall = true; // make it the view's default selection //int iHeight = rbox.get_Height(); int iHeight = rbox.Height; sel = rbox.MakeTextSelection (ihvoRoot, clevels, rgvsli, tagTextProp, cpropPrevious, ichAnchor, ichEnd, ws, fAssocPrev, ihvoEnd, ttpIns, fInstall); isNotNull(sel, "failed to select text"); //areEqual(true, sel.get_IsValid(), "selection is not valid"); areEqual(true, sel.IsValid, "selection is not valid"); ITsTextProps ttp = spyOnSelection(sel); if (ttp != null) { spyOnTextProps(ttp); } } string strSeparator = "|"; ITsString tssFromApp; sel.GetSelectionString(out tssFromApp, strSeparator); ITsStreamWrapper tsw = TsStreamWrapperClass.Create(); //UCOMIStream strm = tsw.get_Stream(); System.Runtime.InteropServices.ComTypes.IStream strm = tsw.Stream; // Copy the string to our address space. ITsStrBldr bldr = TsStrBldrClass.Create(); bldr.ReplaceTsString(0, 0, tssFromApp); ITsString tss = bldr.GetString(); int icchIndent = 2; int iws = 0; bool fWriteObjData = true; //tsw.WriteTssAsXml(tss2, icchIndent, iws, fWriteObjData); //ISilDataAccess da = rbox.get_DataAccess(); ISilDataAccess da = rbox.DataAccess; //ILgWritingSystemFactory wsf = da.get_WritingSystemFactory(); ILgWritingSystemFactory wsf = da.WritingSystemFactory; tss.WriteAsXml(strm, wsf, icchIndent, iws, fWriteObjData); //m_text = tsw.get_Contents(); // XML formatted string m_text = tsw.Contents; // XML formatted string return(m_text != null); }
private string ClickPath(AccessibilityHelper ah, GuiPath gpath) { //bool forAll = false; //bool clickParent = false; //AccessibilityHelper child; //if (m_for != null && "all" == (string)m_for) forAll = true; if (1 == m_logLevel) m_log.paragraph(makeNameTag() + "Click starting path from "" + ah.Role + ":" + ah.Name + """); ah = gpath.FindInGui(ah, this); if (ah != null) { if (1 == m_logLevel) m_log.paragraph(makeNameTag() + "Clicking last pair in path"); int j; for (j = 0; j < m_repeat; j++) { // click 10 pixels from the left edge - see below if (m_side == "right") ah.SimulateRightClickRelative(m_dx, m_dy); else ah.SimulateClickRelative(m_dx, m_dy); // when @wait="no" don't wait at all between repeated clicks if (m_wait) Thread.Sleep(400); // wait a while eg. let menus open, etc. } m_finished = true; // tell do-once it's done } else return m_message; return ""; }
/// <summary> /// Execute a click, creating and executing more for @select and /// creating and executing child instructions. /// When used in a do-once instruction, this call is repeated. /// </summary> public override void Execute() { // Increase the wait time if the rest time is greater // This gives the script writer some control over how // long to try the click. base.Execute(); Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, makeNameTag() + " must occur in some context"); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, makeNameTag() + " context is not accessible"); m_path = Utilities.evalExpr(m_path); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { XmlPath node = SelectToPath(con, m_select); // process m_select m_path = node.Path + m_path; m_dx = getOffset(m_dx, k_offset, node.ModelNode, "dx"); m_dy = getOffset(m_dy, k_offset, node.ModelNode, "dy"); if (m_dx != k_offset || m_dy != k_offset) m_log.paragraph(makeNameTag() + "dx = " + m_dx + ", dy = " + m_dy); m_doneOnce = true; // avoid adding to m_path again on subsequent do-once iterations } if (Application != null) { try { Application.Process.WaitForInputIdle(); } catch (Win32Exception e) { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); } } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(gpath, makeNameTag() + " path='" + m_path + "' not parsed"); ClickPathUntilFound(ah, gpath); } else m_log.fail(makeNameTag() + "attribute 'path' or 'select' must be set or evaluate properly."); }
public override void Execute() { base.Execute(); bool exists = false; m_log.isNotNull(m_path, "attribute 'path' must be set"); m_path = Utilities.evalExpr(m_path); GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(gpath, "attribute path='" + m_path + "' not parsed"); GuiPath lpath = null; if (m_loc != null) // if it's null, get the whole string content { lpath = new GuiPath(m_loc); m_log.isNotNull(lpath, "attribute path='" + m_loc + "' not parsed"); } Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, "Select-text must occur in some context"); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, "Select-text context not accessible"); // The model names are needed in selectText. IPathVisitor visitor = null; ah = gpath.FindInGui(ah, visitor); m_log.isNotNull(ah, "context not accessible from path"); if (ah != null) { exists = getStrValue(ah); /** if (m_loc == null) exists = getStrValue(ah); else exists = selectText(lpath, ah); **/ } Logger.getOnly().result(this); Finished = true; // tell do-once it's done }
/// <summary> /// Method to apply when a path node is not found. /// No path above it and none below will call this method; /// only the one not found. /// </summary> /// <param name="path">The path step last tried.</param> public void notFound(GuiPath path) { // do nothing }
string HoverPath(AccessibilityHelper ah, GuiPath gpath) { ah = gpath.FindInGui(ah, this); visitNode(ah); return(m_message); }
/// <summary> /// Execute a click, creating and executing more for @select and /// creating and executing child instructions. /// When used in a do-once instruction, this call is repeated. /// </summary> public override void Execute() { // Increase the wait time if the rest time is greater // This gives the script writer some control over how // long to try the click. base.Execute(); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, makeNameTag() +" must occur in some context"); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, makeNameTag() + " context is not accessible"); m_path = Utilities.evalExpr(m_path); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { m_path = SelectToPath(con, m_select) + m_path; // process m_select m_doneOnce = true; } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, makeNameTag() + " path='" + m_path + "' not parsed"); ClickPathUntilFound(ah, gpath); } else fail(makeNameTag() + "attribute 'path' or 'select' must be set or evaluate properly."); }
/// <summary> /// The search is almost breadth-first: /// The first step in the path has an unknown sibling index and its role is not 'value'. /// If this ah has children of the step type, they are searched until all the /// subsequent steps find matching ah's. This search substitutes its own visitor /// that records the successful path ah's. Upon success, a sibling index is assigned to /// the variable named in the step, the non-terminal subpath ah's are exposed /// to the caller's visitor in turn and this method returns the last ah on the path. /// Subpath steps are searched for depending on their content. /// </summary> /// <param name="path">The path to search. Each step in the path contains an /// Accessibility name and Accessibility role of the matching gui object.</param> /// <param name="visitor">null or the object providing methods that are called when steps are found.</param> /// <returns>A new <see cref="AccessibilityHelper"/> object that wraps the matched /// window.</returns> private AccessibilityHelper SearchPathForIndex(GuiPath path, IPathVisitor visitor) { Logger log = Logger.getOnly(); log.startList("SearchPathForIndex('" + path.toString() + "') starting from ('" + this.Role + "','" + this.Name + "')"); if (ChildCount <= 0) { if (visitor != null) visitor.notFound(path); log.endList(); return null; } AccessibilityHelper ah = null; int nnum = 0; int index = 0; string parentName = null; if (path.Prev != null) parentName = path.Prev.Name; foreach (AccessibilityHelper child in this) { if (child == null) continue; string logStr = "-> Child(" + (++nnum) + ") ('" + child.Role + "','" + child.Name + "')"; if (path.Next != null && path.Next.Role == AccessibleRole.Alert) logStr += "NOT SUPPOSED TO BE VALUE!! val[" + child.Value + "]"; log.listItem(logStr); if (MatchNameAndRole(path.Name, path.Role, child)) { // this is a candidate for matching the path ++index; // the first one is 1 if (path.Next != null) { // This method won't allow for caller's visitors on candidate nodes until proved needed TrackingVisitor tv = new TrackingVisitor(); // tv may need to open sub menus if (tv != null) tv.visitNode(child); // add child to node list to visit later if this is the right path ah = ValueOrChild(path.Next, child, tv); if (ah != null) { // the subpath was matched to the end if (path.VarId != null && path.VarId != "") { // Create and execute a variable to record the index Var var = new Var(); var.Id = path.VarId; var.Set = System.Convert.ToString(index); // 1 based count var.Execute(); // puts the var in the TestState hash // don't set path.Nth = index since it might change if the path is used again } // let the caller's visitor tend to all the path ah's if (visitor != null) { if (tv != null) tv.StepDownPath(visitor); } log.endList(); return ah; } } } else if (parentName != null && child.Role == AccessibleRole.Client && child.Name == parentName) { // try the client instead ah = child.SearchPathForIndex(path, visitor); if (ah != null) { log.endList(); return ah; // found it } } } if (visitor != null) visitor.notFound(path); log.endList(); return null; }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being appended to m_path more than once. public override void Execute() { base.Execute(); PassFailInContext(m_onPass,m_onFail,out m_onPass,out m_onFail); Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, makeNameTag() + "Glimpse must occur in some context"); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, makeNameTag() + "Glimpse context not accessible"); m_path = Utilities.evalExpr(m_path); m_expect = Utilities.evalExpr(m_expect); /// Use the path or GUI Model or both if (m_select != null && m_select != "" && !m_doneOnce) { XmlPath node = SelectToPath(con, m_select); // process m_select m_path = node.Path + m_path; m_doneOnce = true; // avoid adding to m_path again on subsequent do-once iterations } try { Application.Process.WaitForInputIdle(); } catch (Win32Exception e) { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); } if (m_path != null && m_path != "") { GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(makeNameTag() + gpath, "attribute path='" + m_path + "' not parsed"); GlimpsePath(ah, gpath); } else m_log.fail(makeNameTag() + "attribute 'path' or 'select' must be set."); Logger.getOnly().result(this); }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being prepended to m_path more than once. public override void Execute() { base.Execute(); if (m_path != null && m_path == "") m_path = null; if (m_select != null && m_select == "") m_select = null; if (m_selectPath != null && m_selectPath == "") m_selectPath = null; if (m_names != null && m_names == "") m_names = null; // must have: // one of select or names to provide a list to check against // with names, one of path or selectPath to get the place to check in the GUI isTrue(m_select != null || m_names != null, makeNameTag() + " must have a 'names' or 'select' attribute."); if (m_names != null) isTrue(m_path != null || m_selectPath != null, makeNameTag() + " must have a 'path' or 'selectPath' attribute with 'names'."); Context con = (Context)Ancestor(typeof(Context)); isNotNull(con, makeNameTag() + " must occur in some context"); m_path = Utilities.evalExpr(m_path); m_selectPath = Utilities.evalExpr(m_selectPath); m_select = Utilities.evalExpr(m_select); // set the gui path from path or select if (m_select != null && !m_doneOnce) { // set m_names and possibly m_path m_log.paragraph(makeNameTag() + " creating selection targets via " + m_select); XmlNodeList pathNodes = XmlInstructionBuilder.selectNodes(con, m_select, makeNameTag()); isNotNull(pathNodes, makeNameTag() + " select='" + m_select + "' returned no model node"); // The @select text may have selected a string that is itself xPath! // If so, select on that xPath if (pathNodes.Count == 1 && pathNodes.Item(0).NodeType == XmlNodeType.Text) { // this text node should be an xpath statement string xPathImage = pathNodes.Item(0).Value; m_log.paragraph(makeNameTag() + " selected a text node with more XPATH: " + xPathImage); pathNodes = XmlInstructionBuilder.selectNodes(con, xPathImage, makeNameTag() + " selecting " + xPathImage); isNotNull(pathNodes, makeNameTag() + " selecting " + xPathImage + " from select='" + m_select + "' returned no model node"); } if (pathNodes.Count >= 1) { // there are some nodes - make a list m_names = null; foreach (XmlNode xname in pathNodes) { if (m_names == null) { if (m_path == null) { XmlPath xPath = new XmlPath(xname.ParentNode); m_path = xPath.Path; } } else m_names += "/"; string name = XmlFiler.getAttribute(xname, "name"); if (name == null || name == "") m_names += "#NONE"; else m_names += name; } } m_doneOnce = true; } string sPath = ""; if (m_selectPath != null && m_selectPath != "") sPath = SelectToPath(con, m_selectPath); m_path = sPath + m_path; GuiPath gpath = new GuiPath(m_path); isNotNull(gpath, makeNameTag() + " attribute path='" + m_path + "' not parsed"); if (m_names != null) m_list = Utilities.ParsePath(m_names); PassFailInContext(m_onPass,m_onFail,out m_onPass,out m_onFail); AccessibilityHelper ah = con.Accessibility; isNotNull(ah, makeNameTag() + " context not accessible"); //check to see if it is visible m_Result = false; ah = gpath.FindInGui(ah, null); if (ah != null) m_Result = GlimpseGUI(ah); Finished = true; // tell do-once it's done if ((m_onPass == "assert" && m_Result == true) ||(m_onFail == "assert" && m_Result == false) ) { if (m_message != null) fail(m_message.Read()); else fail(makeNameTag() + " Result = '" + m_Result + "', on-pass='******', on-fail='" + m_onFail + "'"); } Logger.getOnly().result(this); }
/// <summary> /// ValueOrChild determines if the ah's value should be macthed or /// if a child should be matched. /// </summary> /// <param name="nextGP">The next path step beyond this ah</param> /// <param name="ah">The accessibility object currently considered</param> /// <param name="visitor">null or the object providing methods that are called when steps are found.</param> /// <returns>An AccessibilityHelper if checking for a value, otherwise null</returns> public AccessibilityHelper ValueOrChild(GuiPath nextGP, AccessibilityHelper ah, IPathVisitor visitor) { bool result = false; if (nextGP.Role == AccessibleRole.Alert) { // check if the name is a regular expression if (nextGP.Name != null && nextGP.Name.StartsWith("rexp#")) { Regex rx = new Regex(nextGP.Name.Substring(5)); result = rx.IsMatch(ah.Value); Logger.getOnly().paragraph("Path name reg exp " + nextGP.Name.Substring(5) + " on " + ah.Value + " was " + result.ToString()); } else result = nextGP.Name == ah.Value; // match the value to the next path's name if (!result) { // it didn't match, so the search failed if (visitor != null) visitor.notFound(nextGP); return null; } } if (result) return ah; return ah.SearchPath(nextGP, visitor); // continue on the path }
/// <summary> /// Glimpse one gui-path and return the result. If the expected value is not found, /// an assertion is raised. /// </summary> /// <param name="ah">Context accessibility helper, taken as the starting place for gpath.</param> /// <param name="gpath">The path through the GUI to the control.</param> /// <param name="expect">The expected value of the property for the control.</param> /// <returns></returns> bool GlimpsePath(AccessibilityHelper ah, GuiPath gpath, string expect) { m_Result = true; m_got = null; IPathVisitor visitor = null; ah = gpath.FindInGui(ah, visitor); m_Result = GlimpseGUI(ah, expect); if (m_Result) base.Finished = true; // teminates do-once if ((m_onPass == "assert" && m_Result == true) ||(m_onFail == "assert" && m_Result == false) ) { if (m_message != null && m_message.HasContent()) fail(m_message.Read()); else { string image = "Property [" + m_prop + "] was [" + m_got + "] expecting [" + m_expect + "] Result = '" + m_Result + "', on-pass='******', on-fail='" + m_onFail + "'"; if (gpath != null) fail(image + " on gPath = " + gpath.toString()); else fail(image); } } return m_Result; }
string HoverPath(AccessibilityHelper ah, GuiPath gpath) { ah = gpath.FindInGui(ah, this); visitNode(ah); return m_message; }
/// <summary> /// The search is almost breadth-first: /// The first step in the path is searched breath-first. /// Subsequent path steps are searched for depending on their content. /// The Accessibility helper representing the step is returned it is found and is the last step. /// Otherwise, the search continues with the next path step or if not found, null is returned. /// If the first step is found, the visitor is applied before continuing to the next step. /// </summary> /// <param name="path">The path to search. Each step in the path contains an /// Accessibility name and Accessibility role of the matching gui object.</param> /// <param name="visitor">null or the object providing methods that are called when steps are found.</param> /// <returns>A new <see cref="AccessibilityHelper"/> object that wraps the matched /// window.</returns> private AccessibilityHelper SearchPathByBreadth(GuiPath path, IPathVisitor visitor) { if (ChildCount <= 0 || path.Nth <= 0) { if (visitor != null) visitor.notFound(path); return null; } int place = path.Nth; Logger log = Logger.getOnly(); log.startList("SearchPathByBreadth('" + path.toString() + "') starting from ('" + this.Role + "','" + this.Name + "')"); ArrayList lists = new ArrayList(); // list of child lists ArrayList nodes = MakeChildList(this); lists.Add(nodes); // Examine the first node in the list, dropping it after examination // and adding its children to the end if prudent. int lnum = 0; while (lists.Count > 0) { int count = 0; // reset match count nodes = (ArrayList)lists[0]; int nnum = 0; ++lnum; while (nodes.Count > 0) { AccessibilityHelper ah = (AccessibilityHelper)nodes[0]; string logStr = "-> Child(" + lnum + ":" + (++nnum) + ") ('" + ah.Role + "','" + ah.Name + "')"; if (path.Next != null && path.Next.Role == AccessibleRole.Alert) logStr += "val[" + ah.Value + "]"; log.listItem(logStr); if (MatchNameAndRole(path.Name, path.Role, ah)) { // this is the only way to return if (++count >= place) { // Found this step, keep stepping along the path if (path.Next != null) { if (visitor != null) visitor.visitNode(ah); // allow processing of this ah by caller ah = ValueOrChild(path.Next, ah, visitor); } log.endList(); return ah; } } if (ah.m_fRealAccessibleObject && ah.ChildCount > 0) lists.Add(MakeChildList(ah)); nodes.RemoveAt(0); // when 0 is removed, all indices slide down 1 } lists.RemoveAt(0); // when 0 is removed, all indices slide down 1 } if (visitor != null) visitor.notFound(path); log.endList(); return null; }
// when all the instructions pass, do-once passes // otherwise it fails public override void Execute() { // Don't call the base execute method! - want control.. // base.Execute(); if (Number == -1) Number = TestState.getOnly().IncInstructionCount; m_log.mark(this); m_ExecuteTickCount = System.Environment.TickCount; PrepareChildren(); // base method to build child instructions // remove all wait times in this context, but only at the child level this.RemoveWaitTime(); foreach (Instruction ins in m_components) { ins.RemoveWaitTime(); } PassFailInContext(OnPass, OnFail, out m_onPass, out m_onFail); AccessibilityHelper m_ah = Accessibility; if (1 == m_logLevel) m_log.paragraph("Context is "" + m_ah.Role + ":" + m_ah.Name + """); if (m_waitingFor != null && m_waitingFor != "") m_waitingFor = Utilities.evalExpr(m_waitingFor); int startTick = System.Environment.TickCount; m_log.paragraph(image()); bool done = false; bool lastPass = false; // used to allow 1 last pass over instructions after time is up while (!done) { CheckForErrorDialogs(true); // see if there are any cmds not finished done = true; // start as if they're all done foreach (Instruction ins in m_components) { if (!ins.Finished) // not already finished { // Don't assert onFail until it's the last pass (time is up) ins.DeferAssert = !lastPass; ins.Execute(); if (!ins.Finished) // still not finished done = false; } } m_Result = done; AccessibilityHelper ah = null; string title = null; if (m_waitingFor != null && m_waitingFor != "") { m_Result = false; // fail if the window is not found IntPtr foundHwndPtr = FindWindow(null,m_waitingFor); if ((int)foundHwndPtr != 0) { ah = new AccessibilityHelper(foundHwndPtr); // The ah constructor gets the topWindow if our window isn't found // Don't want that // ah = new AccessibilityHelper(m_waitingFor); // get the title, the ah.Name can be different. GuiPath path = new GuiPath("titlebar:NAMELESS"); AccessibilityHelper ah1 = ah.SearchPath(path, null); if (ah1 != null) title = ah1.Value; } } if (ah != null) m_log.paragraph("do-once found window:"+ah.Name); if (title != null) m_log.paragraph("do-once found title:"+title); if (lastPass) done = true; if (title != null && title == m_waitingFor) { lastPass = true; // A window may appear a bit later m_Result = true; } // once time is up, allow finial pass over instructions allowing asserts as needed if (!lastPass) lastPass = Utilities.NumTicks(startTick, System.Environment.TickCount) > m_waitTicks; } // end of while loop Logger.getOnly().result(this); Finished = true; // tell do-once it's done if (m_onPass == "assert" && m_Result == true) fail("do-once accomplished its task(s) but was not supposed to."); if (m_onFail == "assert" && m_Result == false) fail("do-once did not accomplish all of its tasks."); }
/// <summary> /// Searches the path depth-first. /// Nth is not used - if it were, it could get a sibling, ancestor or child. /// </summary> /// <param name="path">The path to search. Each step in the path contains an /// Accessibility name and Accessibility role of the matching gui object.</param> /// <param name="visitor">null or the object providing methods that are called when steps are found.</param> /// <returns>A new <see cref="AccessibilityHelper"/> object that wraps the matched /// window.</returns> private AccessibilityHelper SearchPathByDepth(GuiPath path, IPathVisitor visitor) { Logger log = Logger.getOnly(); log.startList("SearchPathByDepth('" + path.toString() + "') starting from ('" + this.Role + "','" + this.Name + "')"); if (ChildCount <= 0) { if (visitor != null) visitor.notFound(path); return null; } AccessibilityHelper ah = null; // try the client first if there is one, but don't visit it AccessibilityHelper client = FindClient(); if (client != null) ah = client.SearchPathByDepth(path, visitor); if (ah != null) { log.endList(); return ah; } // Rats!! It wasn't below the client, the caller wants some system widget or something foreach (AccessibilityHelper child in this) { if (child == null || child.Equals(client)) continue; // does this object match? // treat name == "" and child.Name == null as a match // Note: a null string shows as "" in the debugger! log.startList("SearchPathByDepth('" + path.toString() + "') Child: ('" + child.Role + "','" + child.Name + "')"); if (MatchNameAndRole(path.Name, path.Role, child)) { if (path.Next != null) { if (visitor != null) visitor.visitNode(child); // allow processing of this ah by caller log.endList(); return ValueOrChild(path.Next, child, visitor); } } // if not a "real" object, a child takes on it's parent's // attributes, so it appears to have the same # of children. // The first child is always the first child, so you get // infinite recursion on it if you don't check "realness". if (child.m_fRealAccessibleObject && child.ChildCount > 0) { // look through the child objects ah = child.SearchPathByDepth(path, visitor); if (ah != null) { if (path.Next != null) { if (visitor != null) visitor.visitNode(ah); // allow processing of this ah by caller log.endList(); return ValueOrChild(path.Next, ah, visitor); } log.endList(); return ah; } } } if (visitor != null) visitor.notFound(path); log.endList(); return null; }
/// <summary> /// Checks for an open error window and closes it. /// This may close the application. /// Also, set doAssert to true if this test should terminate on finding one. /// </summary> /// <param name="doAssert">false when the test should not fail as when another test caused the error window.</param> protected void CheckForErrorDialogs(bool doAssert) { // check for specific error dialogs // Try to get the ah for "An error has occurred" window // Log its info // Close the error window // Assert if directed to AccessibilityHelper ah = new AccessibilityHelper("An error has occurred"); // This constructor returns the top window if it can't find the // one with the title // Even though the ah is not null, sometimes it can't get the name string name = ""; if (ah != null && ah.Name == "An error has occurred") { // this is really bad! string color = "green"; m_log = Logger.getOnly(); m_log.paragraph("Window: " + name); GuiPath path = new GuiPath("button:Exit the application"); AccessibilityHelper ahExit = ah.SearchPath(path, null); if (ahExit == null) { color = "yellow"; // can continue path = new GuiPath("button:Ok"); ahExit = ah.SearchPath(path, null); } if (ahExit == null) { color = "unknown"; } if (color == "green") { m_log.paragraph("Found a green error window!"); } if (color == "yellow") { m_log.paragraph("Found a yellow error window! Continuing..."); } if (color == "unknown") { m_log.paragraph("Found an unknown error window!"); } // write the error text to the log path = new GuiPath("window:NAMELESS[2]"); AccessibilityHelper ahTextWin = ah.SearchPath(path, null); AccessibilityHelper ahText = null; if (ahTextWin != null) { path = new GuiPath("text:NAMELESS[2]"); ahText = ah.SearchPath(path, null); } if (ahText != null) { m_log.paragraph(ahText.Value); } else { m_log.paragraph(@"Don't know where to get the message text from."); } if (color == "green" || color == "yellow") { ahExit.SimulateClickRelative(10, 10); } if (doAssert && color == "green") { fail("Got an error window!"); } if (color == "unknown") { Application.SendKeys(@"{ESC}"); // exits error window but maybe not the app } if (doAssert && color == "unknown") { fail("Closed the unknown error window."); } Thread.Sleep(20000); // if still alive, wait for things to calm down } }
public void findInGui() { Process m_proc = Process.Start(@"C:\WINDOWS\NOTEPAD.EXE"); AccessibilityHelper m_ah; m_proc.WaitForInputIdle(); while (Process.GetProcessById(m_proc.Id).MainWindowHandle == IntPtr.Zero) Thread.Sleep(100); m_proc.WaitForInputIdle(); SIL.FieldWorks.Common.Utils. Win32.SetForegroundWindow(m_proc.MainWindowHandle); m_ah = new AccessibilityHelper(m_proc.MainWindowHandle); AccessibilityHelper ah = null; GuiPath gpath = new GuiPath("menu:Help/menu:Help Topics"); ah = gpath.FindInGui(m_ah, null); Assert.IsNotNull(ah,"'menu:Help/menu:Help Topics' Accessibility Helper not found"); Assert.AreEqual("Help Topics",ah.Name,"'menu:Help/menu:Help Topics' menu item not found"); Assert.AreEqual(AccessibleRole.MenuItem,ah.Role,"'menu:Help/menu:Help Topics' menu item role not found"); try { m_proc.WaitForInputIdle(); Win32.SetForegroundWindow(m_proc.MainWindowHandle); SendKeys.SendWait("%{F4}"); m_proc.WaitForInputIdle(); m_proc.WaitForExit(); } catch { } }
// When used in a do-once instruction, this call is repeated. // Note the code that keeps m_select from being prepended to m_path more than once. public override void Execute() { base.Execute(); if (m_path != null && m_path == "") { m_path = null; } if (m_select != null && m_select == "") { m_select = null; } if (m_selectPath != null && m_selectPath == "") { m_selectPath = null; } if (m_names != null && m_names == "") { m_names = null; } // must have: // one of select or names to provide a list to check against // with names, one of path or selectPath to get the place to check in the GUI m_log.isTrue(m_select != null || m_names != null, makeNameTag() + " must have a 'names' or 'select' attribute."); if (m_names != null) { m_log.isTrue(m_path != null || m_selectPath != null, makeNameTag() + " must have a 'path' or 'selectPath' attribute with 'names'."); } Context con = (Context)Ancestor(typeof(Context)); m_log.isNotNull(con, makeNameTag() + " must occur in some context"); m_path = Utilities.evalExpr(m_path); m_selectPath = Utilities.evalExpr(m_selectPath); m_select = Utilities.evalExpr(m_select); // set the gui path from path or select if (m_select != null && !m_doneOnce) { // set m_names and possibly m_path m_log.paragraph(makeNameTag() + " creating selection targets via " + m_select); XmlNodeList pathNodes = Instructionator.selectNodes(con, m_select, makeNameTag()); m_log.isNotNull(pathNodes, makeNameTag() + " select='" + m_select + "' returned no model node"); // The @select text may have selected a string that is itself xPath! // If so, select on that xPath if (pathNodes.Count == 1 && pathNodes.Item(0).NodeType == XmlNodeType.Text) { // this text node should be an xpath statement string xPathImage = pathNodes.Item(0).Value; m_log.paragraph(makeNameTag() + " selected a text node with more XPATH: " + xPathImage); pathNodes = Instructionator.selectNodes(con, xPathImage, makeNameTag() + " selecting " + xPathImage); m_log.isNotNull(pathNodes, makeNameTag() + " selecting " + xPathImage + " from select='" + m_select + "' returned no model node"); } if (pathNodes.Count >= 1) { // there are some nodes - make a list m_names = null; foreach (XmlNode xname in pathNodes) { if (m_names == null) { if (m_path == null) { XmlPath xPath = new XmlPath(xname.ParentNode); m_path = xPath.Path; } } else { m_names += "/"; } string name = XmlFiler.getAttribute(xname, "name"); if (name == null || name == "") { m_names += "#NONE"; } else { m_names += name; } } } m_doneOnce = true; // avoid adding to m_path again on subsequent do-once iterations } if (m_selectPath != null && m_selectPath != "") { XmlPath node = SelectToPath(con, m_selectPath); // process m_select m_path = node.Path + m_path; } GuiPath gpath = new GuiPath(m_path); m_log.isNotNull(gpath, makeNameTag() + " attribute path='" + m_path + "' not parsed"); if (m_names != null) { m_list = Utilities.ParsePath(m_names); } PassFailInContext(m_onPass, m_onFail, out m_onPass, out m_onFail); AccessibilityHelper ah = con.Accessibility; m_log.isNotNull(ah, makeNameTag() + " context not accessible"); //check to see if it is visible m_Result = false; try { Application.Process.WaitForInputIdle(); } catch (Win32Exception e) { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); m_Result = false; } if (m_Result) { ah = gpath.FindInGui(ah, null); } if (ah != null) { m_Result = GlimpseGUI(ah); } Finished = true; // tell do-once it's done if ((m_onPass == "assert" && m_Result == true) || (m_onFail == "assert" && m_Result == false)) { if (m_message != null) { m_log.fail(m_message.Read()); } else { m_log.fail(makeNameTag() + " Result = '" + m_Result + "', on-pass='******', on-fail='" + m_onFail + "'"); } } Logger.getOnly().result(this); }
/// <summary> /// Tries to find the target ah repeatedly for the "Wait" period /// </summary> /// <param name="ah"></param> /// <param name="gpath"></param> private void ClickPathUntilFound(AccessibilityHelper ah, GuiPath gpath) { string badPath = ""; if (DoingOnce()) badPath = ClickPath(ah, gpath); else { // act as if it's being done once //IntPtr handle = (IntPtr)ah.HWnd; // get an updated ah based on its window handle bool done = false; while(!done && !m_finished) { //ah = new AccessibilityHelper((handle)); // refresh the context ah ah = new AccessibilityHelper(ah); // refresh the context ah if (ah == null) m_log.paragraph(makeNameTag() + "ClickPathUntilFound on " + gpath + " handled a null context"); if (ah != null) badPath = ClickPath(ah, gpath); done = Utilities.NumTicks(m_ExecuteTickCount, System.Environment.TickCount) > m_until; System.Threading.Thread.Sleep(500); // try every half second } // if not clicked, it waited a long time on a bad path if (!m_finished) m_log.fail(makeNameTag() + badPath); } }
/// <summary> /// Checks for an open error window and closes it. /// This may close the application. /// Also, set doAssert to true if this test should terminate on finding one. /// </summary> /// <param name="doAssert">false when the test should not fail as when another test caused the error window.</param> protected void CheckForErrorDialogs(bool doAssert) { // check for specific error dialogs // Try to get the ah for "An error has occurred" window // Log its info // Close the error window // Assert if directed to AccessibilityHelper ah = new AccessibilityHelper("An error has occurred"); // This constructor returns the top window if it can't find the // one with the title // Even though the ah is not null, sometimes it can't get the name string name = ""; if (ah != null && ah.Name == "An error has occurred") { // this is really bad! string color = "green"; m_log.paragraph("Window: " + name); GuiPath path = new GuiPath("button:Exit the application"); AccessibilityHelper ahExit = ah.SearchPath(path, null); if (ahExit == null) { color = "yellow"; // can continue path = new GuiPath("button:Ok"); ahExit = ah.SearchPath(path, null); } if (ahExit == null) color = "unknown"; if (color == "green") m_log.paragraph("Found a green error window!"); if (color == "yellow") m_log.paragraph("Found a yellow error window! Continuing..."); if (color == "unknown") m_log.paragraph("Found an unknown error window!"); // write the error text to the log path = new GuiPath("window:NAMELESS[2]"); AccessibilityHelper ahTextWin = ah.SearchPath(path, null); AccessibilityHelper ahText = null; if (ahTextWin != null) { path = new GuiPath("text:NAMELESS[2]"); ahText = ah.SearchPath(path, null); } if (ahText != null) m_log.paragraph(ahText.Value); else m_log.paragraph(@"Don't know where to get the message text from."); if (color == "green" || color == "yellow") ahExit.SimulateClickRelative(10,10); if (doAssert && color == "green") m_log.fail("Got an error window!"); if (color == "unknown" && Application != null) Application.SendKeys(@"{ESC}"); // exits error window but maybe not the app if (doAssert && color == "unknown") m_log.fail("Closed the unknown error window."); Thread.Sleep(20000); // if still alive, wait for things to calm down } }