PageRenderTime 29ms CodeModel.GetById 17ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

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