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