Beispiel #1
0
        /// <summary>
        /// Interprets a model path (selection), selects the node and returns its path.
        /// </summary>
        /// <param name="con">Current context of the action instruction.</param>
        /// <returns>A "path" string</returns>
        protected XmlPath SelectToPath(Context con, string modelPath)
        {
            if (modelPath == null || modelPath == "")
            {
                return(null);
            }
            // only one node or attribute selected gets clicked
            m_log.paragraph(makeNameTag() + " creating one select-path target via " + modelPath);
            XmlNodeList pathNodes = Instructionator.selectNodes(con, modelPath, makeNameTag());

            m_log.isNotNull(pathNodes, makeNameTag() + " select-path='" + modelPath + "' returned no model node");
            m_log.isTrue(pathNodes.Count > 0, makeNameTag() + " select-path='" + modelPath + "' returned no nodes");
            // The modelPath 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
                m_log.isNotNull(pathNodes.Item(0).Value, makeNameTag() + " select-path='" + modelPath + "was a null string");
                m_log.isTrue(pathNodes.Item(0).Value != "", makeNameTag() + " select-path='" + modelPath + "was an empty string");
                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='" + modelPath + "' returned no model node");
            }
            // Click the first node returned
            XmlNode node  = pathNodes[0];
            XmlPath xPath = new XmlPath(node);

            if (!xPath.isValid())
            {
                m_log.fail(makeNameTag() + " XmlPath not constructable from " + node.OuterXml);
            }
            return(xPath);
        }
Beispiel #2
0
        public override void Execute()
        {
            base.Execute();
            Context con = (Context)Ancestor(typeof(Context));

            m_log.isNotNull(con, makeNameTag() + " must occur in some context");
            m_Result = Condition.EvaluateList(m_conditions);
            if (m_Result == true)
            {
                XmlNode xThen = m_elt.SelectSingleNode("then");
                if (xThen != null)
                {                 // then may have been created via do-once before this
                    if (m_then == null)
                    {             // not created yet
                        Context thenCon = new Context();
                        thenCon.ModelNode = con.ModelNode;
                        thenCon.Parent    = this;
                        string rest = XmlFiler.getAttribute(xThen, "wait");
                        if (rest != null)
                        {
                            thenCon.Wait = Convert.ToInt32(rest);
                        }
                        foreach (XmlNode child in xThen.ChildNodes)
                        {                         // MakeShell adds the ins to thenCon
                            Instructionator.MakeShell(child, thenCon);
                        }
                        SetThen(thenCon);
                    }
                    m_then.Execute();
                }
            }
            else
            {
                XmlNode xElse = m_elt.SelectSingleNode("else");
                if (xElse != null)
                {                 // else may have been created via do-once before this
                    if (m_else == null)
                    {             // not created yet
                        Context elseCon = new Context();
                        elseCon.ModelNode = con.ModelNode;
                        elseCon.Parent    = this;
                        string rest = XmlFiler.getAttribute(xElse, "wait");
                        if (rest != null)
                        {
                            elseCon.Wait = Convert.ToInt32(rest);
                        }
                        foreach (XmlNode child in xElse.ChildNodes)
                        {                         // MakeShell adds the ins to elseCon
                            Instructionator.MakeShell(child, elseCon);
                        }
                        SetElse(elseCon);
                    }
                    m_else.Execute();
                }
            }
            Logger.getOnly().result(this);
            Finished = true;             // tell do-once it's done
        }
Beispiel #3
0
        /// <summary>
        /// Read the var nodes from the model and add them as
        /// child instructions to this context.
        /// </summary>
        private void ReadModelVars()
        {
            XmlNodeList vars = m_model_root.SelectNodes("var");

            if (vars != null)
            {
                foreach (XmlNode varNode in vars)
                {
                    Var varObj = (Var)Instructionator.MakeShell(varNode, this);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Gets the name of a test script and runs it.
        /// There must be a corresponding XML script file in the
        /// location specified in the GtdConfig.xml file.
        /// </summary>
        /// <param name="script">The name of the test script (.xml not needed).</param>
        public void fromFile(string script)
        {
            if (!(script.ToLower()).EndsWith(@".xml"))
            {
                script += ".xml";
            }
            TestState ts = null;

            if (varsDefined)             // true only if AddVariable() was called.
            {
                ts = TestState.getOnly();
                // Re-open the log using the script name - lose what's there.
                Logger.getOnly().close(Logger.Disposition.Hung);
                // The next call to Logger.getOnly() will create one with using the script name.
            }
            else
            {
                ts = TestState.getOnly(m_appSymbol); // Allocating ts here insures deallocation
            }
            ts.Script = script;                      // must come before ts.PublishVars();
            ts.PublishVars();

            // get the script path from the configuration file
            string     path       = ts.getScriptPath() + @"\" + script;
            XmlElement scriptRoot = XmlFiler.getDocumentElement(path, "accil", false);

            Assert.IsNotNull(scriptRoot, "Missing document element 'accil'.");
            Instructionator.initialize("AxilInstructions.xml");
            OnDesktop dt = new OnDesktop();

            Assert.IsNotNull(dt, "OnDesktop not created for script " + path);
            dt.Element = scriptRoot;             // not quite code-behind, but OK
            dt.Number  = ts.IncInstructionCount;
            //dt = new XmlInstructionBuilder().Parse(path);

            // now execute any variables if they've been added before executing the desktop
            foreach (Var v in m_vars)
            {
                v.Execute();
            }

            System.GC.Collect();             // forces collection on NUnit process only

            Beep beeep = new Beep();

            beeep.Execute();             // play a beep tone so we know when the test starts

            dt.Execute();
            varsDefined = false;             // the next test may not have any
            Logger.getOnly().close(Logger.Disposition.Pass);

            Thread.Sleep(1000);
        }
Beispiel #5
0
 /// <summary>
 /// Converts child instructions from XML the first time this is called.
 /// Some contexts need to build their children but control execution
 /// themselves. They don't call this. Execute, which calls this internally.
 /// </summary>
 public void PrepareChildren(bool addMore)
 {
     if (1 == m_logLevel)
     {
         if (m_ah == null)
         {
             m_log.paragraph(makeNameTag() + "PrepareChildren: Context is not yet defined.");
         }
         else
         {
             m_log.paragraph(makeNameTag() + "PrepareChildren: Context is &quot;" + m_ah.Role + ":" + m_ah.Name + "&quot;");
         }
     }
     // m_instructions may have been stocked before execution as by click.
     // They also may have been built on a previous execution via do-once.
     if (addMore || m_instructions.Count == 0)
     {             // Build the child instructions
         // Insertions may be made by expansion of some instructions into
         // multiple instructions (via include) so iterators and foreach can't be used.
         int count = 0;
         if (count < m_elt.ChildNodes.Count)
         {
             XmlNode xn = m_elt.ChildNodes[count];
             while (xn != null)
             {                       // MakeShell can add multiple instructions to m_instructions.
                 Instruction ins = Instructionator.MakeShell(xn, this);
                 // pass higher log levels to the children
                 if (ins != null && ins.Log < Log)
                 {
                     ins.Log = Log;
                 }
                 count += 1;
                 if (count < m_elt.ChildNodes.Count)
                 {
                     xn = m_elt.ChildNodes[count];
                 }
                 else
                 {
                     xn = null;
                 }
             }
         }
     }
 }
Beispiel #6
0
        // 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);
        }
Beispiel #7
0
        // look for the expected dialog to appear. If it does, make an accessibilty
        // helper for it.
        public override void Execute()
        {
            // base.Execute(ts); // can't call this yet as it executes the children
            WaitMsec();           // do call this but make sure Wait is reset to zero!
            Wait = 0;             // reset to zero so there is no delay after the dialog is found.
            // number is needed in diagnostics for the log
            if (Number == -1)
            {
                Number = TestState.getOnly().IncInstructionCount;
            }

            /// If present, use the selected dialog model title
            Context con = (Context)Ancestor(typeof(Context));

            if (m_select != null && m_select != "")
            {              // make a new model context node and move dialog's children to it
                m_select = Utilities.evalExpr(m_select);
                XmlDocument doc    = m_elt.OwnerDocument;
                XmlElement  modElt = doc.CreateElement("model");
                modElt.SetAttribute("select", m_select);
                XmlNodeList children = m_elt.ChildNodes;
                int         count    = children.Count;
                while (count > 0)
                {                                     // move dialog children to model
                    XmlNode child = children.Item(0); //get the first child
                    modElt.AppendChild(child);        // automatically removed from m_elt!!
                    count = children.Count;
                }
                m_elt.AppendChild(modElt);
                // set the title to look for
                // can only have one text node
                XmlNodeList pathNodes = Instructionator.selectNodes(this, m_select, makeName());
                m_log.isNotNull(pathNodes, makeNameTag() + " select='" + m_select + "' returned no model");
                m_log.isTrue(pathNodes.Count > 0, makeNameTag() + " select='" + m_select + "' returned no model nodes");
                // This is the model node
                XmlNode modNode = pathNodes.Item(0);
                if (m_title == null || m_title == "")
                {                  // no title override, so set the title from the model
                    string titleCheck = XmlFiler.getAttribute(modNode, "title");
                    if (titleCheck != null)
                    {
                        m_title = titleCheck;
                        m_log.paragraph("on-dialog title set from selected model " + titleCheck);
                    }
                }
                else
                {
                    m_log.paragraph("on-dialog title set from @title " + m_title);
                }
                string nameCheck = XmlFiler.getAttribute(modNode, "name");
                if (nameCheck != null)
                {
                    m_name = nameCheck;
                    m_log.paragraph("on-dialog name set from selected model " + nameCheck);
                }
                m_select = null;                 // can only do this one time in do-once or model
            }
            // if no name, try title
            if (m_title != null && m_title != "" && (m_name == null || m_name == ""))
            {
                m_name = m_title;
            }

            m_log.isNotNull(m_title, makeNameTag() + " No @title in script or model for this dialog.");
            m_log.isFalse(m_title == "", makeNameTag() + " @title in script or model is blank.");
            m_log.isFalse(m_name == null && !m_title.StartsWith("rexp#"), makeNameTag() + " No @name step in script or model for this dialog.");
            m_log.isFalse(m_name == "" && !m_title.StartsWith("rexp#"), makeNameTag() + " @name step in script or model is blank.");
            //if (m_title != null && m_title != "") m_title = Utilities.evalExpr(m_title);
            //if (m_name != null && m_name != "") m_name = Utilities.evalExpr(m_name);
            m_title = Utilities.evalExpr(m_title);
            m_name  = Utilities.evalExpr(m_name);

            m_log.paragraph(image());

            if (Application != null)
            {
                try { Application.Process.WaitForInputIdle(); }
                catch (Win32Exception e)
                { m_log.paragraph(makeNameTag() + " WaitForInputIdle: " + e.Message); }
            }
            // Give the window m_Rest seconds to show up
            int    startTick = System.Environment.TickCount;
            IntPtr foundHwndPtr;
            string name = null;
            Regex  rx   = null;

            if (m_title != null && m_title.StartsWith("rexp#"))
            {               // Create a regular expression object
                try { rx = new Regex(m_title.Substring(5)); }
                catch (ArgumentException e)
                {
                    m_log.fail(makeNameTag() + " title from rexp# [" + m_title.Substring(5)
                               + "] error: " + e.Message);
                }
            }

            while (!m_found)
            {               // If there is a regular expression, try it.
                if (rx != null)
                {           // try the main window name then other windows it may own via the regular expression
                    m_log.paragraph("Searching all processes");
                    Process[] allProcs = Process.GetProcesses();
                    for (int p = 0; p < allProcs.Length; p++)
                    {
                        Process pro = allProcs[p];
                        try {
                            if (rx.IsMatch(pro.MainWindowTitle))
                            {
                                m_found = true;
                                m_ah    = new AccessibilityHelper(pro.Handle);
                                break;
                            }
                        }
                        catch (Exception e) {
                            m_log.paragraph(makeNameTag() + " main title from rexp# [" + m_title.Substring(5)
                                            + "] process error: " + e.Message);
                        }
                        #region Attempt to explore process threads - useful?
                        // try the windows that belong to this process

                        /*try {
                         *      foreach (ProcessThread pt in pro.Threads)
                         *      {
                         *
                         *              string para = "on-dialog matching proc [" + pro.ProcessName + ":";
                         *              if (pt.Site != null) para += pt.Site.Name + "]";
                         *              else                 para += "]";
                         *              m_log.paragraph(para);
                         *              if (pt.Site != null && rx.IsMatch(pt.Site.Name)) {
                         *                      m_found = true;
                         *                      m_ah = new AccessibilityHelper(pro.Handle);
                         *                      break;
                         *              }
                         *      }
                         * }
                         * catch (Exception e)
                         * {
                         *      m_log.paragraph("on-dialog title from rexp# [" + m_title.Substring(5)
                         + "] process error: " + e.Message);
                         + } */
                        #endregion
                    }
                }
                if (!m_found)
                {                   // get the window handle for windows with the right name
                    // unfortuneately, other windows, or partially formed windows
                    // seem to be obtained too.
                    m_log.paragraph("Searching the desktop for a window via FindWindow");
                    if (rx != null)
                    {
                        foundHwndPtr = FindWindow(null, null);
                    }
                    else
                    {
                        foundHwndPtr = FindWindow(null, m_title);
                    }
                    if ((int)foundHwndPtr != 0)
                    {                       // is this the window? Is it completely formed?
                        m_ah = new AccessibilityHelper(foundHwndPtr);
                        if (m_ah == null)
                        {
                            m_log.paragraph(makeNameTag() + " Obtained window with no Accessibiilty!");
                        }
                        else                        // this window has accessibility - hope it's fully built
                        {                           // is this or one of its children the window?
                            name = m_ah.Name;       //when name1 = "", m_ah is probably bad - i.e. not an object
                            if (name == "")
                            {
                            }                               // do nothing, keep looking
                            else if (name.Equals(m_title) || name.Equals(this.m_name))
                            {                               // this is likely it
                                m_found = true;
                            }
                            else                            // m_ah might be the ah for the main app or dialog window
                            {                               // Maybe one of its children is the window we want
                                m_log.paragraph("Searching for a child window");
                                m_ah = m_ah.FindChild(m_title, AccessibleRole.Dialog);
                                if (m_ah != null)
                                {                                 // is this the window?
                                    name = m_ah.Name;             // name1 can't be null
                                    if (name == "")
                                    {
                                    }                                       // do nothing, keep looking
                                    else if (name.Equals(m_title) || name.Equals(this.m_name))
                                    {                                       // this might be it
                                        m_found = true;
                                    }
                                }
                            }
                        }
                    }
                }

                if (Utilities.NumTicks(startTick, System.Environment.TickCount) > m_until)
                {
                    break;                      // time is up
                }
                System.Threading.Thread.Sleep(100);
            }

            m_Rest = 0;             // don't wait later when base.Execute is invoked

            if (m_found)
            {
                m_DlgHwndStack.Push(m_ah.HWnd);
            }
            else
            {               // Didn't find the window
                m_ah = null;
            }

            string contextPass, contextFail;
            PassFailInContext(OnPass, OnFail, out contextPass, out contextFail);                //  out m_onPass, out m_onFail);
            m_log.paragraph(makeNameTag() + " passIn=" + OnPass + " failIn=" + OnFail + " pass="******" fail=" + contextFail);
            if (!m_found && contextFail == "skip")
            {
                return;                 // quietly exit
            }
            m_log.isTrue(m_found, makeNameTag() + m_title + @"' was not created or not accessible");
            if (name == null)
            {
                m_log.paragraph(makeNameTag() + " Wierd: ah exists but name was null - should NEVER happen!!");
                name = "";
            }
            if (contextPass == "assert")
            {
                m_log.fail(makeNameTag() + m_title + " was not supposed to display.");
            }

            base.Execute();
            m_log.result(this);
            base.Finished = true;               // finished processing this dialog context
            m_DlgHwndStack.Pop();

            if (m_DlgHwndStack.Count > 0)
            {
                int hwnd = (int)m_DlgHwndStack.Peek();
                SendMessage((IntPtr)hwnd,
                            (int)Msg.WM_SETFOCUS, 0, 0);
                m_log.paragraph(makeNameTag() + " Sent Focus message to containing context object");
                //	m_ah.Parent.SendWindowMessage((int)SIL.FieldWorks.Common.Utils.Win32.WinMsgs.WM_SETFOCUS,0,0);
            }
        }
Beispiel #8
0
 /// <summary>
 /// Called to finish construction when an instruction has been instantiated by
 /// a factory and had its properties set.
 /// This can check the integrity of the instruction or perform other initialization tasks.
 /// </summary>
 /// <param name="xn">XML node describing the instruction</param>
 /// <param name="con">Parent xml node instruction</param>
 /// <returns></returns>
 public override bool finishCreation(XmlNode xn, Context con)
 {          // finish factory construction
     m_log.isNotNull(Id, makeNameTag() + " instruction must have a id.");
     m_log.isTrue(Id != "", makeNameTag() + " instruction must have a non-empty id.");
     if (m_select != null && m_select != "")
     {             // the variable can only have one text node or one other node assigned to it.
         m_log.isNotNull(con, "makeNameTag() + select has no context.");
         XmlNodeList pathNodes = Instructionator.selectNodes(con, m_select, "var" + Id);
         m_log.isNotNull(pathNodes, makeNameTag() + "var " + Id + " select='" + m_select + "' returned no result");
         if (pathNodes.Count > 0)
         {                 // append first node to set string
             XmlNode modNode = pathNodes.Item(0);
             string  prop    = null;
             // which property of the node to get?
             if (m_prop == null && modNode is XmlElement)
             {
                 m_prop = "path";
             }
             if (m_prop == null)
             {
                 m_prop = "value";
             }
             if (m_prop != null && m_prop == "value")
             {
                 prop = XmlPath.ResolveModelPath(modNode, modNode.Value);
             }
             if (m_prop != null && m_prop == "name")
             {
                 prop = modNode.Name;
             }
             if (m_prop != null && m_prop == "type")
             {
                 prop = modNode.NodeType.ToString();
             }
             if (m_prop != null && m_prop == "path")
             {
                 XmlPath xp = new XmlPath(modNode);
                 if (xp.isValid())
                 {
                     prop = xp.Path;
                 }
                 else
                 {
                     prop = null;
                 }
             }
             m_set += prop;
         }
         else
         {
             m_set += "#NoSelection#";
         }
     }
     if (Set == null && m_when == null)
     {             // if there is a select/when then don't complain if the select found nothing
         m_log.isNotNull(Add, makeNameTag() + Id +
                         @" set, select or add must result in a string or number value unless when=""exists"" is set.");
         if (m_select != null && m_select != "")
         {
             Set = @"#not-" + m_when + @"#";
         }
     }
     return(true);
 }
Beispiel #9
0
        /// <summary>
        /// Execute this model node context, specified by @select and
        /// creating and executing child instructions.
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (m_created)
            {
                Finished = true;        // tell do-once it's done
                return;                 // all has been done in the base Context.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");

            // If there is a @select, select the nodes
            if (m_select != null && m_select != "")
            {             // each node or attribute selected creates a context
                m_select = Utilities.evalExpr(m_select);
                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 nodes");
                // 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 xPath = pathNodes.Item(0).Value;
                    m_log.paragraph(makeNameTag() + " selected a text node with more XPATH: " + xPath);
                    pathNodes = Instructionator.selectNodes(con, xPath, makeNameTag() + " selecting " + xPath);
                    m_log.isNotNull(pathNodes, makeNameTag() + " selecting " + xPath + " from select='" + m_select + "' returned no model nodes");
                }
                // Create a list of paths to loop over
                Model lastModel = this; // use as an insert reference node
                foreach (XmlNode node in pathNodes)
                {                       // build the path via each model node
                    XmlPath xPath = new XmlPath(node);
                    // xPath may be invalid - it means it has no guiPath
                    //if (!xPath.isValid()) fail(makeNameTag() + " XmlPath not constructable from " + node.OuterXml);
                    if (1 == m_logLevel)
                    {
                        m_log.paragraph(makeNameTag() + " appPath " + xPath.xPath());
                        m_log.paragraph(makeNameTag() + " guiPath " + xPath.Path);
                    }
                    Model model = new Model();
                    model.m_created   = true;
                    model.m_modelNode = xPath;
                    model.m_path      = xPath.Path;
                    model.m_select    = xPath.xPath();
                    model.m_when      = m_when;
                    model.m_name      = XmlFiler.getAttribute(node, "name");
                    model.m_role      = XmlFiler.getAttribute(node, "role");
                    model.m_nodeName  = node.Name;
                    model.Number      = TestState.getOnly().IncInstructionCount;
                    model.Id         += (model.Number - Number).ToString();
                    model.Parent      = con;
                    con.Add(lastModel, model);
                    lastModel = model;                     // insert the next one after this one.
                    m_log.mark(model);                     // log the progress of interpretation
                    // if there is content, add instructions to the new model context
                    if (m_elt.HasChildNodes)
                    {
                        foreach (XmlNode xnChild in m_elt.ChildNodes)
                        {                         // a side-effect of MakeShell is to add the instruction to the model
                            Instructionator.MakeShell(xnChild, model);
                        }
                    }
                }
            }
            Finished = true;             // tell do-once it's done
        }