public void MSASCMD_S19_TC51_Sync_Change_Exceptions()
        {
            Site.Assume.AreNotEqual<string>("12.1", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The Class element is not supported in a Sync command response when the MS-ASProtocolVersion header is set to 12.1. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "Recurrences cannot be added in protocol version 16.0");

            this.Sync(TestSuiteBase.CreateEmptySyncRequest(this.User1Information.CalendarCollectionId));

            #region Call Sync Add operation to add a new recurrence calendar.
            string recurrenceCalendarSubject = Common.GenerateResourceName(Site, "calendarSubject");
            string location = Common.GenerateResourceName(Site, "Room");
            DateTime currentDate = DateTime.Now.AddDays(1);
            DateTime startTime = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, 10, 0, 0);
            DateTime endTime = startTime.AddHours(10);

            Request.ExceptionsException exception = new Request.ExceptionsException();
            exception.ExceptionStartTime = startTime.AddDays(2).ToString("yyyyMMddTHHmmssZ");
            Request.Exceptions exceptions = new Request.Exceptions() { Exception = new Request.ExceptionsException[] { exception } };

            Request.Recurrence recurrence = new Request.Recurrence
            {
                Type = 0
            };

            Request.SyncCollectionAdd recurrenceCalendarData = new Request.SyncCollectionAdd
            {
                ClientId = TestSuiteBase.ClientId,
                ApplicationData =
                    new Request.SyncCollectionAddApplicationData
                    {
                        ItemsElementName =
                            new Request.ItemsChoiceType8[] 
                            { 
                                Request.ItemsChoiceType8.Subject, Request.ItemsChoiceType8.Location,
                                Request.ItemsChoiceType8.StartTime, Request.ItemsChoiceType8.EndTime,
                                Request.ItemsChoiceType8.Recurrence, Request.ItemsChoiceType8.Exceptions,
                                Request.ItemsChoiceType8.UID
                            },
                        Items =
                        new object[] 
                        { 
                            recurrenceCalendarSubject, location, 
                            startTime.ToString("yyyyMMddTHHmmssZ"),
                            endTime.ToString("yyyyMMddTHHmmssZ"),
                            recurrence, exceptions, Guid.NewGuid().ToString()
                        }
                    },
                Class = "Calendar"
            };

            SyncRequest syncRequest = TestSuiteBase.CreateSyncAddRequest(this.LastSyncKey, this.User1Information.CalendarCollectionId, recurrenceCalendarData);
            SyncResponse syncResponse = this.Sync(syncRequest);
            Site.Assert.IsNotNull(syncResponse.ResponseData.Item, "The items returned in the Sync command response should not be null.");
            Response.SyncCollectionsCollectionResponses responses = TestSuiteBase.GetCollectionItem(syncResponse, Response.ItemsChoiceType10.Responses) as Response.SyncCollectionsCollectionResponses;
            Site.Assert.AreEqual<int>(1, int.Parse(responses.Add[0].Status), "The calendar should be added successfully.");
            TestSuiteBase.RecordCaseRelativeItems(this.User1Information, this.User1Information.CalendarCollectionId, recurrenceCalendarSubject);

            syncResponse = this.SyncChanges(this.User1Information.CalendarCollectionId);
            string serverId = TestSuiteBase.FindServerId(syncResponse, "Subject", recurrenceCalendarSubject);
            Site.Assert.IsNotNull(serverId, "The recurrence calendar should be found.");
            #endregion

            #region Change the subject of the added recurrence calendar.
            string updatedCalendarSubject = Common.GenerateResourceName(Site, "updatedCalendarSubject");

            Request.SyncCollectionChangeApplicationData changeCalednarData = new Request.SyncCollectionChangeApplicationData();
            changeCalednarData.ItemsElementName = new Request.ItemsChoiceType7[] { Request.ItemsChoiceType7.Subject, Request.ItemsChoiceType7.Recurrence };
            changeCalednarData.Items = new object[] { updatedCalendarSubject, recurrence };

            Request.SyncCollectionChange appDataChange = new Request.SyncCollectionChange
            {
                ApplicationData = changeCalednarData,
                ServerId = serverId
            };

            syncRequest = CreateSyncChangeRequest(this.LastSyncKey, this.User1Information.CalendarCollectionId, appDataChange);
            syncResponse = this.Sync(syncRequest);
            Site.Assert.AreEqual<uint>(1, Convert.ToUInt32(TestSuiteBase.GetCollectionItem(syncResponse, Response.ItemsChoiceType10.Status)), "The FileAs of the contact should be updated successfully.");
            TestSuiteBase.RemoveRecordCaseRelativeItems(this.User1Information, this.User1Information.CalendarCollectionId, recurrenceCalendarSubject);
            TestSuiteBase.RecordCaseRelativeItems(this.User1Information, this.User1Information.CalendarCollectionId, updatedCalendarSubject);

            syncResponse = this.SyncChanges(this.User1Information.CalendarCollectionId);
            serverId = TestSuiteBase.FindServerId(syncResponse, "Subject", updatedCalendarSubject);
            Site.Assert.IsNotNull(serverId, "The recurrence calendar should be found.");

            Response.SyncCollectionsCollectionCommands commands = TestSuiteBase.GetCollectionItem(syncResponse, Response.ItemsChoiceType10.Commands) as Response.SyncCollectionsCollectionCommands;
            Site.Assert.IsNotNull(commands.Add, "The Add element should not be null.");

            foreach (Response.SyncCollectionsCollectionCommandsAdd item in commands.Add)
            {
                if (item.ServerId == serverId)
                {
                    for (int i = 0; i < item.ApplicationData.ItemsElementName.Length; i++)
                    {
                        if (item.ApplicationData.ItemsElementName[i] == Response.ItemsChoiceType8.Exceptions)
                        {
                            Response.Exceptions currentExceptions = item.ApplicationData.Items[i] as Response.Exceptions;
                            Site.Assert.IsNotNull(currentExceptions, "The Exceptions element should exist.");

                            Response.ExceptionsException currentException = currentExceptions.Exception[0];

                            // Add the debug information
                            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCMD_R877");

                            // Verify MS-ASCMD requirement: MS-ASCMD_R877
                            Site.CaptureRequirementIfAreEqual<string>(
                                exception.ExceptionStartTime.ToString(),
                                currentException.ExceptionStartTime.ToString(),
                                877,
                                @"[In Change] If a calendar:Exception ([MS-ASCAL] section 2.2.2.19) node within the calendar:Exceptions node is not present, that particular exception will remain unchanged.");

                            break;
                        }
                    }

                    break;
                }
            }
            #endregion

            #region Change the subject of the added recurrence calendar again.
            string allNewCalendarSubject = Common.GenerateResourceName(Site, "updatedCalendarSubject");

            changeCalednarData.ItemsElementName = new Request.ItemsChoiceType7[] { Request.ItemsChoiceType7.Subject, Request.ItemsChoiceType7.Recurrence, Request.ItemsChoiceType7.Exceptions, Request.ItemsChoiceType7.UID };
            changeCalednarData.Items = new object[] { allNewCalendarSubject, recurrence, null, Guid.NewGuid().ToString() };

            appDataChange = new Request.SyncCollectionChange
            {
                ApplicationData = changeCalednarData,
                ServerId = serverId
            };

            syncRequest = CreateSyncChangeRequest(this.LastSyncKey, this.User1Information.CalendarCollectionId, appDataChange);
            syncResponse = this.Sync(syncRequest);
            Site.Assert.AreEqual<uint>(1, Convert.ToUInt32(TestSuiteBase.GetCollectionItem(syncResponse, Response.ItemsChoiceType10.Status)), "The FileAs of the contact should be updated successfully.");
            TestSuiteBase.RemoveRecordCaseRelativeItems(this.User1Information, this.User1Information.CalendarCollectionId, updatedCalendarSubject);
            TestSuiteBase.RecordCaseRelativeItems(this.User1Information, this.User1Information.CalendarCollectionId, allNewCalendarSubject);

            syncResponse = this.SyncChanges(this.User1Information.CalendarCollectionId);
            serverId = TestSuiteBase.FindServerId(syncResponse, "Subject", allNewCalendarSubject);
            Site.Assert.IsNotNull(serverId, "The recurrence calendar should be found.");

            commands = TestSuiteBase.GetCollectionItem(syncResponse, Response.ItemsChoiceType10.Commands) as Response.SyncCollectionsCollectionCommands;
            Site.Assert.IsNotNull(commands.Add, "The Add element should not be null.");

            foreach (Response.SyncCollectionsCollectionCommandsAdd item in commands.Add)
            {
                if (item.ServerId == serverId)
                {
                    for (int i = 0; i < item.ApplicationData.ItemsElementName.Length; i++)
                    {
                        if (item.ApplicationData.ItemsElementName[i] == Response.ItemsChoiceType8.Exceptions)
                        {
                            Response.Exceptions currentExceptions = item.ApplicationData.Items[i] as Response.Exceptions;
                            Site.Assert.IsNotNull(currentExceptions, "The Exceptions element should exist.");

                            Response.ExceptionsException currentException = currentExceptions.Exception[0];

                            // Add the debug information
                            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCMD_R876");

                            // Verify MS-ASCMD requirement: MS-ASCMD_R876
                            Site.CaptureRequirementIfAreEqual<string>(
                                exception.ExceptionStartTime.ToString(),
                                currentException.ExceptionStartTime.ToString(),
                                876,
                                @"[In Change] [Certain in-schema properties remain untouched in the following three cases:] If a calendar:Exceptions ([MS-ASCAL] section 2.2.2.20) node is not specified, the properties for that calendar:Exceptions node will remain unchanged.");

                            break;
                        }
                    }

                    break;
                }
            }
            #endregion
        }
        public void MSASCAL_S02_TC06_ExceptionElements()
        {
            #region Organizer calls Sync command to add a calendar to the server, and sync calendars from the server.

            Site.Assume.AreNotEqual<string>("12.1", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The InstanceId element is not supported when the MS-ASProtocolVersion header is set to 12.1. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");
            Site.Assume.AreNotEqual<string>("14.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The InstanceId element is not supported when the MS-ASProtocolVersion header is set to 14.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The recurring calendar item cannot be created when protocol version is set to 16.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();

            DateTime exceptionStartTime = this.StartTime.AddDays(2);
            DateTime startTimeInException = exceptionStartTime.AddMinutes(15);
            DateTime endTimeInException = startTimeInException.AddHours(2);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Calendar BusyStatus element
            calendarItem.Add(Request.ItemsChoiceType8.BusyStatus, (byte)1);

            // Set Calendar Attendees element with required sub-element
            calendarItem.Add(Request.ItemsChoiceType8.Attendees, TestSuiteHelper.CreateAttendeesRequired(new string[] { Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain) }, new string[] { this.User2Information.UserName }));

            // Set Calendar Recurrence element including Occurrence sub-element
            byte recurrenceType = byte.Parse("0");
            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, this.CreateCalendarRecurrence(recurrenceType, 6, 1));

            // Set Calendar Exceptions element
            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            // Set ExceptionStartTime element in exception
            Request.ExceptionsException exception1 = TestSuiteHelper.CreateExceptionRequired(exceptionStartTime.ToString("yyyyMMddTHHmmssZ"));

            exception1.StartTime = startTimeInException.ToString("yyyyMMddTHHmmssZ");
            exception1.EndTime = endTimeInException.ToString("yyyyMMddTHHmmssZ");
            exception1.Attendees = TestSuiteHelper.CreateAttendeesRequired(new string[] { Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain), "*****@*****.**" }, new string[] { this.User2Information.UserName, "test" }).Attendee;

            exception1.Subject = "Calendar Exception";
            exception1.Body = TestSuiteHelper.CreateCalendarBody(2, this.Content + "InException");
            exception1.BusyStatusSpecified = true;
            exception1.BusyStatus = 2;
            exception1.Location = "Room 666";
            exception1.Reminder = "10";
            exceptionList.Add(exception1);
            exceptions.Exception = exceptionList.ToArray();
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);

            string subject = Common.GenerateResourceName(Site, "subject");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subject);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendar.Calendar, "The calendar with subject {0} should exist in server.", subject);

            this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subject);

            #endregion

            #region Organizer sends the meeting request to attendee.

            this.SendMimeMeeting(calendar.Calendar, subject, Common.GetMailAddress(this.User1Information.UserName, this.User1Information.UserDomain), Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain), "REQUEST", null);

            // Sync command to do an initialization Sync, and get the organizer calendars changes after the meeting request sent
            SyncItem calendarOnOrganizer = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendarOnOrganizer.Calendar, "The calendar with subject {0} should exist in server.", subject);

            #endregion

            if (!this.IsActiveSyncProtocolVersion121)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R10611");

                // Verify MS-ASCAL requirement: MS-ASCAL_R10611
                Site.CaptureRequirementIfIsTrue(
                    calendarOnOrganizer.Calendar.Exceptions.Exception[0].Attendees != null,
                    10611,
                    @"[In Attendees] The Attendees element specifies the collection of attendees for the calendar item exception.<2>");
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R39211");

            // Verify MS-ASCAL requirement: MS-ASCAL_R39211
            Site.CaptureRequirementIfIsTrue(
                string.IsNullOrEmpty(calendarOnOrganizer.Calendar.Exceptions.Exception[0].Reminder) == false,
                39211,
                @"[In Reminder] The Reminder element specifies the number of minutes before a calendar item exception's start time to display a reminder notice.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R12611");

            // Verify MS-ASCAL requirement: MS-ASCAL_R12611
            // If Exception.Body is not null, it means the server returns the body text of the calendar item exception
            Site.CaptureRequirementIfIsNotNull(
                calendarOnOrganizer.Calendar.Exceptions.Exception[0].Body,
                12611,
                @"[In Body (AirSyncBase Namespace)] The airsyncbase:Body element specifies the body text of the calendar item exception.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R13411");
        
            // Verify MS-ASCAL requirement: MS-ASCAL_R13411
            this.Site.CaptureRequirementIfAreEqual<byte?>(
                calendar.Calendar.BusyStatus,
                calendarOnOrganizer.Calendar.BusyStatus,
                13411,
                @"[In BusyStatus] A command response has a maximum of one BusyStatus child element per Exception element.");

            #region Switch to attendee to accept the meeting request, and sync calendars from the server.

            // Switch to attendee
            this.SwitchUser(this.User2Information, true);

            // Call Sync command to do an initialization Sync, and get the attendee inbox changes
            SyncItem emailItem = GetChangeItem(this.User2Information.InboxCollectionId, subject);
            Site.Assert.AreEqual<string>(
                subject,
                emailItem.Email.Subject,
                "The attendee should have received the meeting request.");

            this.RecordCaseRelativeItems(this.User2Information.UserName, this.User2Information.InboxCollectionId, subject);

            // Call Sync command to do an initialization Sync, and get the attendee calendars changes before accepting the meeting
            SyncItem calendarOnAttendee = this.GetChangeItem(this.User2Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendarOnAttendee.Calendar, "The calendar with subject {0} should exist in server.", subject);

            this.RecordCaseRelativeItems(this.User2Information.UserName, this.User2Information.CalendarCollectionId, subject);

            // Respond the meeting request
            #region Accept the fourth occurrence

            this.MeetingResponse(byte.Parse("1"), this.User2Information.CalendarCollectionId, calendarOnAttendee.ServerId, startTimeInException.ToString("yyyy-MM-ddThh:mm:ss.000Z"));

            // Call Sync command to do an initialization Sync, and get the attendee calendars changes after accepting the meeting
            calendarOnAttendee = this.GetChangeItem(this.User2Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendarOnAttendee.Calendar, "The calendar with subject {0} should exist in server.", subject);

            if (!this.IsActiveSyncProtocolVersion121)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R89011");

                // Verify MS-ASCAL requirement: MS-ASCAL_R89011
                // If Exception.AppointmentReplyTime is not null, it means the server returns the date and time that the user responded to the meeting request exception
                Site.CaptureRequirementIfIsNotNull(
                    calendarOnAttendee.Calendar.Exceptions.Exception[0].AppointmentReplyTime,
                    89011,
                    @"[In AppointmentReplyTime] The AppointmentReplyTime element specifies the date and time that the user responded to the meeting request exception.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R40211");

                // Verify MS-ASCAL requirement: MS-ASCAL_R40211
                Site.CaptureRequirementIfIsTrue(
                    calendarOnAttendee.Calendar.Exceptions.Exception[0].ResponseTypeSpecified,
                    40211,
                    @"[In ResponseType] The ResponseType<18> element specifies the type of response made by the user to a recurring meeting exception.");
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R23611");

            // Verify MS-ASCAL requirement: MS-ASCAL_R23611
            // If Exception.EndTime is not null, it means the server returns the end time of the calendar item exception
            Site.CaptureRequirementIfIsNotNull(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].EndTime,
                23611,
                @"[In EndTime] The EndTime element specifies the end time of the calendar item exception.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R29611");

            // Verify MS-ASCAL requirement: MS-ASCAL_R29611
            // If Exception.Location is not null, it means the server returns the place where the event specified by the calendar item exception occurs
            Site.CaptureRequirementIfIsNotNull(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].Location,
                29611,
                @"[In Location] The Location element specifies the place where the event specified by the calendar item exception occurs.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R43511");

            // Verify MS-ASCAL requirement: MS-ASCAL_R43511
            // If Exception.StartTime is not null, it means the server returns the start time of the calendar item exception
            Site.CaptureRequirementIfIsNotNull(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].StartTime,
                43511,
                @"[In StartTime] The StartTime element specifies the start time of the calendar item exception.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R44111");

            // Verify MS-ASCAL requirement: MS-ASCAL_R44111
            // If Exception.Subject is not null, it means the server returns the subject of the calendar item exception
            Site.CaptureRequirementIfAreEqual<string>(
                "Calendar Exception".ToLower(CultureInfo.CurrentCulture),
                calendarOnAttendee.Calendar.Exceptions.Exception[0].Subject.ToLower(CultureInfo.CurrentCulture),
                44111,
                @"[In Subject] The Subject element specifies the subject of the calendar item exception.");

            if (!this.IsActiveSyncProtocolVersion121 && !this.IsActiveSyncProtocolVersion140)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R30511");

                // Verify MS-ASCAL requirement: MS-ASCAL_R30511
                Site.CaptureRequirementIfIsTrue(
                    calendarOnAttendee.Calendar.Exceptions.Exception[0].MeetingStatusSpecified,
                    30511,
                    @"[In MeetingStatus] The MeetingStatus element specifies the status of the calendar item exception.");
            }

            #endregion

            #region Decline the fifth occurrence

            this.MeetingResponse(byte.Parse("3"), this.User2Information.CalendarCollectionId, calendarOnAttendee.ServerId, startTimeInException.AddDays(1).ToString("yyyy-MM-ddThh:mm:ss.000Z"));

            // Call Sync command to do an initialization Sync, and get the attendee calendars changes after accepting the meeting
            calendarOnAttendee = this.GetChangeItem(this.User2Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendarOnAttendee.Calendar, "The calendar with subject {0} should exist in server.", subject);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R26111");

            // Verify MS-ASCAL requirement: MS-ASCAL_R26111
            // If Exceptions element is not null, it means the server returns a collection of exceptions to the recurrence pattern of the calendar item
            Site.CaptureRequirementIfIsNotNull(
                calendarOnAttendee.Calendar.Exceptions,
                26111,
                @"[In Exceptions] The Exceptions element specifies a collection of exceptions to the recurrence pattern of the calendar item.");

            foreach (Response.ExceptionsException exception in calendarOnAttendee.Calendar.Exceptions.Exception)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R24111");

                // Verify MS-ASCAL requirement: MS-ASCAL_R24111
                // If Exceptions.Exception is not null, it means the server returns an exception to the calendar item's recurrence pattern
                Site.CaptureRequirementIfIsNotNull(
                    exception,
                    24111,
                    @"[In Exception] The Exception element specifies an exception to the calendar item's recurrence pattern.");
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R20611");

            // Verify MS-ASCAL requirement: MS-ASCAL_R20611
            Site.CaptureRequirementIfIsTrue(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].DeletedSpecified,
                20611,
                @"[In Deleted] The Deleted element specifies whether the exception to the calendar item has been deleted.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R20811");

            // Verify MS-ASCAL requirement: MS-ASCAL_R20811
            Site.CaptureRequirementIfIsTrue(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].DeletedSpecified,
                20811,
                @"[In Deleted] A command response has a maximum of one Deleted child element per Exception element.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R210");

            // Verify MS-ASCAL requirement: MS-ASCAL_R210
            Site.CaptureRequirementIfAreEqual<byte>(
                1,
                calendarOnAttendee.Calendar.Exceptions.Exception[0].Deleted,
                210,
                @"[In Deleted] An exception will be deleted when the Deleted element is included as a child element of the Exception element with a value of 1.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R525221");

            // Verify MS-ASCAL requirement: MS-ASCAL_R525221
            // If Exception.AppointmentReplyTime is null, it means the server does not return the date and time that the user responded to the meeting request exception
            Site.CaptureRequirementIfIsNull(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].AppointmentReplyTime,
                525221,
                @"[In Message Processing Events and Sequencing Rules][The following information pertains to all command responses:] If a meeting request exception has not been accepted, the server MUST NOT include the AppointmentReplyTime element as a child element of the Exception element in a command response.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R52522111");

            // Verify MS-ASCAL requirement: MS-ASCAL_R52522111
            // If Exception.AppointmentReplyTime is null, it means the server does not return the date and time that the user responded to the meeting request exception
            Site.CaptureRequirementIfIsNull(
                calendarOnAttendee.Calendar.Exceptions.Exception[0].AppointmentReplyTime,
                52522111,
                @"[In Message Processing Events and Sequencing Rules][The following information pertains to all command responses:] If a meeting request exception has not been tentatively accepted, the server MUST NOT include the AppointmentReplyTime element as a child element of the Exception element in a command response.");

            #endregion

            #endregion

            #region Switch to organizer to call Sync command to sync calendars from the server.

            // Switch to organizer
            this.SwitchUser(this.User1Information, false);

            // Sync command to do an initialization Sync, and get the organizer calendars changes
            this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            #endregion
        }
        public void MSASCAL_S01_TC10_Categories()
        {
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The recurring calendar item cannot be created when protocol version is set to 16.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");

            #region Call Sync command to add a calendar with the element Categories and one sub-element Category to the server, and sync calendars from the server.

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();
            string subjectWithCategoriesLessThan300 = Common.GenerateResourceName(Site, "subjectWithCategoriesLessThan300");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subjectWithCategoriesLessThan300);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Categories element specifies a category that is assigned to the calendar item
            calendarItem.Add(Request.ItemsChoiceType8.Categories, TestSuiteHelper.CreateCalendarCategories(new string[] { this.Category }));

            // Set Categories element specifies a category that is assigned to the exception item
            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, this.CreateCalendarRecurrence(0, 6, 1));

            string categoryNameInException = this.Category + "InException";

            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            Request.ExceptionsException exceptionWithCategoriesLessThan300 = TestSuiteHelper.CreateExceptionRequired(this.StartTime.AddDays(2).ToString("yyyyMMddTHHmmssZ"));
            exceptionWithCategoriesLessThan300.Categories = TestSuiteHelper.CreateCalendarCategories(new string[] { categoryNameInException }).Category;

            exceptionList.Add(exceptionWithCategoriesLessThan300);
            exceptions.Exception = exceptionList.ToArray();
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendarWithCategoriesLessThan300 = this.GetChangeItem(this.User1Information.CalendarCollectionId, subjectWithCategoriesLessThan300);

            Site.Assert.IsNotNull(calendarWithCategoriesLessThan300.Calendar, "The calendar with subject {0} should exist in server.", subjectWithCategoriesLessThan300);

            this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subjectWithCategoriesLessThan300);

            #endregion

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R2083");

            // Verify MS-ASCAL requirement: MS-ASCAL_R2083
            // If the DtStamp element is not specified as a child element of an Exception element, the value of the DtStamp element is assumed to be the
            // same as the value of the top-level DtStamp element. So this requirement can be covered if DtStamp for the calendar item is returned.
            Site.CaptureRequirementIfIsNotNull(
                calendarWithCategoriesLessThan300.Calendar.DtStamp.Value,
                2083,
                @"[In DtStamp] As a top-level element of the Calendar class, the DtStamp element specifies [the date and time that the calendar item was created or modified or] the date and time at which the exception item was created or modified..");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R17711");

            // Verify MS-ASCAL requirement: MS-ASCAL_R17711
            Site.CaptureRequirementIfAreEqual<string>(
                this.Category,
                calendarWithCategoriesLessThan300.Calendar.Categories.Category[0],
                17711,
                @"[In Categories] The Categories element specifies a collection of categories assigned to the calendar item.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R17911");

            // Verify MS-ASCAL requirement: MS-ASCAL_R17911
            Site.CaptureRequirementIfAreEqual<string>(
                categoryNameInException,
                calendarWithCategoriesLessThan300.Calendar.Exceptions.Exception[0].Categories[0],
                17911,
                @"[In Categories] As a child element of the Exception element (section 2.2.2.19), the Categories element specifies the categories for the exception item.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R18011");

            // Verify MS-ASCAL requirement: MS-ASCAL_R18011
            Site.CaptureRequirementIfAreEqual<string>(
                categoryNameInException,
                calendarWithCategoriesLessThan300.Calendar.Exceptions.Exception[0].Categories[0],
                18011,
                @"[In Categories] A command response has a maximum of one Categories child element per Exception element.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R18311");

            // Verify MS-ASCAL requirement: MS-ASCAL_R18311
            Site.CaptureRequirementIfAreEqual<string>(
                this.Category,
                calendarWithCategoriesLessThan300.Calendar.Categories.Category[0],
                18311,
                @"[In Category] The Category element specifies a category that is assigned to the calendar item.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R18312");

            // Verify MS-ASCAL requirement: MS-ASCAL_R18312
            Site.CaptureRequirementIfAreEqual<string>(
                categoryNameInException,
                calendarWithCategoriesLessThan300.Calendar.Exceptions.Exception[0].Categories[0],
                18312,
                @"[In Category] The Category element specifies a category that is assigned to the exception item.");

            if (Common.IsRequirementEnabled(11026, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R11026");

                // Verify MS-ASCAL requirement: MS-ASCAL_R11026
                Site.CaptureRequirementIfIsTrue(
                    calendarWithCategoriesLessThan300.Calendar.Exceptions.Exception[0].Categories.Length >= 0 && calendarWithCategoriesLessThan300.Calendar.Categories.Category.Length <= 300,
                    11026,
                    @"[In Appendix B: Product Behavior] Implementation command response includes no more than 300 Category child elements per Categories element. (Exchange 2007 SP1 and above follow this behavior.)");
            }

            #region Call Sync command to add a calendar with the element Categories and more than 300 sub-element Category to the server, and sync calendars from the server.

            calendarItem.Clear();

            // Set more than 300 sub-element Category
            List<string> categoryList = new List<string>();
            for (int i = 0; i <= 301; i++)
            {
                categoryList.Add(this.Category);
            }

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Categories element specifies a category that is assigned to the calendar item
            calendarItem.Add(Request.ItemsChoiceType8.Categories, TestSuiteHelper.CreateCalendarCategories(categoryList.ToArray()));

            // Set Categories element specifies a category that is assigned to the exception item
            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, this.CreateCalendarRecurrence(0, 6, 1));

            exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            exceptionList = new List<Request.ExceptionsException>();

            Request.ExceptionsException exceptionWithCategoriesMoreThan300 = TestSuiteHelper.CreateExceptionRequired(this.StartTime.AddDays(2).ToString("yyyyMMddTHHmmssZ"));
            exceptionWithCategoriesMoreThan300.Categories = TestSuiteHelper.CreateCalendarCategories(categoryList.ToArray()).Category;

            exceptionList.Add(exceptionWithCategoriesMoreThan300);
            exceptions.Exception = exceptionList.ToArray();
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);

            SyncStore addCalendarResponse = this.AddSyncCalendar(calendarItem);

            Site.Assert.IsFalse(addCalendarResponse.AddResponses[0].Status.Equals(1), "Command request can not includes more than 300 Category child elements per Categories element.");

            #endregion
        }
        public void MSASCAL_S01_TC34_ExcludePropertyOfException()
        {
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The recurring calendar item cannot be created when protocol version is set to 16.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");

            #region Call Sync command to add a calendar to the server, and sync calendars from the server.

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();

            DateTime exceptionStartTime = this.StartTime.AddDays(3);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Calendar Recurrence element including Occurrence sub-element
            byte recurrenceType = byte.Parse("0");
            Request.Recurrence recurrence = this.CreateCalendarRecurrence(recurrenceType, 6, 1);

            // Set Calendar Exceptions element
            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            // Set ExceptionStartTime element in exception
            Request.ExceptionsException exception = TestSuiteHelper.CreateExceptionRequired(exceptionStartTime.ToString("yyyyMMddTHHmmssZ"));

            exception.Subject = "Calendar Exception";
            exception.Location = "Room 666";
            exceptionList.Add(exception);
            exceptions.Exception = exceptionList.ToArray();

            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, recurrence);
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);
            calendarItem.Add(Request.ItemsChoiceType8.Location, this.Location);

            string emailAddress = Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain);
            calendarItem.Add(Request.ItemsChoiceType8.Attendees, TestSuiteHelper.CreateAttendeesRequired(new string[] { emailAddress }, new string[] { this.User2Information.UserName }));
            calendarItem.Add(Request.ItemsChoiceType8.MeetingStatus, (byte)1);
            if (!this.IsActiveSyncProtocolVersion121)
            {
                calendarItem.Add(Request.ItemsChoiceType8.ResponseRequested, true);
                calendarItem.Add(Request.ItemsChoiceType8.DisallowNewTimeProposal, true);
            }

            string subject = Common.GenerateResourceName(Site, "subject");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subject);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendar.Calendar, "The calendar with subject {0} should exist in server.", subject);
            this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subject);
            #endregion

            #region Call Sync command to change the Exception element of calendar by excluding the Location property, and sync calendars from the server.

            SyncStore syncResponse1 = this.InitializeSync(this.User1Information.CalendarCollectionId, null);
            SyncRequest syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, syncResponse1.SyncKey, true);
            SyncStore syncResponse2 = this.CALAdapter.Sync(syncRequest);

            // Exclude Location property of the Exception
            Dictionary<Request.ItemsChoiceType7, object> changeItem = new Dictionary<Request.ItemsChoiceType7, object>();
            exception.Location = null;
            changeItem.Add(Request.ItemsChoiceType7.Exceptions, exceptions);
            changeItem.Add(Request.ItemsChoiceType7.Recurrence, recurrence);
            changeItem.Add(Request.ItemsChoiceType7.Subject, subject);
            this.UpdateCalendarProperty(calendar.ServerId, this.User1Information.CalendarCollectionId, syncResponse2.SyncKey, changeItem);

            SyncItem newCalendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            bool isUnChanged = newCalendar.Calendar.Exceptions.Exception[0].Subject == exception.Subject
                && newCalendar.Calendar.Exceptions.Exception[0].Location == "Room 666";

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R542");

            // Verify MS-ASCAL requirement: MS-ASCAL_R542
            Site.CaptureRequirementIfIsTrue(
                isUnChanged,
                542,
                @"[In Removing Exceptions] If a particular Exception element (section 2.2.2.19) is excluded in a Sync command request, then that particular exception remains unchanged.");

            #endregion
        }
        public void MSASCAL_S01_TC33_DeletePropertyOfException()
        {
            Site.Assume.IsTrue(Common.IsRequirementEnabled(2242, this.Site), "Exchange 2007 does not support deleting elements of a recurring calendar item in an Exception element.");
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The recurring calendar item cannot be created when protocol version is set to 16.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");

            #region Call Sync command to add a calendar to the server, and sync calendars from the server.

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();

            DateTime exceptionStartTime = this.StartTime.AddDays(3);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Calendar Recurrence element including Occurrence sub-element
            byte recurrenceType = byte.Parse("0");
            Request.Recurrence recurrence = this.CreateCalendarRecurrence(recurrenceType, 6, 1);

            // Set Calendar Exceptions element
            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            // Set ExceptionStartTime element in exception
            Request.ExceptionsException exception = TestSuiteHelper.CreateExceptionRequired(exceptionStartTime.ToString("yyyyMMddTHHmmssZ"));

            exception.Subject = "Calendar Exception";
            exception.Location = "Room 666";
            exceptionList.Add(exception);
            exceptions.Exception = exceptionList.ToArray();

            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, recurrence);
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);
            calendarItem.Add(Request.ItemsChoiceType8.Location, this.Location);

            string emailAddress = Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain);
            calendarItem.Add(Request.ItemsChoiceType8.Attendees, TestSuiteHelper.CreateAttendeesRequired(new string[] { emailAddress }, new string[] { this.User2Information.UserName }));
            calendarItem.Add(Request.ItemsChoiceType8.MeetingStatus, (byte)1);
            if (!this.IsActiveSyncProtocolVersion121)
            {
                calendarItem.Add(Request.ItemsChoiceType8.ResponseRequested, true);
                calendarItem.Add(Request.ItemsChoiceType8.DisallowNewTimeProposal, true);
            }

            string subject = Common.GenerateResourceName(Site, "subject");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subject);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendar.Calendar, "The calendar with subject {0} should exist in server.", subject);
            this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subject);
            #endregion

            #region Call Sync command to delete the Location property of the exception to change the calendar, and sync calendars from the server.

            SyncStore syncResponse1 = this.InitializeSync(this.User1Information.CalendarCollectionId, null);
            SyncRequest syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, syncResponse1.SyncKey, true);
            SyncStore syncResponse2 = this.CALAdapter.Sync(syncRequest);

            // Delete Location property of the Exception
            Dictionary<Request.ItemsChoiceType7, object> changeItem = new Dictionary<Request.ItemsChoiceType7, object>();
            exception.Location = null;
            changeItem.Add(Request.ItemsChoiceType7.Exceptions, exceptions);
            changeItem.Add(Request.ItemsChoiceType7.Recurrence, recurrence);
            changeItem.Add(Request.ItemsChoiceType7.Subject, subject);
            Request.SyncCollectionChangeApplicationData syncChangeData = new Request.SyncCollectionChangeApplicationData
            {
                ItemsElementName = changeItem.Keys.ToArray<Request.ItemsChoiceType7>(),
                Items = changeItem.Values.ToArray<object>()
            };

            Request.SyncCollectionChange syncChange = new Request.SyncCollectionChange
            {
                ApplicationData = syncChangeData,
                ServerId = calendar.ServerId
            };

            SyncRequest syncChangeRequest = new SyncRequest
            {
                RequestData = new Request.Sync { Collections = new Request.SyncCollection[1] }
            };

            syncChangeRequest.RequestData.Collections[0] = new Request.SyncCollection
            {
                Commands = new object[] { syncChange },
                SyncKey = syncResponse2.SyncKey,
                CollectionId = this.User1Information.CalendarCollectionId
            };

            // If an element in a recurring calendar item has been deleted in an Exception element, sends an empty tag
            // for this element to remove the inherited value from the server.
            string syncXmlRequest = syncChangeRequest.GetRequestDataSerializedXML();
            string changedSyncXmlRequest = syncXmlRequest.Insert(syncXmlRequest.IndexOf("</Exception>", StringComparison.CurrentCulture), "<Location />");
            SendStringResponse result = this.CALAdapter.SendStringRequest(changedSyncXmlRequest);

            #endregion

            #region Call Sync command to get the changed calendar.

            SyncStore initializeSyncResponse = this.InitializeSync(this.User1Information.CalendarCollectionId, null);
            syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, initializeSyncResponse.SyncKey, true);
            result = this.CALAdapter.SendStringRequest(syncRequest.GetRequestDataSerializedXML());

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(result.ResponseDataXML);
            XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(doc.NameTable);
            nameSpaceManager.AddNamespace("e", "AirSync");
            XmlNodeList nodes = doc.SelectNodes("//e:Collections/e:Collection/e:Commands/e:Add/e:ApplicationData", nameSpaceManager);
            bool isEmptyLocationContained = false;
            foreach (XmlNode node in nodes)
            {
                bool isFound = false;
                XmlNodeList subNodes = node.ChildNodes;
                foreach (XmlNode subNode in subNodes)
                {
                    if (subNode.Name.Equals("Subject") && subNode.InnerText != null && subNode.InnerText.Equals(subject))
                    {
                        isFound = true;
                    }
                    if (isFound && subNode.Name.Equals("Exceptions"))
                    {
                        isEmptyLocationContained = subNode.InnerXml.Contains("<Location />");
                        break;
                    }
                }
                if (isEmptyLocationContained)
                {
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R2242");

            // Verify MS-ASCAL requirement: MS-ASCAL_R2242
            Site.CaptureRequirementIfIsTrue(
                isEmptyLocationContained,
                2242,
                @"[In Appendix B: Product Behavior]  If an element in a recurring calendar item has been deleted in an Exception element (section 2.2.2.19), the client sends an empty tag for this element to remove the inherited value from the implementation. (Exchange 2010 and above follow this behavior.)");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R539");

            // Verify MS-ASCAL requirement: MS-ASCAL_R539
            Site.CaptureRequirementIfIsTrue(
                isEmptyLocationContained,
                539,
                @"[In Sync Command Response] If one or more properties of an exception for recurring calendar item (that is, any child elements of the Exception element (section 2.2.2.19)) have been deleted, the server MUST transmit an empty element in the Sync command response to indicate that this property is not inherited from the recurrence.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R543");

            // Verify MS-ASCAL requirement: MS-ASCAL_R543
            Site.CaptureRequirementIfIsTrue(
                isEmptyLocationContained,
                543,
                @"[In Indicating Deleted Elements in Exceptions] If an element of a recurring calendar item has been deleted in an Exception element (section 2.2.2.19), the server MUST send an empty tag for this element in the Sync command response ([MS-ASCMD] section 2.2.2.19).");

            #endregion
        }
        public void MSASCAL_S01_TC31_UnchangedExceptions()
        {
            Site.Assume.AreNotEqual<string>("16.0", Common.GetConfigurationPropertyValue("ActiveSyncProtocolVersion", this.Site), "The recurring calendar item cannot be created when protocol version is set to 16.0. MS-ASProtocolVersion header value is determined using Common PTFConfig property named ActiveSyncProtocolVersion.");

            #region Calls Sync command to add a calendar to the server, and sync calendars from the server.

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();

            DateTime exceptionStartTime = this.StartTime.AddDays(3);
            DateTime startTimeInException = exceptionStartTime.AddMinutes(15);
            DateTime endTimeInException = startTimeInException.AddHours(2);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Calendar Recurrence element including Occurrence sub-element
            byte recurrenceType = byte.Parse("0");
            Request.Recurrence recurrence = this.CreateCalendarRecurrence(recurrenceType, 6, 1);
            calendarItem.Add(Request.ItemsChoiceType8.Recurrence, recurrence);

            // Set Calendar Exceptions element
            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            // Set ExceptionStartTime element in exception
            Request.ExceptionsException exception = TestSuiteHelper.CreateExceptionRequired(exceptionStartTime.ToString("yyyyMMddTHHmmssZ"));

            exception.StartTime = startTimeInException.ToString("yyyyMMddTHHmmssZ");
            exception.EndTime = endTimeInException.ToString("yyyyMMddTHHmmssZ");

            exception.Subject = "Calendar Exception";
            exception.Location = "Room 666";
            exceptionList.Add(exception);
            exceptions.Exception = exceptionList.ToArray();
            calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);

            string subject = Common.GenerateResourceName(Site, "subject");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subject);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendar.Calendar, "The calendar with subject {0} should exist in server.", subject);

            this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subject);

            #endregion

            #region Calls Sync command to Sync calendars from the server.

            // Set Supported Element
            Request.Supported supportedElement = new Request.Supported();

            Dictionary<Request.ItemsChoiceType, object> supportedItem = new Dictionary<Request.ItemsChoiceType, object>
            {
                {
                    Request.ItemsChoiceType.Exceptions, exceptions
                },
                {
                    Request.ItemsChoiceType.DtStamp, string.Empty
                },
                {
                    Request.ItemsChoiceType.Categories, TestSuiteHelper.CreateCalendarCategories(new string[] { "Categories" })
                },
                {
                    Request.ItemsChoiceType.Sensitivity, (byte)1
                },
                {
                    Request.ItemsChoiceType.BusyStatus, (byte)1
                },
                {
                    Request.ItemsChoiceType.UID, string.Empty
                },
                {
                    Request.ItemsChoiceType.Timezone, string.Empty
                },
                {
                    Request.ItemsChoiceType.StartTime, string.Empty
                },
                {
                    Request.ItemsChoiceType.EndTime, string.Empty
                },
                {
                    Request.ItemsChoiceType.Subject, string.Empty
                },
                {
                    Request.ItemsChoiceType.Location, string.Empty
                },
                {
                    Request.ItemsChoiceType.Recurrence, recurrence
                },
                {
                    Request.ItemsChoiceType.AllDayEvent, (byte)1
                },
                {
                    Request.ItemsChoiceType.Reminder, string.Empty
                }
            };

            supportedElement.Items = supportedItem.Values.ToArray<object>();
            supportedElement.ItemsElementName = supportedItem.Keys.ToArray<Request.ItemsChoiceType>();

            // Sync calendars with supported element
            SyncStore syncResponse1 = this.InitializeSync(this.User1Information.CalendarCollectionId, supportedElement);

            SyncRequest syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, syncResponse1.SyncKey, true);
            SyncStore syncResponse2 = this.CALAdapter.Sync(syncRequest);
            SyncItem createdCalendar = new SyncItem();

            foreach (SyncItem item in syncResponse2.AddElements)
            {
                if (item.Calendar.Subject == subject)
                {
                    createdCalendar = item;
                    break;
                }
            }

            Site.Assert.IsNotNull(createdCalendar.Calendar, "The calendar with subject {0} should exist in server.", subject);

            syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, syncResponse2.SyncKey, false);
            SyncStore syncResponse3 = this.CALAdapter.Sync(syncRequest);

            Site.Assert.AreEqual<int>(
                0,
                syncResponse3.AddResponses.Count,
                "This Sync command response should be null.");

            SyncItem updatedCalendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(updatedCalendar.Calendar, "The calendar with subject {0} should exist in server.", subject);

            #endregion

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R54111");

            // Verify MS-ASCAL requirement: MS-ASCAL_R54111
            Site.CaptureRequirementIfIsTrue(
                createdCalendar.Calendar.Exceptions.Exception[0].ExceptionStartTime == calendar.Calendar.Exceptions.Exception[0].ExceptionStartTime
                && createdCalendar.Calendar.Exceptions.Exception[0].StartTime == calendar.Calendar.Exceptions.Exception[0].StartTime
                && createdCalendar.Calendar.Exceptions.Exception[0].EndTime == calendar.Calendar.Exceptions.Exception[0].EndTime
                && createdCalendar.Calendar.Exceptions.Exception[0].Subject == calendar.Calendar.Exceptions.Exception[0].Subject
                && createdCalendar.Calendar.Exceptions.Exception[0].Location == calendar.Calendar.Exceptions.Exception[0].Location,
                54111,
                @"[In Removing Exceptions] [If an Exceptions element (section 2.2.2.20) is not specified in a Sync command request ([MS-ASCMD] section 2.2.2.19.2), then] any exceptions previously defined are unchanged, even if the client included the Exceptions element as a child of the Supported element, as specified in [MS-ASCMD] section 2.2.3.164.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R541");

            // Verify MS-ASCAL requirement: MS-ASCAL_R541
            Site.CaptureRequirementIfIsTrue(
                updatedCalendar.Calendar.Exceptions.Exception[0].ExceptionStartTime == calendar.Calendar.Exceptions.Exception[0].ExceptionStartTime
                && updatedCalendar.Calendar.Exceptions.Exception[0].StartTime == calendar.Calendar.Exceptions.Exception[0].StartTime
                && updatedCalendar.Calendar.Exceptions.Exception[0].EndTime == calendar.Calendar.Exceptions.Exception[0].EndTime
                && updatedCalendar.Calendar.Exceptions.Exception[0].Subject == calendar.Calendar.Exceptions.Exception[0].Subject
                && updatedCalendar.Calendar.Exceptions.Exception[0].Location == calendar.Calendar.Exceptions.Exception[0].Location,
                541,
                @"[In Removing Exceptions] If an Exceptions element (section 2.2.2.20) is not specified in a Sync command request ([MS-ASCMD] section 2.2.2.19), then any exceptions previously defined are unchanged. ");
        }
        public void MSASCAL_S01_TC28_GhostedElements()
        {
            #region Call Sync command to add a calendar to the server, and sync calendars from the server.

            Dictionary<Request.ItemsChoiceType8, object> calendarItem = new Dictionary<Request.ItemsChoiceType8, object>();

            DateTime exceptionStartTime = this.StartTime.AddDays(3);
            DateTime startTimeInException = exceptionStartTime.AddMinutes(15);
            DateTime endTimeInException = startTimeInException.AddHours(2);

            // Set Calendar StartTime, EndTime elements
            calendarItem.Add(Request.ItemsChoiceType8.StartTime, this.StartTime.ToString("yyyyMMddTHHmmssZ"));
            calendarItem.Add(Request.ItemsChoiceType8.EndTime, this.EndTime.ToString("yyyyMMddTHHmmssZ"));

            // Set Calendar Recurrence element including Occurrence sub-element
            byte recurrenceType = byte.Parse("0");
            Request.Recurrence recurrence = this.CreateCalendarRecurrence(recurrenceType, 6, 1);

            // Set Calendar Exceptions element
            Request.Exceptions exceptions = new Request.Exceptions { Exception = new Request.ExceptionsException[] { } };
            List<Request.ExceptionsException> exceptionList = new List<Request.ExceptionsException>();

            // Set ExceptionStartTime element in exception
            Request.ExceptionsException exception = TestSuiteHelper.CreateExceptionRequired(exceptionStartTime.ToString("yyyyMMddTHHmmssZ"));

            exception.StartTime = startTimeInException.ToString("yyyyMMddTHHmmssZ");
            exception.EndTime = endTimeInException.ToString("yyyyMMddTHHmmssZ");

            exception.Subject = "Calendar Exception";
            exception.Location = "Room 666";
            exceptionList.Add(exception);
            exceptions.Exception = exceptionList.ToArray();

            if (this.IsActiveSyncProtocolVersion121
                || this.IsActiveSyncProtocolVersion140
                || this.IsActiveSyncProtocolVersion141)
            {
                calendarItem.Add(Request.ItemsChoiceType8.Recurrence, recurrence);
                calendarItem.Add(Request.ItemsChoiceType8.Exceptions, exceptions);
                calendarItem.Add(Request.ItemsChoiceType8.Location, this.Location);
            }

            // Set elements which can be ghosted
            string emailAddress = Common.GetMailAddress(this.User2Information.UserName, this.User2Information.UserDomain);
            calendarItem.Add(Request.ItemsChoiceType8.Attendees, TestSuiteHelper.CreateAttendeesRequired(new string[] { emailAddress }, new string[] { this.User2Information.UserName }));
            calendarItem.Add(Request.ItemsChoiceType8.MeetingStatus, (byte)1);
            if (!this.IsActiveSyncProtocolVersion121)
            {
                calendarItem.Add(Request.ItemsChoiceType8.ResponseRequested, true);
                calendarItem.Add(Request.ItemsChoiceType8.DisallowNewTimeProposal, true);
            }

            string subject = Common.GenerateResourceName(Site, "subject");
            calendarItem.Add(Request.ItemsChoiceType8.Subject, subject);

            this.AddSyncCalendar(calendarItem);

            SyncItem calendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, subject);

            Site.Assert.IsNotNull(calendar.Calendar, "The calendar with subject {0} should exist in server.", subject);

            this.SyncChanges(this.User1Information.CalendarCollectionId);

            #endregion

            #region Call Sync command to change a calendar element, and sync calendars from the server.

            // To support ghosted elements of Calendar, following elements must be included in Supported element.
            Request.Supported supportedElement = null;

            // All Calendar class properties are ghosted by default when protocol version 16.0 is used.
            if (this.IsActiveSyncProtocolVersion121
                || this.IsActiveSyncProtocolVersion140
                || this.IsActiveSyncProtocolVersion141)
            {
                supportedElement = new Request.Supported();
                Dictionary<Request.ItemsChoiceType, object> supportedItem = new Dictionary<Request.ItemsChoiceType, object>
                {
                    {
                        Request.ItemsChoiceType.Exceptions, exceptions
                    },
                    {
                        Request.ItemsChoiceType.DtStamp, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.Categories, TestSuiteHelper.CreateCalendarCategories(new string[] { "Categories" })
                    },
                    {
                        Request.ItemsChoiceType.Sensitivity, (byte)1
                    },
                    {
                        Request.ItemsChoiceType.BusyStatus, (byte)1
                    },
                    {
                        Request.ItemsChoiceType.UID, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.Timezone, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.StartTime, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.EndTime, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.Subject, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.Location, string.Empty
                    },
                    {
                        Request.ItemsChoiceType.Recurrence, recurrence
                    },
                    {
                        Request.ItemsChoiceType.AllDayEvent, (byte)1
                    },
                    {
                        Request.ItemsChoiceType.Reminder, string.Empty
                    }
                };

                supportedElement.Items = supportedItem.Values.ToArray<object>();
                supportedElement.ItemsElementName = supportedItem.Keys.ToArray<Request.ItemsChoiceType>();
            }

            // Sync calendars with supported element
            SyncStore syncResponse1 = this.InitializeSync(this.User1Information.CalendarCollectionId, supportedElement);
            SyncRequest syncRequest = TestSuiteHelper.CreateSyncRequest(this.User1Information.CalendarCollectionId, syncResponse1.SyncKey, true);
            SyncStore syncResponse2 = this.CALAdapter.Sync(syncRequest);

            // Update Subject value
            Dictionary<Request.ItemsChoiceType7, object> changeItem = new Dictionary<Request.ItemsChoiceType7, object>();

            string newSubject = Common.GenerateResourceName(Site, "newSubject");
            changeItem.Add(Request.ItemsChoiceType7.Subject, newSubject);

            this.UpdateCalendarProperty(calendar.ServerId, this.User1Information.CalendarCollectionId, syncResponse2.SyncKey, changeItem);

            SyncItem newCalendar = this.GetChangeItem(this.User1Information.CalendarCollectionId, newSubject);

            if (newCalendar.Calendar != null)
            {
                this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, newSubject);
            }
            else
            {
                this.RecordCaseRelativeItems(this.User1Information.UserName, this.User1Information.CalendarCollectionId, subject);
                Site.Assert.IsNotNull(newCalendar.Calendar, "The calendar with subject {0} should exist in server.", newSubject);
            }

            #endregion

            #region Verify Requirements.

            Site.Assert.IsNotNull(newCalendar.Calendar.Body, "The Body element should not be null.");
            Site.Assert.IsNotNull(calendar.Calendar.Body, "The Body element should not be null.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R128");

            // Verify MS-ASCAL requirement: MS-ASCAL_R128
            Site.CaptureRequirementIfIsTrue(
                newCalendar.Calendar.Body.Type == calendar.Calendar.Body.Type && newCalendar.Calendar.Body.Data == calendar.Calendar.Body.Data,
                128,
                @"[In Body (AirSyncBase Namespace)] The top-level airsyncbase:Body element can be ghosted.");

            if (!this.IsActiveSyncProtocolVersion121)
            {
                Site.Assert.IsNotNull(calendar.Calendar.ResponseRequested, "The ResponseRequested element should not be null.");
                Site.Assert.IsNotNull(newCalendar.Calendar.ResponseRequested, "The ResponseRequested element should not be null.");
                Site.Assert.IsNotNull(calendar.Calendar.ResponseType, "The ResponseType element should not be null.");
                Site.Assert.IsNotNull(newCalendar.Calendar.ResponseType, "The ResponseType element should not be null.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R399");

                // Verify MS-ASCAL requirement: MS-ASCAL_R399
                Site.CaptureRequirementIfAreEqual<bool>(
                    calendar.Calendar.ResponseRequested.Value,
                    newCalendar.Calendar.ResponseRequested.Value,
                    399,
                    @"[In ResponseRequested] The ResponseRequested element can be ghosted.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R419");

                // Verify MS-ASCAL requirement: MS-ASCAL_R419
                Site.CaptureRequirementIfAreEqual<uint>(
                    calendar.Calendar.ResponseType.Value,
                    newCalendar.Calendar.ResponseType.Value,
                    419,
                    @"[In ResponseType] The top-level ResponseType element can be ghosted.");
            }

            Site.Assert.IsNotNull(calendar.Calendar.MeetingStatus, "The MeetingStatus element should not be null.");
            Site.Assert.IsNotNull(newCalendar.Calendar.MeetingStatus, "The MeetingStatus element should not be null.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R319");

            // Verify MS-ASCAL requirement: MS-ASCAL_R319
            Site.CaptureRequirementIfAreEqual<byte>(
                calendar.Calendar.MeetingStatus.Value,
                newCalendar.Calendar.MeetingStatus.Value,
                319,
                @"[In MeetingStatus] The top-level MeetingStatus element can be ghosted.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R365");

            // Verify MS-ASCAL requirement: MS-ASCAL_R365
            Site.CaptureRequirementIfAreEqual<string>(
                calendar.Calendar.OrganizerEmail.ToLower(CultureInfo.CurrentCulture),
                newCalendar.Calendar.OrganizerEmail.ToLower(CultureInfo.CurrentCulture),
                365,
                @"[In OrganizerEmail] The OrganizerEmail element can be ghosted.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R370");

            // Verify MS-ASCAL requirement: MS-ASCAL_R370
            Site.CaptureRequirementIfAreEqual<string>(
                calendar.Calendar.OrganizerName.ToLower(CultureInfo.CurrentCulture),
                newCalendar.Calendar.OrganizerName.ToLower(CultureInfo.CurrentCulture),
                370,
                @"[In OrganizerName] The OrganizerName element can be ghosted.");

            // There is only one attendee.
            Site.Assert.AreEqual<int>(
                1,
                newCalendar.Calendar.Attendees.Attendee.Length,
                "The Attendees element should be ghosted");

            bool isR111Verified = newCalendar.Calendar.Attendees.Attendee[0].AttendeeStatusSpecified == calendar.Calendar.Attendees.Attendee[0].AttendeeStatusSpecified &&
                newCalendar.Calendar.Attendees.Attendee[0].AttendeeStatus == calendar.Calendar.Attendees.Attendee[0].AttendeeStatus &&
                newCalendar.Calendar.Attendees.Attendee[0].AttendeeTypeSpecified == calendar.Calendar.Attendees.Attendee[0].AttendeeTypeSpecified &&
                newCalendar.Calendar.Attendees.Attendee[0].AttendeeType == calendar.Calendar.Attendees.Attendee[0].AttendeeType &&
                newCalendar.Calendar.Attendees.Attendee[0].Email == calendar.Calendar.Attendees.Attendee[0].Email &&
                newCalendar.Calendar.Attendees.Attendee[0].Name == calendar.Calendar.Attendees.Attendee[0].Name;

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-ASCAL_R111.\n" + "The AttendeeStatus is {0};\n" + "The AttendeeType is {1};\n" + "The Email is {2};\n" + "The Name is {3}.",
                newCalendar.Calendar.Attendees.Attendee[0].AttendeeStatus,
                newCalendar.Calendar.Attendees.Attendee[0].AttendeeType,
                newCalendar.Calendar.Attendees.Attendee[0].Email,
                newCalendar.Calendar.Attendees.Attendee[0].Name);

            // Verify MS-ASCAL requirement: MS-ASCAL_R111
            Site.CaptureRequirementIfIsTrue(
                isR111Verified,
                111,
                @"[In Attendees] The top-level Attendees element can be ghosted.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R217");

            // Verify MS-ASCAL requirement: MS-ASCAL_R217
            Site.CaptureRequirementIfAreEqual<bool?>(
                calendar.Calendar.DisallowNewTimeProposal,
                newCalendar.Calendar.DisallowNewTimeProposal,
                217,
                @"[In DisallowNewTimeProposal] The DisallowNewTimeProposal element can be ghosted.");

            if (this.IsActiveSyncProtocolVersion121 || this.IsActiveSyncProtocolVersion140 || this.IsActiveSyncProtocolVersion141)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-ASCAL_R301");

                // Verify MS-ASCAL requirement: MS-ASCAL_R301
                Site.CaptureRequirementIfIsNull(
                    newCalendar.Calendar.Location,
                    301,
                    @"[In Location] The top-level Location element cannot be ghosted.");
            }

            #endregion
        }