예제 #1
0
        public override void Body()
        {
            ActualResult = TestCaseResult.Failed;

            Stopwatch watch         = new Stopwatch();
            string    lastException = string.Empty;

            watch.Start();
            while (watch.ElapsedMilliseconds < timeout + 10)
            {
                try
                {
                    UIControlBase c = UIControlBase.FindControlByPath(control, _logControlSearch);

                    if (c.Exists)
                    {
                        ActualResult = TestCaseResult.Passed;
                        return;
                    }
                }
                catch (Exception ex)
                {
                    lastException = ex.ToString();
                }
            }

            LogFailedByExpectedResult("Control not found after " + timeout + " milliseconds", control);
            if (lastException != string.Empty)
            {
                Log.Warning("Exception caught", lastException, EntryVerbosity.Debug);
            }
        }
예제 #2
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                Log.Error("Control not found");
                return;
            }

            IScrollItemPattern pattern = c.GetControlInterface <IScrollItemPattern>();

            if (pattern != null && _scrollIntoView)
            {
                pattern.ScrollIntoView();
            }

            LowLevelInput.PressKeys(_modifierKeys);
            c.Click(button, point);
            LowLevelInput.ReleaseKeys(_modifierKeys);

            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
        }
예제 #3
0
        private static string GetText(string control, bool logErrors)
        {
            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (c == null || !c.Exists)
            {
                if (logErrors)
                {
                    Log.Error("Control not found");
                }

                return(null);
            }

            IText text = c.GetControlInterface <IText>();

            if (text == null)
            {
                // TODO: Add support for HTML controls (or REALLY do generic implementations on the interfaces)
                if (logErrors)
                {
                    Log.Error("Couldn't find an appropriate way to get text from the control.");
                }

                return(null);
            }

            return(text.Text);
        }
예제 #4
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
            _resultTable = null;

            UIControlBase c = UIControlBase.FindControlByPath(_control);

            if (c == null || !c.Exists)
            {
                Log.Error("Control not found", _control);
                return;
            }

            IGridPattern grid = c.GetControlInterface <IGridPattern>();

            if (grid == null)
            {
                Log.Error("Couldn't find an appropriate way to get at grid data.");
                return;
            }

            string[]   headers;
            string[][] rows = grid.CaptureGrid(out headers);

            if (headers != null && headers.Distinct().Count() != headers.Length)
            {
                Log.Error("Duplicate column names", "Could not produce an output table because there are two columns with the same name.");
                return;
            }

            DataTable table = new DataTable("Captured grid");

            if (headers != null)
            {
                foreach (string header in headers)
                {
                    table.Columns.Add(XPath.EscapeLiteral(header), typeof(string));
                }
            }
            else
            {
                int columnCount = grid.ColumnCount;

                for (int i = 0; i < columnCount; i++)
                {
                    table.Columns.Add("Column " + i.ToString(CultureInfo.CurrentUICulture), typeof(string));
                }
            }

            foreach (string[] row in rows)
            {
                table.Rows.Add(row.Select(cell => cell ?? string.Empty).Select(XPath.EscapeLiteral).ToArray());
            }

            _resultTable = table;

            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
        }
예제 #5
0
        public static string[] CaptureList(string control, bool logErrors)
        {
            // Capture the list
            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (c == null || !c.Exists)
            {
                if (logErrors)
                {
                    Log.Error("Control not found", control);
                }

                return(null);
            }

            IListPattern list = c.GetControlInterface <IListPattern>();

            if (list != null)
            {
                return(list.CaptureList());
            }

            ISelector selector = c.GetControlInterface <ISelector>();

            if (selector != null)
            {
                return(selector.Items);
            }

            // Try one control up; we could be on the combo box's edit or button controls
            c = c.Parent;

            if (c != null)
            {
                list = c.GetControlInterface <IListPattern>();

                if (list != null)
                {
                    return(list.CaptureList());
                }

                selector = c.GetControlInterface <ISelector>();

                if (selector != null)
                {
                    return(selector.Items);
                }
            }

            if (logErrors)
            {
                Log.Error("Couldn't find a way to read the list.");
            }

            return(null);
        }
예제 #6
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control not found");
            }

            IWindowPattern window = c.GetControlInterface <IWindowPattern>();

            if (window == null)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control doesn't appear to be a window");
            }

            switch (opType)
            {
            case WindowOperationType.Close:
                window.Close();
                break;

            case WindowOperationType.Maximize:
                if (!window.CanMaximize)
                {
                    Log.Error("Window does not support maximizing.", string.Empty, EntryVerbosity.Internal);
                    return;
                }

                window.SetState(WindowVisualState.Maximized);
                break;

            case WindowOperationType.Minimize:
                if (!window.CanMinimize)
                {
                    Log.Error("Window does not support maximizing.", string.Empty, EntryVerbosity.Internal);
                    return;
                }

                window.SetState(WindowVisualState.Minimized);
                break;

            case WindowOperationType.Restore:
                window.SetState(WindowVisualState.Normal);
                break;

            case WindowOperationType.SetFocus:
                window.SetState(WindowVisualState.Normal);
                c.SetFocus();
                break;
            }
        }
예제 #7
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control not found");
            }

            c.GetImage().Save(file);
        }
예제 #8
0
        public override void Body()
        {
            ActualResult = TestCaseResult.Failed;

            Stopwatch     watch         = new Stopwatch();
            string        lastException = null;
            UIControlBase c             = null;

            watch.Start();
            while (watch.ElapsedMilliseconds < _timeout + 10)
            {
                try
                {
                    c = UIControlBase.FindControlByPath(_control);

                    if (c.Exists)
                    {
                        break;
                    }
                }
                catch (Exception ex) {
                    lastException = ex.ToString();
                }
            }

            if (c == null || !c.Exists)
            {
                Log.Error("Control not found after " + _timeout + " milliseconds", _control);

                if (lastException != null)
                {
                    Log.Warning("Exception caught", lastException, EntryVerbosity.Debug);
                }

                return;
            }

            UIAControl uia = c as UIAControl;

            if (uia != null && uia.XPathElementName == "titlebar")
            {
                // Go with the parent
                c = uia.Parent;
            }

            c.SetFocus();
            ActualResult = TestCaseResult.Passed;
        }
예제 #9
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control not found");
            }

            Bitmap image = c.GetImage();

            Log.Image(image, logDescription);
        }
예제 #10
0
        public override void Body()
        {
            try
            {
                UIControlBase c = UIControlBase.FindControlByPath(control);

                if (!c.Exists)
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new InvalidOperationException("Control not found");
                }

                ISelector selectorPattern = c.GetControlInterface <ISelector>();

                if (selectorPattern != null)
                {
                    listItems    = selectorPattern.Items;
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
                }
                else if (c is HTMLSelect)
                {
                    HTMLOption[] ops = ((HTMLSelect)c).Options;
                    listItems = new string[ops.Length];
                    for (int idx = 0; idx < ops.Length; idx++)
                    {
                        listItems[idx] = ops[idx].Text;
                    }

                    ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
                }
                else
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new InvalidOperationException("Control is not list type control");
                }
            }
            catch (Exception ex)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw ex;
            }
        }
예제 #11
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            try
            {
                UIControlBase c = UIControlBase.FindControlByPath(control);

                if (!c.Exists)
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new InvalidOperationException("Control not found");
                }

                c.MoveMouseTo(point);
            }
            catch (System.Reflection.TargetInvocationException)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
            }
        }
예제 #12
0
        public override void Body()
        {
            ActualResult = TestCaseResult.Failed;

            UIControlBase c = UIControlBase.FindControlByPath(_control);

            if (!c.Exists)
            {
                Log.Error("Control not found");
                return;
            }

            if (!c.Enabled)
            {
                Log.Error("Control not enabled");
                return;
            }

            ITogglePattern toggle = c.GetControlInterface <ITogglePattern>();

            if (toggle != null)
            {
                ToggleState currentState = toggle.ToggleState;

                if (currentState != _state)
                {
                    LogFailedByExpectedResult("Did not match",
                                              string.Format("The control's state was \"{0}\" instead of \"{1}\".",
                                                            currentState, _state));
                    return;
                }

                ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
            }
            else
            {
                Log.Error("The target control doesn't support toggle operations.");
                return;
            }
        }
예제 #13
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control not found");
            }

            ITransformPattern transform = c.GetControlInterface <ITransformPattern>();

            if (transform == null)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control doesn't appear to be a window");
            }

            transform.Move(point.X, point.Y);
        }
예제 #14
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
            text         = string.Empty;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                Logger.Log.Error("Couldn't find control", control);
                ActualResult = RemotingModel.TestCaseResult.Failed;
                return;
            }

            IText textPattern = c.GetControlInterface <IText>();

            if (textPattern != null)
            {
                text = textPattern.Text;
                Logger.Log.Info("Found text property", text);
                return;
            }

            if (c is QAliber.Engine.Controls.Web.WebControl)
            {
                text = ((QAliber.Engine.Controls.Web.WebControl)c).InnerText;
                Logger.Log.Info("Found inner text property of web control", text);
                return;
            }

            Logger.Log.Info("Couldn't find a text property, trying to do optical character recognition");
            OCRItem ocrItem = new OCRItem(c.GetImage());

            text = ocrItem.ProcessImage();
            Logger.Log.Info("OCR result = " + text);
        }
예제 #15
0
        public override void Body()
        {
            try
            {
                UIControlBase c = UIControlBase.FindControlByPath(control);

                if (!c.Exists)
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new InvalidOperationException("Control not found");
                }

                ISelector selectorPattern = c.GetControlInterface <ISelector>();

                if (selectorPattern != null)
                {
                    selectorPattern.Select(index);
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
                }
                else if (c is HTMLSelect)
                {
                    ((HTMLSelect)c).SelectItem(index);
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
                }
                else
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new InvalidOperationException("Control is not list type control");
                }
            }
            catch (Exception ex)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw ex;
            }
        }
예제 #16
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                Log.Error("Start control not found.");
                return;
            }

            IScrollItemPattern pattern = c.GetControlInterface <IScrollItemPattern>();

            if (pattern != null && _scrollIntoView)
            {
                pattern.ScrollIntoView();
            }

            if (!c.Visible)
            {
                Log.Error("Start control not visible.");
                return;
            }

            Point point2 = _point2;

            if (!string.IsNullOrEmpty(_endControl))
            {
                UIControlBase endControl = UIControlBase.FindControlByPath(_endControl);

                if (!endControl.Exists)
                {
                    Log.Error("End control not found.");
                    return;
                }

                pattern = endControl.GetControlInterface <IScrollItemPattern>();

                if (pattern != null && _scrollIntoView)
                {
                    pattern.ScrollIntoView();
                }

                if (!endControl.Visible)
                {
                    Log.Error("End control not visible.");
                    return;
                }

                // Figure out end coordinate relative to begin coord
                Vector offset = endControl.Layout.TopLeft - c.Layout.TopLeft;
                point2 += offset;
            }

            LowLevelInput.PressKeys(_modifierKeys);
            c.Drag(button, point1, point2);
            LowLevelInput.ReleaseKeys(_modifierKeys);

            ActualResult = TestCaseResult.Passed;
        }
예제 #17
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;

            UIControlBase c = UIControlBase.FindControlByPath(control);

            if (!c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new InvalidOperationException("Control not found");
            }

            List <string> values = new List <string>();

            foreach (string item in _list)
            {
                switch (item)
                {
                case "Layout.X":
                    values.Add(c.Layout.X.ToString());
                    break;

                case "Layout.Y":
                    values.Add(c.Layout.Y.ToString());
                    break;

                case "Layout.Width":
                    values.Add(c.Layout.Width.ToString());
                    break;

                case "Layout.Height":
                    values.Add(c.Layout.Height.ToString());
                    break;

                case "Name":
                    values.Add(c.Name);
                    break;

                case "ClassName":
                    values.Add(c.ClassName);
                    break;

                case "ID":
                    values.Add(c.ID);
                    break;

                case "Enabled":
                    values.Add(c.Enabled.ToString());
                    break;

                case "Visible":
                    values.Add(c.Visible.ToString());
                    break;

                default:
                    values.Add("(unknown property)");
                    break;
                }
            }

            vals = string.Join(",", values);
        }
예제 #18
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
            _foundValue  = string.Empty;

            // Build the regex if we have one
            Regex regex = null;

            if (_useRegex)
            {
                regex = new Regex(_expectedValue, RegexOptions.Singleline | (_caseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase));
            }

            // Find the control
            UIControlBase c = UIControlBase.FindControlByPath(_control);

            if (c == null || !c.Exists)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                Log.Error("Control not found", "Could not find control " + _control);
                return;
            }

            // Find the property
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(c);
            PropertyDescriptor           prop       = properties.Find(_property, false);

            Log.Info("Properties found were...", "Properties found were: " +
                     string.Join(", ", properties.Cast <PropertyDescriptor>().Select(p => p.Name)));

            if (prop == null)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                Log.Warning(_property + " property not found",
                            "Could not find property " + _property + " on control " + _control);

                return;
            }

            // Read the value
            _foundValue = Convert.ToString(prop.GetValue(c), CultureInfo.CurrentCulture);

            Log.Info("Found value: \"" + _foundValue + "\"");

            // Verify it
            if (regex != null)
            {
                if (!regex.IsMatch(_foundValue))
                {
                    ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                    throw new ArgumentException("The property's value didn't match the regular expression.");
                }
            }
            else if (_caseSensitive && _foundValue != _expectedValue)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new ArgumentException("The property's value didn't match the specified text.");
            }
            else if (!_caseSensitive && StringComparer.CurrentCultureIgnoreCase.Compare(_foundValue, _expectedValue) != 0)
            {
                ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
                throw new ArgumentException("The property's value didn't match the specified text.");
            }

            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
        }
예제 #19
0
        public override void Body()
        {
            ActualResult = TestCaseResult.Failed;

            UIControlBase c = UIControlBase.FindControlByPath(_control);

            if (!c.Exists)
            {
                Log.Error("Control not found");
                return;
            }

            if (!c.Enabled)
            {
                Log.Error("Control not enabled");
                return;
            }

            ITogglePattern toggle = c.GetControlInterface <ITogglePattern>();
            IInvokePattern invoke = c.GetControlInterface <IInvokePattern>();

            HTMLInput input = c as HTMLInput;

            if (toggle != null)
            {
                switch (_action)
                {
                case ToggleAction.On:
                    for (int i = 0; i < 3; i++)
                    {
                        if (toggle.ToggleState != ToggleState.On)
                        {
                            toggle.Toggle();
                        }
                    }

                    if (toggle.ToggleState != ToggleState.On)
                    {
                        Log.Error("Tried three times, but couldn't set the checkbox to On.");
                        return;
                    }

                    break;

                case ToggleAction.Off:
                    for (int i = 0; i < 3; i++)
                    {
                        if (toggle.ToggleState != ToggleState.Off)
                        {
                            toggle.Toggle();
                        }
                    }

                    if (toggle.ToggleState != ToggleState.Off)
                    {
                        Log.Error("Tried three times, but couldn't set the checkbox to Off.");
                        return;
                    }

                    break;

                case ToggleAction.Toggle:
                    toggle.Toggle();
                    break;
                }

                ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
            }
            else if (invoke != null)
            {
                if (_action != ToggleAction.Toggle)
                {
                    Log.Error("The target control only supports invoke operations. Try toggle action instead.");
                    return;
                }

                switch (_action)
                {
                case ToggleAction.On:
                case ToggleAction.Off:
                    Log.Error("The target control only supports invoke operations. Try toggle action instead.");
                    return;

                case ToggleAction.Toggle:
                    invoke.Invoke();
                    break;
                }

                ActualResult = TestCaseResult.Passed;
            }
            else if (input != null)
            {
                switch (_action)
                {
                case ToggleAction.Toggle:
                    input.Click();
                    break;

                case ToggleAction.On:
                    if (!input.Checked)
                    {
                        input.Click();
                    }

                    break;

                case ToggleAction.Off:
                    if (input.Checked)
                    {
                        input.Click();
                    }

                    break;
                }

                ActualResult = TestCaseResult.Passed;
            }
            else
            {
                Log.Error("Couldn't find an appropriate way to toggle the control.");
                ActualResult = TestCaseResult.Failed;
            }
        }
예제 #20
0
        public override void Body()
        {
            ActualResult = QAliber.RemotingModel.TestCaseResult.Failed;
            _resultTable = null;

            // Get the variable we're testing against
            ScenarioVariable <DataTable> testTableVar = Scenario.Tables[_variable];

            if (testTableVar == null)
            {
                Log.Error("Could not find variable \"" + _variable + "\"");
                return;
            }

            // Filter the test table down to what the user wants us to find
            DataTable testTable = testTableVar.Value.Clone();

            if (_verifyRows.Length == 0)
            {
                // Grab all rows
                testTable.Merge(testTableVar.Value);
            }
            else
            {
                foreach (int rowIndex in _verifyRows)
                {
                    if (rowIndex >= testTableVar.Value.Rows.Count)
                    {
                        Log.Error("Verify Rows refers to an invalid row",
                                  "The Verify Rows property refers to a row that's not in the source table.");
                        return;
                    }

                    testTable.Rows.Add(testTableVar.Value.Rows[rowIndex].ItemArray);
                }
            }

            if (_verifyColumns.Length != 0)
            {
                HashSet <string> verifyColumns = new HashSet <string>(_verifyColumns);

                string[] verifyColumnsNotFound =
                    verifyColumns.Except(testTable.Columns.Cast <DataColumn>().Select(col => col.ColumnName)).ToArray();

                if (verifyColumnsNotFound.Length != 0)
                {
                    Log.Error("Verify Columns refers to an invalid column",
                              "The Verify Columns property refers to one or more invalid columns: " +
                              string.Join(", ", verifyColumnsNotFound));
                    return;
                }

                foreach (DataColumn column in testTable.Columns.Cast <DataColumn>().ToArray())
                {
                    if (!verifyColumns.Contains(column.ColumnName))
                    {
                        testTable.Columns.Remove(column);
                    }
                }
            }

            // Capture the grid
            UIControlBase c = UIControlBase.FindControlByPath(_control);

            if (c == null || !c.Exists)
            {
                Log.Error("Control not found", _control);
                return;
            }

            IGridPattern grid = c.GetControlInterface <IGridPattern>();

            if (grid == null)
            {
                Log.Error("Can't capture grid", "Couldn't find an appropriate way to get at grid data.");
                return;
            }

            string[]   headers;
            string[][] rows = grid.CaptureGrid(out headers);

            if (_requireHeaders && headers == null)
            {
                LogFailedByExpectedResult("No headers in target grid", "Target grid didn't have any headers, and Require Headers was set.");
                return;
            }

            bool columnsUnique = true;

            if (headers != null && headers.Distinct().Count() != headers.Length)
            {
                columnsUnique = false;
                Log.Warning("Duplicate column names", "Could not produce an output table because there are two columns with the same name.");
            }

            // Create the grid result table
            if (columnsUnique)
            {
                DataTable table = new DataTable("Captured grid");

                if (headers != null)
                {
                    headers = Array.ConvertAll(headers, header => XPath.EscapeLiteral(header));

                    foreach (string header in headers)
                    {
                        table.Columns.Add(header, typeof(string));
                    }
                }
                else
                {
                    int columnCount = grid.ColumnCount;

                    for (int i = 0; i < columnCount; i++)
                    {
                        table.Columns.Add("Column " + i.ToString(CultureInfo.CurrentUICulture), typeof(string));
                    }
                }

                rows = Array.ConvertAll(rows, row =>
                                        Array.ConvertAll(row, cell => XPath.EscapeLiteral(cell ?? string.Empty)));

                foreach (string[] row in rows)
                {
                    table.Rows.Add(row);
                }

                _resultTable = table;
            }

            // Go ahead and log the capture
            string rowText = string.Join("\r\n", rows.Select(row => "[" + string.Join(", ", row) + "]"));

            if (headers != null)
            {
                rowText = "[" + string.Join(", ", headers) + "]\r\n" + rowText;
            }

            Log.Info("Captured grid", rowText);

            // Shortcut out on some special cases
            if (rows.Length < testTable.Rows.Count)
            {
                LogFailedByExpectedResult("Not enough rows in target grid",
                                          string.Format("Target grid had {0} rows, expected at least {1}.", rows.Length, testTable.Rows.Count));
                return;
            }

            if (!_allowExtraRows && rows.Length > testTable.Rows.Count)
            {
                LogFailedByExpectedResult("Too many rows in target grid",
                                          string.Format("Target grid had {0} rows, expected {1}.", rows.Length, testTable.Rows.Count));
                return;
            }

            if (rows.Length != 0)
            {
                if (rows[0].Length < testTable.Columns.Count)
                {
                    LogFailedByExpectedResult("Not enough columns in target grid",
                                              string.Format("Target grid had {0} columns, expected at least {1}.", rows[0].Length, testTable.Columns.Count));
                    return;
                }

                if (!_allowExtraColumns && rows[0].Length > testTable.Columns.Count)
                {
                    LogFailedByExpectedResult("Too many columns in target grid",
                                              string.Format("Target grid had {0} columns, expected {1}.", rows[0].Length, testTable.Columns.Count));
                    return;
                }
            }

            // Filter out any columns we don't care about
            if (headers != null)
            {
                // Filter by column name
                List <string> testColumns = testTable.Columns.Cast <DataColumn>()
                                            .Select(col => col.ColumnName).ToList();

                int[] keptColumns = new int[testColumns.Count];

                for (int index = 0; index < headers.Length; index++)
                {
                    int foundIndex = testColumns.IndexOf(headers[index]);

                    if (foundIndex != -1)
                    {
                        testColumns[foundIndex] = null;
                        keptColumns[foundIndex] = index;
                    }
                    else if (!_allowExtraColumns)
                    {
                        LogFailedByExpectedResult("Found extra column \"" + headers[index] + "\" in grid", string.Empty);
                        return;
                    }
                }

                // keptColumns as created will reorder the columns into the expected order;
                // if the user wants us to verify the column order as well, we have to re-sort
                // into the original order as found in the target grid
                if (_verifyColumnOrder)
                {
                    Array.Sort <int>(keptColumns);
                }

                headers = keptColumns.Select(i => headers[i]).ToArray();
                rows    = rows.Select(row => keptColumns.Select(i => row[i]).ToArray()).ToArray();
            }

            // Finally, verify rows
            if (_verifyRowOrder)
            {
                List <HashedRow> extraRows  = new List <HashedRow>();
                HashedRow[]      targetRows = rows.Select(row => new HashedRow(row)).ToArray();
                var testRows = testTable.Rows.Cast <DataRow>()
                               .Select(row => new HashedRow(row.ItemArray.Cast <string>().ToArray()));
                int targetRowIndex = 0;

                foreach (var testRow in testRows)
                {
                    // We must find this row in the target to proceed
                    bool matched          = false;
                    int  expectedPosition = targetRowIndex;

                    while (targetRowIndex < targetRows.Length)
                    {
                        if (targetRows[targetRowIndex].Equals(testRow))
                        {
                            // Row found, stop here
                            targetRowIndex++;
                            matched = true;
                            break;
                        }

                        // Target row which does not match
                        extraRows.Add(targetRows[targetRowIndex]);
                        targetRowIndex++;
                    }

                    if (matched)
                    {
                        continue;
                    }

                    // Made it to the end of the target rows without finding it
                    if (extraRows.Contains(testRow))
                    {
                        LogFailedByExpectedResult("Row in wrong place", "This row was in the wrong position while \"Verify Row Order\" was on: [" +
                                                  string.Join(", ", testRow) + "]\r\n\r\nIt was expected at or after row " + (expectedPosition + 1).ToString() + ".");
                    }
                    else
                    {
                        LogFailedByExpectedResult("Expected row missing", "Could not find this row in the target grid: [" +
                                                  string.Join(", ", testRow) + "]\r\n\r\nIt was expected at or after row " + (expectedPosition + 1).ToString() + ".");

                        if (extraRows.Count != 0 && !_allowExtraRows)
                        {
                            LogFailedByExpectedResult("Found extra row(s)", "Found these rows in the target grid while \"Allow Extra Rows\" was off:\r\n\r\n" +
                                                      string.Join("\r\n",
                                                                  extraRows.Select(row => "[" + string.Join(", ", row) + "]")));
                        }
                    }

                    return;
                }

                if (extraRows.Count != 0 && !_allowExtraRows)
                {
                    LogFailedByExpectedResult("Found extra row(s)", "Found these rows in the target grid while \"Allow Extra Rows\" was off:\r\n\r\n" +
                                              string.Join("\r\n",
                                                          extraRows.Select(row => "[" + string.Join(", ", row) + "]")));
                    return;
                }
            }
            else
            {
                // Unordered find; make sure there are the right number of each kind of row
                List <HashedRow> missingRows = new List <HashedRow>();
                List <HashedRow> targetRows  = rows.Select(row => new HashedRow(row)).ToList();
                var testRows = testTable.Rows.Cast <DataRow>()
                               .Select(row => new HashedRow(row.ItemArray.Cast <string>().ToArray()));

                foreach (var testRow in testRows)
                {
                    int index = targetRows.IndexOf(testRow);

                    if (index == -1)
                    {
                        missingRows.Add(testRow);
                    }
                    else
                    {
                        targetRows.RemoveAt(index);
                    }
                }

                if (missingRows.Count != 0)
                {
                    LogFailedByExpectedResult("Expected row(s) missing", "These rows were expected but not found in the target grid:\r\n\r\n" +
                                              string.Join("\r\n",
                                                          missingRows.Select(row => "[" + string.Join(", ", row) + "]")));
                    return;
                }

                // Make sure there are none left if we aren't supposed to allow extra rows
                if (!_allowExtraRows && targetRows.Count != 0)
                {
                    LogFailedByExpectedResult("Found extra row(s)", "Found these rows in the target grid while \"Allow Extra Rows\" was off:\r\n\r\n" +
                                              string.Join("\r\n",
                                                          targetRows.Select(row => "[" + string.Join(", ", row) + "]")));
                    return;
                }
            }

            ActualResult = QAliber.RemotingModel.TestCaseResult.Passed;
        }