Ver código fonte

Added Unit tests for InsertText, RemoveText, ReplaceText and subsequently fixed many bugs.

master
coffeycathal_cp 15 anos atrás
pai
commit
4569014c0e
4 arquivos alterados com 255 adições e 54 exclusões
  1. 4
    19
      DocX.sln
  2. 2
    1
      DocX/HelperFunctions.cs
  3. 39
    34
      DocX/Paragraph.cs
  4. 210
    0
      UnitTests/UnitTest1.cs

+ 4
- 19
DocX.sln Ver arquivo

@@ -10,25 +10,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX", "DocX\DocX.csproj", "{E863D072-AA8B-4108-B5F1-785241B37F67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApplication1", "ConsoleApplication1\ConsoleApplication1.csproj", "{5C3408FE-0F80-4093-9C2B-1C46B4358F72}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}"
EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 4
SccNumberOfProjects = 3
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs08
SccLocalPath0 = .
SccProjectUniqueName1 = DocX\\DocX.csproj
SccProjectName1 = DocX
SccLocalPath1 = DocX
SccProjectUniqueName2 = ConsoleApplication1\\ConsoleApplication1.csproj
SccProjectName2 = ConsoleApplication1
SccLocalPath2 = ConsoleApplication1
SccProjectUniqueName3 = UnitTests\\UnitTests.csproj
SccProjectName3 = UnitTests
SccLocalPath3 = UnitTests
SccProjectUniqueName2 = UnitTests\\UnitTests.csproj
SccProjectName2 = UnitTests
SccLocalPath2 = UnitTests
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = DocX.vsmdi
@@ -52,16 +47,6 @@ Global
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|x86.ActiveCfg = Release|Any CPU
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Debug|Any CPU.ActiveCfg = Debug|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Debug|Mixed Platforms.Build.0 = Debug|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Debug|x86.ActiveCfg = Debug|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Debug|x86.Build.0 = Debug|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Release|Any CPU.ActiveCfg = Release|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Release|Mixed Platforms.ActiveCfg = Release|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Release|Mixed Platforms.Build.0 = Release|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Release|x86.ActiveCfg = Release|x86
{5C3408FE-0F80-4093-9C2B-1C46B4358F72}.Release|x86.Build.0 = Release|x86
{3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EA73F1C-9E0B-4ED5-B04B-6C043D14D1AA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

+ 2
- 1
DocX/HelperFunctions.cs Ver arquivo

@@ -386,7 +386,8 @@ namespace Novacode
static internal XElement[] SplitParagraph(Paragraph p, int index)
{
Run r = p.GetFirstRunEffectedByInsert(index);
// In this case edit dosent really matter, you have a choice.
Run r = p.GetFirstRunEffectedByEdit(index, EditType.ins);
XElement[] split;
XElement before, after;

+ 39
- 34
DocX/Paragraph.cs Ver arquivo

@@ -851,7 +851,7 @@ namespace Novacode
/// -->
public Paragraph InsertHyperlink(int index, Hyperlink h)
{
Run run = GetFirstRunEffectedByInsert(index);
Run run = GetFirstRunEffectedByEdit(index);
if (run == null)
return AppendHyperlink(h);
@@ -1277,7 +1277,7 @@ namespace Novacode
{
Picture picture = CreatePicture(Document, imageID, name, description);
Run run = GetFirstRunEffectedByInsert(index);
Run run = GetFirstRunEffectedByEdit(index);
if (run == null)
Xml.Add(picture.Xml);
@@ -1406,7 +1406,7 @@ namespace Novacode
);
}
internal Run GetFirstRunEffectedByInsert(int index)
internal Run GetFirstRunEffectedByEdit(int index, EditType type = EditType.ins)
{
// Make sure we are looking within an acceptable index range.
if (index < 0 || index > HelperFunctions.GetText(Xml).Length)
@@ -1416,22 +1416,27 @@ namespace Novacode
int count = 0;
Run theOne = null;
GetFirstRunEffectedByInsertRecursive(Xml, index, ref count, ref theOne);
GetFirstRunEffectedByEditRecursive(Xml, index, ref count, ref theOne, type);
return theOne;
}
internal void GetFirstRunEffectedByInsertRecursive(XElement Xml, int index, ref int count, ref Run theOne)
internal void GetFirstRunEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Run theOne, EditType type)
{
count += HelperFunctions.GetSize(Xml);
if (count > 0 && count >= index)
// If the EditType is deletion then we must return the next blah
if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index)))
{
// Correct the index
foreach (XElement e in Xml.ElementsBeforeSelf())
count -= HelperFunctions.GetSize(e);
count -= HelperFunctions.GetSize(Xml);
// We have found the element, now find the run it belongs to.
while (Xml.Name.LocalName != "r")
{
count -= HelperFunctions.GetSize(Xml);
Xml = Xml.Parent;
}
theOne = new Run(Document, Xml, count);
return;
@@ -1440,7 +1445,7 @@ namespace Novacode
if (Xml.HasElements)
foreach (XElement e in Xml.Elements())
if (theOne == null)
GetFirstRunEffectedByInsertRecursive(e, index, ref count, ref theOne);
GetFirstRunEffectedByEditRecursive(e, index, ref count, ref theOne, type);
}
/// <!--
@@ -1472,9 +1477,9 @@ namespace Novacode
internal XElement[] SplitEdit(XElement edit, int index, EditType type)
{
Run run = GetFirstRunEffectedByInsert(index);
Run run = GetFirstRunEffectedByEdit(index, type);
XElement[] splitRun = Run.SplitRun(run, index);
XElement[] splitRun = Run.SplitRun(run, index, type);
XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[0]);
if (GetElementTextLength(splitLeft) == 0)
@@ -1539,7 +1544,7 @@ namespace Novacode
/// <param name="index">The index position of the insertion.</param>
/// <param name="value">The System.String to insert.</param>
/// <param name="trackChanges">Flag this insert as a change.</param>
public void InsertText(int index, string value, bool trackChanges)
public void InsertText(int index, string value, bool trackChanges = false)
{
InsertText(index, value, trackChanges, null);
}
@@ -1726,7 +1731,7 @@ namespace Novacode
DateTime insert_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc);
// Get the first run effected by this Insert
Run run = GetFirstRunEffectedByInsert(index);
Run run = GetFirstRunEffectedByEdit(index);
if (run == null)
{
@@ -2771,7 +2776,7 @@ namespace Novacode
/// <param name="index">The position to begin deleting characters.</param>
/// <param name="count">The number of characters to delete</param>
/// <param name="trackChanges">Track changes</param>
public void RemoveText(int index, int count, bool trackChanges)
public void RemoveText(int index, int count, bool trackChanges = false)
{
// Timestamp to mark the start of insert
DateTime now = DateTime.Now;
@@ -2783,7 +2788,7 @@ namespace Novacode
do
{
// Get the first run effected by this Remove
Run run = GetFirstRunEffectedByInsert(index + processed);
Run run = GetFirstRunEffectedByEdit(index, EditType.del);
// The parent of this Run
XElement parentElement = run.Xml.Parent;
@@ -2791,11 +2796,11 @@ namespace Novacode
{
case "ins":
{
XElement[] splitEditBefore = SplitEdit(parentElement, index + processed, EditType.del);
XElement[] splitEditBefore = SplitEdit(parentElement, index, EditType.del);
int min = Math.Min(count - processed, run.Xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e)));
XElement[] splitEditAfter = SplitEdit(parentElement, index + processed + min, EditType.del);
XElement[] splitEditAfter = SplitEdit(parentElement, index + min, EditType.del);
XElement temp = SplitEdit(splitEditBefore[1], index + processed + min, EditType.del)[0];
XElement temp = SplitEdit(splitEditBefore[1], index + min, EditType.del)[0];
object middle = CreateEdit(EditType.del, remove_datetime, temp.Elements());
processed += GetElementTextLength(middle as XElement);
@@ -2829,11 +2834,11 @@ namespace Novacode
default:
{
XElement[] splitRunBefore = Run.SplitRun(run, index + processed);
XElement[] splitRunBefore = Run.SplitRun(run, index, EditType.del);
int min = Math.Min(index + processed + (count - processed), run.EndIndex);
XElement[] splitRunAfter = Run.SplitRun(run, min);
XElement[] splitRunAfter = Run.SplitRun(run, min, EditType.del);
object middle = CreateEdit(EditType.del, remove_datetime, new List<XElement>() { Run.SplitRun(new Run(Document, splitRunBefore[1], run.StartIndex + GetElementTextLength(splitRunBefore[0])), min)[0] });
object middle = CreateEdit(EditType.del, remove_datetime, new List<XElement>() { Run.SplitRun(new Run(Document, splitRunBefore[1], run.StartIndex + GetElementTextLength(splitRunBefore[0])), min, EditType.del)[0] });
processed += GetElementTextLength(middle as XElement);
if (!trackChanges)
@@ -2853,7 +2858,7 @@ namespace Novacode
// If after this remove the parent element is empty, remove it.
if (GetElementTextLength(parentElement) == 0)
{
if (parentElement.Parent != null && parentElement.Parent.Name.LocalName != "tc")
if (parentElement.Parent != null && parentElement.Parent.Name.LocalName != "tc")
parentElement.Remove();
}
}
@@ -3050,7 +3055,7 @@ namespace Novacode
do
{
// Get the next run effected
Run run = GetFirstRunEffectedByInsert(m.Index + processed);
Run run = GetFirstRunEffectedByEdit(m.Index + processed);
// Get this runs properties
XElement rPr = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName));
@@ -3215,7 +3220,7 @@ namespace Novacode
/// <param name="newValue">A System.String to replace all occurances of oldValue.</param>
/// <param name="oldValue">A System.String to be replaced.</param>
/// <param name="trackChanges">Track changes</param>
public void ReplaceText(string oldValue, string newValue, bool trackChanges)
public void ReplaceText(string oldValue, string newValue, bool trackChanges = false)
{
ReplaceText(oldValue, newValue, trackChanges, RegexOptions.None, null, null, MatchFormattingOptions.SubsetMatch);
}
@@ -3293,11 +3298,11 @@ namespace Novacode
endIndex = start;
}
static internal XElement[] SplitRun(Run r, int index)
static internal XElement[] SplitRun(Run r, int index, EditType type = EditType.ins)
{
index = index - r.StartIndex;
Text t = r.GetFirstTextEffectedByInsert(index);
Text t = r.GetFirstTextEffectedByEdit(index, type);
XElement[] splitText = Text.SplitText(t, index);
XElement splitLeft = new XElement(r.Xml.Name, r.Xml.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.Xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]);
@@ -3318,7 +3323,7 @@ namespace Novacode
);
}
internal Text GetFirstTextEffectedByInsert(int index)
internal Text GetFirstTextEffectedByEdit(int index, EditType type = EditType.ins)
{
// Make sure we are looking within an acceptable index range.
if (index < 0 || index > HelperFunctions.GetText(Xml).Length)
@@ -3328,24 +3333,24 @@ namespace Novacode
int count = 0;
Text theOne = null;
GetFirstTextEffectedByInsertRecursive(Xml, index, ref count, ref theOne);
GetFirstTextEffectedByEditRecursive(Xml, index, ref count, ref theOne, type);
return theOne;
}
internal void GetFirstTextEffectedByInsertRecursive(XElement Xml, int index, ref int count, ref Text theOne)
internal void GetFirstTextEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Text theOne, EditType type = EditType.ins)
{
count += HelperFunctions.GetSize(Xml);
if (count > 0 && count >= index)
if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index)))
{
theOne = new Text(Document, Xml, 0);
theOne = new Text(Document, Xml, count - HelperFunctions.GetSize(Xml));
return;
}
if (Xml.HasElements)
foreach (XElement e in Xml.Elements())
if (theOne == null)
GetFirstTextEffectedByInsertRecursive(e, index, ref count, ref theOne);
GetFirstTextEffectedByEditRecursive(e, index, ref count, ref theOne);
}
}
@@ -3434,7 +3439,7 @@ namespace Novacode
else
{
if (index == t.StartIndex)
if (index == t.EndIndex)
splitLeft = t.Xml;
else

+ 210
- 0
UnitTests/UnitTest1.cs Ver arquivo

@@ -8,6 +8,7 @@ using System.Reflection;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Xml.Linq;
namespace UnitTests
{
@@ -122,9 +123,217 @@ namespace UnitTests
b.Save(i.GetStream(FileMode.Create, FileAccess.Write), ImageFormat.Png);
}
[TestMethod]
public void Test_Paragraph_ReplaceText()
{
// Create a new document
using (DocX document = DocX.Create("Test.docx"))
{
// Simple
Paragraph p1 = document.InsertParagraph("Apple Pear Apple Apple Pear Apple");
p1.ReplaceText("Apple", "Orange"); Assert.IsTrue(p1.Text == "Orange Pear Orange Orange Pear Orange");
p1.ReplaceText("Pear", "Apple"); Assert.IsTrue(p1.Text == "Orange Apple Orange Orange Apple Orange");
p1.ReplaceText("Orange", "Pear"); Assert.IsTrue(p1.Text == "Pear Apple Pear Pear Apple Pear");
// Difficult
Paragraph p2 = document.InsertParagraph("Apple Pear Apple Apple Pear Apple");
p2.ReplaceText(" ", "\t"); Assert.IsTrue(p2.Text == "Apple\tPear\tApple\tApple\tPear\tApple");
p2.ReplaceText("\tApple\tApple", ""); Assert.IsTrue(p2.Text == "Apple\tPear\tPear\tApple");
p2.ReplaceText("Apple\tPear\t", ""); Assert.IsTrue(p2.Text == "Pear\tApple");
p2.ReplaceText("Pear\tApple", ""); Assert.IsTrue(p2.Text == "");
}
}
[TestMethod]
public void Test_Paragraph_RemoveText()
{
// Create a new document
using (DocX document = DocX.Create("Test.docx"))
{
// Simple
//<p>
// <r><t>HellWorld</t></r>
//</p>
Paragraph p1 = document.InsertParagraph("HelloWorld");
p1.RemoveText(0, 1); Assert.IsTrue(p1.Text == "elloWorld");
p1.RemoveText(p1.Text.Length - 1, 1); Assert.IsTrue(p1.Text == "elloWorl");
p1.RemoveText(p1.Text.IndexOf("o"), 1); Assert.IsTrue(p1.Text == "ellWorl");
// Difficult
//<p>
// <r><t>A</t></r>
// <r><t>B</t></r>
// <r><t>C</t></r>
//</p>
Paragraph p2 = document.InsertParagraph("A\tB\tC");
p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == "\tB\tC");
p2.RemoveText(p2.Text.Length - 1, 1); Assert.IsTrue(p2.Text == "\tB\t");
p2.RemoveText(p2.Text.IndexOf("B"), 1); Assert.IsTrue(p2.Text == "\t\t");
p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == "\t");
p2.RemoveText(0, 1); Assert.IsTrue(p2.Text == "");
// Contrived 1
//<p>
// <r>
// <t>A</t>
// <t>B</t>
// <t>C</t>
// </r>
//</p>
Paragraph p3 = document.InsertParagraph("");
p3.Xml = XElement.Parse
(
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr />
<w:r>
<w:rPr />
<w:t>A</w:t>
<w:t>B</w:t>
<w:t>C</w:t>
</w:r>
</w:p>"
);
p3.RemoveText(0, 1); Assert.IsTrue(p3.Text == "BC");
p3.RemoveText(p3.Text.Length - 1, 1); Assert.IsTrue(p3.Text == "B");
p3.RemoveText(0, 1); Assert.IsTrue(p3.Text == "");
// Contrived 2
//<p>
// <r>
// <t>A</t>
// <t>B</t>
// <t>C</t>
// </r>
//</p>
Paragraph p4 = document.InsertParagraph("");
p4.Xml = XElement.Parse
(
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr />
<w:r>
<w:rPr />
<tab />
<w:t>A</w:t>
<tab />
</w:r>
<w:r>
<w:rPr />
<tab />
<w:t>B</w:t>
<tab />
</w:r>
</w:p>"
);
p4.RemoveText(0, 1); Assert.IsTrue(p4.Text == "A\t\tB\t");
p4.RemoveText(1, 1); Assert.IsTrue(p4.Text == "A\tB\t");
p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "A\tB");
p4.RemoveText(1, 1); Assert.IsTrue(p4.Text == "AB");
p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "A");
p4.RemoveText(p4.Text.Length - 1, 1); Assert.IsTrue(p4.Text == "");
}
}
[TestMethod]
public void Test_Paragraph_InsertText()
{
// Create a new document
using (DocX document = DocX.Create("Test.docx"))
{
// Simple
//<p>
// <r><t>HelloWorld</t></r>
//</p>
Paragraph p1 = document.InsertParagraph("HelloWorld");
p1.InsertText(0, "-"); Assert.IsTrue(p1.Text == "-HelloWorld");
p1.InsertText(p1.Text.Length, "-"); Assert.IsTrue(p1.Text == "-HelloWorld-");
p1.InsertText(p1.Text.IndexOf("W"), "-"); Assert.IsTrue(p1.Text == "-Hello-World-");
// Difficult
//<p>
// <r><t>A</t></r>
// <r><t>B</t></r>
// <r><t>C</t></r>
//</p>
Paragraph p2 = document.InsertParagraph("A\tB\tC");
p2.InsertText(0, "-"); Assert.IsTrue(p2.Text == "-A\tB\tC");
p2.InsertText(p2.Text.Length, "-"); Assert.IsTrue(p2.Text == "-A\tB\tC-");
p2.InsertText(p2.Text.IndexOf("B"), "-"); Assert.IsTrue(p2.Text == "-A\t-B\tC-");
p2.InsertText(p2.Text.IndexOf("C"), "-"); Assert.IsTrue(p2.Text == "-A\t-B\t-C-");
// Contrived 1
//<p>
// <r>
// <t>A</t>
// <t>B</t>
// <t>C</t>
// </r>
//</p>
Paragraph p3 = document.InsertParagraph("");
p3.Xml = XElement.Parse
(
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr />
<w:r>
<w:rPr />
<w:t>A</w:t>
<w:t>B</w:t>
<w:t>C</w:t>
</w:r>
</w:p>"
);
p3.InsertText(0, "-"); Assert.IsTrue(p3.Text == "-ABC");
p3.InsertText(p3.Text.Length, "-"); Assert.IsTrue(p3.Text == "-ABC-");
p3.InsertText(p3.Text.IndexOf("B"), "-"); Assert.IsTrue(p3.Text == "-A-BC-");
p3.InsertText(p3.Text.IndexOf("C"), "-"); Assert.IsTrue(p3.Text == "-A-B-C-");
// Contrived 2
//<p>
// <r>
// <t>A</t>
// <t>B</t>
// <t>C</t>
// </r>
//</p>
Paragraph p4 = document.InsertParagraph("");
p4.Xml = XElement.Parse
(
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr />
<w:r>
<w:rPr />
<w:t>A</w:t>
<w:t>B</w:t>
<w:t>C</w:t>
</w:r>
</w:p>"
);
p4.InsertText(0, "\t"); Assert.IsTrue(p4.Text == "\tABC");
p4.InsertText(p4.Text.Length, "\t"); Assert.IsTrue(p4.Text == "\tABC\t");
p4.InsertText(p4.Text.IndexOf("B"), "\t"); Assert.IsTrue(p4.Text == "\tA\tBC\t");
p4.InsertText(p4.Text.IndexOf("C"), "\t"); Assert.IsTrue(p4.Text == "\tA\tB\tC\t");
}
}
[TestMethod]
public void Test_Document_Paragraphs()
{
// This document contains a run with two text next to each other.
// <run>
// <text>Hello World</text>
// <text>foo</text>
// </run>
using (DocX document = DocX.Load(@"C:\Users\Cathal\Desktop\Bug.docx"))
{
Paragraph p = document.Paragraphs[0];
Assert.IsTrue(p.Text == "Hello worldfoo");
p.RemoveText("Hello world".Length, 3, false);
Assert.IsTrue(p.Text == "Hello world");
}
// Load the document 'Paragraphs.docx'
using (DocX document = DocX.Load(directory_documents + "Paragraphs.docx"))
{
@@ -163,6 +372,7 @@ namespace UnitTests
// Test ReplaceText
p2.ReplaceText("foo", "bar", false);
Assert.IsTrue(p2.Text == "Paragraph 2bar bar bar");
// Test RemoveText

Carregando…
Cancelar
Salvar