2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Security / Test / System.Security.Cryptography.Xml / XmlDsigC14NTransformTest.cs
1 //
2 // XmlDsigC14NTransformTest.cs - NUnit Test Cases for XmlDsigC14NTransform
3 //
4 // Author:
5 //      Sebastien Pouliot <sebastien@ximian.com>
6 //      Aleksey Sanin (aleksey@aleksey.com)
7 //
8 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
9 // (C) 2003 Aleksey Sanin (aleksey@aleksey.com)
10 // (C) 2004 Novell (http://www.novell.com)
11 //
12
13 using System;
14 using System.IO;
15 using System.Security.Cryptography.Xml;
16 using System.Text;
17 using System.Xml;
18
19 using NUnit.Framework;
20
21 namespace MonoTests.System.Security.Cryptography.Xml {
22
23         // Note: GetInnerXml is protected in XmlDsigC14NTransform making it
24         // difficult to test properly. This class "open it up" :-)
25         public class UnprotectedXmlDsigC14NTransform : XmlDsigC14NTransform {
26
27                 public XmlNodeList UnprotectedGetInnerXml () {
28                         return base.GetInnerXml ();
29                 }
30         }
31
32         [TestFixture]
33         public class XmlDsigC14NTransformTest : Assertion {
34
35                 protected UnprotectedXmlDsigC14NTransform transform;
36
37                 [SetUp]
38                 protected void SetUp () 
39                 {
40                         transform = new UnprotectedXmlDsigC14NTransform ();
41                 }
42
43                 [TearDown]
44                 protected void CleanUp () 
45                 {
46                         try {
47                                 if (File.Exists ("doc.dtd"))
48                                         File.Delete ("doc.dtd");
49                                 if (File.Exists ("world.txt"))
50                                         File.Delete ("world.txt");
51                         }
52                         catch {}
53                 }
54
55                 [Test]
56                 public void Properties () 
57                 {
58                         AssertEquals ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", transform.Algorithm);
59
60                         Type[] input = transform.InputTypes;
61                         Assert ("Input #", (input.Length == 3));
62                         // check presence of every supported input types
63                         bool istream = false;
64                         bool ixmldoc = false;
65                         bool ixmlnl = false;
66                         foreach (Type t in input) {
67                                 if (t.ToString () == "System.IO.Stream")
68                                         istream = true;
69                                 if (t.ToString () == "System.Xml.XmlDocument")
70                                         ixmldoc = true;
71                                 if (t.ToString () == "System.Xml.XmlNodeList")
72                                         ixmlnl = true;
73                         }
74                         Assert ("Input Stream", istream);
75                         Assert ("Input XmlDocument", ixmldoc);
76                         Assert ("Input XmlNodeList", ixmlnl);
77
78                         Type[] output = transform.OutputTypes;
79                         Assert ("Output #", (output.Length == 1));
80                         // check presence of every supported output types
81                         bool ostream = false;
82                         foreach (Type t in output) {
83                                 if (t.ToString () == "System.IO.Stream")
84                                         ostream = true;
85                         }
86                         Assert ("Output Stream", ostream);
87                 }
88
89                 [Test]
90                 public void GetInnerXml () 
91                 {
92                         XmlNodeList xnl = transform.UnprotectedGetInnerXml ();
93                         AssertNull ("Default InnerXml", xnl);
94                 }
95
96                 private string Stream2String (Stream s) 
97                 {
98                         StringBuilder sb = new StringBuilder ();
99                         int b = s.ReadByte ();
100                         while (b != -1) {
101                                 sb.Append (Convert.ToChar (b));
102                                 b = s.ReadByte ();
103                         }
104                         return sb.ToString ();
105                 }
106
107                 static string xml = "<Test  attrib='at ' xmlns=\"http://www.go-mono.com/\" > \r\n <Toto/> text &amp; </Test   >";
108                 // BAD (framework 1.0 result)
109                 static string c14xml1 = "<Test xmlns=\"http://www.go-mono.com/\" attrib=\"at \"> \r\n <Toto></Toto> text &amp; </Test>";
110                 // BAD (framework 1.1 result for Stream)
111                 static string c14xml2 = "<Test xmlns=\"http://www.go-mono.com/\" attrib=\"at \"> \n <Toto></Toto> text &amp; </Test>";
112                 // GOOD (framework 1.1 for XmlDocument and Mono::)
113                 static string c14xml3 = "<Test xmlns=\"http://www.go-mono.com/\" attrib=\"at \"> &#xD;\n <Toto></Toto> text &amp; </Test>";
114
115                 private XmlDocument GetDoc () 
116                 {
117                         XmlDocument doc = new XmlDocument ();
118                         doc.PreserveWhitespace = true;
119                         doc.LoadXml (xml);
120                         return doc;
121                 }
122
123                 [Test]
124                 public void LoadInputAsXmlDocument () 
125                 {
126                         XmlDocument doc = GetDoc ();
127                         transform.LoadInput (doc);
128                         Stream s = (Stream) transform.GetOutput ();
129                         string output = Stream2String (s);
130 #if NET_1_0
131                         // .NET 1.0 keeps the \r\n (0x0D, 0x0A) - bug
132                         AssertEquals("XmlDocument", c14xml1, output);
133 #else
134                         AssertEquals("XmlDocument", c14xml3, output);
135 #endif
136                 }
137
138                 [Test]
139                 public void LoadInputAsXmlNodeList () 
140                 {
141                         XmlDocument doc = GetDoc ();
142                         // Argument list just contains element Test.
143                         transform.LoadInput (doc.ChildNodes);
144                         Stream s = (Stream) transform.GetOutput ();
145                         string output = Stream2String (s);
146                         AssertEquals ("XmlChildNodes", "<Test></Test>", output);
147                 }
148
149                 [Test]
150                 public void LoadInputAsXmlNodeList2 () 
151                 {
152                         XmlDocument doc = GetDoc ();
153                         transform.LoadInput (doc.SelectNodes ("//*"));
154                         Stream s = (Stream) transform.GetOutput ();
155                         string output = Stream2String (s);
156                         string expected = @"<Test><Toto></Toto></Test>";
157                         AssertEquals ("XmlChildNodes", expected, output);
158                 }
159
160                 [Test]
161                 public void LoadInputAsStream () 
162                 {
163                         MemoryStream ms = new MemoryStream ();
164                         byte[] x = Encoding.ASCII.GetBytes (xml);
165                         ms.Write (x, 0, x.Length);
166                         ms.Position = 0;
167                         transform.LoadInput (ms);
168                         Stream s = (Stream) transform.GetOutput ();
169                         string output = Stream2String (s);
170                         // ARGH! HOW CAN MS RETURN SOMETHING DIFFERENT IF A 
171                         // STREAM IS USED THAN IF A XMLDOCUMENT IS USED :-(
172                         bool result = ((output == c14xml2) || (output == c14xml3));
173                         Assert ("MemoryStream", result);
174                 }
175
176                 [Test]
177                 public void LoadInputWithUnsupportedType () 
178                 {
179                         byte[] bad = { 0xBA, 0xD };
180                         // LAMESPEC: input MUST be one of InputType - but no exception is thrown (not documented)
181                         transform.LoadInput (bad);
182                 }
183
184                 [Test]
185                 [ExpectedException (typeof (ArgumentException))]
186                 public void UnsupportedOutput () 
187                 {
188                         XmlDocument doc = new XmlDocument();
189                         object o = transform.GetOutput (doc.GetType ());
190                 }
191
192                 [Test]
193                 public void C14NSpecExample1 ()
194                 {
195                         using (StreamWriter sw = new StreamWriter ("doc.dtd", false, Encoding.ASCII)) {
196                                 sw.Write ("<!-- presence, not content, required -->");
197                                 sw.Close ();
198                         }
199                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample1Input);
200                         AssertEquals ("Example 1 from c14n spec - PIs, Comments, and Outside of Document Element (without comments)", 
201                                         C14NSpecExample1Output, res);
202                 }
203
204                 [Test]
205                 public void C14NSpecExample2 ()
206                 {
207                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample2Input);
208                         AssertEquals ("Example 2 from c14n spec - Whitespace in Document Content (without comments)", 
209                                         C14NSpecExample2Output, res);
210                 }
211
212                 [Test]
213                 public void C14NSpecExample3 ()
214                 {
215                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample3Input);
216                         AssertEquals ("Example 3 from c14n spec - Start and End Tags (without comments)", 
217                                         C14NSpecExample3Output, res);
218                 }
219             
220                 [Test]
221 //              [Ignore ("This test should be fine, but it does not pass under MS.NET")]
222                 public void C14NSpecExample4 ()
223                 {
224                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample4Input);
225                         AssertEquals ("Example 4 from c14n spec - Character Modifications and Character References (without comments)", 
226                                         C14NSpecExample4Output, res);
227                 }
228             
229                 [Test]
230                 public void C14NSpecExample5 ()
231                 {
232                         using (StreamWriter sw = new StreamWriter ("world.txt", false, Encoding.ASCII)) {
233                                 sw.Write ("world");
234                                 sw.Close ();
235                         }
236                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample5Input);
237                         AssertEquals ("Example 5 from c14n spec - Entity References (without comments)", 
238                                         C14NSpecExample5Output, res);
239                 }
240     
241                 [Test]
242                 public void C14NSpecExample6 ()
243                 {
244                         string res = ExecuteXmlDSigC14NTransform (C14NSpecExample6Input);
245                         AssertEquals ("Example 6 from c14n spec - UTF-8 Encoding (without comments)", 
246                                         C14NSpecExample6Output, res);
247                 }
248
249                 private string ExecuteXmlDSigC14NTransform (string InputXml)
250                 {
251                         XmlDocument doc = new XmlDocument ();
252                         doc.PreserveWhitespace = true;
253                         doc.LoadXml (InputXml);
254                 
255                         // Testing default attribute support with
256                         // vreader.ValidationType = ValidationType.None.
257                         //
258                         UTF8Encoding utf8 = new UTF8Encoding ();
259                         byte[] data = utf8.GetBytes (InputXml.ToString ());
260                         Stream stream = new MemoryStream (data);
261                         XmlTextReader reader = new XmlTextReader (stream);
262                         XmlValidatingReader vreader = new XmlValidatingReader (reader);
263                         vreader.ValidationType = ValidationType.None;
264                         vreader.EntityHandling = EntityHandling.ExpandCharEntities;
265                         doc.Load (vreader);
266
267                         transform.LoadInput (doc);
268                         return Stream2String ((Stream)transform.GetOutput ());
269                 }
270
271                 //
272                 // Example 1 from C14N spec - PIs, Comments, and Outside of Document Element: 
273                 // http://www.w3.org/TR/xml-c14n#Example-OutsideDoc
274                 // 
275                 // Aleksey: 
276                 // removed reference to an empty external DTD
277                 //
278                 static string C14NSpecExample1Input =  
279                         "<?xml version=\"1.0\"?>\n" +
280                         "\n" +
281                         "<?xml-stylesheet   href=\"doc.xsl\"\n" +
282                         "   type=\"text/xsl\"   ?>\n" +
283                         "\n" +
284                         // "<!DOCTYPE doc SYSTEM \"doc.dtd\">\n" +
285                         "\n" +
286                         "<doc>Hello, world!<!-- Comment 1 --></doc>\n" +
287                         "\n" +
288                         "<?pi-without-data     ?>\n\n" +
289                         "<!-- Comment 2 -->\n\n" +
290                         "<!-- Comment 3 -->\n";
291                 static string C14NSpecExample1Output =   
292                         "<?xml-stylesheet href=\"doc.xsl\"\n" +
293                         "   type=\"text/xsl\"   ?>\n" +
294                         "<doc>Hello, world!</doc>\n" +
295                         "<?pi-without-data?>";
296                 
297                 //
298                 // Example 2 from C14N spec - Whitespace in Document Content: 
299                 // http://www.w3.org/TR/xml-c14n#Example-WhitespaceInContent
300                 // 
301                 static string C14NSpecExample2Input =  
302                         "<doc>\n" +
303                         "  <clean>   </clean>\n" +
304                         "   <dirty>   A   B   </dirty>\n" +
305                         "   <mixed>\n" +
306                         "      A\n" +
307                         "      <clean>   </clean>\n" +
308                         "      B\n" +
309                         "      <dirty>   A   B   </dirty>\n" +
310                         "      C\n" +
311                         "   </mixed>\n" +
312                         "</doc>\n";
313                 static string C14NSpecExample2Output =   
314                         "<doc>\n" +
315                         "  <clean>   </clean>\n" +
316                         "   <dirty>   A   B   </dirty>\n" +
317                         "   <mixed>\n" +
318                         "      A\n" +
319                         "      <clean>   </clean>\n" +
320                         "      B\n" +
321                         "      <dirty>   A   B   </dirty>\n" +
322                         "      C\n" +
323                         "   </mixed>\n" +
324                         "</doc>";
325             
326                 //
327                 // Example 3 from C14N spec - Start and End Tags: 
328                 // http://www.w3.org/TR/xml-c14n#Example-SETags
329                 //
330                 static string C14NSpecExample3Input =  
331                         "<!DOCTYPE doc [<!ATTLIST e9 attr CDATA \"default\">]>\n" +
332                         "<doc>\n" +
333                         "   <e1   />\n" +
334                         "   <e2   ></e2>\n" +
335                         "   <e3    name = \"elem3\"   id=\"elem3\"    />\n" +
336                         "   <e4    name=\"elem4\"   id=\"elem4\"    ></e4>\n" +
337                         "   <e5 a:attr=\"out\" b:attr=\"sorted\" attr2=\"all\" attr=\"I\'m\"\n" +
338                         "       xmlns:b=\"http://www.ietf.org\" \n" +
339                         "       xmlns:a=\"http://www.w3.org\"\n" +
340                         "       xmlns=\"http://www.uvic.ca\"/>\n" +
341                         "   <e6 xmlns=\"\" xmlns:a=\"http://www.w3.org\">\n" +
342                         "       <e7 xmlns=\"http://www.ietf.org\">\n" +
343                         "           <e8 xmlns=\"\" xmlns:a=\"http://www.w3.org\">\n" +
344                         "               <e9 xmlns=\"\" xmlns:a=\"http://www.ietf.org\"/>\n" +
345                         "           </e8>\n" +
346                         "       </e7>\n" +
347                         "   </e6>\n" +
348                         "</doc>\n";
349                 static string C14NSpecExample3Output =   
350                         "<doc>\n" +
351                         "   <e1></e1>\n" +
352                         "   <e2></e2>\n" +
353                         "   <e3 id=\"elem3\" name=\"elem3\"></e3>\n" +
354                         "   <e4 id=\"elem4\" name=\"elem4\"></e4>\n" +
355                         "   <e5 xmlns=\"http://www.uvic.ca\" xmlns:a=\"http://www.w3.org\" xmlns:b=\"http://www.ietf.org\" attr=\"I\'m\" attr2=\"all\" b:attr=\"sorted\" a:attr=\"out\"></e5>\n" +
356                         "   <e6 xmlns:a=\"http://www.w3.org\">\n" +
357                         "       <e7 xmlns=\"http://www.ietf.org\">\n" +
358                         "           <e8 xmlns=\"\">\n" +
359                         "               <e9 xmlns:a=\"http://www.ietf.org\" attr=\"default\"></e9>\n" +
360 //                      "               <e9 xmlns:a=\"http://www.ietf.org\"></e9>\n" +
361                         "           </e8>\n" +
362                         "       </e7>\n" +
363                         "   </e6>\n" +
364                         "</doc>";
365             
366             
367                 //
368                 // Example 4 from C14N spec - Character Modifications and Character References: 
369                 // http://www.w3.org/TR/xml-c14n#Example-Chars
370                 //
371                 // Aleksey: 
372                 // This test does not include "normId" element
373                 // because it has an invalid ID attribute "id" which
374                 // should be normalized by XML parser. Currently Mono
375                 // does not support this (see comment after this example
376                 // in the spec).
377                 static string C14NSpecExample4Input =  
378                         "<!DOCTYPE doc [<!ATTLIST normId id ID #IMPLIED>]>\n" +
379                         "<doc>\n" +
380                         "   <text>First line&#x0d;&#10;Second line</text>\n" +
381                         "   <value>&#x32;</value>\n" +
382                         "   <compute><![CDATA[value>\"0\" && value<\"10\" ?\"valid\":\"error\"]]></compute>\n" +
383                         "   <compute expr=\'value>\"0\" &amp;&amp; value&lt;\"10\" ?\"valid\":\"error\"\'>valid</compute>\n" +
384                         "   <norm attr=\' &apos;   &#x20;&#13;&#xa;&#9;   &apos; \'/>\n" +
385                         // "   <normId id=\' &apos;   &#x20;&#13;&#xa;&#9;   &apos; \'/>\n" +
386                         "</doc>\n";
387                 static string C14NSpecExample4Output =   
388                         "<doc>\n" +
389                         "   <text>First line&#xD;\n" +
390                         "Second line</text>\n" +
391                         "   <value>2</value>\n" +
392                         "   <compute>value&gt;\"0\" &amp;&amp; value&lt;\"10\" ?\"valid\":\"error\"</compute>\n" +
393                         "   <compute expr=\"value>&quot;0&quot; &amp;&amp; value&lt;&quot;10&quot; ?&quot;valid&quot;:&quot;error&quot;\">valid</compute>\n" +
394                         "   <norm attr=\" \'    &#xD;&#xA;&#x9;   \' \"></norm>\n" +
395                         // "   <normId id=\"\' &#xD;&#xA;&#x9; \'\"></normId>\n" +
396                         "</doc>";
397             
398                 //
399                 // Example 5 from C14N spec - Entity References: 
400                 // http://www.w3.org/TR/xml-c14n#Example-Entities
401                 //
402                 static string C14NSpecExample5Input =  
403                         "<!DOCTYPE doc [\n" +
404                         "<!ATTLIST doc attrExtEnt ENTITY #IMPLIED>\n" +
405                         "<!ENTITY ent1 \"Hello\">\n" +
406                         "<!ENTITY ent2 SYSTEM \"world.txt\">\n" +
407                         "<!ENTITY entExt SYSTEM \"earth.gif\" NDATA gif>\n" +
408                         "<!NOTATION gif SYSTEM \"viewgif.exe\">\n" +
409                         "]>\n" +
410                         "<doc attrExtEnt=\"entExt\">\n" +
411                         "   &ent1;, &ent2;!\n" +
412                         "</doc>\n" +
413                         "\n" +
414                         "<!-- Let world.txt contain \"world\" (excluding the quotes) -->\n";
415                 static string C14NSpecExample5Output =  
416                         "<doc attrExtEnt=\"entExt\">\n" +
417                         "   Hello, world!\n" +
418                         "</doc>";           
419     
420                 //
421                 // Example 6 from C14N spec - UTF-8 Encoding: 
422                 // http://www.w3.org/TR/xml-c14n#Example-UTF8
423                 // 
424                 static string C14NSpecExample6Input =  
425                         "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" +
426                         "<doc>&#169;</doc>\n";
427                 static string C14NSpecExample6Output =  
428                         "<doc>\xC2\xA9</doc>";
429             
430
431                 //
432                 // Example 7 from C14N spec - Document Subsets: 
433                 // http://www.w3.org/TR/xml-c14n#Example-DocSubsets
434                 // 
435                 // Aleksey:
436                 // Well, XPath support in Mono is far from complete....
437                 // I was not able to simplify the xpath expression from this test
438                 // so it runs on Mono and still makes sense for testing this feature.
439                 // Thus this test is not included in the suite now.
440                 static string C14NSpecExample7Input =  
441                         "<!DOCTYPE doc [\n" +
442                         "<!ATTLIST e2 xml:space (default|preserve) \'preserve\'>\n" +
443                         "<!ATTLIST e3 id ID #IMPLIED>\n" +
444                         "]>\n" +
445                         "<doc xmlns=\"http://www.ietf.org\" xmlns:w3c=\"http://www.w3.org\">\n" +
446                         "   <e1>\n" +
447                         "      <e2 xmlns=\"\">\n" +
448                         "         <e3 id=\"E3\"/>\n" +
449                         "      </e2>\n" +
450                         "   </e1>\n" +
451                         "</doc>\n";
452
453                 static string C14NSpecExample7Xpath =  
454                         "(//.|//@*|//namespace::*)\n" +
455                         "[\n" +
456                         "self::ietf:e1\n" +
457                         "    or\n" +
458                         "(parent::ietf:e1 and not(self::text() or self::e2))\n" +
459                         "    or\n" +
460                         "count(id(\"E3\")|ancestor-or-self::node()) = count(ancestor-or-self::node())\n" +
461                         "]";
462                 static string C14NSpecExample7Output =  
463                         "<e1 xmlns=\"http://www.ietf.org\" xmlns:w3c=\"http://www.w3.org\"><e3 xmlns=\"\" id=\"E3\" xml:space=\"preserve\"></e3></e1>";
464         }    
465 }