blob: 417ae62f03ec05db9df5f1042ccd1705057d1e1c [file] [log] [blame]
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using Xunit;
#if !ELIDE_XUNIT_TESTS
namespace OpenXmlPowerTools.Tests
{
public class OpenXmlRegexTests
{
private const WordprocessingDocumentType DocumentType = WordprocessingDocumentType.Document;
private const string LeftDoubleQuotationMarks = @"[\u0022“„«»”]";
private const string Words = @"[\w\-&/]+(?:\s[\w\-&/]+)*";
private const string RightDoubleQuotationMarks = @"[\u0022”‟»«“]";
private const string QuotationMarksDocumentXmlString =
@"<w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:body>
<w:p>
<w:r>
<w:t xml:space=""preserve"">Text can be enclosed in “normal double quotes” and in </w:t>
</w:r>
<w:r>
<w:t>«</w:t>
</w:r>
<w:r>
<w:t>double angle quotation marks</w:t>
</w:r>
<w:r>
<w:t>»</w:t>
</w:r>
<w:r>
<w:t>.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>";
private const string QuotationMarksAndTrackedChangesDocumentXmlString =
@"<w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:body>
<w:p>
<w:r>
<w:t xml:space=""preserve"">Text can be enclosed in “normal </w:t>
</w:r>
<w:ins w:id=""8"" w:author=""Thomas Barnekow"" w:date=""2016-12-03T15:54:00Z"">
<w:r>
<w:t xml:space=""preserve"">double </w:t>
</w:r>
</w:ins>
<w:r>
<w:t xml:space=""preserve"">quotes” </w:t>
</w:r>
<w:del w:id=""9"" w:author=""Thomas Barnekow"" w:date=""2016-12-03T15:55:00Z"">
<w:r>
<w:delText xml:space=""preserve"">or </w:delText>
</w:r>
</w:del>
<w:ins w:id=""10"" w:author=""Thomas Barnekow"" w:date=""2016-12-03T15:55:00Z"">
<w:r>
<w:t xml:space=""preserve"">and </w:t>
</w:r>
</w:ins>
<w:r>
<w:t xml:space=""preserve"">in </w:t>
</w:r>
<w:r>
<w:t>«</w:t>
</w:r>
<w:r>
<w:t xml:space=""preserve"">double </w:t>
</w:r>
<w:ins w:id=""11"" w:author=""Thomas Barnekow"" w:date=""2016-12-03T15:54:00Z"">
<w:r>
<w:t xml:space=""preserve"">angle </w:t>
</w:r>
</w:ins>
<w:r>
<w:t>quotation marks</w:t>
</w:r>
<w:r>
<w:t>»</w:t>
</w:r>
<w:r>
<w:t>.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>";
private const string SymbolsAndTrackedChangesDocumentXmlString =
@"<w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:body>
<w:p>
<w:r>
<w:t xml:space=""preserve"">We can also use symbols such as </w:t>
</w:r>
<w:del w:id=""4"" w:author=""Thomas Barnekow"" w:date=""2017-04-16T12:31:00Z"">
<w:r>
<w:sym w:font=""Wingdings"" w:char=""F028""/>
</w:r>
<w:r>
<w:delText xml:space=""preserve"">, </w:delText>
</w:r>
</w:del>
<w:r>
<w:sym w:font=""Wingdings"" w:char=""F021""/>
</w:r>
<w:r>
<w:t xml:space=""preserve""> or </w:t>
</w:r>
<w:r>
<w:sym w:font=""Wingdings"" w:char=""F028""/>
</w:r>
<w:r>
<w:t>.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>";
private const string FieldsDocumentXmlString =
@"<w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:body>
<w:p>
<w:pPr>
<w:pStyle w:val=""Heading1""/>
</w:pPr>
<w:bookmarkStart w:id=""0"" w:name=""_Ref491716064""/>
<w:r>
<w:t>Article</w:t>
</w:r>
<w:bookmarkEnd w:id=""0""/>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val=""Heading2""/>
</w:pPr>
<w:bookmarkStart w:id=""1"" w:name=""_Ref491716082""/>
<w:r>
<w:t>Section</w:t>
</w:r>
<w:bookmarkEnd w:id=""1""/>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val=""HeadingBody2""/>
</w:pPr>
<w:r>
<w:t xml:space=""preserve"">As stated in Article </w:t>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""begin""/>
</w:r>
<w:r>
<w:instrText xml:space=""preserve""> REF _Ref491716064 \r \h </w:instrText>
</w:r>
<w:r>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""separate""/>
</w:r>
<w:r>
<w:t>1</w:t>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""end""/>
</w:r>
<w:r>
<w:t xml:space=""preserve""> and this Section </w:t>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""begin""/>
</w:r>
<w:r>
<w:instrText xml:space=""preserve""> REF _Ref491716082 \r \h </w:instrText>
</w:r>
<w:r>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""separate""/>
</w:r>
<w:r>
<w:t>1.1</w:t>
</w:r>
<w:r>
<w:fldChar w:fldCharType=""end""/>
</w:r>
<w:r>
<w:t>, this is described in Schedule C (Performance Framework).</w:t>
</w:r>
</w:p>
</w:body>
</w:document>";
private static string InnerText(XContainer e)
{
return e.Descendants(W.r)
.Where(r => r.Parent.Name != W.del)
.Select(UnicodeMapper.RunToString)
.StringConcatenate();
}
private static string InnerDelText(XContainer e)
{
return e.Descendants(W.delText)
.Select(delText => delText.Value)
.StringConcatenate();
}
[Fact]
public void CanReplaceTextWithQuotationMarks()
{
XDocument partDocument = XDocument.Parse(QuotationMarksDocumentXmlString);
XElement p = partDocument.Descendants(W.p).First();
string innerText = InnerText(p);
Assert.Equal(
"Text can be enclosed in “normal double quotes” and in «double angle quotation marks».",
innerText);
using (var stream = new MemoryStream())
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(partDocument);
IEnumerable<XElement> content = partDocument.Descendants(W.p);
var regex = new Regex(string.Format("{0}(?<words>{1}){2}", LeftDoubleQuotationMarks, Words,
RightDoubleQuotationMarks));
int count = OpenXmlRegex.Replace(content, regex, "‘changed ${words}’", null);
p = partDocument.Descendants(W.p).First();
innerText = InnerText(p);
Assert.Equal(2, count);
Assert.Equal(
"Text can be enclosed in ‘changed normal double quotes’ and in ‘changed double angle quotation marks’.",
innerText);
}
}
[Fact]
public void CanReplaceTextWithQuotationMarksAndAddTrackedChangesWhenReplacing()
{
XDocument partDocument = XDocument.Parse(QuotationMarksDocumentXmlString);
XElement p = partDocument.Descendants(W.p).First();
string innerText = InnerText(p);
Assert.Equal(
"Text can be enclosed in “normal double quotes” and in «double angle quotation marks».",
innerText);
using (var stream = new MemoryStream())
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(partDocument);
IEnumerable<XElement> content = partDocument.Descendants(W.p);
var regex = new Regex(string.Format("{0}(?<words>{1}){2}", LeftDoubleQuotationMarks, Words,
RightDoubleQuotationMarks));
int count = OpenXmlRegex.Replace(content, regex, "‘changed ${words}’", null, true, "John Doe");
p = partDocument.Descendants(W.p).First();
innerText = InnerText(p);
Assert.Equal(2, count);
Assert.Equal(
"Text can be enclosed in ‘changed normal double quotes’ and in ‘changed double angle quotation marks’.",
innerText);
Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed normal double quotes’");
Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed double angle quotation marks’");
Assert.Contains(p.Elements(W.del), e => InnerDelText(e) == "“normal double quotes”");
Assert.Contains(p.Elements(W.del), e => InnerDelText(e) == "«double angle quotation marks»");
}
}
[Fact]
public void CanReplaceTextWithQuotationMarksAndTrackedChanges()
{
XDocument partDocument = XDocument.Parse(QuotationMarksAndTrackedChangesDocumentXmlString);
XElement p = partDocument.Descendants(W.p).First();
string innerText = InnerText(p);
Assert.Equal(
"Text can be enclosed in “normal double quotes” and in «double angle quotation marks».",
innerText);
using (var stream = new MemoryStream())
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(partDocument);
IEnumerable<XElement> content = partDocument.Descendants(W.p);
var regex = new Regex(string.Format("{0}(?<words>{1}){2}", LeftDoubleQuotationMarks, Words,
RightDoubleQuotationMarks));
int count = OpenXmlRegex.Replace(content, regex, "‘changed ${words}’", null, true, "John Doe");
p = partDocument.Descendants(W.p).First();
innerText = InnerText(p);
Assert.Equal(2, count);
Assert.Equal(
"Text can be enclosed in ‘changed normal double quotes’ and in ‘changed double angle quotation marks’.",
innerText);
Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed normal double quotes’");
Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed double angle quotation marks’");
}
}
[Fact]
public void CanReplaceTextWithSymbolsAndTrackedChanges()
{
XDocument partDocument = XDocument.Parse(SymbolsAndTrackedChangesDocumentXmlString);
XElement p = partDocument.Descendants(W.p).First();
string innerText = InnerText(p);
Assert.Equal("We can also use symbols such as \uF021 or \uF028.", innerText);
using (var stream = new MemoryStream())
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(partDocument);
IEnumerable<XElement> content = partDocument.Descendants(W.p);
var regex = new Regex(@"[\uF021]");
int count = OpenXmlRegex.Replace(content, regex, "\uF028", null, true, "John Doe");
p = partDocument.Descendants(W.p).First();
innerText = InnerText(p);
Assert.Equal(1, count);
Assert.Equal("We can also use symbols such as \uF028 or \uF028.", innerText);
Assert.Contains(p.Descendants(W.ins), ins => ins.Descendants(W.sym).Any(
sym => sym.Attribute(W.font).Value == "Wingdings" &&
sym.Attribute(W._char).Value == "F028"));
}
}
[Fact]
public void CanReplaceTextWithFields()
{
XDocument partDocument = XDocument.Parse(FieldsDocumentXmlString);
XElement p = partDocument.Descendants(W.p).Last();
string innerText = InnerText(p);
Assert.Equal("As stated in Article {__1} and this Section {__1.1}, this is described in Schedule C (Performance Framework).",
innerText);
using (var stream = new MemoryStream())
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(partDocument);
IEnumerable<XElement> content = partDocument.Descendants(W.p);
var regex = new Regex(@"Schedule C \(Performance Framework\)");
int count = OpenXmlRegex.Replace(content, regex, "Exhibit 4", null, true, "John Doe");
p = partDocument.Descendants(W.p).Last();
innerText = InnerText(p);
Assert.Equal(1, count);
Assert.Equal("As stated in Article {__1} and this Section {__1.1}, this is described in Exhibit 4.", innerText);
}
}
}
}
#endif