2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.XML / Test / System.Xml / XmlNodeTests.cs
1 //
2 // System.Xml.XmlNodeTests
3 //
4 // Authors:
5 //   Kral Ferch <kral_ferch@hotmail.com>
6 //   Martin Willemoes Hansen
7 //
8 // (C) 2002 Kral Ferch
9 // (C) 2003 Martin Willemoes Hansen
10 //
11
12 using System;
13 using System.IO;
14 using System.Text;
15 using System.Xml;
16
17 using NUnit.Framework;
18
19 namespace MonoTests.System.Xml
20 {
21         [TestFixture]
22         public class XmlNodeTests : Assertion
23         {
24                 XmlDocument document;
25                 XmlElement element;
26                 XmlElement element2;
27                 bool inserted;
28                 bool inserting;
29                 bool changed;
30                 bool changing;
31                 bool removed;
32                 bool removing;
33
34                 [SetUp]
35                 public void GetReady ()
36                 {
37                         document = new XmlDocument ();
38                         document.NodeInserted += new XmlNodeChangedEventHandler (this.EventNodeInserted);
39                         document.NodeInserting += new XmlNodeChangedEventHandler (this.EventNodeInserting);
40                         document.NodeRemoved += new XmlNodeChangedEventHandler (this.EventNodeRemoved);
41                         document.NodeRemoving += new XmlNodeChangedEventHandler (this.EventNodeRemoving);
42                         element = document.CreateElement ("foo");
43                         element2 = document.CreateElement ("bar");
44                 }
45
46                 private void EventNodeInserted(Object sender, XmlNodeChangedEventArgs e)
47                 {
48                         inserted = true;
49                 }
50
51                 private void EventNodeInserting (Object sender, XmlNodeChangedEventArgs e)
52                 {
53                         inserting = true;
54                 }
55
56                 private void EventNodeChanged(Object sender, XmlNodeChangedEventArgs e)
57                 {
58                         changed = true;
59                 }
60
61                 private void EventNodeChanging (Object sender, XmlNodeChangedEventArgs e)
62                 {
63                         changing = true;
64                 }
65
66                 private void EventNodeRemoved(Object sender, XmlNodeChangedEventArgs e)
67                 {
68                         removed = true;
69                 }
70
71                 private void EventNodeRemoving (Object sender, XmlNodeChangedEventArgs e)
72                 {
73                         removing = true;
74                 }
75
76                 [Test]
77                 public void AppendChild ()
78                 {
79                         XmlComment comment;
80
81                         inserted = false;
82                         inserting = false;
83                         element.AppendChild (element2);
84                         Assert (inserted);
85                         Assert (inserting);
86
87                         // Can only append to elements, documents, and attributes
88                         try 
89                         {
90                                 comment = document.CreateComment ("baz");
91                                 comment.AppendChild (element2);
92                                 Fail ("Expected an InvalidOperationException to be thrown.");
93                         } 
94                         catch (InvalidOperationException) {}
95
96                         // Can't append a node from one document into another document.
97                         XmlDocument document2 = new XmlDocument();
98                         AssertEquals (1, element.ChildNodes.Count);
99                         try 
100                         {
101                                 element2 = document2.CreateElement ("qux");
102                                 element.AppendChild (element2);
103                                 Fail ("Expected an ArgumentException to be thrown.");
104                         } 
105                         catch (ArgumentException) {}
106                         AssertEquals (1, element.ChildNodes.Count);
107
108                         // Can't append to a readonly node.
109 /* TODO put this in when I figure out how to create a read-only node.
110                         try 
111                         {
112                                 XmlElement element3 = (XmlElement)element.CloneNode (false);
113                                 Assert (!element.IsReadOnly);
114                                 Assert (element3.IsReadOnly);
115                                 element2 = document.CreateElement ("quux");
116                                 element3.AppendChild (element2);
117                                 Fail ("Expected an ArgumentException to be thrown.");
118                         } 
119                         catch (ArgumentException) {}
120 */
121                 }
122
123                 [Test]
124                 public void GetNamespaceOfPrefix ()
125                 {
126                         document.LoadXml ("<root xmlns='urn:default' attr='value' "
127                                 + "xml:lang='en' xmlns:foo='urn:foo' foo:att='fooatt'>text node</root>");
128                         XmlNode n = document.DocumentElement;
129                         AssertEquals ("#1", "urn:default", n.GetNamespaceOfPrefix (String.Empty));
130                         AssertEquals ("#2", "urn:foo", n.GetNamespaceOfPrefix ("foo"));
131                         AssertEquals ("#3", String.Empty, n.GetNamespaceOfPrefix ("bar"));
132 #if NET_2_0
133                         AssertEquals ("#4", "http://www.w3.org/XML/1998/namespace", n.GetNamespaceOfPrefix ("xml"));
134                         AssertEquals ("#5", "http://www.w3.org/2000/xmlns/", n.GetNamespaceOfPrefix ("xmlns"));
135 #else
136                         AssertEquals ("#4", String.Empty, n.GetNamespaceOfPrefix ("xml"));
137                         AssertEquals ("#5", String.Empty, n.GetNamespaceOfPrefix ("xmlns"));
138 #endif
139
140                         n = document.DocumentElement.FirstChild;
141                         AssertEquals ("#6", "urn:default", n.GetNamespaceOfPrefix (String.Empty));
142                         AssertEquals ("#7", "urn:foo", n.GetNamespaceOfPrefix ("foo"));
143                         AssertEquals ("#8", String.Empty, n.GetNamespaceOfPrefix ("bar"));
144 #if NET_2_0
145                         AssertEquals ("#9", "http://www.w3.org/XML/1998/namespace", n.GetNamespaceOfPrefix ("xml"));
146                         AssertEquals ("#10", "http://www.w3.org/2000/xmlns/", n.GetNamespaceOfPrefix ("xmlns"));
147 #else
148                         AssertEquals ("#9", String.Empty, n.GetNamespaceOfPrefix ("xml"));
149                         AssertEquals ("#10", String.Empty, n.GetNamespaceOfPrefix ("xmlns"));
150 #endif
151                 }
152
153                 [Test]
154                 [ExpectedException (typeof (ArgumentNullException))]
155                 public void GetNamespaceOfPrefixNullArg ()
156                 {
157                         new XmlDocument ().GetNamespaceOfPrefix (null);
158                 }
159
160                 [Test]
161                 public void InsertBefore()
162                 {
163                         document = new XmlDocument();
164                         document.LoadXml("<root><sub /></root>");
165                         XmlElement docelem = document.DocumentElement;
166                         docelem.InsertBefore(document.CreateElement("good_child"), docelem.FirstChild);
167                         AssertEquals("InsertBefore.Normal", "good_child", docelem.FirstChild.Name);
168                         // These are required for .NET 1.0 but not for .NET 1.1.
169                         try {
170                                 document.InsertBefore (document.CreateElement ("BAD_MAN"), docelem);
171                                 Fail ("#InsertBefore.BadPositionButNoError.1");
172                         }
173                         catch (Exception) {}
174                 }
175
176                 [Test]
177                 public void InsertAfter()
178                 {
179                         document = new XmlDocument();
180                         document.LoadXml("<root><sub1 /><sub2 /></root>");
181                         XmlElement docelem = document.DocumentElement;
182                         XmlElement newelem = document.CreateElement("good_child");
183                         docelem.InsertAfter(newelem, docelem.FirstChild);
184                         AssertEquals("InsertAfter.Normal", 3, docelem.ChildNodes.Count);
185                         AssertEquals("InsertAfter.First", "sub1", docelem.FirstChild.Name);
186                         AssertEquals("InsertAfter.Last", "sub2", docelem.LastChild.Name);
187                         AssertEquals("InsertAfter.Prev", "good_child", docelem.FirstChild.NextSibling.Name);
188                         AssertEquals("InsertAfter.Next", "good_child", docelem.LastChild.PreviousSibling.Name);
189                         // this doesn't throw any exception *only on .NET 1.1*
190                         // .NET 1.0 throws an exception.
191                         try {
192                                 document.InsertAfter(document.CreateElement("BAD_MAN"), docelem);
193 #if USE_VERSION_1_1
194                                 AssertEquals("InsertAfter with bad location", 
195                                 "<root><sub1 /><good_child /><sub2 /></root><BAD_MAN />",
196                                         document.InnerXml);
197                         } catch (XmlException ex) {
198                                 throw ex;
199                         }
200 #else
201                         } catch (Exception) {}
202 #endif
203 }
204
205                 [Test]
206                 public void Normalize ()
207                 {
208                         XmlDocument doc = new XmlDocument ();
209                         doc.LoadXml ("<root>This is the <b>hardest</b> one.</root>");
210                         doc.NodeInserted += new XmlNodeChangedEventHandler (EventNodeInserted);
211                         doc.NodeChanged += new XmlNodeChangedEventHandler (EventNodeChanged);
212                         doc.NodeRemoved += new XmlNodeChangedEventHandler (EventNodeRemoved);
213
214                         AssertEquals (3, doc.DocumentElement.ChildNodes.Count);
215
216                         doc.DocumentElement.Normalize ();
217                         AssertEquals (3, doc.DocumentElement.ChildNodes.Count);
218                         Assert (changed);
219                         inserted = changed = removed = false;
220
221                         doc.DocumentElement.AppendChild (doc.CreateTextNode ("Addendum."));
222                         AssertEquals (4, doc.DocumentElement.ChildNodes.Count);
223                         inserted = changed = removed = false;
224
225                         doc.DocumentElement.Normalize ();
226                         AssertEquals (3, doc.DocumentElement.ChildNodes.Count);
227                         Assert (changed);
228                         Assert (removed);
229                         inserted = changed = removed = false;
230
231                         doc.DocumentElement.SetAttribute ("attr", "");
232                         XmlAttribute attr = doc.DocumentElement.Attributes [0] as XmlAttribute;
233                         AssertEquals (1, attr.ChildNodes.Count);
234                         inserted = changed = removed = false;
235                         attr.Normalize ();
236                         // Such behavior violates DOM Level 2 Node#normalize(),
237                         // but MS DOM is designed as such.
238                         AssertEquals (1, attr.ChildNodes.Count);
239                 }
240
241                 [Test]
242                 public void Normalize2 ()
243                 {
244                         XmlDocument doc = new XmlDocument ();
245                         doc.PreserveWhitespace = true;
246                         doc.LoadXml ("<root>  </root>");
247                         XmlElement root = doc.DocumentElement;
248                         root.AppendChild (doc.CreateTextNode ("foo"));
249                         root.AppendChild (doc.CreateTextNode ("bar"));
250                         root.AppendChild (doc.CreateWhitespace ("   "));
251                         root.AppendChild (doc.CreateTextNode ("baz"));
252                         doc.NodeInserted += new XmlNodeChangedEventHandler (OnChange);
253                         doc.NodeChanged += new XmlNodeChangedEventHandler (OnChange);
254                         doc.NodeRemoved += new XmlNodeChangedEventHandler (OnChange);
255                         AssertEquals ("Before Normalize()", 5, root.ChildNodes.Count);
256                         root.Normalize ();
257                         AssertEquals ("<root>  foobar   baz</root>", root.OuterXml);
258                         AssertEquals ("After Normalize()", 1, root.ChildNodes.Count);
259                 }
260
261                 int normalize2Count;
262
263                 private void OnChange (object o, XmlNodeChangedEventArgs e)
264                 {
265                         switch (normalize2Count) {
266                         case 0:
267                                 AssertEquals ("Action0", XmlNodeChangedAction.Remove, e.Action);
268                                 AssertEquals ("Value0", "  ", e.Node.Value);
269                                 break;
270                         case 1:
271                                 AssertEquals ("Action1", XmlNodeChangedAction.Remove, e.Action);
272                                 AssertEquals ("Value1", "bar", e.Node.Value);
273                                 break;
274                         case 2:
275                                 AssertEquals ("Action2", XmlNodeChangedAction.Remove, e.Action);
276                                 AssertEquals ("Value2", "   ", e.Node.Value);
277                                 break;
278                         case 3:
279                                 AssertEquals ("Action3", XmlNodeChangedAction.Remove, e.Action);
280                                 AssertEquals ("Value3", "baz", e.Node.Value);
281                                 break;
282                         case 4:
283                                 AssertEquals ("Action4", XmlNodeChangedAction.Change, e.Action);
284                                 AssertEquals ("Value4", "  foobar   baz", e.Node.Value);
285                                 break;
286                         default:
287                                 Fail (String.Format ("Unexpected event. Action = {0}, node type = {1}, node name = {2}, node value = {3}", e.Action, e.Node.NodeType, e.Node.Name, e.Node.Value));
288                                 break;
289                         }
290                         normalize2Count++;
291                 }
292
293                 [Test]
294                 public void PrependChild()
295                 {
296                         document = new XmlDocument();
297                         document.LoadXml("<root><sub1 /><sub2 /></root>");
298                         XmlElement docelem = document.DocumentElement;
299                         docelem.PrependChild(document.CreateElement("prepender"));
300                         AssertEquals("PrependChild", "prepender", docelem.FirstChild.Name);
301                 }
302
303                 public void saveTestRemoveAll ()
304                 {
305                         // TODO:  put this test back in when AttributeCollection.RemoveAll() is implemented.
306                         element.AppendChild(element2);
307                         removed = false;
308                         removing = false;
309                         element.RemoveAll ();
310                         Assert (removed);
311                         Assert (removing);
312                 }
313
314                 [Test]
315                 public void RemoveChild ()
316                 {
317                         element.AppendChild(element2);
318                         removed = false;
319                         removing = false;
320                         element.RemoveChild (element2);
321                         Assert (removed);
322                         Assert (removing);
323                 }
324                 
325                 [Test]
326                 public void RemoveLastChild ()
327                 {
328                         element.InnerXml = "<foo/><bar/><baz/>";
329                         element.RemoveChild (element.LastChild);
330                         AssertNotNull (element.FirstChild);
331                 }
332                 
333                 [Test]
334                 public void GetPrefixOfNamespace ()
335                 {
336                         document.LoadXml ("<root><c1 xmlns='urn:foo'><c2 xmlns:foo='urn:foo' xmlns='urn:bar'><c3 xmlns=''/></c2></c1></root>");
337                         AssertEquals ("root", String.Empty, document.DocumentElement.GetPrefixOfNamespace ("urn:foo"));
338                         AssertEquals ("c1", String.Empty, document.DocumentElement.GetPrefixOfNamespace ("urn:foo"));
339                         AssertEquals ("c2", String.Empty, document.DocumentElement.FirstChild.GetPrefixOfNamespace ("urn:foo"));
340                         AssertEquals ("c3", "foo", document.DocumentElement.FirstChild.FirstChild.GetPrefixOfNamespace ("urn:foo"));
341
342                         // disconnected nodes.
343                         XmlNode n = document.CreateElement ("foo");
344                         AssertEquals (String.Empty, n.GetPrefixOfNamespace ("foo"));
345                         n = document.CreateTextNode ("text"); // does not have Attributes
346                         AssertEquals (String.Empty, n.GetPrefixOfNamespace ("foo"));
347                         n = document.CreateXmlDeclaration ("1.0", null, null); // does not have Attributes
348                         AssertEquals (String.Empty, n.GetPrefixOfNamespace ("foo"));
349                 }
350
351                 [Test]
352                 public void GetPrefixOfNamespace2 ()
353                 {
354                         XmlDocument doc = new XmlDocument ();
355                         doc.AppendChild (doc.CreateElement ("foo"));
356                         doc.DocumentElement.SetAttributeNode (
357                         doc.CreateAttribute ("xmlns", "u", "http://www.w3.org/2000/xmlns/"));
358                         doc.DocumentElement.Attributes [0].Value = "urn:foo";
359                         XmlElement el = doc.CreateElement ("bar");
360                         doc.DocumentElement.AppendChild (el);
361                         AssertEquals ("u", el.GetPrefixOfNamespace ("urn:foo"));
362                 }
363
364                 [Test]
365                 public void ReplaceChild ()
366                 {
367                         document.LoadXml ("<root/>");
368                         document.NodeInserted += new XmlNodeChangedEventHandler (this.EventNodeInserted);
369                         document.NodeChanged += new XmlNodeChangedEventHandler (this.EventNodeChanged);
370                         document.NodeRemoved += new XmlNodeChangedEventHandler (this.EventNodeRemoved);
371                         inserted = changed = removed = false;
372                         XmlElement el = document.CreateElement("root2");
373                         document.ReplaceChild (el, document.DocumentElement);
374                         AssertEquals ("root2", document.DocumentElement.Name);
375                         AssertEquals (1, document.ChildNodes.Count);
376                         Assert (inserted && removed && !changed);
377                 }
378
379                 [Test]
380                 public void InnerText ()
381                 {
382                         document.LoadXml ("<root>This is <b>mixed</b> content. Also includes <![CDATA[CDATA section]]>.<!-- Should be ignored --></root>");
383                         string total = "This is mixed content. Also includes CDATA section.";
384                         XmlNode elemB = document.DocumentElement.ChildNodes [1];
385                         AssertEquals ("mixed", elemB.FirstChild.InnerText);     // text node
386                         AssertEquals ("mixed", elemB.InnerText);        // element b
387                         AssertEquals (total, document.DocumentElement.InnerText);       // element root
388                         AssertEquals (total, document.InnerText);       // whole document
389                 }
390
391                 [Test]
392                 public void InnerXmlWithXmlns ()
393                 {
394                         XmlDocument document = new XmlDocument ();
395                         XmlElement xel = document.CreateElement ("KeyValue", "http://www.w3.org/2000/09/xmldsig#");
396                         xel.SetAttribute ("xmlns", "http://www.w3.org/2000/09/xmldsig#");
397                         xel.InnerXml = "<DSAKeyValue>blablabla</DSAKeyValue>";
398                         string expected = "<KeyValue xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><DSAKeyValue>blablabla</DSAKeyValue></KeyValue>";
399                         AssertEquals (expected, xel.OuterXml);
400                 }
401
402                 [Test]
403                 public void SelectNodes ()
404                 {
405                         // This test is done in this class since it tests only XmlDocumentNavigator.
406                         string xpath = "//@*|//namespace::*";
407                         XmlDocument doc = new XmlDocument ();
408                         doc.LoadXml ("<element xmlns='urn:foo'><foo><bar>test</bar></foo></element>");
409                         XmlNodeList nl = doc.SelectNodes (xpath);
410                         AssertEquals (6, nl.Count);
411                         // BTW, as for namespace nodes, Node does not exist
412                         // in the tree, so the return value should be
413                         // implementation dependent.
414                         AssertEquals ("#1", XmlNodeType.Attribute, nl [0].NodeType);
415                         AssertEquals ("#2", XmlNodeType.Attribute, nl [1].NodeType);
416                         AssertEquals ("#3", XmlNodeType.Attribute, nl [2].NodeType);
417                         AssertEquals ("#4", XmlNodeType.Attribute, nl [3].NodeType);
418                         AssertEquals ("#5", XmlNodeType.Attribute, nl [4].NodeType);
419                         AssertEquals ("#6", XmlNodeType.Attribute, nl [5].NodeType);
420                         AssertEquals ("xmlns", nl [0].LocalName);
421                         AssertEquals ("xml", nl [1].LocalName);
422                         AssertEquals ("xmlns", nl [2].LocalName);
423                         AssertEquals ("xml", nl [3].LocalName);
424                         AssertEquals ("xmlns", nl [4].LocalName);
425                         AssertEquals ("xml", nl [5].LocalName);
426                 }
427
428                 [Test]
429                 [Ignore ("MS.NET has a bug; it does not return nodes in document order.")]
430                 public void SelectNodes2 ()
431                 {
432                         // This test is done in this class since it tests only XmlDocumentNavigator.
433                         string xpath = "//*|//@*|//namespace::*";
434                         XmlDocument doc = new XmlDocument ();
435                         doc.LoadXml ("<element xmlns='urn:foo'><foo><bar>test</bar></foo></element>");
436                         XmlNodeList nl = doc.SelectNodes (xpath);
437                         AssertEquals (9, nl.Count);
438                         AssertEquals (XmlNodeType.Element, nl [0].NodeType);
439                         AssertEquals (XmlNodeType.Attribute, nl [1].NodeType);
440                         AssertEquals (XmlNodeType.Attribute, nl [2].NodeType);
441                         AssertEquals (XmlNodeType.Element, nl [3].NodeType);
442                         AssertEquals (XmlNodeType.Attribute, nl [4].NodeType);
443                         AssertEquals (XmlNodeType.Attribute, nl [5].NodeType);
444                         AssertEquals (XmlNodeType.Element, nl [6].NodeType);
445                         AssertEquals (XmlNodeType.Attribute, nl [7].NodeType);
446                         AssertEquals (XmlNodeType.Attribute, nl [8].NodeType);
447                         AssertEquals ("element", nl [0].LocalName);
448                         AssertEquals ("xmlns", nl [1].LocalName);
449                         AssertEquals ("xml", nl [2].LocalName);
450                         AssertEquals ("foo", nl [3].LocalName);
451                         AssertEquals ("xmlns", nl [4].LocalName);
452                         AssertEquals ("xml", nl [5].LocalName);
453                         AssertEquals ("bar", nl [6].LocalName);
454                         AssertEquals ("xmlns", nl [7].LocalName);
455                         AssertEquals ("xml", nl [8].LocalName);
456                 }
457
458                 [Test]
459                 public void BaseURI ()
460                 {
461                         // See bug #64120.
462                         XmlDocument doc = new XmlDocument ();
463                         doc.Load ("Test/XmlFiles/simple.xml");
464                         XmlElement el = doc.CreateElement ("foo");
465                         AssertEquals (String.Empty, el.BaseURI);
466                         doc.DocumentElement.AppendChild (el);
467                         Assert (String.Empty != el.BaseURI);
468                         XmlAttribute attr = doc.CreateAttribute ("attr");
469                         AssertEquals (String.Empty, attr.BaseURI);
470                 }
471
472                 [Test]
473                 public void CloneReadonlyNode ()
474                 {
475                         // Clone() should return such node that is not readonly
476                         string dtd = "<!DOCTYPE root ["
477                                 + "<!ELEMENT root (#PCDATA|foo)*>"
478                                 + "<!ELEMENT foo EMPTY>"
479                                 + "<!ENTITY ent1 '<foo /><![CDATA[cdata]]>'>]>";
480                         string xml = dtd + "<root>&ent1;</root>";
481
482                         XmlDocument doc = new XmlDocument ();
483                         doc.LoadXml (xml);
484                         XmlNode n = doc.DocumentElement.FirstChild.FirstChild;
485                         Assert ("#1", n.IsReadOnly);
486                         Assert ("#2", !n.CloneNode (true).IsReadOnly);
487                 }
488
489                 [Test] // bug #80233
490                 public void InnerTextComment ()
491                 {
492                         XmlDocument doc = new XmlDocument ();
493                         doc.LoadXml ("<a><!--xx--></a>");
494                         AssertEquals (String.Empty, doc.InnerText);
495                 }
496
497                 [Test] // part of bug #80331
498                 public void AppendReferenceChildAsNewChild ()
499                 {
500                         XmlDocument d = new XmlDocument ();
501                         XmlElement r = d.CreateElement ("Docs");
502                         d.AppendChild (r);
503
504                         XmlElement s = Create (d, "param", "pattern");
505                         s.AppendChild (Create (d, "para", "insert text here"));
506
507                         r.AppendChild (s);
508
509                         r.AppendChild (Create (d, "param", "pattern"));
510                         r.AppendChild (Create (d, "param", "pattern"));
511
512                         r.InsertBefore (s, r.FirstChild);
513                 }
514
515                 XmlElement Create (XmlDocument d, string name, string param)
516                 {
517                         XmlElement e = d.CreateElement (name);
518                         e.SetAttribute ("name", param);
519                         return e;
520                 }
521
522                 [Test] // bug #80331
523                 public void PrependChild2 ()
524                 {
525                         XmlDocument d = new XmlDocument ();
526                         XmlElement r = d.CreateElement ("Docs");
527                         d.AppendChild (r);
528
529                         XmlElement s = Create (d, "param", "pattern");
530                         s.AppendChild (Create (d, "para", "insert text here"));
531
532                         r.AppendChild (s);
533
534                         r.AppendChild (Create (d, "param", "pattern"));
535                         r.AppendChild (Create (d, "param", "pattern"));
536
537                         r.PrependChild (s);
538                 }
539
540         }
541 }