for TARGET_J2EE only:
[mono.git] / mcs / class / System.Web / Test / mainsoft / MainsoftWebTest / WebTest.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 using System;
30 using System.IO;
31 using System.Xml;
32 using System.Net;
33 using System.Text;
34 using System.Collections;
35
36 namespace MonoTests.stand_alone.WebHarness
37 {
38         public abstract class XmlComparableTest
39         {
40                 public abstract XmlDocument GetTestXml(TestInfo testInfo);
41                 public abstract bool XmlCompare(XmlDocument d1, XmlDocument d2, bool ignoreAlmost);
42         }
43
44         public class HtmlDiff : XmlComparableTest
45         {
46                 private string _testsBaseUrl = "";
47                 private string _ignoreListFile = "";
48                 private XmlDocument _xmlIgnoreList = null;
49                 private string _compareStatus = "";
50
51                 public HtmlDiff()
52                 {
53                 }
54
55                 public string TestsBaseUrl
56                 {
57                         get {return _testsBaseUrl;}
58                         set {_testsBaseUrl = value;}
59                 }
60                 public string IgnoreListFile
61                 {
62                         get {return _ignoreListFile;}
63                         set {_ignoreListFile = value;}
64                 }
65                 public string CompareStatus
66                 {
67                         get {return _compareStatus.ToString();}
68                 }
69
70                 public override XmlDocument GetTestXml(TestInfo testInfo)
71                 {
72                         return BuildXml( GetSubTests( GetUrl(testInfo.Url) ), testInfo );
73                 }
74
75                 public override bool XmlCompare(XmlDocument d1, XmlDocument d2, bool ignoreAlmost)
76                 {
77                         XmlComparer comparer = new XmlComparer();
78                         if (ignoreAlmost == false)
79                         {
80                                 DoAlmost(d1);
81                                 DoAlmost(d2);
82                         }
83                         bool c = comparer.AreEqual(d1, d2);
84                         _compareStatus = comparer.LastCompare;
85                         return c;
86                 }
87
88                 //============================================================================
89                 //
90
91                 private string GetUrl(string url)
92                 {
93                         try
94                         {
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, */*";
98
99                                 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
100
101                                 Stream responseStream = response.GetResponseStream();
102                                 StreamReader sr = new StreamReader(responseStream);
103
104                                 string s = sr.ReadToEnd();
105                                 sr.Close();
106
107                                 return s;
108                         }
109                         catch(Exception e)
110                         {
111                                 Console.WriteLine("Cannot retrieve document from url " + _testsBaseUrl + url);
112                                 Console.WriteLine(e.Message);
113                         }
114
115                         return "";
116                 }
117
118                 private ArrayList GetSubTests(string s)
119                 {
120                         ArrayList subTestList = new ArrayList();
121                         int startIndex = SkipViewstate (s);
122                         string subTest = FindSubTest(s, startIndex);
123                         
124                         while (subTest != "")
125                         {
126                                 if (subTest.ToLower().IndexOf("ghtsubtest") != -1)
127                                         subTestList.Add(subTest);
128                                 subTest = FindSubTest(s, s.IndexOf(subTest) + subTest.Length);
129                         }
130
131                         return subTestList;
132                 }
133                 #region "Sub Test extraction routines"
134                 private string FindSubTest(string s, int startIndex)
135                 {
136                         int tagBeginCount = 0;
137                         int stringPosition = startIndex;
138                         int tagPosition = 0;
139
140                         tagPosition = GetNextDivPosition(s, stringPosition);
141                         if (tagPosition == -1) return "";
142
143                         if (isBeginTag(s, tagPosition))
144                                 tagBeginCount++;
145                         else
146                                 return "";
147
148                         startIndex = tagPosition;
149
150                         while (tagBeginCount > 0)
151                         {
152                                 stringPosition = tagPosition + 1;
153                                 tagPosition = GetNextDivPosition(s, stringPosition);
154                                 if (tagPosition == -1) return "";
155
156                                 if (isBeginTag(s, tagPosition))
157                                         tagBeginCount++;
158                                 else
159                                         tagBeginCount--;
160                         }
161
162                         return s.Substring(startIndex, tagPosition - startIndex + 6);
163                 }
164
165                 private int GetNextDivPosition(string s, int startIndex)
166                 {
167                         int tagBeginPos = GetBeginDivPosition(s, startIndex);
168                         int tagEndPos = GetEndDivPosition(s, startIndex);
169
170                         if ((tagBeginPos == -1) && (tagEndPos == -1)) return -1;
171                         if ((tagBeginPos > 0) && (tagEndPos > 0))
172                         {
173                                 if (tagBeginPos < tagEndPos)
174                                         return tagBeginPos;
175                                 else
176                                         return tagEndPos;
177                         }
178                         else
179                         {
180                                 if (tagBeginPos > tagEndPos)
181                                         return tagBeginPos;
182                                 else
183                                         return tagEndPos;
184                         }
185                 }
186
187                 private int SkipViewstate (string s)
188                 {
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>");
193
194                         if (startVS > 0 && startVS < vs && vs < endVS && startVS < start)
195                                 return endVS + 7;
196
197                         return 0;
198                 }
199
200                 private int GetBeginDivPosition(string s, int startIndex)
201                 {
202                         return s.IndexOf("<div id", startIndex);
203                 }
204
205                 private int GetEndDivPosition(string s, int startIndex)
206                 {
207                         return s.IndexOf("</div", startIndex);
208                 }
209
210                 private bool isBeginTag(string tag, int pos)
211                 {
212                         return tag.Substring(pos).StartsWith("<div");
213                 }
214                 private bool isEndTag(string tag, int pos)
215                 {
216                         return tag.Substring(pos).StartsWith("</div");
217                 }
218                 #endregion
219
220                 private XmlDocument BuildXml(ArrayList subTests, TestInfo ti)
221                 {
222                         StringBuilder xmltext = new StringBuilder();
223                         xmltext.Append("<TestResults name=\"" + ti.Name + "\">");
224                         foreach(string st in subTests)
225                         {
226                                 xmltext.Append(st);
227                         }
228                         xmltext.Append("</TestResults>");
229
230                         XmlDocument r = new XmlDocument();
231                         r.LoadXml(HtmltoXml(xmltext.ToString()));
232                         return r;
233                 }
234
235                 private string HtmltoXml(string html)
236                 {
237                         HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
238                         doc.LoadHtml(html);
239
240                         StringBuilder fixedxml = new StringBuilder();
241                         StringWriter sw = new StringWriter(fixedxml);
242
243                         try
244                         {
245                                 StringBuilder tempxml = new StringBuilder();
246                                 StringWriter tsw = new StringWriter(tempxml);
247
248                                 doc.OptionOutputAsXml = true;
249                                 doc.Save(tsw);
250
251                                 // fix style attribute
252                                 // the reason is that style attribute name-value pairs come in different order
253                                 // in .NET and GH
254                                 // Here I will sort the values of style attribute
255                                 XmlDocument tempDoc = new XmlDocument();
256                                 tempDoc.LoadXml(tempxml.ToString());
257
258                                 XmlNodeList allNodes = tempDoc.SelectNodes("//*");
259                                 foreach (XmlNode n in allNodes)
260                                 {
261                                         if (n.Attributes["style"] != null)
262                                         {
263                                                 string att = n.Attributes["style"].Value;
264                                                 string [] style = att.Trim(new char[]{' ', ';'}).Split(';');
265
266                                                 for (int styleIndex=0; styleIndex<style.Length; styleIndex++)
267                                                 {
268                                                         style[styleIndex] = FixStyleNameValue(style[styleIndex]);
269                                                 }
270                                                 Array.Sort(style);
271                                                 n.Attributes["style"].Value = string.Join(";", style);
272                                         }
273                                 }
274                                 tempDoc.Save(sw);
275                         }
276                         catch (Exception)
277                         {
278                                 Console.WriteLine("Error parsing html response...");
279                                 Console.WriteLine("Test case aborted");
280                                 return "<TestCaseAborted></TestCaseAborted>";
281                         }
282                         return fixedxml.ToString();
283                 }
284
285                 private string FixStyleNameValue(string nameValue)
286                 {
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(' ');
291                         Array.Sort(nvalue);
292                         nv[1] = string.Join(" ", nvalue);
293                         return nv[0].Trim().ToLower() + ":" + nv[1].Trim().ToLower();
294                 }
295
296                 private void DoAlmost(XmlDocument xmlDocument)
297                 {
298                         XmlNode XmlIgnoreNode;
299                         IEnumerator xmlIgnoreEnum;
300
301                         if (_xmlIgnoreList == null)
302                         {
303                                 _xmlIgnoreList = new XmlDocument();
304                                 _xmlIgnoreList.Load(_ignoreListFile);
305                         }
306
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())
312                         {
313                                 XmlNodeList DocNodeList;
314                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
315                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
316                                 if (DocNodeList != null)
317                                 {
318                                         foreach (XmlElement tmpXmlElement in DocNodeList)
319                                         {
320                                                 foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
321                                                 {
322                                                         if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
323                                                         {
324                                                                 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
325                                                                 {
326                                                                         if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name].Value.ToLower() == tmpIgnoreAttr.Value.ToLower())
327                                                                         {
328                                                                                 tmpXmlElement.RemoveAllAttributes();
329                                                                         }
330                                                                 }
331                                                         }
332                                                 }
333                                         }
334                                 }       
335                         }
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())
340                         {
341                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
342                                 XmlNodeList DocNodeList;
343                                 //clean specific element
344
345                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
346                                 if (DocNodeList != null)
347                                 {
348                                         foreach (XmlElement tmpXmlElement in DocNodeList)
349                                         {
350                                                 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
351                                                 {
352                                                         foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
353                                                         {
354                                                                 tmpXmlElement.RemoveAttribute(tmpIgnoreAttr.Name);
355                                                         }
356                                                 }
357                                         }
358                                 }
359                         }
360
361                         // clean javascript attribute value
362                         xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode("Almost/CleanJavaScriptValueList").GetEnumerator(); //FirstChild.GetEnumerator
363                         while (xmlIgnoreEnum.MoveNext())
364                         {
365                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
366                                 XmlNodeList DocNodeList;
367                                 //clean Java Script attribute values
368                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
369                                 if (DocNodeList != null)
370                                 {
371                                         foreach (XmlElement tmpXmlElement in DocNodeList)
372                                         {
373                                                 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
374                                                 {
375                                                         foreach (XmlAttribute tmpIgnoreAttr in XmlIgnoreNode.Attributes)
376                                                         {
377                                                                 if (tmpXmlElement.Attributes[tmpIgnoreAttr.Name] != null )
378                                                                 {\r
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
382                                                                         }
383                                                                 }
384                                                         }
385                                                 }
386                                         }
387                                 }
388                         }
389                         // remove whole tags\r
390                         ArrayList tagsToRemove = new ArrayList ();\r
391                         xmlIgnoreEnum = _xmlIgnoreList.SelectSingleNode ("Almost/RemoveTags").GetEnumerator (); //FirstChild.GetEnumerator
392                         while (xmlIgnoreEnum.MoveNext())
393                         {
394                                 XmlIgnoreNode = (XmlNode)xmlIgnoreEnum.Current;
395                                 XmlNodeList DocNodeList;
396                                 //clean Java Script attribute values
397                                 DocNodeList = xmlDocument.GetElementsByTagName("*");
398                                 if (DocNodeList != null)
399                                 {
400                                         foreach (XmlElement tmpXmlElement in DocNodeList)
401                                         {
402                                                 if (tmpXmlElement.Name.ToLower() == XmlIgnoreNode.Name.ToLower()) 
403                                                 {\r
404                                                         tagsToRemove.Add (tmpXmlElement);\r
405                                                         //tmpXmlElement.ParentNode.RemoveChild (tmpXmlElement);
406                                                 }
407                                         }
408                                 }
409                         }\r
410                         if (tagsToRemove.Count > 0) {\r
411                                 foreach (XmlElement el in tagsToRemove) {\r
412                                         try {\r
413                                                 el.ParentNode.RemoveChild (el);\r
414                                         }\r
415                                         catch { }\r
416                                 }\r
417                         }
418                 }
419         }
420 }