New test.
[mono.git] / mcs / class / System.XML / Test / System.Xml.XPath / XPathNavigatorTests.cs
1 //
2 // MonoTests.System.Xml.XPathNavigatorTests
3 //
4 // Authors:
5 //   Jason Diamond <jason@injektilo.org>
6 //   Martin Willemoes Hansen <mwh@sysrq.dk>
7 //
8 // (C) 2002 Jason Diamond
9 // (C) 2003 Martin Willemoes Hansen
10 //
11
12 using System;
13 using System.IO;
14 using System.Xml;
15 using System.Xml.XPath;
16 using System.Xml.Xsl;
17
18 using NUnit.Framework;
19
20 namespace MonoTests.System.Xml
21 {
22         [TestFixture]
23         public class XPathNavigatorTests : Assertion
24         {
25                 XmlDocument document;
26                 XPathNavigator navigator;
27
28                 [SetUp]
29                 public void GetReady ()
30                 {
31                         document = new XmlDocument ();
32                 }
33                 
34                 [Test]
35                 public void CreateNavigator ()
36                 {
37                         document.LoadXml ("<foo />");
38                         navigator = document.CreateNavigator ();
39                         AssertNotNull (navigator);
40                 }
41
42                 [Test]
43                 public void PropertiesOnDocument ()
44                 {
45                         document.LoadXml ("<foo:bar xmlns:foo='#foo' />");
46                         navigator = document.CreateNavigator ();
47                         
48                         AssertEquals (XPathNodeType.Root, navigator.NodeType);
49                         AssertEquals (String.Empty, navigator.Name);
50                         AssertEquals (String.Empty, navigator.LocalName);
51                         AssertEquals (String.Empty, navigator.NamespaceURI);
52                         AssertEquals (String.Empty, navigator.Prefix);
53                         Assert (!navigator.HasAttributes);
54                         Assert (navigator.HasChildren);
55                         Assert (!navigator.IsEmptyElement);
56                 }
57
58                 [Test]
59                 public void PropertiesOnElement ()
60                 {
61                         document.LoadXml ("<foo:bar xmlns:foo='#foo' />");
62                         navigator = document.DocumentElement.CreateNavigator ();
63                         
64                         AssertEquals (XPathNodeType.Element, navigator.NodeType);
65                         AssertEquals ("foo:bar", navigator.Name);
66                         AssertEquals ("bar", navigator.LocalName);
67                         AssertEquals ("#foo", navigator.NamespaceURI);
68                         AssertEquals ("foo", navigator.Prefix);
69                         Assert (!navigator.HasAttributes);
70                         Assert (!navigator.HasChildren);
71                         Assert (navigator.IsEmptyElement);
72                 }
73
74                 [Test]
75                 public void PropertiesOnAttribute ()
76                 {
77                         document.LoadXml ("<foo bar:baz='quux' xmlns:bar='#bar' />");
78                         navigator = document.DocumentElement.GetAttributeNode("baz", "#bar").CreateNavigator ();
79                         
80                         AssertEquals (XPathNodeType.Attribute, navigator.NodeType);
81                         AssertEquals ("bar:baz", navigator.Name);
82                         AssertEquals ("baz", navigator.LocalName);
83                         AssertEquals ("#bar", navigator.NamespaceURI);
84                         AssertEquals ("bar", navigator.Prefix);
85                         Assert (!navigator.HasAttributes);
86                         Assert (!navigator.HasChildren);
87                         Assert (!navigator.IsEmptyElement);
88                 }
89
90                 [Test]
91                 public void PropertiesOnNamespace ()
92                 {
93                         document.LoadXml ("<root xmlns='urn:foo' />");\r
94                         navigator = document.DocumentElement.Attributes [0].CreateNavigator ();\r
95                         AssertEquals (XPathNodeType.Namespace, navigator.NodeType);
96                 }
97
98                 [Test]
99                 public void Navigation ()
100                 {
101                         document.LoadXml ("<foo><bar /><baz /></foo>");
102                         navigator = document.DocumentElement.CreateNavigator ();
103                         
104                         AssertEquals ("foo", navigator.Name);
105                         Assert (navigator.MoveToFirstChild ());
106                         AssertEquals ("bar", navigator.Name);
107                         Assert (navigator.MoveToNext ());
108                         AssertEquals ("baz", navigator.Name);
109                         Assert (!navigator.MoveToNext ());
110                         AssertEquals ("baz", navigator.Name);
111                         Assert (navigator.MoveToPrevious ());
112                         AssertEquals ("bar", navigator.Name);
113                         Assert (!navigator.MoveToPrevious ());
114                         Assert (navigator.MoveToParent ());
115                         AssertEquals ("foo", navigator.Name);
116                         navigator.MoveToRoot ();
117                         AssertEquals (XPathNodeType.Root, navigator.NodeType);
118                         Assert (!navigator.MoveToParent ());
119                         AssertEquals (XPathNodeType.Root, navigator.NodeType);
120                         Assert (navigator.MoveToFirstChild ());
121                         AssertEquals ("foo", navigator.Name);
122                         Assert (navigator.MoveToFirst ());
123                         AssertEquals ("foo", navigator.Name);
124                         Assert (navigator.MoveToFirstChild ());
125                         AssertEquals ("bar", navigator.Name);
126                         Assert (navigator.MoveToNext ());
127                         AssertEquals ("baz", navigator.Name);
128                         Assert (navigator.MoveToFirst ());
129                         AssertEquals ("bar", navigator.Name);
130                 }
131
132                 [Test]
133                 public void MoveToAndIsSamePosition ()
134                 {
135                         XmlDocument document1 = new XmlDocument ();
136                         document1.LoadXml ("<foo><bar /></foo>");
137                         XPathNavigator navigator1a = document1.DocumentElement.CreateNavigator ();
138                         XPathNavigator navigator1b = document1.DocumentElement.CreateNavigator ();
139
140                         XmlDocument document2 = new XmlDocument ();
141                         document2.LoadXml ("<foo><bar /></foo>");
142                         XPathNavigator navigator2 = document2.DocumentElement.CreateNavigator ();
143
144                         AssertEquals ("foo", navigator1a.Name);
145                         Assert (navigator1a.MoveToFirstChild ());
146                         AssertEquals ("bar", navigator1a.Name);
147
148                         Assert (!navigator1b.IsSamePosition (navigator1a));
149                         AssertEquals ("foo", navigator1b.Name);
150                         Assert (navigator1b.MoveTo (navigator1a));
151                         Assert (navigator1b.IsSamePosition (navigator1a));
152                         AssertEquals ("bar", navigator1b.Name);
153
154                         Assert (!navigator2.IsSamePosition (navigator1a));
155                         AssertEquals ("foo", navigator2.Name);
156                         Assert (!navigator2.MoveTo (navigator1a));
157                         AssertEquals ("foo", navigator2.Name);
158                 }
159
160                 [Test]
161                 public void AttributeNavigation ()
162                 {
163                         document.LoadXml ("<foo bar='baz' quux='quuux' />");
164                         navigator = document.DocumentElement.CreateNavigator ();
165
166                         AssertEquals (XPathNodeType.Element, navigator.NodeType);
167                         AssertEquals ("foo", navigator.Name);
168                         Assert (navigator.MoveToFirstAttribute ());
169                         AssertEquals (XPathNodeType.Attribute, navigator.NodeType);
170                         AssertEquals ("bar", navigator.Name);
171                         AssertEquals ("baz", navigator.Value);
172                         Assert (navigator.MoveToNextAttribute ());
173                         AssertEquals (XPathNodeType.Attribute, navigator.NodeType);
174                         AssertEquals ("quux", navigator.Name);
175                         AssertEquals ("quuux", navigator.Value);
176                 }
177
178                 [Test]
179                 public void ElementAndRootValues()
180                 {
181                         document.LoadXml ("<foo><bar>baz</bar><quux>quuux</quux></foo>");
182                         navigator = document.DocumentElement.CreateNavigator ();
183
184                         AssertEquals (XPathNodeType.Element, navigator.NodeType);
185                         AssertEquals ("foo", navigator.Name);
186                         //AssertEquals ("bazquuux", navigator.Value);
187
188                         navigator.MoveToRoot ();
189                         //AssertEquals ("bazquuux", navigator.Value);
190                 }
191
192                 [Test]
193                 public void DocumentWithXmlDeclaration ()
194                 {
195                         document.LoadXml ("<?xml version=\"1.0\" standalone=\"yes\"?><Root><foo>bar</foo></Root>");
196                         navigator = document.CreateNavigator ();
197
198                         navigator.MoveToRoot ();
199                         navigator.MoveToFirstChild ();
200                         AssertEquals (XPathNodeType.Element, navigator.NodeType);
201                         AssertEquals ("Root", navigator.Name);
202                 }
203
204                 [Test]
205                 public void DocumentWithProcessingInstruction ()
206                 {
207                         document.LoadXml ("<?xml-stylesheet href='foo.xsl' type='text/xsl' ?><foo />");
208                         navigator = document.CreateNavigator ();
209
210                         Assert (navigator.MoveToFirstChild ());
211                         AssertEquals (XPathNodeType.ProcessingInstruction, navigator.NodeType);
212                         AssertEquals ("xml-stylesheet", navigator.Name);
213
214                         XPathNodeIterator iter = navigator.SelectChildren (XPathNodeType.Element);
215                         AssertEquals (0, iter.Count);
216                 }
217
218                 [Test]
219                 public void SelectFromOrphan ()
220                 {
221                         // SelectSingleNode () from node without parent.
222                         XmlDocument doc = new XmlDocument ();
223                         doc.LoadXml ("<foo><include id='original' /></foo>");
224
225                         XmlNode node = doc.CreateElement ("child");
226                         node.InnerXml = "<include id='new' />";
227
228                         XmlNode new_include = node.SelectSingleNode ("//include");
229                         AssertEquals ("<include id=\"new\" />", new_include.OuterXml);
230
231                         // In this case 'node2' has parent 'node'
232                         doc = new XmlDocument ();
233                         doc.LoadXml ("<foo><include id='original' /></foo>");
234
235                         node = doc.CreateElement ("child");
236                         XmlNode node2 = doc.CreateElement ("grandchild");
237                         node.AppendChild (node2);
238                         node2.InnerXml = "<include id='new' />";
239
240                         new_include = node2.SelectSingleNode ("/");
241                         AssertEquals ("<child><grandchild><include id=\"new\" /></grandchild></child>",
242                                 new_include.OuterXml);
243                 }
244
245                 [Test]
246                 public void XPathDocumentMoveToId ()
247                 {
248                         string dtd = "<!DOCTYPE root [<!ELEMENT root EMPTY><!ATTLIST root id ID #REQUIRED>]>";\r
249                         string xml = dtd + "<root id='aaa'/>";\r
250                         StringReader sr = new StringReader (xml);\r
251                         XPathNavigator nav = new XPathDocument (sr).CreateNavigator ();\r
252                         Assert ("ctor() from TextReader", nav.MoveToId ("aaa"));\r
253
254                         XmlValidatingReader xvr = new XmlValidatingReader (xml, XmlNodeType.Document, null);\r
255                         nav = new XPathDocument (xvr).CreateNavigator ();\r
256                         Assert ("ctor() from XmlValidatingReader", nav.MoveToId ("aaa"));\r
257
258                         // FIXME: it seems to result in different in .NET 2.0.
259 #if NET_2_0
260 #else
261                         // When it is XmlTextReader, XPathDocument fails.
262                         XmlTextReader xtr = new XmlTextReader (xml, XmlNodeType.Document, null);\r
263                         nav = new XPathDocument (xtr).CreateNavigator ();\r
264                         Assert ("ctor() from XmlTextReader", !nav.MoveToId ("aaa"));\r
265                         xtr.Close ();\r
266 #endif
267                 }
268
269                 [Test]
270                 public void SignificantWhitespaceConstruction ()
271                 {
272                         string xml = @"<root>
273         <child xml:space='preserve'>    <!-- -->   </child>
274         <child xml:space='preserve'>    </child>
275 </root>";
276                         XPathNavigator nav = new XPathDocument (
277                                 new XmlTextReader (xml, XmlNodeType.Document, null),
278                                 XmlSpace.Preserve).CreateNavigator ();
279                         nav.MoveToFirstChild ();
280                         nav.MoveToFirstChild ();
281                         AssertEquals ("#1", XPathNodeType.Whitespace, nav.NodeType);
282                         nav.MoveToNext ();
283                         nav.MoveToFirstChild ();
284                         AssertEquals ("#2", XPathNodeType.SignificantWhitespace,
285                                 nav.NodeType);
286                 }
287
288                 [Test]
289                 public void VariableReference ()
290                 {
291                         XPathDocument xpd = new XPathDocument (
292                                 new StringReader ("<root>sample text</root>"));
293                         XPathNavigator nav = xpd.CreateNavigator ();
294
295                         XPathExpression expr = nav.Compile ("foo(string(.),$idx)");
296                         XsltArgumentList args = new XsltArgumentList ();
297                         args.AddParam ("idx", "", 5);
298                         MyContext ctx = new MyContext (nav.NameTable as NameTable, args);
299                         ctx.AddNamespace ("x", "urn:foo");
300
301                         expr.SetContext (ctx);
302
303                         XPathNodeIterator iter = nav.Select ("/root");
304                         iter.MoveNext ();
305                         AssertEquals ("e", iter.Current.Evaluate (expr));
306                 }
307
308                 class MyContext : XsltContext
309                 {
310                         XsltArgumentList args;
311
312                         public MyContext (NameTable nt, XsltArgumentList args)
313                                 : base (nt)
314                         {
315                                 this.args = args;
316                         }
317
318                         public override IXsltContextFunction ResolveFunction (
319                                 string prefix, string name, XPathResultType [] argtypes)
320                         {
321                                 if (name == "foo")
322                                         return new MyFunction (argtypes);
323                                 return null;
324                         }
325
326                         public override IXsltContextVariable ResolveVariable (string prefix, string name)
327                         {
328                                 return new MyVariable (name);
329                         }
330
331                         public override bool PreserveWhitespace (XPathNavigator nav)
332                         {
333                                 return false;
334                         }
335
336                         public override int CompareDocument (string uri1, string uri2)
337                         {
338                                 return String.CompareOrdinal (uri1, uri2);
339                         }
340
341                         public override bool Whitespace {
342                                 get { return false; }
343                         }
344
345                         public object GetParam (string name, string ns)
346                         {
347                                 return args.GetParam (name, ns);
348                         }
349                 }
350
351                 public class MyFunction : IXsltContextFunction
352                 {
353                         XPathResultType [] argtypes;
354
355                         public MyFunction (XPathResultType [] argtypes)
356                         {
357                                 this.argtypes = argtypes;
358                         }
359
360                         public XPathResultType [] ArgTypes {
361                                 get { return argtypes; }
362                         }
363
364                         public int Maxargs {
365                                 get { return 2; }
366                         }
367
368                         public int Minargs {
369                                 get { return 2; }
370                         }
371
372                         public XPathResultType ReturnType {
373                                 get { return XPathResultType.String; }
374                         }
375
376                         public object Invoke (XsltContext xsltContext,
377                                 object [] args, XPathNavigator instanceContext)
378                         {
379                                 return ((string) args [0]) [(int) (double) args [1]].ToString ();
380                         }
381                 }
382
383                 public class MyVariable : IXsltContextVariable
384                 {
385                         string name;
386
387                         public MyVariable (string name)
388                         {
389                                 this.name = name;
390                         }
391
392                         public object Evaluate (XsltContext ctx)
393                         {
394                                 return ((MyContext) ctx).GetParam (name, String.Empty);
395                         }
396
397                         public bool IsLocal {
398                                 get { return false; }
399                         }
400
401                         public bool IsParam {
402                                 get { return false; }
403                         }
404
405                         public XPathResultType VariableType {
406                                 get { return XPathResultType.Any; }
407                         }
408                 }
409
410 #if NET_2_0
411                 [Test]
412                 public void ValueAsBoolean ()
413                 {
414                         string xml = "<root>1</root>";
415                         XmlDocument doc = new XmlDocument ();
416                         doc.LoadXml (xml);
417                         XPathNavigator nav = doc.CreateNavigator ();
418                         nav.MoveToFirstChild ();
419                         AssertEquals ("#1", true, nav.ValueAsBoolean);
420                         nav.MoveToFirstChild ();
421                         AssertEquals ("#2", true, nav.ValueAsBoolean);
422                 }
423
424                 [Test]
425                 [ExpectedException (typeof (FormatException))]
426                 public void ValueAsBooleanFail ()
427                 {
428                         string xml = "<root>1.0</root>";
429                         XmlDocument doc = new XmlDocument ();
430                         doc.LoadXml (xml);
431                         XPathNavigator nav = doc.CreateNavigator ();
432                         nav.MoveToFirstChild ();
433                         bool i = nav.ValueAsBoolean;
434                 }
435
436                 [Test]
437                 public void ValueAsDateTime ()
438                 {
439                         DateTime time = new DateTime (2005, 12, 13);
440                         string xml = "<root>2005-12-13</root>";
441                         XmlDocument doc = new XmlDocument ();
442                         doc.LoadXml (xml);
443                         XPathNavigator nav = doc.CreateNavigator ();
444                         nav.MoveToFirstChild ();
445                         AssertEquals ("#1", time, nav.ValueAsDateTime);
446                         nav.MoveToFirstChild ();
447                         AssertEquals ("#2", time, nav.ValueAsDateTime);
448                 }
449
450                 [Test]
451                 [ExpectedException (typeof (FormatException))]
452                 public void ValueAsDateTimeFail ()
453                 {
454                         string xml = "<root>dating time</root>";
455                         XmlDocument doc = new XmlDocument ();
456                         doc.LoadXml (xml);
457                         XPathNavigator nav = doc.CreateNavigator ();
458                         nav.MoveToFirstChild ();
459                         DateTime time = nav.ValueAsDateTime;
460                 }
461
462                 [Test]
463                 public void ValueAsDouble ()
464                 {
465                         string xml = "<root>3.14159265359</root>";
466                         XmlDocument doc = new XmlDocument ();
467                         doc.LoadXml (xml);
468                         XPathNavigator nav = doc.CreateNavigator ();
469                         nav.MoveToFirstChild ();
470                         AssertEquals ("#1", 3.14159265359, nav.ValueAsDouble);
471                         nav.MoveToFirstChild ();
472                         AssertEquals ("#2", 3.14159265359, nav.ValueAsDouble);
473                 }
474
475                 [Test]
476                 [ExpectedException (typeof (FormatException))]
477                 public void ValueAsDoubleFail ()
478                 {
479                         string xml = "<root>Double Dealer</root>";
480                         XmlDocument doc = new XmlDocument ();
481                         doc.LoadXml (xml);
482                         XPathNavigator nav = doc.CreateNavigator ();
483                         nav.MoveToFirstChild ();
484                         Double dealer = nav.ValueAsDouble;
485                 }
486
487                 [Test]
488                 public void ValueAsInt ()
489                 {
490                         string xml = "<root>1</root>";
491                         XmlDocument doc = new XmlDocument ();
492                         doc.LoadXml (xml);
493                         XPathNavigator nav = doc.CreateNavigator ();
494                         nav.MoveToFirstChild ();
495                         AssertEquals ("#1", 1, nav.ValueAsInt);
496                         nav.MoveToFirstChild ();
497                         AssertEquals ("#2", 1, nav.ValueAsInt);
498                 }
499
500                 [Test]
501                 // Here, it seems to be using XQueryConvert (whatever was called)
502                 [ExpectedException (typeof (FormatException))]
503                 public void ValueAsIntFail ()
504                 {
505                         string xml = "<root>1.0</root>";
506                         XmlDocument doc = new XmlDocument ();
507                         doc.LoadXml (xml);
508                         XPathNavigator nav = doc.CreateNavigator ();
509                         nav.MoveToFirstChild ();
510                         int i = nav.ValueAsInt;
511                 }
512
513                 [Test]
514                 public void ValueAsLong ()
515                 {
516                         string xml = "<root>10000000000000000</root>";
517                         XmlDocument doc = new XmlDocument ();
518                         doc.LoadXml (xml);
519                         XPathNavigator nav = doc.CreateNavigator ();
520                         nav.MoveToFirstChild ();
521                         AssertEquals ("#1", 10000000000000000, nav.ValueAsLong);
522                         nav.MoveToFirstChild ();
523                         AssertEquals ("#2", 10000000000000000, nav.ValueAsLong);
524                 }
525
526                 [Test]
527                 // Here, it seems to be using XQueryConvert (whatever was called)
528                 [ExpectedException (typeof (FormatException))]
529                 public void ValueAsLongFail ()
530                 {
531                         string xml = "<root>0x10000000000000000</root>";
532                         XmlDocument doc = new XmlDocument ();
533                         doc.LoadXml (xml);
534                         XPathNavigator nav = doc.CreateNavigator ();
535                         nav.MoveToFirstChild ();
536                         long l = nav.ValueAsLong;
537                 }
538
539                 [Test] // bug #79874
540                 public void InnerXmlText ()
541                 {
542                         StringReader sr = new StringReader ("<Abc><Foo>Hello</Foo></Abc>");
543                         XPathDocument doc = new XPathDocument (sr);
544                         XPathNavigator nav = doc.CreateNavigator ();
545                         XPathNodeIterator iter = nav.Select ("/Abc/Foo");
546                         iter.MoveNext ();
547                         AssertEquals ("#1", "Hello", iter.Current.InnerXml);
548                         AssertEquals ("#2", "<Foo>Hello</Foo>", iter.Current.OuterXml);
549                         iter = nav.Select ("/Abc/Foo/text()");
550                         iter.MoveNext ();
551                         AssertEquals ("#3", String.Empty, iter.Current.InnerXml);
552                         AssertEquals ("#4", "Hello", iter.Current.OuterXml);
553                 }
554
555                 [Test] // bug #79875
556                 public void InnerXmlAttribute ()
557                 {
558                         StringReader sr = new StringReader ("<Abc><Foo attr='val1'/></Abc>");
559                         XPathDocument doc = new XPathDocument (sr);
560                         XPathNavigator nav = doc.CreateNavigator ();
561
562                         XPathNodeIterator iter = nav.Select ("/Abc/Foo/@attr");
563                         iter.MoveNext ();
564                         AssertEquals ("val1", iter.Current.InnerXml);
565                 }
566
567                 [Test]
568                 public void InnerXmlTextEscape ()
569                 {
570                         StringReader sr = new StringReader ("<Abc><Foo>Hello&lt;\r\nInnerXml</Foo></Abc>");
571                         XPathDocument doc = new XPathDocument (sr);
572                         XPathNavigator nav = doc.CreateNavigator ();
573                         XPathNodeIterator iter = nav.Select ("/Abc/Foo");
574                         iter.MoveNext ();
575                         AssertEquals ("#1", "Hello&lt;\r\nInnerXml", iter.Current.InnerXml);
576                         AssertEquals ("#2", "<Foo>Hello&lt;\r\nInnerXml</Foo>", iter.Current.OuterXml);
577                         iter = nav.Select ("/Abc/Foo/text()");
578                         iter.MoveNext ();
579                         AssertEquals ("#3", String.Empty, iter.Current.InnerXml);
580                         AssertEquals ("#4", "Hello&lt;\r\nInnerXml", iter.Current.OuterXml);
581                 }
582
583                 [Test]
584                 [Category ("NotDotNet")] // .NET bug; it should escape value
585                 public void InnerXmlAttributeEscape ()
586                 {
587                         StringReader sr = new StringReader ("<Abc><Foo attr='val&quot;1&#13;&#10;&gt;'/></Abc>");
588                         XPathDocument doc = new XPathDocument (sr);
589                         XPathNavigator nav = doc.CreateNavigator ();
590
591                         XPathNodeIterator iter = nav.Select ("/Abc/Foo/@attr");
592                         iter.MoveNext ();
593                         AssertEquals ("val&quot;1&#10;&gt;", iter.Current.InnerXml);
594                 }
595 #endif
596         }
597 }