3 // Rafael Mizrahi <rafim@mainsoft.com>
4 // Erez Lotan <erezl@mainsoft.com>
5 // Vladimir Krasnov <vladimirk@mainsoft.com>
8 // Copyright (c) 2002-2005 Mainsoft Corporation.
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
36 namespace MonoTests.stand_alone.WebHarness
38 public abstract class XmlComparableTest
40 public abstract XmlDocument GetTestXml(TestInfo testInfo);
41 public abstract bool XmlCompare(XmlDocument d1, XmlDocument d2, bool ignoreAlmost);
44 public class HtmlDiff : XmlComparableTest
46 private string _testsBaseUrl = "";
47 private string _ignoreListFile = "";
48 private XmlDocument _xmlIgnoreList = null;
49 private string _compareStatus = "";
55 public string TestsBaseUrl
57 get {return _testsBaseUrl;}
58 set {_testsBaseUrl = value;}
60 public string IgnoreListFile
62 get {return _ignoreListFile;}
63 set {_ignoreListFile = value;}
65 public string CompareStatus
67 get {return _compareStatus.ToString();}
70 public override XmlDocument GetTestXml(TestInfo testInfo)
72 return BuildXml( GetSubTests( GetUrl(testInfo.Url) ), testInfo );
75 public override bool XmlCompare(XmlDocument d1, XmlDocument d2, bool ignoreAlmost)
77 XmlComparer comparer = new XmlComparer();
78 if (ignoreAlmost == false)
83 bool c = comparer.AreEqual(d1, d2);
84 _compareStatus = comparer.LastCompare;
88 //============================================================================
91 private string GetUrl(string url)
95 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_testsBaseUrl + url);
96 request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";
97 request.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*";
99 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
101 Stream responseStream = response.GetResponseStream();
102 StreamReader sr = new StreamReader(responseStream);
104 string s = sr.ReadToEnd();
111 Console.WriteLine("Cannot retrieve document from url " + _testsBaseUrl + url);
112 Console.WriteLine(e.Message);
118 private ArrayList GetSubTests(string s)
120 ArrayList subTestList = new ArrayList();
121 int startIndex = SkipViewstate (s);
122 string subTest = FindSubTest(s, startIndex);
124 while (subTest != "")
126 if (subTest.ToLower().IndexOf("ghtsubtest") != -1)
127 subTestList.Add(subTest);
128 subTest = FindSubTest(s, s.IndexOf(subTest) + subTest.Length);
133 #region "Sub Test extraction routines"
134 private string FindSubTest(string s, int startIndex)
136 int tagBeginCount = 0;
137 int stringPosition = startIndex;
140 tagPosition = GetNextDivPosition(s, stringPosition);
141 if (tagPosition == -1) return "";
143 if (isBeginTag(s, tagPosition))
148 startIndex = tagPosition;
150 while (tagBeginCount > 0)
152 stringPosition = tagPosition + 1;
153 tagPosition = GetNextDivPosition(s, stringPosition);
154 if (tagPosition == -1) return "";
156 if (isBeginTag(s, tagPosition))
162 return s.Substring(startIndex, tagPosition - startIndex + 6);
165 private int GetNextDivPosition(string s, int startIndex)
167 int tagBeginPos = GetBeginDivPosition(s, startIndex);
168 int tagEndPos = GetEndDivPosition(s, startIndex);
170 if ((tagBeginPos == -1) && (tagEndPos == -1)) return -1;
171 if ((tagBeginPos > 0) && (tagEndPos > 0))
173 if (tagBeginPos < tagEndPos)
180 if (tagBeginPos > tagEndPos)
187 private int SkipViewstate (string s)
189 int start = s.IndexOf ("<div id");
190 int startVS = s.IndexOf ("<div>");
191 int vs = s.IndexOf ("VIEWSTATE");
192 int endVS = s.IndexOf ("</div>");
194 if (startVS > 0 && startVS < vs && vs < endVS && startVS < start)
200 private int GetBeginDivPosition(string s, int startIndex)
202 return s.IndexOf("<div id", startIndex);
205 private int GetEndDivPosition(string s, int startIndex)
207 return s.IndexOf("</div", startIndex);
210 private bool isBeginTag(string tag, int pos)
212 return tag.Substring(pos).StartsWith("<div");
214 private bool isEndTag(string tag, int pos)
216 return tag.Substring(pos).StartsWith("</div");
220 private XmlDocument BuildXml(ArrayList subTests, TestInfo ti)
222 StringBuilder xmltext = new StringBuilder();
223 xmltext.Append("<TestResults name=\"" + ti.Name + "\">");
224 foreach(string st in subTests)
228 xmltext.Append("</TestResults>");
230 XmlDocument r = new XmlDocument();
231 r.LoadXml(HtmltoXml(xmltext.ToString()));
235 private string HtmltoXml(string html)
237 HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
240 StringBuilder fixedxml = new StringBuilder();
241 StringWriter sw = new StringWriter(fixedxml);
245 StringBuilder tempxml = new StringBuilder();
246 StringWriter tsw = new StringWriter(tempxml);
248 doc.OptionOutputAsXml = true;
251 // fix style attribute
252 // the reason is that style attribute name-value pairs come in different order
254 // Here I will sort the values of style attribute
255 XmlDocument tempDoc = new XmlDocument();
256 tempDoc.LoadXml(tempxml.ToString());
258 XmlNodeList allNodes = tempDoc.SelectNodes("//*");
259 foreach (XmlNode n in allNodes)
261 if (n.Attributes["style"] != null)
263 string att = n.Attributes["style"].Value;
264 string [] style = att.Trim(new char[]{' ', ';'}).Split(';');
266 for (int styleIndex=0; styleIndex<style.Length; styleIndex++)
268 style[styleIndex] = FixStyleNameValue(style[styleIndex]);
271 n.Attributes["style"].Value = string.Join(";", style);
278 Console.WriteLine("Error parsing html response...");
279 Console.WriteLine("Test case aborted");
280 return "<TestCaseAborted></TestCaseAborted>";
282 return fixedxml.ToString();
285 private string FixStyleNameValue(string nameValue)
287 string [] nv = nameValue.Split(':');
288 // value may contain spaces in case of
289 // multiple values for one key
290 string [] nvalue = nv[1].Trim().Split(' ');
292 nv[1] = string.Join(" ", nvalue);
293 return nv[0].Trim().ToLower() + ":" + nv[1].Trim().ToLower();
296 private void DoAlmost(XmlDocument xmlDocument)
298 XmlNode XmlIgnoreNode;
299 IEnumerator xmlIgnoreEnum;
301 if (_xmlIgnoreList == null)
303 _xmlIgnoreList = new XmlDocument();
304 _xmlIgnoreList.Load(_ignoreListFile);
307 // Remove by Id or Name
308 // search by tag and if id or name match, remove all attributes
309 // must be the first almost since the following almost delete the id and name
310 xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/RemoveById").GetEnumerator();
311 while (xmlIgnoreEnum.MoveNext())
313 XmlNodeList DocNodeList;
314 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
315 DocNodeList = xmlDocument.GetElementsByTagName("*");
316 if (DocNodeList != null)
318 foreach (XmlElement tmpXmlElement in DocNodeList)
320 foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
322 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower())
324 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
326 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name].Value.ToLower() == tmpIgnoreAttr.Value.ToLower())
328 tmpXmlElement.RemoveAllAttributes();
336 // remove ignored attributes
337 // search for tag and remove it's attributes
338 xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/IgnoreList").GetEnumerator(); //FirstChild.GetEnumerator
339 while (xmlIgnoreEnum.MoveNext())
341 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
342 XmlNodeList DocNodeList;
343 //clean specific element
345 DocNodeList = xmlDocument.GetElementsByTagName("*");
346 if (DocNodeList != null)
348 foreach (XmlElement tmpXmlElement in DocNodeList)
350 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower())
352 foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
354 tmpXmlElement.RemoveAttribute(tmpIgnoreAttr.Name);
361 // clean javascript attribute value
362 xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/CleanJavaScriptValueList").GetEnumerator(); //FirstChild.GetEnumerator
363 while (xmlIgnoreEnum.MoveNext())
365 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
366 XmlNodeList DocNodeList;
367 //clean Java Script attribute values
368 DocNodeList = xmlDocument.GetElementsByTagName("*");
369 if (DocNodeList != null)
371 foreach (XmlElement tmpXmlElement in DocNodeList)
373 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower())
375 foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
377 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
379 if ((tmpXmlElement.Attributes [tmpIgnoreAttr.Name].Value.ToLower ().IndexOf ("javascript") >= 0) ||
\r
380 (tmpXmlElement.Attributes [tmpIgnoreAttr.Name].Value.ToLower ().IndexOf ("dopostback") >= 0)) {
\r
381 tmpXmlElement.SetAttribute (tmpIgnoreAttr.Name, "");
\r
389 // remove whole tags
\r
390 ArrayList tagsToRemove = new ArrayList ();
\r
391 xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode ("Almost/RemoveTags").GetEnumerator (); //FirstChild.GetEnumerator
392 while (xmlIgnoreEnum.MoveNext())
394 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
395 XmlNodeList DocNodeList;
396 //clean Java Script attribute values
397 DocNodeList = xmlDocument.GetElementsByTagName("*");
398 if (DocNodeList != null)
400 foreach (XmlElement tmpXmlElement in DocNodeList)
402 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower())
404 tagsToRemove.Add (tmpXmlElement);
\r
405 //tmpXmlElement.ParentNode.RemoveChild (tmpXmlElement);
410 if (tagsToRemove.Count > 0) {
\r
411 foreach (XmlElement el in tagsToRemove) {
\r
413 el.ParentNode.RemoveChild (el);
\r