/* * <wsnt:Message> * <tt:Message UtcTime="2010-09-28T14:17:12.801" PropertyOperation="Initialized"> * <tt:Source> * <tt:SimpleItem Name="VideoSourceToken" Value="1"></tt:SimpleItem> * </tt:Source> * <tt:Data> * <tt:SimpleItem Name="State" Value="true"></tt:SimpleItem> * </tt:Data> * </tt:Message> * </wsnt:Message>*/ void GetMessageElements(List <FindEventResult> result, Dictionary <FindEventResult, XmlDocument> rawResults, Dictionary <FindEventResult, XmlElement> messageElements) { string messagePath; messagePath = "/s:Envelope/s:Body/search:GetEventSearchResultsResponse/search:ResultList/onvif:Result/onvif:Event"; for (int i = 0; i < result.Count;) { FindEventResult ev = result[i]; XmlDocument soapRawPacket = rawResults[ev]; XmlNamespaceManager manager = CreateNamespaceManager(soapRawPacket); XmlNodeList responseNodeList = soapRawPacket.SelectNodes(messagePath, manager); for (int j = 0; j < responseNodeList.Count; j++) { XmlNode node = responseNodeList[j]; XmlElement element = node as XmlElement; if (element != null) { messageElements.Add(ev, element); i++; if (i < result.Count) { ev = result[i]; } } } } }
TopicInfo CreateTopicInfo(FindEventResult e, XmlElement messageElement) { XmlElement topicElement = null; foreach (XmlElement child in messageElement.ChildNodes) { if (child.LocalName == "Topic" && child.NamespaceURI == BaseNotification.WSNT) { topicElement = child; break; } } XmlText text = GetTopicElement(e); if (topicElement == null) { return(null); } if (text == null) { return(null); } //TopicInfo actual = TopicInfo.ExtractTopicInfoAll(text.Value, topicElement); //[26.03.2013] AKS: return behavior like before merge TopicInfo actual = TopicInfo.ExtractTopicInfoPACS(text.Value, topicElement); return(actual); }
XmlText GetTopicElement(FindEventResult e) { XmlText text = null; foreach (XmlNode child in e.Event.Topic.Any) { if (child is XmlText) { text = child as XmlText; break; } } return(text); }
bool AreTheSame(FindEventResult ev1, TopicInfo topic1, FindEventResult ev2, XmlElement element2) { bool scopeMatches = (ev1.Time == ev2.Time) && (ev2.RecordingToken == ev1.RecordingToken) && (ev1.TrackToken == ev2.TrackToken); bool topicMatches = false; if (scopeMatches) { TopicInfo t2 = CreateTopicInfo(ev2, element2); topicMatches = TopicInfo.TopicsMatch(topic1, t2); } return(topicMatches); }
bool CheckEventTopic(FindEventResult e, XmlElement rawResultElement, string topic, string ns) { if (e.Event != null && e.Event.Topic != null) { TopicInfo expected = TopicInfo.ConstructTopicInfo(new EventsTopicInfo() { NamespacesDefinition = ns, Topic = topic }); TopicInfo actual = CreateTopicInfo(e, rawResultElement); bool topicMatches = TopicInfo.TopicsMatch(actual, expected); return(topicMatches); } return(false); }
FindEventResult GenerateTrackEvent(RecordingInformation recording, TrackInformation track) { FindEventResult eventResult = new FindEventResult(); eventResult.RecordingToken = recording.RecordingToken; if (track != null) { eventResult.TrackToken = track.TrackToken; } else { eventResult.TrackToken = ""; } eventResult.Event = new NotificationMessageHolderType(); //eventResult.Event.ProducerReference = new EndpointReferenceType(); //eventResult.Event.ProducerReference.Address = new AttributedURIType(){Value= "http://localhost/dut.asmx"}; eventResult.Event.Topic = new TopicExpressionType(); eventResult.Event.Topic.Dialect = "http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"; return(eventResult); }
bool ValidateMessage(FindEventResult eventResult, StringBuilder dump) { XmlText topicText = GetTopicElement(eventResult); string topic = topicText.Value; bool valid = true; List <string> simpleItems = new List <string>(); XmlNamespaceManager manager = new XmlNamespaceManager(eventResult.Event.Message.OwnerDocument.NameTable); manager.AddNamespace(OnvifMessage.ONVIFPREFIX, OnvifMessage.ONVIF); string path; path = "/tt:Data/tt:SimpleItem"; XmlNodeList itemNodesList = eventResult.Event.Message.SelectNodes(path, manager); StringBuilder local = new StringBuilder(); foreach (XmlNode node in itemNodesList) { XmlElement element = node as XmlElement; if (element == null) { continue; } string name = element.GetAttribute(OnvifMessage.NAME); if (simpleItems.Contains(name)) { valid = false; local.AppendFormat(" Multiple SimpleItem elements with 'Name' attribute set to '{0}' found{1}", name, Environment.NewLine); } simpleItems.Add(name); } if (!valid) { dump.AppendFormat("Message for event with time={0}, topic ={1} is incorrect: {2}", eventResult.Time.StdDateTimeToString(), topic, Environment.NewLine); dump.Append(local.ToString()); } return(valid); }
bool AreTheSame(FindEventResult ev1, TopicInfo topic1, FindEventResult ev2, XmlElement element2) { // Two Event Results will be assumed as the same, if they have the same values for // GetEventSearchResultsResponse.ResultList.Result.RecordingToken, // GetEventSearchResultsResponse.ResultList.Result.TrackToken, // GetEventSearchResultsResponse.ResultList.Result.Time, // GetEventSearchResultsResponse.ResultList.Result.Event.Topic and // fields and values of GetEventSearchResultsResponse.ResultList.Result.Event.Message.Data. bool scopeMatches = (ev1.Time == ev2.Time) && (ev2.RecordingToken == ev1.RecordingToken) && (ev1.TrackToken == ev2.TrackToken); bool topicMatches = false; if (scopeMatches) { TopicInfo t2 = CreateTopicInfo(ev2, element2); topicMatches = TopicInfo.TopicsMatch(topic1, t2); } return(topicMatches); }
bool HaveTheSamePayload(FindEventResult ev1, FindEventResult ev2) { bool theSame = true; if (ev1.Event != null && ev2.Event != null) { if (ev1.Event.Message != null && ev2.Event.Message != null) { Dictionary <string, string> items1 = GetMessageSimpleItems(ev1.Event.Message); Dictionary <string, string> items2 = GetMessageSimpleItems(ev2.Event.Message); List <string> common = new List <string>(); bool localOk = true; foreach (string key in items1.Keys) { if (!items2.ContainsKey(key)) { localOk = false; break; } else { common.Add(key); } } if (localOk) { foreach (string key in items2.Keys) { if (!items2.ContainsKey(key)) { localOk = false; break; } } } if (localOk) { foreach (string key in common) { if (items1[key] != items2[key]) { localOk = false; } } } theSame = localOk; } else { theSame = (ev1.Event.Message == null && ev2.Event.Message == null); } } else { theSame = (ev1.Event == null && ev2.Event == null); } return(theSame); }
void CompareLists(IEnumerable <FindEventResult> list1, IEnumerable <FindEventResult> list2, Dictionary <FindEventResult, XmlElement> rawMessages1, Dictionary <FindEventResult, XmlElement> rawMessages2, string descr1, string descr2) { bool ok = true; StringBuilder dump = new StringBuilder(); Dictionary <FindEventResult, FindEventResult> intersection = new Dictionary <FindEventResult, FindEventResult>(); Func <FindEventResult, string, string> getDescription = new Func <FindEventResult, string, string>( (e, topic) => { return(string.Format("Event with Time={0}, RecordingToken='{1}', TrackToken='{2}', Topic='{3}'", e.Time, e.RecordingToken, e.TrackToken, topic)); }); // check events in list1, find events that are not in list2, // find events that are in both lists (intersection) foreach (FindEventResult ev1 in list1) { if (!ev1.StartStateEvent) { XmlText topicText = GetTopicElement(ev1); TopicInfo topicInfo = CreateTopicInfo(ev1, rawMessages1[ev1]); List <FindEventResult> filtered2 = list2.Where(E => AreTheSame(ev1, topicInfo, E, rawMessages2[E])).ToList(); string topic = topicText.Value; string descr = getDescription(ev1, topic); if (filtered2.Count() == 0) { ok = false; dump.AppendFormat("{0} not found in {1}{2}", descr, descr2, Environment.NewLine); } else { FindEventResult ev2 = filtered2.Where(E => HaveTheSamePayload(ev1, E)).FirstOrDefault(); if (ev2 != null) { intersection.Add(ev1, ev2); } else { // how to describe the error ????? ok = false; dump.AppendFormat("For {0} (or one of them) in {1}, no event with the same Data can be found in {2}{3}", descr, descr1, descr2, Environment.NewLine); } } } } // check events in list2, find events that are not in list1 foreach (FindEventResult ev2 in list2) { if (!ev2.StartStateEvent) { XmlText topicText = GetTopicElement(ev2); TopicInfo topicInfo = CreateTopicInfo(ev2, rawMessages2[ev2]); string topic = topicText.Value; string descr = getDescription(ev2, topic); List <FindEventResult> filtered1 = list1.Where(E => AreTheSame(ev2, topicInfo, E, rawMessages1[E])).ToList(); if (filtered1.Count() == 0) { ok = false; dump.AppendFormat("{0} not found in {1}{2}", descr, descr1, Environment.NewLine); } else { FindEventResult ev1 = filtered1.FirstOrDefault(E => HaveTheSamePayload(ev2, E)); if (ev1 == null) { ok = false; dump.AppendFormat("For {0} (or one of them) in {1}, no event with the same Data can be found in {2}{3}", descr, descr2, descr1, Environment.NewLine); } } } } // compare event in intersection // StartStateEvent // in Event: ProducerReference, SubscriptionReference (should not both be empty?) // message items... foreach (FindEventResult ev1 in intersection.Keys) { bool localOk = true; StringBuilder sb = new StringBuilder(getDescription(ev1, GetTopicElement(ev1).Value)); sb.AppendLine(" is different: "); FindEventResult ev2 = intersection[ev1]; if (ev1.StartStateEvent != ev2.StartStateEvent) { sb.AppendLine("StartStateEvent fields don't match"); } // ProducerReference ? if (ev1.Event.ProducerReference != null && ev2.Event.ProducerReference != null) { if (ev1.Event.ProducerReference.Address.Value != ev2.Event.ProducerReference.Address.Value) { localOk = false; sb.AppendFormat("Event.ProducerReference fields don't match {0}", Environment.NewLine); } } else { if (ev1.Event.ProducerReference != null) { localOk = false; sb.AppendFormat("Event.ProducerReference is missing in message from {0}{1}", descr2, Environment.NewLine); } if (ev2.Event.ProducerReference != null) { localOk = false; sb.AppendFormat("Event.ProducerReference is missing in message from {0}{1}", descr1, Environment.NewLine); } } // SubscriptionReference (?) if (ev1.Event.SubscriptionReference != null && ev2.Event.SubscriptionReference != null) { if (ev1.Event.SubscriptionReference.Address.Value != ev2.Event.SubscriptionReference.Address.Value) { localOk = false; sb.AppendFormat("Event.SubscriptionReference fields don't match {0}", Environment.NewLine); } } else { if (ev1.Event.SubscriptionReference != null) { localOk = false; sb.AppendFormat("Event.SubscriptionReference is missing in message from {0}{1}", descr2, Environment.NewLine); } if (ev2.Event.SubscriptionReference != null) { localOk = false; sb.AppendFormat("Event.SubscriptionReference is missing in message from {0}{1}", descr1, Environment.NewLine); } } // Message items //if (ev1.Event.Message != null && ev2.Event.Message != null) //{ // Dictionary<string, string> items1 = GetMessageSimpleItems(ev1.Event.Message); // Dictionary<string, string> items2 = GetMessageSimpleItems(ev2.Event.Message); // List<string> common = new List<string>(); // foreach (string key in items1.Keys) // { // if (!items2.ContainsKey(key)) // { // localOk = false; // sb.AppendFormat("SimpleItem with name='{0}' not found in message from {1}{2}", key, descr2, // Environment.NewLine); // } // else // { // common.Add(key); // } // } // foreach (string key in items2.Keys) // { // if (!items2.ContainsKey(key)) // { // localOk = false; // sb.AppendFormat("SimpleItem with name='{0}' not found in message from {1}{2}", key, descr1, // Environment.NewLine); // } // } // foreach (string key in common) // { // if (items1[key] != items2[key]) // { // localOk = false; // sb.AppendFormat("SimpleItem elements with name='{0}' have different values {1}", key, Environment.NewLine); // } // } //} //else //{ // if (ev1.Event.Message == null) // { // localOk = false; // sb.AppendLine(string.Format("Message field is missing in structure from {0}", descr1)); // } // if (ev2.Event.Message == null) // { // localOk = false; // sb.AppendLine(string.Format("Message field is missing in structure from {0}", descr2)); // } //} if (!localOk) { ok = false; dump.Append(sb.ToString()); } } Assert(ok, dump.ToStringTrimNewLine(), "Check that events lists are the same"); }
void GenerateEvents() { XmlDocument doc = new XmlDocument(); _events = new List <FindEventResult>(); foreach (RecordingInformation recording in Recordings) { foreach (TrackInformation track in recording.Track) { { FindEventResult dataAppeared = GenerateTrackEvent(recording, track); dataAppeared.Time = track.DataFrom; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Track/State"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); dataAppeared.Event.Topic.Xmlns = xmlns; dataAppeared.Event.Topic.Any = new XmlNode[] { topic }; dataAppeared.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); XmlElement data = doc.CreateElement("tt", "Data", "http://www.onvif.org/ver10/schema"); dataAppeared.Event.Message.AppendChild(data); data.AppendChild(CreateSimpleItemElement(doc, "IsDataPresent", "True")); if (_eventsGenerationCrashTest) { dataAppeared.StartStateEvent = true; dataAppeared.Event.ProducerReference = new EndpointReferenceType() { Address = new AttributedURIType() { Value = "http://localhost/dut/events.asmx" } }; } _events.Add(dataAppeared); } { FindEventResult dataSaved = GenerateTrackEvent(recording, track); dataSaved.Time = track.DataTo; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Track/State"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); dataSaved.Event.Topic.Xmlns = xmlns; dataSaved.Event.Topic.Any = new XmlNode[] { topic }; dataSaved.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); XmlElement data = doc.CreateElement("tt", "Data", "http://www.onvif.org/ver10/schema"); dataSaved.Event.Message.AppendChild(data); data.AppendChild(CreateSimpleItemElement(doc, "IsDataPresent", "False")); data.AppendChild(CreateSimpleItemElement(doc, "IsDataPresent", "True")); //if (_eventsGenerationCrashTest) //{ // dataSaved.Event.ProducerReference = null; //} //else //{ // dataSaved.Event.ProducerReference = new EndpointReferenceType() { Address = new AttributedURIType() { Value = "http://localhost/dut/events1.asmx" } }; //} _events.Add(dataSaved); } if (_eventsGenerationCrashTest) { FindEventResult parametersEvent = GenerateTrackEvent(recording, track); parametersEvent.Time = recording.EarliestRecording; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Track/VideoParameters"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); parametersEvent.Event.Topic.Xmlns = xmlns; parametersEvent.Event.Topic.Any = new XmlNode[] { topic }; parametersEvent.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); _events.Add(parametersEvent); //if (_eventsGenerationCrashTest) //{ // parametersEvent.Event.SubscriptionReference = new EndpointReferenceType() { Address = new AttributedURIType() { Value = "http://localhost/dut/events.asmx" } }; //} //else //{ // parametersEvent.Event.SubscriptionReference = new EndpointReferenceType() { Address = new AttributedURIType() { Value = "http://localhost/dut/events1.asmx" } }; //} } if (!_eventsGenerationCrashTest) { FindEventResult parametersEvent = GenerateTrackEvent(recording, track); parametersEvent.Time = recording.EarliestRecording; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Track/AudioParameters"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); parametersEvent.Event.Topic.Xmlns = xmlns; parametersEvent.Event.Topic.Any = new XmlNode[] { topic }; parametersEvent.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); _events.Add(parametersEvent); //if (_eventsGenerationCrashTest) //{ // parametersEvent.Event.SubscriptionReference = new EndpointReferenceType() { Address = new AttributedURIType() { Value = "http://localhost/dut/events.asmx" } }; //} } } // foreach Track { FindEventResult recordingStarted = GenerateTrackEvent(recording, null); recordingStarted.Time = recording.EarliestRecording; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Recording/State"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); recordingStarted.Event.Topic.Xmlns = xmlns; recordingStarted.Event.Topic.Any = new XmlNode[] { topic }; recordingStarted.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); XmlElement data = doc.CreateElement("tt", "Data", "http://www.onvif.org/ver10/schema"); recordingStarted.Event.Message.AppendChild(data); data.AppendChild(CreateSimpleItemElement(doc, "IsRecording", "True")); data.AppendChild(CreateSimpleItemElement(doc, "IsRecording", "True")); //if (_eventsGenerationCrashTest) //{ // data.AppendChild(CreateSimpleItemElement(doc, "SomeValue", "True")); //} _events.Add(recordingStarted); } { FindEventResult recordingfinished = GenerateTrackEvent(recording, null); recordingfinished.Time = recording.LatestRecording; XmlText topic = doc.CreateTextNode("tns1:RecordingHistory/Recording/State"); System.Xml.Serialization.XmlSerializerNamespaces xmlns = new System.Xml.Serialization.XmlSerializerNamespaces(); xmlns.Add("tns1", "http://www.onvif.org/ver10/topics"); recordingfinished.Event.Topic.Xmlns = xmlns; recordingfinished.Event.Topic.Any = new XmlNode[] { topic }; recordingfinished.Event.Message = doc.CreateElement("tt:Message", "http://docs.oasis-open.org/wsn/b-2"); XmlElement data = doc.CreateElement("tt", "Data", "http://www.onvif.org/ver10/schema"); recordingfinished.Event.Message.AppendChild(data); data.AppendChild(CreateSimpleItemElement(doc, "IsRecording", "False")); //if (_eventsGenerationCrashTest) //{ // data.AppendChild(CreateSimpleItemElement(doc, "SomeValue", "True")); //} //else //{ // data.AppendChild(CreateSimpleItemElement(doc, "SomeValue", "False")); //} _events.Add(recordingfinished); } } }
public static bool IsOnvifMessage(FindEventResult msg) { return(IsOnvifMessage(msg.Event)); }
void ValidateTrackEvents(RecordingInformation recording, TrackInformation track, IEnumerable <FindEventResult> results, Dictionary <FindEventResult, XmlElement> elements, bool checkEdges) { { Func <FindEventResult, bool> eventCheck = (E => { bool topicMatches = CheckEventTopic(E, elements[E], "tns1:RecordingHistory/Track/State", TNS1NAMESPACE); return(topicMatches); }); List <FindEventResult> filtered = results.Where(E => eventCheck(E) && E.TrackToken == track.TrackToken).OrderBy(E => E.Time).ToList(); bool dataPresentOk = true; bool?lastDataPresent = null; if (checkEdges) { lastDataPresent = false; // checkEdges = false means that interval is narrowed and virtual events are sent // in this case 1 event is OK Assert(filtered.Count >= 2, string.Format( "Not enough events with topic=tns1:RecordingHistory/Track/State, RecordingToken='{0}' for track '{1}' found in the response", recording.RecordingToken, track.TrackToken), string.Format("Check that at least two events with topic tns1:RecordingHistory/Track/State are present for track '{0}'", track.TrackToken)); } StringBuilder dump = new StringBuilder(); for (int i = 0; i < filtered.Count; i++) { FindEventResult ev = filtered[i]; XmlElement message = ev.Event.Message; string value = GetSimpleItem(message, "IsDataPresent"); if (value == null) { dataPresentOk = false; dump.AppendFormat( string.Format( "IsDataPresent value not found for event with RecordingToken='{0}', Time='{1}'{2}", ev.RecordingToken, ev.Time.StdDateTimeToString(), Environment.NewLine)); } else { bool dataPresent; bool attrOk = bool.TryParse(value, out dataPresent); if (!attrOk) { dataPresentOk = false; dump.AppendFormat( string.Format( "IsDataPresent value for event with RecordingToken='{0}', Time='{1}' is incorrect ({2}){3}", ev.RecordingToken, ev.Time.StdDateTimeToString(), value, Environment.NewLine)); } else { if (ev.StartStateEvent) { continue; } if (lastDataPresent.HasValue) { if (dataPresent == lastDataPresent) { dataPresentOk = false; if (i == 0) { dump.AppendFormat( string.Format( "IsDataPresent value for first event with RecordingToken='{0}', Time='{1}' is false {2}", ev.RecordingToken, ev.Time.StdDateTimeToString(), Environment.NewLine)); } else { dump.AppendFormat( string.Format( "IsDataPresent value for event with RecordingToken='{0}', Time='{1}' is {2} while previous is also {2}{3}", ev.RecordingToken, ev.Time.StdDateTimeToString(), dataPresent, Environment.NewLine)); } } } lastDataPresent = dataPresent; } } } Assert(dataPresentOk, dump.ToStringTrimNewLine(), "Check that IsDataPresent values in events are correct"); } }
void ValidateRecordingEventsSequence(RecordingInformation recording, IEnumerable <FindEventResult> results, Dictionary <FindEventResult, XmlElement> elements, bool checkEdges) { Func <FindEventResult, bool> eventCheck; // // recording events // eventCheck = (E => { bool topicMatches = CheckEventTopic(E, elements[E], "tns1:RecordingHistory/Recording/State", TNS1NAMESPACE); return(topicMatches); }); // select Recording/State events List <FindEventResult> filtered = results.Where(eventCheck).OrderBy(E => E.Time).ToList(); // check that there is no events for other recordings List <FindEventResult> nonmatching = filtered.Where(E => E.RecordingToken != recording.RecordingToken).ToList(); Assert(nonmatching.Count == 0, "Event with topic 'tns1:RecordingHistory/Recording/State' for other recordings found", string.Format( "Check that all events with topic 'tns1:RecordingHistory/Recording/State' relate to recording '{0}'", recording.RecordingToken)); bool isRecordingOk = true; bool?lastIsRecording = null; if (checkEdges) { lastIsRecording = false; // when checkEdges = false (narrowed interval), 1 event is OK (only virtual event) Assert(filtered.Count >= 2, "Not enough tns1:RecordingHistory/Recording/State events found", "Check that at least two events with topic tns1:RecordingHistory/Recording/State found"); } StringBuilder dump = new StringBuilder(); for (int i = 0; i < filtered.Count; i++) { FindEventResult ev = filtered[i]; XmlElement message = ev.Event.Message; string value = GetSimpleItem(message, "IsRecording"); if (value == null) { isRecordingOk = false; dump.AppendFormat( string.Format( "IsRecording value not found for event with RecordingToken='{0}', Time='{1}'{2}", ev.RecordingToken, ev.Time.StdDateTimeToString(), Environment.NewLine)); } else { bool isRecording; bool attrOk = bool.TryParse(value, out isRecording); if (!attrOk) { isRecordingOk = false; dump.AppendFormat( string.Format( "IsRecording value for event with RecordingToken='{0}', Time='{1}' is incorrect ({2}){3}", ev.RecordingToken, ev.Time.StdDateTimeToString(), value, Environment.NewLine)); } else { if (ev.StartStateEvent) { continue; } if (lastIsRecording.HasValue) { if (isRecording == lastIsRecording.Value) { isRecordingOk = false; if (i == 0) { dump.AppendFormat( string.Format( "IsRecording value for first event with RecordingToken='{0}', Time='{1}' is false {2}", ev.RecordingToken, ev.Time.StdDateTimeToString(), Environment.NewLine)); } else { dump.AppendFormat( string.Format( "IsRecording value for event with RecordingToken='{0}', Time='{1}' is {2} while previous is also {2}{3}", ev.RecordingToken, ev.Time.StdDateTimeToString(), isRecording, Environment.NewLine)); } } } lastIsRecording = isRecording; } } } Assert(isRecordingOk, dump.ToStringTrimNewLine(), "Check that IsRecording values in events are correct"); }