New test.
[mono.git] / mcs / class / System.Web / Test / mainsoft / MainsoftWebTest / NunitWebTest.cs
1 //
2 // Authors:
3 //   Rafael Mizrahi   <rafim@mainsoft.com>
4 //   Erez Lotan       <erezl@mainsoft.com>
5 //   Vladimir Krasnov <vladimirk@mainsoft.com>
6 //   
7 // 
8 // Copyright (c) 2002-2005 Mainsoft Corporation.
9 // 
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:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
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.
28 //
29
30
31
32 using System;
33 using System.IO;
34 using System.Xml;
35 using System.Net;
36 using System.Text;
37 using System.Collections;
38 using System.Reflection;
39 using NUnit.Framework;
40
41 namespace MonoTests.stand_alone.WebHarness
42 {
43         public class HtmlDiff
44         {
45                 public const string BEGIN_TAG = "begint";
46                 public const string END_TAG = "endt";
47
48                 private XmlDocument _xmlIgnoreList = null;
49                 private string _compareStatus = "";
50                 private static string _compareActual = "";
51                 private static string _compareExpect = "";
52                 private string _ignoreListFile = "";
53
54                 
55
56                 public HtmlDiff()
57                 {
58                 }
59
60                 public string IgnoreListFile
61                 {
62                         get {return _ignoreListFile;}
63                         set {_ignoreListFile = value;}
64                 }
65
66                 public string CompareStatus
67                 {
68                         get {return _compareStatus.ToString();}
69                 }
70
71                 public static string GetControlFromPageHtml (string str)
72                 {
73                         if (str == null || str == string.Empty)
74                                 throw new ArgumentException ("internal error: str is null or empty");
75                         int beginPos = str.IndexOf (BEGIN_TAG);
76                         int endPos = str.IndexOf (END_TAG);
77                         if (beginPos == -1)
78                                 throw new Exception ("internal error: BEGIN_TAG is missing. Full source: "+str);
79                         if (endPos == -1)
80                                 throw new Exception ("internal error: END_TAG is missing. Full source: "+str);
81                                 
82                         StringBuilder sb = new StringBuilder ();
83                         sb.Append (str.Substring (beginPos + BEGIN_TAG.Length, endPos - beginPos - BEGIN_TAG.Length));
84                         return sb.ToString ();
85                 }
86
87                 public static void AssertAreEqual (string origin, string derived, string msg)
88                 {
89                         bool test = false;\r
90                         try {\r
91                                 test = HtmlComparer (origin, derived);\r
92                         }\r
93                         catch (Exception e) {\r
94                                 //swallow e when there is XML error and fallback\r
95                                 //to the text comparison\r
96                         }
97                         if (!test) {\r
98                                 Assert.AreEqual (_compareExpect, _compareActual, msg);
99                         }
100                 }\r
101 \r
102                 private static bool HtmlComparer (string origin, string derived)
103                 {
104                         XmlDocument or = new XmlDocument ();
105                         MonoTests.stand_alone.WebHarness.HtmlDiff helper = new MonoTests.stand_alone.WebHarness.HtmlDiff ();
106                         or.LoadXml (helper.HtmltoXml (origin));
107                         XmlDocument dr = new XmlDocument ();
108                         dr.LoadXml (helper.HtmltoXml (derived));
109                         return helper.XmlCompare (or, dr, false);
110                 }
111
112                 private bool XmlCompare(XmlDocument expected, XmlDocument actual, bool ignoreAlmost)
113                 {
114                         XmlComparer comparer = new XmlComparer();
115                         if (ignoreAlmost == false)
116                         {
117                                 DoAlmost(expected);
118                                 DoAlmost(actual);
119                         }
120                         bool c = comparer.AreEqual(expected, actual);
121                         _compareStatus = comparer.LastCompare;
122                         _compareActual = comparer.Actual;
123                         _compareExpect = comparer.Expected;
124                         return c;
125                 }\r
126 \r
127                 public string HtmltoXml (string html) //throws XmlException\r
128                 {\r
129                         HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument ();\r
130                         doc.LoadHtml (html.Trim (new char[] { '\r', '\n', ' ' })); // bug in HtmlAgilityPack\r
131 \r
132                         StringBuilder fixedxml = new StringBuilder ();\r
133                         StringWriter sw = new StringWriter (fixedxml);\r
134 \r
135                         StringBuilder tempxml = new StringBuilder ();\r
136                         StringWriter tsw = new StringWriter (tempxml);\r
137 \r
138                         doc.OptionOutputAsXml = true;\r
139                         doc.Save (tsw);\r
140 \r
141                         // fix style attribute\r
142                         // the reason is that style attribute name-value pairs come in different order\r
143                         // in .NET and GH\r
144                         // Here I will sort the values of style attribute\r
145                         XmlDocument tempDoc = new XmlDocument ();\r
146                         tempDoc.LoadXml (tempxml.ToString ());\r
147 \r
148                         XmlNodeList allNodes = tempDoc.SelectNodes ("//*");\r
149                         foreach (XmlNode n in allNodes) {\r
150                                 if (n.Attributes["style"] != null) {\r
151                                         string att = n.Attributes["style"].Value;\r
152                                         string[] style = att.Trim (new char[] { ' ', ';' }).Split (';');\r
153 \r
154                                         for (int styleIndex = 0; styleIndex < style.Length; styleIndex++) {\r
155                                                 style[styleIndex] = FixStyleNameValue (style[styleIndex]);\r
156                                         }\r
157                                         Array.Sort (style);\r
158                                         n.Attributes["style"].Value = string.Join (";", style);\r
159                                 }\r
160                         }\r
161                         tempDoc.Save (sw);\r
162                         return fixedxml.ToString ();\r
163                 }
164
165                 private string FixStyleNameValue(string nameValue)
166                 {
167                         string [] nv = nameValue.Split(':');
168                         // value may contain spaces in case of
169                         // multiple values for one key
170                         string [] nvalue = nv[1].Trim().Split(' ');
171                         Array.Sort(nvalue);
172                         nv[1] = string.Join(" ", nvalue);
173                         return nv[0].Trim().ToLower() + ":" + nv[1].Trim().ToLower();
174                 }
175
176                 private void DoAlmost(XmlDocument xmlDocument)
177                 {
178                         XmlNode XmlIgnoreNode;
179                         IEnumerator xmlIgnoreEnum;
180
181
182                         if (_xmlIgnoreList == null)
183                         {
184                                 _xmlIgnoreList = new XmlDocument();
185                                 string xml;\r
186 \r
187                                 Stream source = Assembly.GetExecutingAssembly ()\r
188                                         .GetManifestResourceStream ("HtmlCompare.nunitweb_config.xml");\r
189                                 if (source == null) {\r
190                                         source = Assembly.GetExecutingAssembly ()\r
191                                         .GetManifestResourceStream ("nunitweb_config.xml");\r
192                                 }\r
193                                                                 \r
194                                 try {\r
195                                         using (StreamReader sr = new StreamReader (source))\r
196                                                 xml = sr.ReadToEnd ();\r
197                                 }\r
198                                 finally {\r
199                                         source.Close ();\r
200                                 }\r
201                                 \r
202                                 _xmlIgnoreList.LoadXml (xml);
203                         }
204                         // Remove by Id or Name
205                         // search by tag and if id or name match, remove all attributes
206                         // must be the first almost since the following almost delete the id and name
207                         
208                         xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/RemoveById").GetEnumerator();
209                         while (xmlIgnoreEnum.MoveNext())
210                         {
211                                 XmlNodeList DocNodeList;
212                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
213                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
214                                 if (DocNodeList != null)
215                                 {
216                                         foreach (XmlElement tmpXmlElement in DocNodeList)
217                                         {
218                                                 foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
219                                                 {
220                                                         if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
221                                                         {
222                                                                 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
223                                                                 {
224                                                                         if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name].Value.ToLower() == tmpIgnoreAttr.Value.ToLower())
225                                                                         {
226                                                                                 tmpXmlElement.RemoveAllAttributes();
227                                                                         }
228                                                                 }
229                                                         }
230                                                 }
231                                         }
232                                 }       
233                         }
234                         // remove ignored attributes
235                         // search for tag and remove it's attributes
236                         xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/IgnoreList").GetEnumerator(); //FirstChild.GetEnumerator
237                         while (xmlIgnoreEnum.MoveNext())
238                         {
239                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
240                                 XmlNodeList DocNodeList;
241                                 //clean specific element
242
243                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
244                                 if (DocNodeList != null)
245                                 {
246                                         foreach (XmlElement tmpXmlElement in DocNodeList)
247                                         {
248                                                 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
249                                                 {
250                                                         foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
251                                                         {
252                                                                 tmpXmlElement.RemoveAttribute(tmpIgnoreAttr.Name);
253                                                         }
254                                                 }
255                                         }
256                                 }
257                         }
258
259                         // clean javascript attribute value
260                         xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/CleanJavaScriptValueList").GetEnumerator(); //FirstChild.GetEnumerator
261                         while (xmlIgnoreEnum.MoveNext())
262                         {
263                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
264                                 XmlNodeList DocNodeList;
265                                 //clean Java Script attribute values
266                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
267                                 if (DocNodeList != null)
268                                 {
269                                         foreach (XmlElement tmpXmlElement in DocNodeList)
270                                         {
271                                                 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
272                                                 {
273                                                         foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
274                                                         {
275                                                                 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
276                                                                 {
277                                                                         if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name].Value.ToLower().IndexOf("javascript") >= 0 )
278                                                                         {
279                                                                                 tmpXmlElement.SetAttribute(tmpIgnoreAttr.Name, "");
280                                                                         }
281                                                                 }
282                                                         }
283                                                 }
284                                         }
285                                 }
286                         }
287                 }
288         }
289 }