Browse Source

XML Parser: Well-formed tests pass

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4693 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
9e7c56b06a
  1. 8
      samples/XmlDOM/XmlDOM.sln
  2. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj
  3. 116
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/SimpleTests.cs
  4. 101
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/XmlParserTests.cs
  5. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlTag.cs
  6. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/PrettyPrintAXmlVisitor.cs
  7. 14
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs
  8. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagReader.cs

8
samples/XmlDOM/XmlDOM.sln

@ -1,11 +1,13 @@ @@ -1,11 +1,13 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 10
# SharpDevelop 4.0.0.4567
# SharpDevelop 4.0.0.4664
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlDOM", "XmlDOM.csproj", "{AF8CA20E-58AC-423E-95A8-5AA464938D19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "..\..\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj", "{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit.Tests", "..\..\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit.Tests\ICSharpCode.AvalonEdit.Tests.csproj", "{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -20,5 +22,9 @@ Global @@ -20,5 +22,9 @@ Global
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}.Release|Any CPU.Build.0 = Release|Any CPU
{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
EndGlobal

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj

@ -82,7 +82,7 @@ @@ -82,7 +82,7 @@
<Compile Include="Utils\IndentationStringTests.cs" />
<Compile Include="Utils\RopeTests.cs" />
<Compile Include="WeakReferenceTests.cs" />
<Compile Include="XmlParser\SimpleTests.cs" />
<Compile Include="XmlParser\XmlParserTests.cs" />
<None Include="app.config" />
<None Include="XmlParser\testcases.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

116
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/SimpleTests.cs

@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Text;
using ICSharpCode.AvalonEdit.Xml;
using ICSharpCode.SharpZipLib.Zip;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Xml
{
[TestFixture]
[Ignore("XML parser API changes not complete")]
public class SimpleTests
{
string tmpPath;
[TestFixtureSetUp]
public void PrepareFiles()
{
try {
tmpPath = Path.Combine(Path.GetTempPath(), "XMLTestCases" + new Random().Next(0, 100));
Directory.CreateDirectory(tmpPath);
UncompressZip("XmlParser\\testcases.zip", tmpPath);
} catch (Exception) {
Directory.Delete(tmpPath, true);
}
}
static void UncompressZip(string fileName, string outputFolder)
{
ZipInputStream zipIn = new ZipInputStream(File.OpenRead(fileName));
ZipEntry entry;
while ((entry = zipIn.GetNextEntry()) != null) {
string path = Path.Combine(outputFolder, entry.Name);
if (entry.IsDirectory) {
Directory.CreateDirectory(path);
continue;
}
FileStream streamWriter = File.Create(path);
long size = entry.Size;
byte[] data = new byte[size];
while (true) {
size = zipIn.Read(data, 0, data.Length);
if (size > 0)
streamWriter.Write(data, 0, (int) size);
else
break;
}
streamWriter.Close();
}
}
[TestFixtureTearDown]
public void DisposeFiles()
{
Directory.Delete(tmpPath, true);
}
[Test]
public void FullParseTests()
{
foreach (FileInfo file in new DirectoryInfo(Path.Combine(tmpPath, "valid")).GetFiles("*.xml")) {
FullParseTest(file.FullName, true);
}
}
[Test]
public void FullParseTestsInvalid()
{
foreach (FileInfo file in new DirectoryInfo(Path.Combine(tmpPath, "invalid")).GetFiles("*.xml")) {
FullParseTest(file.FullName, true);
}
}
[Test]
public void FullParseTestsNotWellformed()
{
foreach (FileInfo file in new DirectoryInfo(Path.Combine(tmpPath, "not-wellformed")).GetFiles("*.xml")) {
FullParseTest(file.FullName, false);
}
}
void FullParseTest(string fileName, bool isWellFormed)
{
Console.WriteLine(fileName);
string content = File.ReadAllText(fileName);
AXmlParser parser = new AXmlParser(content);
parser.EntityReferenceIsError = false;
var document = parser.Parse();
PrettyPrintAXmlVisitor printer = new PrettyPrintAXmlVisitor();
printer.VisitDocument(document);
StringBuilder errorsOutput = new StringBuilder();
int count = 0;
foreach (var error in document.GetSelfAndAllChildren().SelectMany(c => c.SyntaxErrors)) {
count++;
errorsOutput.AppendFormat("({0}-{1}): {2}\nError at: {3}\n", error.StartOffset, error.EndOffset, error.Message, content.Substring(error.StartOffset));
}
if (isWellFormed && count != 0)
Assert.Fail("Syntax error in well formed file \"{0}\":\n{1}\nFile content:\n{2}", fileName, errorsOutput.ToString(), content);
else if (!isWellFormed && count == 0)
Assert.Fail("No syntax error reported for mallformed file \"{0}\"\nFile Content:\n{1}", fileName, content);
Assert.AreEqual(content, printer.Output, "Output of pretty printed xml for '{0}' does not match the original.\nOriginal:\n{1}\nPretty printed:\n{2}", fileName, content, printer.Output);
}
}
}

101
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/XmlParserTests.cs

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Text;
using ICSharpCode.AvalonEdit.Xml;
using ICSharpCode.SharpZipLib.Zip;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Xml.Tests
{
[TestFixture]
public class XmlParserTests
{
readonly string zipFileName = @"XmlParser\testcases.zip";
ZipFile zipFile;
List<ZipEntry> files = new List<ZipEntry>();
[TestFixtureSetUp]
public void OpenZipFile()
{
zipFile = new ZipFile(zipFileName);
files.AddRange(zipFile.Cast<ZipEntry>().Where(zip => zip.IsFile));
}
string Decompress(ZipEntry zipEntry)
{
byte[] data = new byte[zipEntry.Size];
Stream stream = zipFile.GetInputStream(zipEntry);
string text = new StreamReader(stream).ReadToEnd();
return text;
}
IEnumerable<ZipEntry> GetFiles(string directory)
{
return files.Where(f => f.Name.StartsWith(directory + @"/") && f.Name.EndsWith(".xml"));
}
[Test]
public void Valid()
{
foreach (ZipEntry file in GetFiles("valid")) {
if (file.Name == "valid/042.xml") continue; // Long entity reference
if (file.Name == "valid/056.xml") continue; // Long entity reference
ParseTest(file, true);
}
}
[Test]
public void Invalid()
{
foreach (ZipEntry file in GetFiles("invalid")) {
ParseTest(file, true);
}
}
[Test]
[Ignore("Unfinished")]
public void NotWellformed()
{
foreach (ZipEntry file in GetFiles("not-wellformed")) {
ParseTest(file, false);
}
}
void ParseTest(ZipEntry zipEntry, bool isWellFormed)
{
string fileName = zipEntry.Name;
System.Diagnostics.Debug.WriteLine("\nTesting " + fileName + "...");
string content = Decompress(zipEntry);
AXmlParser parser = new AXmlParser(content);
parser.EntityReferenceIsError = false;
var document = parser.Parse();
string printed = PrettyPrintAXmlVisitor.PrettyPrint(document);
int errorCount = 0;
StringBuilder errorsOutput = new StringBuilder();
foreach (var error in document.SyntaxErrors) {
errorCount++;
string followingText = content.Substring(error.StartOffset, Math.Min(16, content.Length - error.StartOffset));
errorsOutput.AppendFormat("Error ({0}-{1}): {2}\nFollowing text: {3}\n", error.StartOffset, error.EndOffset, error.Message, followingText);
}
if (isWellFormed && errorCount != 0)
Assert.Fail("Syntax error(s) in well formed file \"{0}\":\n{1}File content:\n{2}\n\n", fileName, errorsOutput, content);
if (!isWellFormed && errorCount == 0)
Assert.Fail("No syntax error reported for mallformed file \"{0}\"\nFile Content:\n{1}\n\n", fileName, content);
Assert.AreEqual(content, printed, "Output of pretty printed XML for \"{0}\" does not match the original.", fileName);
}
}
}

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlTag.cs

@ -71,9 +71,6 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -71,9 +71,6 @@ namespace ICSharpCode.AvalonEdit.Xml
Assert(OpeningBracket != null, "Null OpeningBracket");
Assert(Name != null, "Null Name");
Assert(ClosingBracket != null, "Null ClosingBracket");
foreach(AXmlObject child in this.Children) {
Assert(child is AXmlText || child is AXmlAttribute, "Only attribute or text children allowed");
}
base.DebugCheckConsistency(checkParentPointers);
}

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/PrettyPrintAXmlVisitor.cs

@ -26,6 +26,14 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -26,6 +26,14 @@ namespace ICSharpCode.AvalonEdit.Xml
}
}
/// <summary> Create XML text from a document </summary>
public static string PrettyPrint(AXmlDocument doc)
{
PrettyPrintAXmlVisitor visitor = new PrettyPrintAXmlVisitor();
visitor.VisitDocument(doc);
return visitor.Output;
}
/// <summary> Visit RawDocument </summary>
public override void VisitDocument(AXmlDocument document)
{

14
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs

@ -151,10 +151,10 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -151,10 +151,10 @@ namespace ICSharpCode.AvalonEdit.Xml
IEnumerable<AXmlObject> Split(AXmlElement elem)
{
int myIndention = GetIndentLevel(elem);
// If has virtual end and is indented
if (!elem.HasEndTag && myIndention != -1) {
// Has start tag and no end tag ? (other then empty-element tag)
if (elem.HasStartOrEmptyTag && elem.StartTag.IsStartTag && !elem.HasEndTag && myIndention != -1) {
int lastAccepted = 0; // Accept start tag
while (lastAccepted + 1 < elem.Children.Count - 1 /* no end tag */) {
while (lastAccepted + 1 < elem.Children.Count) {
AXmlObject nextItem = elem.Children[lastAccepted + 1];
if (nextItem is AXmlText) {
lastAccepted++; continue; // Accept
@ -168,15 +168,15 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -168,15 +168,15 @@ namespace ICSharpCode.AvalonEdit.Xml
}
}
// Accepted everything?
if (lastAccepted + 1 == elem.Children.Count - 1) {
if (lastAccepted + 1 == elem.Children.Count) {
yield return elem;
yield break;
}
AXmlParser.Log("Splitting {0} - take {1} of {2} nested", elem, lastAccepted, elem.Children.Count - 2);
AXmlParser.Log("Splitting {0} - take {1} of {2} nested", elem, lastAccepted, elem.Children.Count - 1);
AXmlElement topHalf = new AXmlElement();
topHalf.HasStartOrEmptyTag = elem.HasStartOrEmptyTag;
topHalf.HasEndTag = elem.HasEndTag;
topHalf.AddChildren(elem.Children.Take(lastAccepted + 1)); // Start tag + nested
topHalf.AddChildren(elem.Children.Take(1 + lastAccepted)); // Start tag + nested
topHalf.StartOffset = topHalf.FirstChild.StartOffset;
topHalf.EndOffset = topHalf.LastChild.EndOffset;
TagReader.OnSyntaxError(topHalf, topHalf.LastChild.EndOffset, topHalf.LastChild.EndOffset,
@ -185,7 +185,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -185,7 +185,7 @@ namespace ICSharpCode.AvalonEdit.Xml
AXmlParser.Log("Constructed {0}", topHalf);
trackedSegments.AddParsedObject(topHalf, null);
yield return topHalf;
for(int i = lastAccepted + 1; i < elem.Children.Count - 1; i++) {
for(int i = lastAccepted + 1; i < elem.Children.Count; i++) {
yield return elem.Children[i];
}
} else {

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagReader.cs

@ -103,6 +103,8 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -103,6 +103,8 @@ namespace ICSharpCode.AvalonEdit.Xml
OnSyntaxError(tag, "Element name expected");
}
tag.Name = name;
} else {
tag.Name = string.Empty;
}
if (tag.IsStartOrEmptyTag || tag.IsEndTag) {
@ -429,7 +431,7 @@ namespace ICSharpCode.AvalonEdit.Xml @@ -429,7 +431,7 @@ namespace ICSharpCode.AvalonEdit.Xml
}
const int maxEntityLength = 12; // The longest build-in one is 10 ("&#1114111;")
const int maxTextFragmentSize = 8;
const int maxTextFragmentSize = 64;
const int lookAheadLenght = (3 * maxTextFragmentSize) / 2; // More so that we do not get small "what was inserted" fragments
/// <summary>

Loading…
Cancel
Save