/// <summary>
        /// Parse the RopFindRow structure.
        /// </summary>
        /// <param name="s">An stream containing RopFindRow structure.</param>
        public override void Parse(Stream s)
        {
            base.Parse(s);

            this.RopId = (RopIdType)ReadByte();
            this.LogonId = ReadByte();
            this.InputHandleIndex = ReadByte();
            this.FindRowFlags = (FindRowFlags)ReadByte();
            this.RestrictionDataSize = ReadUshort();
            if (RestrictionDataSize > 0)
            {
                RestrictionType tempRestriction = new RestrictionType();
                this.RestrictionData = tempRestriction;
                this.RestrictionData.Parse(s);
            }
            this.Origin = (Bookmarks)ReadByte();
            this.BookmarkSize = ReadUshort();
            this.Bookmark = ReadBytes(BookmarkSize);
        }
        public static void RopFindRowResponse(FindRowFlags findRowFlags, bool isValidRestriction, bool hasRowData, bool isCorrectRowData, bool rowNoLongerVisible, bool isLastSetColumnData)
        {
            if (requirementContainer[608])
            {
                if (globleTableType == TableType.HIERARCHY_TABLE)
                {
                    Condition.IsTrue(!rowNoLongerVisible);
                    ModelHelper.CaptureRequirement(608, @"[In Appendix A: Product Behavior] Implementation does always set this value [RowNoLongerVisible] to ""FALSE"" (0x00) for hierarchy tables in RopFindRow. (<15> Section 2.2.2.14.2: Exchange 2007 and Exchange 2010 always set this value [RowNoLongerVisible] to ""FALSE"" (0x00) for hierarchy tables in RopFindRow.)");
                }
            }

            // RopFindRow sets the cursor position to the first row that matches the criteria specified in the ROP (starting the search from the current cursor position) and returns the found row
            if (isValidRestriction && hasRowData)
            {
                Condition.IsTrue(isCorrectRowData);
                ModelHelper.CaptureRequirement(534, @"[In Processing RopFindRow]The RopFindRow ROP ([MS-OXCROPS] section 2.2.5.13) sets the cursor position to the first row that matches the search criteria specified in the ROP (starting the search from the current cursor position) and returns the found row when there is enough space in the output buffer.");
                ModelHelper.CaptureRequirement(243, @"[In RopFindRow ROP Response Buffer] If a row that meets the specified search criteria was found and the row data is included in the response, this field [HasRowData] MUST be set to ""TRUE"" (0x01).");
            }

            // The columns sent for the row found MUST be the columns that are specified on RopSetColumns
            if (setColumnsFlags.ContainsValue(true))
            {
                if (!resetTableDone)
                {
                    Condition.IsTrue(isLastSetColumnData);
                    ModelHelper.CaptureRequirement(540, @"[In Processing RopFindRow] The columns sent for the row found MUST be the columns that are specified on the RopSetColumns ROP.");
                    ModelHelper.CaptureRequirement(539, @"[In Processing RopFindRow]A RopSetColumns ROP request ([MS-OXCROPS] section 2.2.5.1) MUST be sent on the table before sending a RopFindRow ROP request.");
                    ModelHelper.CaptureRequirement(813, @"[In RopSetColumns ROP Request Buffer] PropertyTags (variable): An array of PropertyTag structures, as described in [MS-OXCDATA] section 2.9, that identify the set and order of property values to be returned by the server in the ROP response buffer of the RopFindRow ([MS-OXCROPS] section 2.2.5.13)ROP, as specified in section 2.2.2.14.");
                    ModelHelper.CaptureRequirement(824, @"[In Processing RopSetColumns] The columns that are set by the RopSetColumns ROP MUST be the ones sent in the responses to subsequent RopFindRow ([MS-OXCROPS] section 2.2.5.13) ROP executed on that table.");
                }
            }

            if (findRowFlags == FindRowFlags.Forwards)
            {
                // If the value of FindRowFlags is set to 0x00 in the request and the correct row can be found, this requirement can be verified.
                Condition.IsTrue(isCorrectRowData);
                ModelHelper.CaptureRequirement(225, @"[In RopFindRow ROP Request Buffer] The value of FindRowFlags is 0x00 means perform the find forwards.");
            }
            else if (findRowFlags == FindRowFlags.Backwards)
            {
                // If the value of findRowFlags is set to 0x01 in the request and the correct row can be found, this requirement can be verified.
                Condition.IsTrue(isCorrectRowData);
                ModelHelper.CaptureRequirement(226, @"[In RopFindRow ROP Request Buffer] The value of FindRowFlags is 0x01 means perform the find backwards.");
            }

            if (validBookmark)
            {
                Condition.IsTrue(!rowNoLongerVisible);
                ModelHelper.CaptureRequirement(239, @"[In RopFindRow ROP Response Buffer] Otherwise [if the row to which the bookmark pointed, has not been removed from the table.], this field [RowNoLongerVisible] MUST be set to ""FALSE"" (0x00).");
            }
        }
        public static TableRopReturnValues RopFindRow(FindRowFlags findRowFlags, BookmarkType origin, bool isValidRestriction)
        {
            // This ROP is valid only on contents table, rules table and hierarchy table.
            if (globleTableType == TableType.ATTACHMENTS_TABLE || globleTableType == TableType.PERMISSIONS_TABLE)
            {
                ModelHelper.CaptureRequirement(544, @"[In Processing RopFindRow] The error code ecNotSupported will be returned with value 0x80040102,%x02.01.04.80, if the object on which this ROP was sent is not a contents table, hierarchy table, or rules table.");
                return TableRopReturnValues.ecNotSupported;
            }
            else if (globleTableType == TableType.CONTENT_TABLE)
            {
                // The RopFindRow ROP MUST be supported on contents tables.
                ModelHelper.CaptureRequirement(859, @"[In Processing RopFindRow] The RopFindRow ROP MUST be supported on contents tables.");
            }
            else if (globleTableType == TableType.HIERARCHY_TABLE)
            {
                // The RopFindRow ROP MUST be supported on hierarchy tables.
                ModelHelper.CaptureRequirement(858, @"[In Processing RopFindRow] The RopFindRow ROP MUST be supported on hierarchy tables.");
            }
            else if (globleTableType == TableType.RULES_TABLE)
            {
                // The RopFindRow ROP MUST be supported on rules tables.
                ModelHelper.CaptureRequirement(874, @"[In Processing RopFindRow] The RopFindRow ROP MUST be supported on rules tables.");
            }
            else
            {
                // If the table type is invalid, ecNotSupported will be returned, in this test suite, invalid table
                // is referred as a folderId, for details, see the table initial method in adapter project
                ModelHelper.CaptureRequirement(682, @"[In RopFindRow ROP] This ROP is valid only on Table objects.");
                return TableRopReturnValues.ecNotSupported;
            }

            // Before a success SetColumnsRop, FindRowRop will fail in Exchange2010 and above
            if (!setColumnsFlags.ContainsValue(true))
            {
                if (requirementContainer[827])
                {
                    ModelHelper.CaptureRequirement(827, @"[In Appendix A: Product Behavior] If a RopFindRow ROP is sent before a successful RopSetColumns ROP, then the implementation fails the ROP with ""ecNullObject"". (Microsoft Exchange Server 2010 and above follow this behavior.)");
                    return TableRopReturnValues.ecNullObject;
                }
                else
                {
                    return TableRopReturnValues.unexpected;
                }
            }

            if (!validBookmark && bookmarkCreated)
            {
                // After resetTable Rop, attempts to use the bookmark will fail with ecInvalidBookmark except Exchange 2007.
                if (resetTableDone)
                {
                    Condition.IsTrue((requirementContainer[902] && !requirementContainer[903]) || (!requirementContainer[902] && requirementContainer[903]));
                    if (requirementContainer[902])
                    {
                        ModelHelper.CaptureRequirement(902, @"[In Appendix A: Product Behavior] Implementation does set the ReturnValue field to ""ecInvalidBookmark"" [for RopFindRow], if the client requested that the find be performed from a custom bookmark, as specified in section 2.2.2.1.2, but the bookmark has become invalid because of a RopResetTable ([MS-OXCROPS] section 2.2.5.15) ROP request. (Exchange Server 2010 and above follow this behavior.)");
                        return TableRopReturnValues.ecInvalidBookmark;
                    }

                    if (requirementContainer[903])
                    {
                        ModelHelper.CaptureRequirement(903, @"[In Appendix A: Product Behavior] Implementation returns ecSuccess [for RopFindRow], if the client requested that the find be performed from a custom bookmark, as specified in section 2.2.2.1.2, but the bookmark has become invalid because of a RopResetTable ([MS-OXCROPS] section 2.2.5.15) ROP request. (<33> Section 3.2.5.14: Exchange 2007 returns ecSuccess.)");
                    }
                }

                // After sortTable Rop, attempts to use the bookmark will fail with ecInvalidBookmark except Exchange 2007.
                if (sortTableFlags.ContainsValue(true))
                {
                    Condition.IsTrue((requirementContainer[898] && !requirementContainer[899]) || (!requirementContainer[898] && requirementContainer[899]));
                    if (requirementContainer[898])
                    {
                        ModelHelper.CaptureRequirement(898, @"[In Appendix A: Product Behavior] Implementation does set the ReturnValue field to ""ecInvalidBookmark"" [for RopFindRow], if the client requested that the find be performed from a custom bookmark, as specified in section 2.2.2.1.2, but the bookmark has become invalid because of a RopSortTable ([MS-OXCROPS] section 2.2.5.2) ROP request. (Exchange Server 2010 and above follow this behavior.)");
                        return TableRopReturnValues.ecInvalidBookmark;
                    }

                    if (requirementContainer[899])
                    {
                        ModelHelper.CaptureRequirement(899, @"[In Appendix A: Product Behavior] Implementation returns ecSuccess [for RopFindRow], if the client requested that the find be performed from a custom bookmark, as specified in section 2.2.2.1.2, but the bookmark has become invalid because of a RopSortTable ([MS-OXCROPS] section 2.2.5.2) ROP request. (<33> Section 3.2.5.14: Exchange 2007 returns ecSuccess.)");
                    }
                }

                // After restrict Table Rop, attempts to use the bookmark will fail with ecInvalidBookmark in Exchange 2010 and above.
                if (restrictFlags.ContainsValue(true))
                {
                    if (requirementContainer[900])
                    {
                        ModelHelper.CaptureRequirement(900, @"[In Appendix A: Product Behavior] Implementation does set the ReturnValue field to ""ecInvalidBookmark"" [for RopFindRow], if the client requested that the find be performed from a custom bookmark, as specified in section 2.2.2.1.2, but the bookmark has become invalid because of a RopRestrict ([MS-OXCROPS] section 2.2.5.3) ROP request. (Exchange Server 2010 and above follow this behavior.)");
                        return TableRopReturnValues.ecInvalidBookmark;
                    }
                }
            }

            return TableRopReturnValues.success;
        }
        /// <summary>
        /// This method is used to find row for a table
        /// </summary>
        /// <param name="findRowFlags">Identify the flags for this operation</param>
        /// <param name="origin">Identify the bookmark</param>
        /// <param name="isValidRestriction">Identify whether the restriction is valid</param>
        /// <returns>Table ROP return value</returns>
        public TableRopReturnValues RopFindRow(FindRowFlags findRowFlags, BookmarkType origin, bool isValidRestriction)
        {
            RopFindRowRequest findRowRequest;
            RopFindRowResponse findRowResponse;

            findRowRequest.RopId = 0x4F;
            findRowRequest.LogonId = 0x00;
            findRowRequest.InputHandleIndex = 0x00;
            findRowRequest.FindRowFlags = (byte)findRowFlags;
            byte[] data;
            if (isValidRestriction)
            {
                data = AdapterHelper.GenerateValidRestrictData(this.Site, this.tableType);
            }
            else
            {
                data = new byte[] { 0x03, 0x02, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x1a, 0x0c, 0x1f, 0x00, 0x1a, 0x0c, 0x24 }; // SenderName is $, which is not exist.
            }

            findRowRequest.RestrictionDataSize = (ushort)data.Length;
            findRowRequest.RestrictionData = data;
            findRowRequest.Origin = (byte)origin;
            if (origin == BookmarkType.BOOKMARK_CUSTOM)
            {
                findRowRequest.Bookmark = this.userDefinedBookmark; // Returned by a previous RopCreateBookmark request.
                findRowRequest.BookmarkSize = this.userDefinedBookmarkSize;
            }
            else
            {
                findRowRequest.Bookmark = null;
                findRowRequest.BookmarkSize = 0x0;
            }

            if (Common.IsRequirementEnabled(827, this.Site))
            {
                this.DoSingleCallROP(findRowRequest, this.tableHandle, ref this.response, ref this.rawData);
            }
            else
            {
                try
                {
                    this.DoSingleCallROP(findRowRequest, this.tableHandle, ref this.response, ref this.rawData);
                }
                catch (Exception ex)
                {
                    Site.Log.Add(LogEntryKind.Comment, ex.Message);
                    Site.Log.Add(LogEntryKind.Comment, "The behavior when a RopFindRow ROP is sent before a successful RopSetColumns ROP is undefined for implementation following Exchange 2007.");
                    return TableRopReturnValues.unexpected;
                }
            }

            findRowResponse = (RopFindRowResponse)this.response;
            bool rowNoLongerVisible = findRowResponse.RowNoLongerVisible == 0x01 ? true : false;

            bool hasRowData = Convert.ToBoolean(findRowResponse.HasRowData);

            bool isCorrectRowData = true;
            bool isLastSetColumnData = true;
            if ((TableRopReturnValues)findRowResponse.ReturnValue == TableRopReturnValues.success)
            {
                if (hasRowData)
                {
                    if (this.tableType == TableType.CONTENT_TABLE)
                    {
                        // Gets the SenderName.
                        string strSenderName = Encoding.Unicode.GetString(findRowResponse.RowData.PropertyValues[2].Value);

                        // TRUE:the senderName is Test1.
                        isCorrectRowData = this.IsExpectedSender(strSenderName, Common.GetConfigurationPropertyValue("Sender1Name", this.Site));
                    }
                    else if (this.tableType == TableType.HIERARCHY_TABLE)
                    {
                        // Gets the DisplayName.
                        string strDisplayName = Encoding.Unicode.GetString(findRowResponse.RowData.PropertyValues[5].Value);

                        // TRUE:the displayName is Test1.
                        isCorrectRowData = strDisplayName == (Constants.TestGetHierarchyTableFolderName1 + '\0');
                    }
                    else if (this.tableType == TableType.RULES_TABLE)
                    {
                        // Gets the RuleName property.
                        string strRuleName = Encoding.Unicode.GetString(findRowResponse.RowData.PropertyValues[1].Value);

                        // TRUE:the RuleName is MarkAsRead.
                        isCorrectRowData = strRuleName == (Constants.RuleNameMarkAsRead + '\0');
                    }

                    isLastSetColumnData = this.latestPropertyTags.Length == findRowResponse.RowData.PropertyValues.Count;
                }
            }

            if (this.RopFindRowResponse != null)
            {
                this.RopFindRowResponse(findRowFlags, isValidRestriction, hasRowData, isCorrectRowData, rowNoLongerVisible, isLastSetColumnData);
            }

            return (TableRopReturnValues)findRowResponse.ReturnValue;
        }