// // XmlDsigC14NTransformTest.cs - NUnit Test Cases for XmlDsigC14NTransform // // Author: // Sebastien Pouliot // Aleksey Sanin (aleksey@aleksey.com) // // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) // (C) 2003 Aleksey Sanin (aleksey@aleksey.com) // (C) 2004 Novell (http://www.novell.com) // using System; using System.IO; using System.Security.Cryptography.Xml; using System.Text; using System.Xml; using NUnit.Framework; namespace MonoTests.System.Security.Cryptography.Xml { // Note: GetInnerXml is protected in XmlDsigC14NTransform making it // difficult to test properly. This class "open it up" :-) public class UnprotectedXmlDsigC14NTransform : XmlDsigC14NTransform { public XmlNodeList UnprotectedGetInnerXml () { return base.GetInnerXml (); } } [TestFixture] public class XmlDsigC14NTransformTest : Assertion { protected UnprotectedXmlDsigC14NTransform transform; [SetUp] protected void SetUp () { transform = new UnprotectedXmlDsigC14NTransform (); } [TearDown] protected void CleanUp () { try { if (File.Exists ("doc.dtd")) File.Delete ("doc.dtd"); if (File.Exists ("world.txt")) File.Delete ("world.txt"); } catch {} } [Test] public void Properties () { AssertEquals ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", transform.Algorithm); Type[] input = transform.InputTypes; Assert ("Input #", (input.Length == 3)); // check presence of every supported input types bool istream = false; bool ixmldoc = false; bool ixmlnl = false; foreach (Type t in input) { if (t.ToString () == "System.IO.Stream") istream = true; if (t.ToString () == "System.Xml.XmlDocument") ixmldoc = true; if (t.ToString () == "System.Xml.XmlNodeList") ixmlnl = true; } Assert ("Input Stream", istream); Assert ("Input XmlDocument", ixmldoc); Assert ("Input XmlNodeList", ixmlnl); Type[] output = transform.OutputTypes; Assert ("Output #", (output.Length == 1)); // check presence of every supported output types bool ostream = false; foreach (Type t in output) { if (t.ToString () == "System.IO.Stream") ostream = true; } Assert ("Output Stream", ostream); } [Test] public void GetInnerXml () { XmlNodeList xnl = transform.UnprotectedGetInnerXml (); AssertNull ("Default InnerXml", xnl); } private string Stream2String (Stream s) { StringBuilder sb = new StringBuilder (); int b = s.ReadByte (); while (b != -1) { sb.Append (Convert.ToChar (b)); b = s.ReadByte (); } return sb.ToString (); } static string xml = " \r\n text & "; // BAD (framework 1.0 result) static string c14xml1 = " \r\n text & "; // BAD (framework 1.1 result for Stream) static string c14xml2 = " \n text & "; // GOOD (framework 1.1 for XmlDocument and Mono::) static string c14xml3 = " \n text & "; private XmlDocument GetDoc () { XmlDocument doc = new XmlDocument (); doc.PreserveWhitespace = true; doc.LoadXml (xml); return doc; } [Test] public void LoadInputAsXmlDocument () { XmlDocument doc = GetDoc (); transform.LoadInput (doc); Stream s = (Stream) transform.GetOutput (); string output = Stream2String (s); #if NET_1_0 // .NET 1.0 keeps the \r\n (0x0D, 0x0A) - bug AssertEquals("XmlDocument", c14xml1, output); #else AssertEquals("XmlDocument", c14xml3, output); #endif } [Test] public void LoadInputAsXmlNodeList () { XmlDocument doc = GetDoc (); // Argument list just contains element Test. transform.LoadInput (doc.ChildNodes); Stream s = (Stream) transform.GetOutput (); string output = Stream2String (s); AssertEquals ("XmlChildNodes", "", output); } [Test] public void LoadInputAsXmlNodeList2 () { XmlDocument doc = GetDoc (); transform.LoadInput (doc.SelectNodes ("//*")); Stream s = (Stream) transform.GetOutput (); string output = Stream2String (s); string expected = @""; AssertEquals ("XmlChildNodes", expected, output); } [Test] public void LoadInputAsStream () { MemoryStream ms = new MemoryStream (); byte[] x = Encoding.ASCII.GetBytes (xml); ms.Write (x, 0, x.Length); ms.Position = 0; transform.LoadInput (ms); Stream s = (Stream) transform.GetOutput (); string output = Stream2String (s); // ARGH! HOW CAN MS RETURN SOMETHING DIFFERENT IF A // STREAM IS USED THAN IF A XMLDOCUMENT IS USED :-( bool result = ((output == c14xml2) || (output == c14xml3)); Assert ("MemoryStream", result); } [Test] public void LoadInputWithUnsupportedType () { byte[] bad = { 0xBA, 0xD }; // LAMESPEC: input MUST be one of InputType - but no exception is thrown (not documented) transform.LoadInput (bad); } [Test] [ExpectedException (typeof (ArgumentException))] public void UnsupportedOutput () { XmlDocument doc = new XmlDocument(); object o = transform.GetOutput (doc.GetType ()); } [Test] public void C14NSpecExample1 () { using (StreamWriter sw = new StreamWriter ("doc.dtd", false, Encoding.ASCII)) { sw.Write (""); sw.Close (); } string res = ExecuteXmlDSigC14NTransform (C14NSpecExample1Input); AssertEquals ("Example 1 from c14n spec - PIs, Comments, and Outside of Document Element (without comments)", C14NSpecExample1Output, res); } [Test] public void C14NSpecExample2 () { string res = ExecuteXmlDSigC14NTransform (C14NSpecExample2Input); AssertEquals ("Example 2 from c14n spec - Whitespace in Document Content (without comments)", C14NSpecExample2Output, res); } [Test] public void C14NSpecExample3 () { string res = ExecuteXmlDSigC14NTransform (C14NSpecExample3Input); AssertEquals ("Example 3 from c14n spec - Start and End Tags (without comments)", C14NSpecExample3Output, res); } [Test] // [Ignore ("This test should be fine, but it does not pass under MS.NET")] public void C14NSpecExample4 () { string res = ExecuteXmlDSigC14NTransform (C14NSpecExample4Input); AssertEquals ("Example 4 from c14n spec - Character Modifications and Character References (without comments)", C14NSpecExample4Output, res); } [Test] public void C14NSpecExample5 () { using (StreamWriter sw = new StreamWriter ("world.txt", false, Encoding.ASCII)) { sw.Write ("world"); sw.Close (); } string res = ExecuteXmlDSigC14NTransform (C14NSpecExample5Input); AssertEquals ("Example 5 from c14n spec - Entity References (without comments)", C14NSpecExample5Output, res); } [Test] public void C14NSpecExample6 () { string res = ExecuteXmlDSigC14NTransform (C14NSpecExample6Input); AssertEquals ("Example 6 from c14n spec - UTF-8 Encoding (without comments)", C14NSpecExample6Output, res); } private string ExecuteXmlDSigC14NTransform (string InputXml) { XmlDocument doc = new XmlDocument (); doc.PreserveWhitespace = true; doc.LoadXml (InputXml); // Testing default attribute support with // vreader.ValidationType = ValidationType.None. // UTF8Encoding utf8 = new UTF8Encoding (); byte[] data = utf8.GetBytes (InputXml.ToString ()); Stream stream = new MemoryStream (data); XmlTextReader reader = new XmlTextReader (stream); XmlValidatingReader vreader = new XmlValidatingReader (reader); vreader.ValidationType = ValidationType.None; vreader.EntityHandling = EntityHandling.ExpandCharEntities; doc.Load (vreader); transform.LoadInput (doc); return Stream2String ((Stream)transform.GetOutput ()); } // // Example 1 from C14N spec - PIs, Comments, and Outside of Document Element: // http://www.w3.org/TR/xml-c14n#Example-OutsideDoc // // Aleksey: // removed reference to an empty external DTD // static string C14NSpecExample1Input = "\n" + "\n" + "\n" + "\n" + // "\n" + "\n" + "Hello, world!\n" + "\n" + "\n\n" + "\n\n" + "\n"; static string C14NSpecExample1Output = "\n" + "Hello, world!\n" + ""; // // Example 2 from C14N spec - Whitespace in Document Content: // http://www.w3.org/TR/xml-c14n#Example-WhitespaceInContent // static string C14NSpecExample2Input = "\n" + " \n" + " A B \n" + " \n" + " A\n" + " \n" + " B\n" + " A B \n" + " C\n" + " \n" + "\n"; static string C14NSpecExample2Output = "\n" + " \n" + " A B \n" + " \n" + " A\n" + " \n" + " B\n" + " A B \n" + " C\n" + " \n" + ""; // // Example 3 from C14N spec - Start and End Tags: // http://www.w3.org/TR/xml-c14n#Example-SETags // static string C14NSpecExample3Input = "]>\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; static string C14NSpecExample3Output = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + // " \n" + " \n" + " \n" + " \n" + ""; // // Example 4 from C14N spec - Character Modifications and Character References: // http://www.w3.org/TR/xml-c14n#Example-Chars // // Aleksey: // This test does not include "normId" element // because it has an invalid ID attribute "id" which // should be normalized by XML parser. Currently Mono // does not support this (see comment after this example // in the spec). static string C14NSpecExample4Input = "]>\n" + "\n" + " First line Second line\n" + " 2\n" + " \"0\" && value<\"10\" ?\"valid\":\"error\"]]>\n" + " \"0\" && value<\"10\" ?\"valid\":\"error\"\'>valid\n" + " \n" + // " \n" + "\n"; static string C14NSpecExample4Output = "\n" + " First line \n" + "Second line\n" + " 2\n" + " value>\"0\" && value<\"10\" ?\"valid\":\"error\"\n" + " "0" && value<"10" ?"valid":"error"\">valid\n" + " \n" + // " \n" + ""; // // Example 5 from C14N spec - Entity References: // http://www.w3.org/TR/xml-c14n#Example-Entities // static string C14NSpecExample5Input = "\n" + "\n" + "\n" + "\n" + "\n" + "]>\n" + "\n" + " &ent1;, &ent2;!\n" + "\n" + "\n" + "\n"; static string C14NSpecExample5Output = "\n" + " Hello, world!\n" + ""; // // Example 6 from C14N spec - UTF-8 Encoding: // http://www.w3.org/TR/xml-c14n#Example-UTF8 // static string C14NSpecExample6Input = "\n" + "©\n"; static string C14NSpecExample6Output = "\xC2\xA9"; // // Example 7 from C14N spec - Document Subsets: // http://www.w3.org/TR/xml-c14n#Example-DocSubsets // // Aleksey: // Well, XPath support in Mono is far from complete.... // I was not able to simplify the xpath expression from this test // so it runs on Mono and still makes sense for testing this feature. // Thus this test is not included in the suite now. static string C14NSpecExample7Input = "\n" + "\n" + "]>\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; static string C14NSpecExample7Xpath = "(//.|//@*|//namespace::*)\n" + "[\n" + "self::ietf:e1\n" + " or\n" + "(parent::ietf:e1 and not(self::text() or self::e2))\n" + " or\n" + "count(id(\"E3\")|ancestor-or-self::node()) = count(ancestor-or-self::node())\n" + "]"; static string C14NSpecExample7Output = ""; } }