/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/ParserTests.cs

http://github.com/icsharpcode/ILSpy · C# · 223 lines · 176 code · 26 blank · 21 comment · 28 complexity · 48d994ab80aa4a7542b98c75b0735e8d MD5 · raw file

  1. // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
  2. // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Text;
  9. using ICSharpCode.AvalonEdit.Xml;
  10. using ICSharpCode.SharpZipLib.Zip;
  11. using NUnit.Framework;
  12. namespace ICSharpCode.AvalonEdit.Xml
  13. {
  14. class TestFile
  15. {
  16. public string Name { get; set; }
  17. public string Content { get; set; }
  18. public string Canonical { get; set; }
  19. public string Description { get; set; }
  20. }
  21. [TestFixture]
  22. public class ParserTests
  23. {
  24. readonly string zipFileName = @"XmlParser\W3C.zip";
  25. List<TestFile> xmlFiles = new List<TestFile>();
  26. [TestFixtureSetUp]
  27. public void OpenZipFile()
  28. {
  29. ZipFile zipFile = new ZipFile(zipFileName);
  30. Dictionary<string, TestFile> xmlFiles = new Dictionary<string, TestFile>();
  31. // Decompress XML files
  32. foreach(ZipEntry zipEntry in zipFile.Cast<ZipEntry>().Where(zip => zip.IsFile && zip.Name.EndsWith(".xml"))) {
  33. Stream stream = zipFile.GetInputStream(zipEntry);
  34. string content = new StreamReader(stream).ReadToEnd();
  35. xmlFiles.Add(zipEntry.Name, new TestFile { Name = zipEntry.Name, Content = content });
  36. }
  37. // Add descriptions
  38. foreach(TestFile metaData in xmlFiles.Values.Where(f => f.Name.StartsWith("ibm/ibm_oasis"))) {
  39. var doc = System.Xml.Linq.XDocument.Parse(metaData.Content);
  40. foreach(var testElem in doc.Descendants("TEST")) {
  41. string uri = "ibm/" + testElem.Attribute("URI").Value;
  42. string description = testElem.Value.Replace("\n ", "\n").TrimStart('\n');
  43. if (xmlFiles.ContainsKey(uri))
  44. xmlFiles[uri].Description = description;
  45. }
  46. }
  47. // Copy canonical forms
  48. foreach(TestFile canonical in xmlFiles.Values.Where(f => f.Name.Contains("/out/"))) {
  49. string uri = canonical.Name.Replace("/out/", "/");
  50. if (xmlFiles.ContainsKey(uri))
  51. xmlFiles[uri].Canonical = canonical.Content;
  52. }
  53. // Copy resuts to field
  54. this.xmlFiles.AddRange(xmlFiles.Values.Where(f => !f.Name.Contains("/out/")));
  55. }
  56. IEnumerable<TestFile> GetXmlFilesStartingWith(string directory)
  57. {
  58. return xmlFiles.Where(f => f.Name.StartsWith(directory));
  59. }
  60. [Test]
  61. public void W3C_Valid()
  62. {
  63. string[] exclude = {
  64. // NAME in DTD infoset
  65. "ibm02v01", "ibm03v01", "ibm85v01", "ibm86v01", "ibm87v01", "ibm88v01", "ibm89v01",
  66. };
  67. TestFiles(GetXmlFilesStartingWith("ibm/valid/"), true, exclude);
  68. }
  69. [Test]
  70. public void W3C_Invalid()
  71. {
  72. string[] exclude = {
  73. // Default attribute value
  74. "ibm56i03",
  75. };
  76. TestFiles(GetXmlFilesStartingWith("ibm/invalid/"), true, exclude);
  77. }
  78. [Test]
  79. public void W3C_NotWellformed()
  80. {
  81. string[] exclude = {
  82. // XML declaration well formed
  83. "ibm23n", "ibm24n", "ibm26n01", "ibm32n", "ibm80n06", "ibm81n01", "ibm81n02", "ibm81n03", "ibm81n04", "ibm81n05", "ibm81n06", "ibm81n07", "ibm81n08", "ibm81n09",
  84. // Invalid chars in a comment - do we care?
  85. "ibm02n",
  86. // Invalid char ref - do we care?
  87. "ibm66n12", "ibm66n13", "ibm66n14", "ibm66n15",
  88. // DTD in wrong location
  89. "ibm27n01", "ibm43n",
  90. // Entity refs depending on DTD
  91. "ibm41n10", "ibm41n11", "ibm41n12", "ibm41n13", "ibm41n14", "ibm68n04", "ibm68n06", "ibm68n07", "ibm68n08", "ibm68n09", "ibm68n10",
  92. // DTD Related tests
  93. "ibm09n01", "ibm09n02", "ibm13n01", "ibm13n02", "ibm13n03", "ibm28n01", "ibm28n02", "ibm28n03", "ibm29n01", "ibm29n03", "ibm29n04", "ibm29n07", "ibm30n01", "ibm31n01", "ibm45n01", "ibm45n02", "ibm45n03", "ibm45n04", "ibm45n05", "ibm45n06", "ibm46n01", "ibm46n02", "ibm46n03", "ibm46n04",
  94. "ibm46n05", "ibm47n01", "ibm47n02", "ibm47n03", "ibm47n04", "ibm47n05", "ibm47n06", "ibm48n01", "ibm48n02", "ibm48n03", "ibm48n04", "ibm48n05", "ibm48n06", "ibm48n07", "ibm49n01", "ibm49n02", "ibm49n03", "ibm49n04", "ibm49n05", "ibm49n06", "ibm50n01", "ibm50n02", "ibm50n03", "ibm50n04",
  95. "ibm50n05", "ibm50n06", "ibm50n07", "ibm51n01", "ibm51n02", "ibm51n03", "ibm51n04", "ibm51n05", "ibm51n06", "ibm51n07", "ibm52n01", "ibm52n02", "ibm52n03", "ibm53n01", "ibm53n02", "ibm53n03", "ibm53n04", "ibm53n05", "ibm53n06", "ibm53n07", "ibm53n08", "ibm54n01", "ibm54n02", "ibm55n01",
  96. "ibm55n02", "ibm55n03", "ibm56n01", "ibm56n02", "ibm56n03", "ibm56n04", "ibm56n05", "ibm56n06", "ibm56n07", "ibm57n01", "ibm58n01", "ibm58n02", "ibm58n03", "ibm58n04", "ibm58n05", "ibm58n06", "ibm58n07", "ibm58n08", "ibm59n01", "ibm59n02", "ibm59n03", "ibm59n04", "ibm59n05", "ibm59n06",
  97. "ibm60n01", "ibm60n02", "ibm60n03", "ibm60n04", "ibm60n05", "ibm60n06", "ibm60n07", "ibm60n08", "ibm61n01", "ibm62n01", "ibm62n02", "ibm62n03", "ibm62n04", "ibm62n05", "ibm62n06", "ibm62n07", "ibm62n08", "ibm63n01", "ibm63n02", "ibm63n03", "ibm63n04", "ibm63n05", "ibm63n06", "ibm63n07",
  98. "ibm64n01", "ibm64n02", "ibm64n03", "ibm65n01", "ibm65n02", "ibm66n01", "ibm66n03", "ibm66n05", "ibm66n07", "ibm66n09", "ibm66n11", "ibm69n01", "ibm69n02", "ibm69n03", "ibm69n04", "ibm69n05", "ibm69n06", "ibm69n07", "ibm70n01", "ibm71n01", "ibm71n02", "ibm71n03", "ibm71n04", "ibm71n05",
  99. "ibm72n01", "ibm72n02", "ibm72n03", "ibm72n04", "ibm72n05", "ibm72n06", "ibm72n09", "ibm73n01", "ibm73n03", "ibm74n01", "ibm75n01", "ibm75n02", "ibm75n03", "ibm75n04", "ibm75n05", "ibm75n06", "ibm75n07", "ibm75n08", "ibm75n09", "ibm75n10", "ibm75n11", "ibm75n12", "ibm75n13", "ibm76n01",
  100. "ibm76n02", "ibm76n03", "ibm76n04", "ibm76n05", "ibm76n06", "ibm76n07", "ibm77n01", "ibm77n02", "ibm77n03", "ibm77n04", "ibm78n01", "ibm78n02", "ibm79n01", "ibm79n02", "ibm82n01", "ibm82n02", "ibm82n03", "ibm82n04", "ibm82n08", "ibm83n01", "ibm83n03", "ibm83n04", "ibm83n05", "ibm83n06",
  101. // No idea what this is
  102. "misc/432gewf", "ibm28an01",
  103. };
  104. TestFiles(GetXmlFilesStartingWith("ibm/not-wf/"), false, exclude);
  105. }
  106. StringBuilder errorOutput;
  107. void TestFiles(IEnumerable<TestFile> files, bool areWellFormed, string[] exclude)
  108. {
  109. errorOutput = new StringBuilder();
  110. int testsRun = 0;
  111. int ignored = 0;
  112. foreach (TestFile file in files) {
  113. if (exclude.Any(exc => file.Name.Contains(exc))) {
  114. ignored++;
  115. } else {
  116. testsRun++;
  117. TestFile(file, areWellFormed);
  118. }
  119. }
  120. if (testsRun == 0) {
  121. Assert.Fail("Test files not found");
  122. }
  123. if (errorOutput.Length > 0) {
  124. // Can not output ]]> otherwise nuint will crash
  125. Assert.Fail(errorOutput.Replace("]]>", "]]~NUNIT~>").ToString());
  126. }
  127. }
  128. /// <remarks>
  129. /// If using DTD, canonical representation is not checked
  130. /// If using DTD, uknown entiry references are not error
  131. /// </remarks>
  132. bool TestFile(TestFile testFile, bool isWellFormed)
  133. {
  134. bool passed = true;
  135. string content = testFile.Content;
  136. Debug.WriteLine("Testing " + testFile.Name + "...");
  137. AXmlParser parser = new AXmlParser();
  138. bool usingDTD = content.Contains("<!DOCTYPE") && (content.Contains("<!ENTITY") || content.Contains(" SYSTEM "));
  139. if (usingDTD)
  140. parser.UnknownEntityReferenceIsError = false;
  141. AXmlDocument document;
  142. parser.Lock.EnterWriteLock();
  143. try {
  144. document = parser.Parse(content, null);
  145. } finally {
  146. parser.Lock.ExitWriteLock();
  147. }
  148. string printed = PrettyPrintAXmlVisitor.PrettyPrint(document);
  149. if (content != printed) {
  150. errorOutput.AppendFormat("Output of pretty printed XML for \"{0}\" does not match the original.\n", testFile.Name);
  151. errorOutput.AppendFormat("Pretty printed:\n{0}\n", Indent(printed));
  152. passed = false;
  153. }
  154. if (isWellFormed && !usingDTD) {
  155. string canonicalPrint = CanonicalPrintAXmlVisitor.Print(document);
  156. if (testFile.Canonical != null) {
  157. if (testFile.Canonical != canonicalPrint) {
  158. errorOutput.AppendFormat("Canonical XML for \"{0}\" does not match the excpected.\n", testFile.Name);
  159. errorOutput.AppendFormat("Expected:\n{0}\n", Indent(testFile.Canonical));
  160. errorOutput.AppendFormat("Seen:\n{0}\n", Indent(canonicalPrint));
  161. passed = false;
  162. }
  163. } else {
  164. errorOutput.AppendFormat("Can not find canonical output for \"{0}\"", testFile.Name);
  165. errorOutput.AppendFormat("Suggested canonical output:\n{0}\n", Indent(canonicalPrint));
  166. passed = false;
  167. }
  168. }
  169. bool hasErrors = document.SyntaxErrors.FirstOrDefault() != null;
  170. if (isWellFormed && hasErrors) {
  171. errorOutput.AppendFormat("Syntax error(s) in well formed file \"{0}\":\n", testFile.Name);
  172. foreach (var error in document.SyntaxErrors) {
  173. string followingText = content.Substring(error.StartOffset, Math.Min(10, content.Length - error.StartOffset));
  174. errorOutput.AppendFormat("Error ({0}-{1}): {2} (followed by \"{3}\")\n", error.StartOffset, error.EndOffset, error.Message, followingText);
  175. }
  176. passed = false;
  177. }
  178. if (!isWellFormed && !hasErrors) {
  179. errorOutput.AppendFormat("No syntax errors reported for mallformed file \"{0}\"\n", testFile.Name);
  180. passed = false;
  181. }
  182. // Epilog
  183. if (!passed) {
  184. if (testFile.Description != null) {
  185. errorOutput.AppendFormat("Test description:\n{0}\n", Indent(testFile.Description));
  186. }
  187. errorOutput.AppendFormat("File content:\n{0}\n", Indent(content));
  188. errorOutput.AppendLine();
  189. }
  190. return passed;
  191. }
  192. string Indent(string text)
  193. {
  194. return " " + text.TrimEnd().Replace("\n", "\n ");
  195. }
  196. }
  197. }