coffeycathal_cp преди 17 години
родител
ревизия
839c5c15c3

+ 72
- 0
CustomPropertyTestApp/CustomPropertyTestApp.csproj Целия файл

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CustomPropertyTestApp</RootNamespace>
<AssemblyName>CustomPropertyTestApp</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DocX, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DocX\bin\Debug\DocX.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Template.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 10
- 0
CustomPropertyTestApp/CustomPropertyTestApp.csproj.vspscc Целия файл

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

+ 78
- 0
CustomPropertyTestApp/Program.cs Целия файл

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Novacode;
namespace CustomPropertyTestApp
{
// This class represents a user
class User
{
public string forname, username, freeGift, HomeAddress;
public DateTime joined;
public bool RecieveFurtherMail;
public User()
{ }
}
class Program
{
static void Main(string[] args)
{
// A list which contains three new users
List<User> newUsers = new List<User>
{
new User
{
forname = "John", username = "John87",
freeGift = "toaster", joined = DateTime.Now,
HomeAddress = "21 Hillview, Naas, Co. Kildare",
RecieveFurtherMail = true
},
new User
{
forname = "James", username = "KingJames",
freeGift = "kitchen knife", joined = DateTime.Now,
HomeAddress = "37 Mill Lane, Maynooth, Co. Meath",
RecieveFurtherMail = false
},
new User
{
forname = "Mary", username = "McNamara1",
freeGift = "microwave", joined = DateTime.Now,
HomeAddress = "110 Cherry Orchard Drive, Navan, Co. Roscommon", RecieveFurtherMail= true
}
};
// Foreach of the three new user create a welcome document based on template.docx
foreach (User newUser in newUsers)
{
// Copy template.docx so that we can customize it for this user
string filename = string.Format(@"{0}.docx", newUser.username);
File.Copy(@"Template.docx", filename, true);
/*
* Load the document to be manipulated and set the custom properties to this
* users specific data
*/
DocX doc = DocX.Load(filename);
doc.SetCustomProperty("Forname", CustomPropertyType.Text, newUser.forname);
doc.SetCustomProperty("Username", CustomPropertyType.Text, newUser.username);
doc.SetCustomProperty("FreeGift", CustomPropertyType.Text, newUser.freeGift);
doc.SetCustomProperty("HomeAddress", CustomPropertyType.Text, newUser.HomeAddress);
doc.SetCustomProperty("PleaseWaitNDays", CustomPropertyType.NumberInteger, 4);
doc.SetCustomProperty("GiftArrivalDate", CustomPropertyType.Date, newUser.joined.AddDays(4).ToUniversalTime());
doc.SetCustomProperty("RecieveFurtherMail", CustomPropertyType.YesOrNo, newUser.RecieveFurtherMail);
// File will be saved to \CustomPropertyTestApp\bin\Debug
doc.Save();
}
}
}
}

+ 36
- 0
CustomPropertyTestApp/Properties/AssemblyInfo.cs Целия файл

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CustomPropertyTestApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft IT")]
[assembly: AssemblyProduct("CustomPropertyTestApp")]
[assembly: AssemblyCopyright("Copyright © Microsoft IT 2009")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("54e1d528-31a1-4718-a659-472cbaf1a551")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Двоични данни
CustomPropertyTestApp/Template.docx Целия файл


+ 69
- 0
DocX.sln Целия файл

@@ -0,0 +1,69 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocX", "DocX\DocX.csproj", "{E863D072-AA8B-4108-B5F1-785241B37F67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}"
ProjectSection(ProjectDependencies) = postProject
{E863D072-AA8B-4108-B5F1-785241B37F67} = {E863D072-AA8B-4108-B5F1-785241B37F67}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF41F5CE-8BCB-40CC-835F-54A3DB7D802F}"
ProjectSection(SolutionItems) = preProject
DocX.vsmdi = DocX.vsmdi
LocalTestRun.testrunconfig = LocalTestRun.testrunconfig
..\..\..\..\..\Desktop\DocX zipped\ReadMe.docx = ..\..\..\..\..\Desktop\DocX zipped\ReadMe.docx
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringReplaceTestApp", "StringReplaceTestApp\StringReplaceTestApp.csproj", "{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomPropertyTestApp", "CustomPropertyTestApp\CustomPropertyTestApp.csproj", "{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}"
EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 5
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = https://tfs08.codeplex.com/
SccLocalPath0 = .
SccProjectUniqueName1 = CustomPropertyTestApp\\CustomPropertyTestApp.csproj
SccProjectName1 = CustomPropertyTestApp
SccLocalPath1 = CustomPropertyTestApp
SccProjectUniqueName2 = DocX\\DocX.csproj
SccProjectName2 = DocX
SccLocalPath2 = DocX
SccProjectUniqueName3 = StringReplaceTestApp\\StringReplaceTestApp.csproj
SccProjectName3 = StringReplaceTestApp
SccLocalPath3 = StringReplaceTestApp
SccProjectUniqueName4 = UnitTests\\UnitTests.csproj
SccProjectName4 = UnitTests
SccLocalPath4 = UnitTests
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = DocX.vsmdi
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E863D072-AA8B-4108-B5F1-785241B37F67}.Release|Any CPU.Build.0 = Release|Any CPU
{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}.Release|Any CPU.Build.0 = Release|Any CPU
{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}.Release|Any CPU.Build.0 = Release|Any CPU
{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9EABCAA8-175C-4FA2-9829-59E9D9E275D3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

+ 6
- 0
DocX.vsmdi Целия файл

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<RunConfiguration id="6869d4b0-c7c0-449b-a3b2-541bd9ae1155" name="Local Test Run" storage="localtestrun.testrunconfig" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, PublicKeyToken=b03f5f7f11d50a3a" />
</TestList>
</TestLists>

+ 10
- 0
DocX.vssscc Целия файл

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

+ 81
- 0
DocX/CustomProperty.cs Целия файл

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Novacode
{
/// <summary>
/// Represents a .docx custom property.
/// </summary>
public class CustomProperty
{
// The underlying XElement which this CustomProperty wraps
private XElement cp;
// This customPropertys name
private string name;
// This customPropertys type
private CustomPropertyType type;
// This customPropertys value
private object value;
/// <summary>
/// Custom Propertys name.
/// </summary>
public string Name { get { return name; } }
/// <summary>
/// Custom Propertys type.
/// </summary>
public CustomPropertyType Type { get { return type; } }
/// <summary>
/// Custom Propertys value.
/// </summary>
public object Value { get { return value; } }
/// <summary>
/// Wraps a System.Xml.Linq.XElement as an instance of Novacode.DocX.CustomProperty
/// </summary>
/// <param name="cp">The XElement to wrap</param>
public CustomProperty(XElement cp)
{
this.cp = cp;
name = cp.Attribute(XName.Get("name")).Value;
XElement p = cp.Elements().SingleOrDefault();
switch (p.Name.LocalName)
{
case "i4":
type = CustomPropertyType.NumberInteger;
value = int.Parse(p.Value);
break;
case "r8":
type = CustomPropertyType.NumberDecimal;
value = double.Parse(p.Value);
break;
case "lpwstr":
type = CustomPropertyType.Text;
value = p.Value;
break;
case "filetime":
type = CustomPropertyType.Date;
value = DateTime.Parse(p.Value);
break;
case "bool":
type = CustomPropertyType.YesOrNo;
value = bool.Parse(p.Value);
break;
default:
throw new Exception(string.Format("The custom property type {0} is not supported", p.Name.LocalName));
}
}
}
}

+ 404
- 0
DocX/DocX.cs Целия файл

@@ -0,0 +1,404 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Packaging;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
namespace Novacode
{
/// <summary>
/// Represents a .docx file.
/// </summary>
public class DocX: IDisposable
{
static internal string editSessionID;
public static XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
/// <summary>
/// Default constructor
/// </summary>
public DocX()
{
editSessionID = Guid.NewGuid().ToString().Substring(0, 8);
}
#region Private static variable declarations
// The URI of this .docx
private static string uri;
// Object representation of the .docx
private static WordprocessingDocument wdDoc;
// Object representation of the \word\document.xml part
private static MainDocumentPart mainDocumentPart;
// Object representation of the \docProps\custom.xml part
private static CustomFilePropertiesPart customPropertiesPart = null;
// The mainDocument is loaded into a XDocument object for easy querying and editing
private static XDocument mainDoc;
// The customPropertyDocument is loaded into a XDocument object for easy querying and editing
private static XDocument customPropDoc;
// The collection of Paragraphs <w:p></w:p> in this .docx
private static IEnumerable<Paragraph> paragraphs;
// The collection of custom properties in this .docx
private static IEnumerable<CustomProperty> customProperties = new List<CustomProperty>();
private static XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
private static XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
private Random random = new Random();
#endregion
/// <summary>
/// Gets the paragraphs of the .docx file.
/// </summary>
/// <seealso cref="Paragraph.Remove"/>
/// <seealso cref="Paragraph.Insert"/>
/// <seealso cref="Paragraph.Replace"/>
/// <example>
/// <code>
/// // Load Test.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs
/// foreach(Paragraph p in dx.Paragraphs)
/// {
/// string paragraphText = p.Value;
/// }
/// </code>
/// </example>
public IEnumerable<Paragraph> Paragraphs
{
get { return paragraphs; }
}
/// <summary>
/// Gets the custom properties of the .docx file.
/// </summary>
/// <seealso cref="SetCustomProperty"/>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the custom properties
/// foreach(CustomProperty cp in dx.CustomProperties)
/// {
/// string customPropertyName = cp.Name;
/// CustomPropertyType customPropertyType = cp.Type;
/// object customPropertyValue = cp.Value;
/// }
/// </code>
/// </example>
public IEnumerable<CustomProperty> CustomProperties
{
get { return customProperties; }
}
/// <summary>
/// Loads a .docx file into a DocX object.
/// </summary>
/// <param name="uri">The fully qualified name of the .docx file, or the relative file name.</param>
/// <returns>
/// Returns a DocX object which represents the .docx file.
/// </returns>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
/// </code>
/// </example>
public static DocX Load(string uri)
{
FileInfo fi = new FileInfo(uri);
if (fi.Extension != ".docx")
throw new Exception(string.Format("The input file {0} is not a .docx file", fi.FullName));
if (!fi.Exists)
throw new Exception(string.Format("The input file {0} does not exist", fi.FullName));
DocX.uri = uri;
// Open the docx package
wdDoc = WordprocessingDocument.Open(uri, true);
#region MainDocumentPart
// Get the main document part from the package
mainDocumentPart = wdDoc.MainDocumentPart;
// Load the document part into a XDocument object
using (TextReader tr = new StreamReader(mainDocumentPart.GetStream(FileMode.Open, FileAccess.Read)))
{
mainDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
}
// Get all of the paragraphs in this document
DocX.paragraphs = from p in mainDoc.Descendants(XName.Get("p", "http://schemas.openxmlformats.org/wordprocessingml/2006/main"))
select new Paragraph(p);
#endregion
#region CustomFilePropertiesPart
// Get the custom file properties part from the package
customPropertiesPart = wdDoc.CustomFilePropertiesPart;
// This docx contains a customFilePropertyPart
if (customPropertiesPart != null)
{
// Load the customFilePropertyPart
using (TextReader tr = new StreamReader(customPropertiesPart.GetStream(FileMode.Open, FileAccess.Read)))
{
customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
}
// Get all of the custom properties in this document
DocX.customProperties = from cp in customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName))
select new CustomProperty(cp);
}
#endregion
return new DocX();
}
/// <summary>
/// Saves all changes made to the DocX object back to the .docx file it represents.
/// </summary>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Insert code to do something useful with dx
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
public void Save()
{
// Save the main document part back to disk
using (TextWriter w = new StreamWriter(mainDocumentPart.GetStream(FileMode.Create, FileAccess.Write)))
{
mainDoc.Save(w, SaveOptions.DisableFormatting);
}
if (customPropertiesPart != null)
{
// Save the custom properties part back to disk
using (TextWriter w = new StreamWriter(customPropertiesPart.GetStream(FileMode.Create, FileAccess.Write)))
{
customPropDoc.Save(w, SaveOptions.DisableFormatting);
}
}
// Save and close the .docx file
wdDoc.Close();
// Reopen the .docx file
Load(uri);
}
#region IDisposable Members
/// <summary>
/// Releases all resources used by Novacode.DocX object.
/// </summary>
public void Dispose()
{
wdDoc.Dispose();
}
#endregion
/// <summary>
/// Set the value of a custom property. If no custom property exists with the name customPropertyName, then a new custom property is created.
/// </summary>
/// <param name="customPropertyName">The name of the custom property to set</param>
/// <param name="customPropertyType">The type of the custom property</param>
/// <param name="customPropertyValue">The value of the custom property</param>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Add custom property 'Name'
/// dx.SetCustomProperty("Name", CustomPropertyType.Text, "Helium");
///
/// // Add custom property 'Date discovered'
/// dx.SetCustomProperty("Date discovered", CustomPropertyType.Date, new DateTime(1868, 08, 18));
///
/// // Add the custom property 'Noble gas'
/// dx.SetCustomProperty("Noble gas", CustomPropertyType.YesOrNo, true);
///
/// // Add the custom property 'Atomic number'
/// dx.SetCustomProperty("Atomic number", CustomPropertyType.NumberInteger, 2);
///
/// // Add the custom property 'Boiling point'
/// dx.SetCustomProperty("Boiling point", CustomPropertyType.NumberDecimal, -268.93);
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Add the custom property 'LCID'
/// dx.SetCustomProperty("LCID", CustomPropertyType.NumberInteger, 1036);
///
/// // Save changes to Example.docx
/// dx.Save();
///
/// // Update the custom property 'LCID' with a new value
/// dx.SetCustomProperty("LCID", CustomPropertyType.NumberInteger, 1041);
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
public void SetCustomProperty(string customPropertyName, CustomPropertyType customPropertyType, object customPropertyValue)
{
string type = "";
string value = "";
switch (customPropertyType)
{
case CustomPropertyType.Text:
{
if (!(customPropertyValue is string))
throw new Exception("Not a string");
type = "lpwstr";
value = customPropertyValue as string;
break;
}
case CustomPropertyType.Date:
{
if (!(customPropertyValue is DateTime))
throw new Exception("Not a DateTime");
type = "filetime";
// Must be UTC time
value = (((DateTime)customPropertyValue).ToUniversalTime()).ToString();
break;
}
case CustomPropertyType.YesOrNo:
{
if (!(customPropertyValue is bool))
throw new Exception("Not a Boolean");
type = "bool";
// Must be lower case either {true or false}
value = (((bool)customPropertyValue)).ToString().ToLower();
break;
}
case CustomPropertyType.NumberInteger:
{
if (!(customPropertyValue is int))
throw new Exception("Not an int");
type = "i4";
value = customPropertyValue.ToString();
break;
}
case CustomPropertyType.NumberDecimal:
{
if (!(customPropertyValue is double))
throw new Exception("Not a double");
type = "r8";
value = customPropertyValue.ToString();
break;
}
}
// This docx does not contain a customFilePropertyPart
if (customPropertiesPart == null)
{
customPropertiesPart = wdDoc.AddCustomFilePropertiesPart();
customPropDoc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new XElement(XName.Get("Properties", customPropertiesSchema.NamespaceName),
new XAttribute(XNamespace.Xmlns + "vt", customVTypesSchema),
new XElement(XName.Get("property", customPropertiesSchema.NamespaceName),
new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"),
new XAttribute("pid", "2"),
new XAttribute("name", customPropertyName),
new XElement(customVTypesSchema + type, customPropertyValue)
)));
}
// This docx contains a customFilePropertyPart
else
{
// Get the highest PID
int pid = (from d in customPropDoc.Descendants()
where d.Name.LocalName == "property"
select int.Parse(d.Attribute(XName.Get("pid")).Value)).Max<int>();
// Get the custom property or null
var customProperty = (from d in customPropDoc.Descendants()
where (d.Name.LocalName == "property") && (d.Attribute(XName.Get("name")).Value == customPropertyName)
select d).SingleOrDefault();
if (customProperty != null)
{
customProperty.Descendants(XName.Get(type, customVTypesSchema.NamespaceName)).SingleOrDefault().ReplaceWith(
new XElement(customVTypesSchema + type, customPropertyValue));
}
else
{
XElement propertiesElement = customPropDoc.Element(XName.Get("Properties", customPropertiesSchema.NamespaceName));
propertiesElement.Add(new XElement(XName.Get("property", customPropertiesSchema.NamespaceName),
new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"),
new XAttribute("pid", pid + 1),
new XAttribute("name", customPropertyName),
new XElement(customVTypesSchema + type, customPropertyValue)
));
}
}
UpdateCustomPropertyValue(customPropertyName, customPropertyValue.ToString());
}
private static void UpdateCustomPropertyValue(string customPropertyName, string customPropertyValue)
{
foreach (XElement e in mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName)))
{
if (e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Equals(string.Format(@" DOCPROPERTY {0} \* MERGEFORMAT ", customPropertyName), StringComparison.CurrentCultureIgnoreCase))
{
XElement firstRun = e.Element(w + "r");
// Delete everything and insert updated text value
e.RemoveNodes();
XElement t = new XElement(w + "t", customPropertyValue);
Text.PreserveSpace(t);
e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
}
}
}
/// <summary>
/// Renumber all ins and del ids in this .docx file.
/// </summary>
private static void RenumberIDs()
{
IEnumerable<XAttribute> trackerIDs =
(from d in mainDoc.Descendants()
where d.Name.LocalName == "ins" || d.Name.LocalName == "del"
select d.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/wordprocessingml/2006/main")));
for (int i = 0; i < trackerIDs.Count(); i++)
trackerIDs.ElementAt(i).Value = i.ToString();
}
}
}

+ 74
- 0
DocX/DocX.csproj Целия файл

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E863D072-AA8B-4108-B5F1-785241B37F67}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Novacode</RootNamespace>
<AssemblyName>DocX</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\DocX.XML</DocumentationFile>
<DeepSeaObfuscate>false</DeepSeaObfuscate>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DocumentFormat.OpenXml, Version=2.0.3302.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="CustomProperty.cs" />
<Compile Include="Enumerations.cs" />
<Compile Include="Paragraph.cs" />
<Compile Include="DocX.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Run.cs" />
<Compile Include="Text.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\DeepSea Obfuscator\DeepSea.Obfuscator.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 10
- 0
DocX/DocX.csproj.vspscc Целия файл

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

+ 64
- 0
DocX/Enumerations.cs Целия файл

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Novacode
{
/// <summary>
/// Paragraph edit types
/// </summary>
public enum EditType
{
/// <summary>
/// A ins is a tracked insertion
/// </summary>
ins,
/// <summary>
/// A del is tracked deletion
/// </summary>
del
}
/// <summary>
/// Custom property types.
/// </summary>
public enum CustomPropertyType
{
/// <summary>
/// System.String
/// </summary>
Text,
/// <summary>
/// System.DateTime
/// </summary>
Date,
/// <summary>
/// System.Int32
/// </summary>
NumberInteger,
/// <summary>
/// System.Double
/// </summary>
NumberDecimal,
/// <summary>
/// System.Boolean
/// </summary>
YesOrNo
}
/// <summary>
/// Text types in a Run
/// </summary>
public enum RunTextType
{
/// <summary>
/// System.String
/// </summary>
Text,
/// <summary>
/// System.String
/// </summary>
DelText,
}
}

+ 556
- 0
DocX/Paragraph.cs Целия файл

@@ -0,0 +1,556 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml.Drawing;
using System.Security.Principal;
using System.Collections;
namespace Novacode
{
/// <summary>
/// Represents a .docx paragraph.
/// </summary>
public class Paragraph
{
// A lookup for the runs in this paragraph
Dictionary<int, Run> runLookup = new Dictionary<int, Run>();
// The underlying XElement which this Paragraph wraps
private XElement p;
/// <summary>
/// Wraps a XElement as a Paragraph.
/// </summary>
/// <param name="p">The XElement to wrap.</param>
public Paragraph(XElement p)
{
this.p = p;
BuildRunLookup(p);
}
private void BuildRunLookup(XElement p)
{
// Get the runs in this paragraph
IEnumerable<XElement> runs = p.Descendants(XName.Get("r", "http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
int startIndex = 0;
// Loop through each run in this paragraph
foreach (XElement run in runs)
{
Run r = new Run(startIndex, run);
runLookup.Add(r.EndIndex, r);
startIndex = r.EndIndex;
}
}
/// <summary>
/// Gets the value of this Novacode.DocX.Paragraph.
/// </summary>
public string Value
{
// Returns the underlying XElement's Value property.
get
{
StringBuilder sb = new StringBuilder();
// Loop through each run in this paragraph
foreach (XElement r in p.Descendants(XName.Get("r", DocX.w.NamespaceName)))
{
// Loop through each text item in this run
foreach (XElement descendant in r.Descendants())
{
switch (descendant.Name.LocalName)
{
case "tab":
sb.Append("\t");
break;
case "br":
sb.Append("\n");
break;
case "t":
goto case "delText";
case "delText":
sb.Append(descendant.Value);
break;
default: break;
}
}
}
return sb.ToString();
}
}
/// <summary>
/// Creates an Edit either a ins or a del with the specified content and date
/// </summary>
/// <param name="t">The type of this edit (ins or del)</param>
/// <param name="edit_time">The time stamp to use for this edit</param>
/// <param name="content">The initial content of this edit</param>
/// <returns></returns>
private XElement CreateEdit(EditType t, DateTime edit_time, params object[] content)
{
if (t == EditType.del)
{
foreach (object o in content)
{
if (o is XElement)
{
XElement e = (o as XElement);
IEnumerable<XElement> ts = e.DescendantsAndSelf(XName.Get("t", DocX.w.NamespaceName));
for(int i = 0; i < ts.Count(); i ++)
{
XElement text = ts.ElementAt(i);
text.ReplaceWith(new XElement(DocX.w + "delText", text.Attributes(), text.Value));
}
}
}
}
return
(
new XElement(DocX.w + t.ToString(),
new XAttribute(DocX.w + "id", 0),
new XAttribute(DocX.w + "author", WindowsIdentity.GetCurrent().Name),
new XAttribute(DocX.w + "date", edit_time),
content)
);
}
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Run GetFirstRunEffectedByEdit(int index)
{
foreach (int runEndIndex in runLookup.Keys)
{
if (runEndIndex > index)
return runLookup[runEndIndex];
}
if (runLookup.Last().Value.EndIndex == index)
return runLookup.Last().Value;
throw new ArgumentOutOfRangeException();
}
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Run GetFirstRunEffectedByInsert(int index)
{
foreach (int runEndIndex in runLookup.Keys)
{
if (runEndIndex >= index)
return runLookup[runEndIndex];
}
throw new ArgumentOutOfRangeException();
}
/// <summary>
/// If the value to be inserted contains tab elements or br elements, multiple runs will be inserted.
/// </summary>
/// <param name="text">The text to be inserted, this text can contain the special characters \t (tab) and \n (br)</param>
/// <returns></returns>
private List<XElement> formatInput(string text, XElement rPr)
{
List<XElement> newRuns = new List<XElement>();
XElement tabRun = new XElement(DocX.w + "tab");
string[] runTexts = text.Split('\t');
XElement firstRun;
if (runTexts[0] != String.Empty)
{
XElement firstText = new XElement(DocX.w + "t", runTexts[0]);
Text.PreserveSpace(firstText);
firstRun = new XElement(DocX.w + "r", rPr, firstText);
newRuns.Add(firstRun);
}
if (runTexts.Length > 1)
{
for (int k = 1; k < runTexts.Length; k++)
{
XElement newText = new XElement(DocX.w + "t", runTexts[k]);
XElement newRun;
if (runTexts[k] == String.Empty)
newRun = new XElement(DocX.w + "r", tabRun);
else
{
// Value begins or ends with a space
Text.PreserveSpace(newText);
newRun = new XElement(DocX.w + "r", rPr, tabRun, newText);
}
newRuns.Add(newRun);
}
}
return newRuns;
}
/// <summary>
/// Counts the text length of an element
/// </summary>
/// <param name="run">An element</param>
/// <returns>The length of this elements text</returns>
public static int GetElementTextLength(XElement run)
{
int count = 0;
if (run == null)
return count;
foreach (var d in run.Descendants())
{
switch (d.Name.LocalName)
{
case "tab": goto case "br";
case "br": count++; break;
case "t": goto case "delText";
case "delText": count += d.Value.Length; break;
default: break;
}
}
return count;
}
/// <summary>
/// Splits an edit element at the specified run, at the specified index.
/// </summary>
/// <param name="edit">The edit element to split</param>
/// <param name="run">The run element to split</param>
/// <param name="index">The index to split at</param>
/// <returns></returns>
public XElement[] SplitEdit(XElement edit, int index, EditType type)
{
Run run;
if(type == EditType.del)
run = GetFirstRunEffectedByEdit(index);
else
run = GetFirstRunEffectedByInsert(index);
XElement[] splitRun = Run.SplitRun(run, index);
XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[0]);
if (GetElementTextLength(splitLeft) == 0)
splitLeft = null;
XElement splitRight = new XElement(edit.Name, edit.Attributes(), splitRun[1], run.Xml.ElementsAfterSelf());
if (GetElementTextLength(splitRight) == 0)
splitRight = null;
return
(
new XElement[]
{
splitLeft,
splitRight
}
);
}
/// <summary>
/// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
/// </summary>
/// <example>
/// <code>
/// // Description: Simple string insertion
///
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// {
/// // Insert the string "Start: " at the begining of every paragraph and flag it as a change.
/// p.Insert(0, "Start: ", true);
/// }
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
/// <example>
/// <code>
/// // Description: Inserting tabs using the \t switch
///
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// {
/// // Insert the string "\tStart:\t" at the begining of every paragraph and flag it as a change.
/// p.Insert(0, "\tStart:\t", true);
/// }
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
/// <seealso cref="Paragraph.Remove"/>
/// <seealso cref="Paragraph.Replace"/>
/// <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 Insert(int index, string value, bool trackChanges)
{
// Timestamp to mark the start of insert
DateTime now = DateTime.Now;
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);
// Convert value into a List of XElement's
List<XElement> newRuns = formatInput(value, run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)));
// The parent of this Run
XElement parentElement = run.Xml.Parent;
switch (parentElement.Name.LocalName)
{
case "ins":
{
// The datetime that this ins was created
DateTime parent_ins_date = DateTime.Parse(parentElement.Attribute(XName.Get("date", DocX.w.NamespaceName)).Value);
/*
* Special case: You want to track changes,
* and the first Run effected by this insert
* has a datetime stamp equal to now.
*/
if (trackChanges && parent_ins_date.CompareTo(insert_datetime) == 0)
{
/*
* Inserting into a non edit and this special case, is the same procedure.
*/
goto default;
}
/*
* If not the special case above,
* then inserting into an ins or a del, is the same procedure.
*/
goto case "del";
}
case "del":
{
object insert = newRuns;
if (trackChanges)
insert = CreateEdit(EditType.ins, insert_datetime, newRuns);
// Split this Edit at the point you want to insert
XElement[] splitEdit = SplitEdit(parentElement, index, EditType.ins);
// Replace the origional run
parentElement.ReplaceWith
(
splitEdit[0],
insert,
splitEdit[1]
);
break;
}
default:
{
object insert = newRuns;
if (trackChanges && !parentElement.Name.LocalName.Equals("ins"))
insert = CreateEdit(EditType.ins, insert_datetime, newRuns);
// Split this run at the point you want to insert
XElement[] splitRun = Run.SplitRun(run, index);
// Replace the origional run
run.Xml.ReplaceWith
(
splitRun[0],
insert,
splitRun[1]
);
break;
}
}
// Rebuild the run lookup for this paragraph
runLookup.Clear();
BuildRunLookup(p);
}
/// <summary>
/// Removes characters from a Novacode.DocX.Paragraph.
/// </summary>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// {
/// // Remove the first two characters from every paragraph
/// p.Remove(0, 2);
/// }
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
/// <seealso cref="Paragraph.Insert"/>
/// <seealso cref="Paragraph.Replace"/>
/// <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 Remove(int index, int count, bool trackChanges)
{
// Timestamp to mark the start of insert
DateTime now = DateTime.Now;
DateTime remove_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc);
// The number of characters processed so far
int processed = 0;
do
{
// Get the first run effected by this Remove
Run run = GetFirstRunEffectedByEdit(index + processed);
// The parent of this Run
XElement parentElement = run.Xml.Parent;
switch (parentElement.Name.LocalName)
{
case "ins":
{
XElement[] splitEditBefore = SplitEdit(parentElement, index + processed, EditType.del);
int min = Math.Min(count - processed, run.Xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e)));
XElement[] splitEditAfter = SplitEdit(parentElement, index + processed + min, EditType.del);
object middle = CreateEdit(EditType.del, remove_datetime, SplitEdit(splitEditBefore[1], min, EditType.del)[0].Descendants());
processed += GetElementTextLength(middle as XElement);
if (!trackChanges)
middle = null;
parentElement.ReplaceWith
(
splitEditBefore[0],
middle,
splitEditAfter[1]
);
processed += GetElementTextLength(middle as XElement);
break;
}
case "del":
{
if (trackChanges)
{
// You cannot delete from a deletion, advance processed to the end of this del
processed += GetElementTextLength(parentElement);
}
else
goto case "ins";
break;
}
default:
{
XElement[] splitRunBefore = Run.SplitRun(run, index + processed);
int min = Math.Min(index + processed + (count - processed), run.EndIndex);
XElement[] splitRunAfter = Run.SplitRun(run, min);
object middle = CreateEdit(EditType.del, remove_datetime, Run.SplitRun(new Run(run.StartIndex + GetElementTextLength(splitRunBefore[0]), splitRunBefore[1]), min)[0]);
processed += GetElementTextLength(middle as XElement);
if (!trackChanges)
middle = null;
run.Xml.ReplaceWith
(
splitRunBefore[0],
middle,
splitRunAfter[1]
);
break;
}
}
// If after this remove the parent element is empty, remove it.
if (GetElementTextLength(parentElement) == 0)
parentElement.Remove();
}
while (processed < count);
// Rebuild the run lookup
runLookup.Clear();
BuildRunLookup(p);
}
/// <summary>
/// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
/// </summary>
/// <example>
/// <code>
/// // Load Example.docx
/// DocX dx = DocX.Load(@"C:\Example.docx");
///
/// // Iterate through the paragraphs
/// foreach (Paragraph p in dx.Paragraphs)
/// {
/// // Replace all instances of the string "wrong" with the stirng "right"
/// p.Replace("wrong", "right");
/// }
///
/// // Save changes to Example.docx
/// dx.Save();
/// </code>
/// </example>
/// <seealso cref="Paragraph.Remove"/>
/// <seealso cref="Paragraph.Insert"/>
/// <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="options">A bitwise OR combination of RegexOption enumeration options.</param>
/// <param name="trackChanges">Track changes</param>
public void Replace(string oldValue, string newValue, bool trackChanges, RegexOptions options)
{
MatchCollection mc = Regex.Matches(this.Value, oldValue, options);
// Loop through the matches in reverse order
foreach (Match m in mc.Cast<Match>().Reverse())
{
Insert(m.Index + oldValue.Length, newValue, trackChanges);
Remove(m.Index, m.Length, trackChanges);
}
}
public void Replace(string oldValue, string newValue, bool trackChanges)
{
Replace(oldValue, newValue, trackChanges, RegexOptions.None);
}
}
}

+ 36
- 0
DocX/Properties/AssemblyInfo.cs Целия файл

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Docx")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Docx")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("16123f21-f3d1-47bb-ae9a-eb7c82c0f3c8")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 138
- 0
DocX/Run.cs Целия файл

@@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Novacode
{
public class Run
{
// A lookup for the text elements in this paragraph
Dictionary<int, Text> textLookup = new Dictionary<int, Text>();
private int startIndex;
private int endIndex;
private string text;
private XElement e;
/// <summary>
/// Gets the start index of this Text (text length before this text)
/// </summary>
public int StartIndex { get { return startIndex; } }
/// <summary>
/// Gets the end index of this Text (text length before this text + this texts length)
/// </summary>
public int EndIndex { get { return endIndex; } }
/// <summary>
/// The text value of this text element
/// </summary>
private string Value { set { value = text; } get { return text; } }
/// <summary>
/// The underlying XElement of this run
/// </summary>
public XElement Xml { get { return e; } }
/// <summary>
/// A Run can contain text, delText, br, t and rPr elements
/// </summary>
/// <param name="startIndex">The start index of this run (text length before this run)</param>
/// <param name="endIndex">The end index of this run (text length before this run, plus this runs text length)</param>
/// <param name="runText">The text value of this run</param>
/// <param name="e">The underlying XElement of this run</param>
public Run(int startIndex, XElement e)
{
this.startIndex = startIndex;
this.e = e;
// Get the text elements in this run
IEnumerable<XElement> texts = e.Descendants();
int start = startIndex;
// Loop through each text in this run
foreach (XElement text in texts)
{
switch (text.Name.LocalName)
{
case "tab":
{
textLookup.Add(start + 1, new Text(start, text));
Value += "\t";
start++;
break;
}
case "br":
{
textLookup.Add(start + 1, new Text(start, text));
Value += "\n";
start++;
break;
}
case "t": goto case "delText";
case "delText":
{
textLookup.Add(start + text.Value.Length, new Text(start, text));
Value += text.Value;
start += text.Value.Length;
break;
}
default: break;
}
}
endIndex = start;
}
/// <summary>
/// Splits a run element at a specified index
/// </summary>
/// <param name="r">The run element to split</param>
/// <param name="index">The index to split at</param>
/// <returns>A two element array which contains both sides of the split</returns>
public static XElement[] SplitRun(Run r, int index)
{
Text t = r.GetFirstTextEffectedByEdit(index);
XElement[] splitText = Text.SplitText(t, index);
XElement splitLeft = new XElement(r.e.Name, r.e.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.Xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]);
if(Paragraph.GetElementTextLength(splitLeft) == 0)
splitLeft = null;
XElement splitRight = new XElement(r.e.Name, r.e.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), splitText[1], t.Xml.ElementsAfterSelf().Where(n => n.Name.LocalName != "rPr"));
if(Paragraph.GetElementTextLength(splitRight) == 0)
splitRight = null;
return
(
new XElement[]
{
splitLeft,
splitRight
}
);
}
/// <summary>
/// Return the first Run that will be effected by an edit at the index
/// </summary>
/// <param name="index">The index of this edit</param>
/// <returns>The first Run that will be effected</returns>
public Text GetFirstTextEffectedByEdit(int index)
{
foreach (int textEndIndex in textLookup.Keys)
{
if (textEndIndex > index)
return textLookup[textEndIndex];
}
if (textLookup.Last().Value.EndIndex == index)
return textLookup.Last().Value;
throw new ArgumentOutOfRangeException();
}
}
}

+ 160
- 0
DocX/Text.cs Целия файл

@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Novacode
{
public class Text
{
private int startIndex;
private int endIndex;
private string text;
private XElement e;
/// <summary>
/// Gets the start index of this Text (text length before this text)
/// </summary>
public int StartIndex { get { return startIndex; } }
/// <summary>
/// Gets the end index of this Text (text length before this text + this texts length)
/// </summary>
public int EndIndex { get { return endIndex; } }
/// <summary>
/// The text value of this text element
/// </summary>
public string Value { get { return text; } }
/// <summary>
/// The underlying XElement of this run
/// </summary>
public XElement Xml { get { return e; } }
/// <summary>
/// A Text element
/// </summary>
/// <param name="startIndex">The index this text starts at</param>
/// <param name="text">The index this text ends at</param>
/// <param name="e">The underlying xml element that this text wraps</param>
public Text(int startIndex, XElement e)
{
this.startIndex = startIndex;
this.e = e;
switch (e.Name.LocalName)
{
case "t":
{
goto case "delText";
}
case "delText":
{
endIndex = startIndex + e.Value.Length;
text = e.Value;
break;
}
case "br":
{
text = "\n";
endIndex = startIndex + 1;
break;
}
case "tab":
{
text = "\t";
endIndex = startIndex + 1;
break;
}
default:
{
break;
}
}
}
/// <summary>
/// Splits a text element at a specified index
/// </summary>
/// <param name="e">The text element to split</param>
/// <param name="index">The index to split at</param>
/// <returns>A two element array which contains both sides of the split</returns>
public static XElement[] SplitText(Text t, int index)
{
if (index < t.startIndex || index > t.EndIndex)
throw new ArgumentOutOfRangeException("index");
XElement splitLeft = null, splitRight = null;
if (t.e.Name.LocalName == "t" || t.e.Name.LocalName == "delText")
{
// The origional text element, now containing only the text before the index point.
splitLeft = new XElement(t.e.Name, t.e.Attributes(), t.e.Value.Substring(0, index - t.startIndex));
if (splitLeft.Value.Length == 0)
splitLeft = null;
else
PreserveSpace(splitLeft);
// The origional text element, now containing only the text after the index point.
splitRight = new XElement(t.e.Name, t.e.Attributes(), t.e.Value.Substring(index - t.startIndex, t.e.Value.Length - (index - t.startIndex)));
if (splitRight.Value.Length == 0)
splitRight = null;
else
PreserveSpace(splitRight);
}
else
{
if (index == t.StartIndex)
splitLeft = t.e;
else
splitRight = t.e;
}
return
(
new XElement[]
{
splitLeft,
splitRight
}
);
}
/// <summary>
/// If a text element or delText element, starts or ends with a space,
/// it must have the attribute space, otherwise it must not have it.
/// </summary>
/// <param name="e">The (t or delText) element check</param>
public static void PreserveSpace(XElement e)
{
// PreserveSpace should only be used on (t or delText) elements
if (!e.Name.Equals(DocX.w + "t") && !e.Name.Equals(DocX.w + "delText"))
throw new ArgumentException("SplitText can only split elements of type t or delText", "e");
// Check if this w:t contains a space atribute
XAttribute space = e.Attributes().Where(a => a.Name.Equals(XNamespace.Xml + "space")).SingleOrDefault();
// This w:t's text begins or ends with whitespace
if (e.Value.StartsWith(" ") || e.Value.EndsWith(" "))
{
// If this w:t contains no space attribute, add one.
if (space == null)
e.Add(new XAttribute(XNamespace.Xml + "space", "preserve"));
}
// This w:t's text does not begin or end with a space
else
{
// If this w:r contains a space attribute, remove it.
if (space != null)
space.Remove();
}
}
}
}

+ 17
- 0
LocalTestRun.testrunconfig Целия файл

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestRunConfiguration name="Local Test Run" id="6869d4b0-c7c0-449b-a3b2-541bd9ae1155" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
<Description>This is a default test run configuration for a local test run.</Description>
<TestTypeSpecific>
<WebTestRunConfiguration testTypeId="4e7599fa-5ecb-43e9-a887-cd63cf72d207">
<Browser name="Internet Explorer 7.0">
<Headers>
<Header name="User-Agent" value="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" />
<Header name="Accept" value="*/*" />
<Header name="Accept-Language" value="{{$IEAcceptLanguage}}" />
<Header name="Accept-Encoding" value="GZIP" />
</Headers>
</Browser>
<Network Name="LAN" BandwidthInKbps="0" />
</WebTestRunConfiguration>
</TestTypeSpecific>
</TestRunConfiguration>

+ 37
- 0
StringReplaceTestApp/Program.cs Целия файл

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Novacode;
using System.Text.RegularExpressions;
using System.IO;
namespace StringReplaceTestApp
{
class Program
{
static void Main(string[] args)
{
File.Copy(@"Test.docx", "Manipulated.docx", true);
// Load the document that you want to manipulate
DocX document = DocX.Load(@"Manipulated.docx");
// Loop through the paragraphs in the document
foreach (Paragraph p in document.Paragraphs)
{
/*
* Replace each instance of the string pear with the string banana.
* Specifying true as the third argument informs DocX to track the
* changes made by this replace. The fourth argument tells DocX to
* ignore case when matching the string pear.
*/
p.Replace("pear", "banana", true, RegexOptions.IgnoreCase);
}
// File will be saved to \StringReplaceTestApp\bin\Debug
document.Save();
}
}
}

+ 36
- 0
StringReplaceTestApp/Properties/AssemblyInfo.cs Целия файл

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("StringReplaceTestApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft IT")]
[assembly: AssemblyProduct("StringReplaceTestApp")]
[assembly: AssemblyCopyright("Copyright © Microsoft IT 2009")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3ec6b0e8-aceb-402b-ab0d-03201cc62865")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 72
- 0
StringReplaceTestApp/StringReplaceTestApp.csproj Целия файл

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{EA960F96-7CA4-4AA1-BB43-0478E3407C5C}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StringReplaceTestApp</RootNamespace>
<AssemblyName>StringReplaceTestApp</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DocX, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DocX\bin\Debug\DocX.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Test.docx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 10
- 0
StringReplaceTestApp/StringReplaceTestApp.csproj.vspscc Целия файл

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

Двоични данни
StringReplaceTestApp/Test.docx Целия файл


+ 136
- 0
UnitTests/AuthoringTests.txt Целия файл

@@ -0,0 +1,136 @@
==========================================================================
Visual Studio Team System: Overview of Authoring and Running Tests
==========================================================================
This overview describes the features for authoring and running tests in
Visual Studio Team System and Visual Studio Team Edition for Software Testers.
Opening Tests
-------------
To open a test, open a test project or a test metadata file (a file with
extension .vsmdi) that contains the definition of the test. You can find
test projects and metadata files in Solution Explorer.
Viewing Tests
-------------
To see which tests are available to you, open the Test View window. Or,
if you have installed Team Edition for Software Testers, you can also open
the Test List Editor window to view tests.
To open the Test View window, click the Test menu, point to Windows, and
then click Test View. To open the Test List Editor window (if you have
installed Team Edition for Software Testers), click Test, point to Windows,
and then click Test List Editor.
Running Tests
-------------
You can run tests from the Test View window and the Test List Editor window.
See Viewing Tests to learn how to open these windows. To run one or more
tests displayed in the Test View window, first select the tests in that
window; to select multiple tests, hold either the Shift or CTRL key while
clicking tests. Then click the Run Tests button in the Test View window
toolbar.
If you have installed Visual Studio Team Edition for Software Testers, you can
also use the Test List Editor window to run tests. To run tests in Test List Editor,
select the check box next to each test that you want to run. Then click the
Run Tests button in the Test List Editor window toolbar.
Viewing Test Results
--------------------
When you run a test or a series of tests, the results of the test run will be
shown in the Test Results window. Each individual test in the run is shown on
a separate line so that you can see its status. The window contains an
embedded status bar in the top half of the window that provides you with
summary details of the complete test run.
To see more detailed results for a particular test result, double-click it in
the Test Results window. This opens a window that provides more information
about the particular test result, such as any specific error messages returned
by the test.
Changing the way that tests are run
-----------------------------------
Each time you run one or more tests, a collection of settings is used to
determine how those tests are run. These settings are contained in a “test
run configuration” file.
Here is a partial list of the changes you can make with a test run
configuration file:
- Change the naming scheme for each test run.
- Change the test controller that the tests are run on so that you can run
tests remotely.
- Gather code coverage data for the code being tested so that you can see
which lines of code are covered by your tests.
- Enable and disable test deployment.
- Specify additional files to deploy before tests are run.
- Select a different host, ASP.NET, for running ASP.NET unit tests.
- Select a different host, the smart device test host, for running smart device unit tests.
- Set various properties for the test agents that run your tests.
- Run custom scripts at the start and end of each test run so that you can
set up the test environment exactly as required each time tests are run.
- Set time limits for tests and test runs.
- Set the browser mix and the number of times to repeat Web tests in the
test run.
By default, a test run configuration file is created whenever you create a
new test project. You make changes to this file by double-clicking it in
Solution Explorer and then changing its settings. (Test run configuration
files have the extension .testrunconfig.)
A solution can contain multiple test run configuration files. Only one of
those files, known as the “Active” test run configuration file, is used to
determine the settings that are currently used for test runs. You select
the active test run configuration by clicking Select Active Test Run
Configuration on the Test menu.
-------------------------------------------------------------------------------
Test Types
----------
Using Visual Studio Team Edition for Software Testers, you can create a number
of different test types:
Unit test: Use a unit test to create a programmatic test in C++, Visual C# or
Visual Basic that exercises source code. A unit test calls the methods of a
class, passing suitable parameters, and verifies that the returned value is
what you expect.
There are three specialized variants of unit tests:
- Data-driven unit tests are created when you configure a unit test to be
called repeatedly for each row of a data source. The data from each row
is used by the unit test as input data.
- ASP.NET unit tests are unit tests that exercise code in an ASP.NET Web
application.
- Smart device unit tests are unit tests that are deployed to a smart device
or emulator and then executed by the smart device test host.
Web Test: Web tests consist of an ordered series of HTTP requests that you
record in a browser session using Microsoft Internet Explorer. You can have
the test report specific details about the pages or sites it requests, such
as whether a particular page contains a specified string.
Load Test: You use a load test to encapsulate non-manual tests, such as
unit, Web, and generic tests, and then run them simultaneously by using
virtual users. Running these tests under load generates test results,
including performance and other counters, in tables and in graphs.
Generic test: A generic test is an existing program wrapped to function as a
test in Visual Studio. The following are examples of tests or programs that
you can turn into generic tests:
- An existing test that uses process exit codes to communicate whether the
test passed or failed. 0 indicates passing and any other value indicates
a failure.
- A general program to obtain specific functionality during a test scenario.
- A test or program that uses a special XML file (called a “summary results
file”), to communicate detailed results.
Manual test: The manual test type is used when the test tasks are to be
completed by a test engineer as opposed to an automated script.
Ordered test: Use an ordered test to execute a set of tests in an order you
specify.
-------------------------------------------------------------------------------

+ 155
- 0
UnitTests/PreserveSpaceCheckTests.cs Целия файл

@@ -0,0 +1,155 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Novacode;
using System.Xml.Linq;
namespace UnitTests
{
/// <summary>
/// Summary description for PreserveSpaceCheckTests
/// </summary>
[TestClass]
public class PreserveSpaceTests
{
public PreserveSpaceTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void TestPreserveSpace_NoChangeRequired()
{
XElement t_origional, t_afterPreserveSpace;
#region Doesn't start or end with a space
// The test text element to check
t_origional = new XElement(DocX.w + "t", "Hello I am a string");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual(t_origional.ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Starts with a space, doesn't end with a space
// The test text element to check
t_origional = new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " Hello I am a string");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual(t_origional.ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Ends with a space, doesn't start with a space
// The test text element to check
t_origional = new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), "Hello I am a string ");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual(t_origional.ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Starts and ends with a space
// The test text element to check
t_origional = new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " Hello I am a string ");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual(t_origional.ToString(), t_afterPreserveSpace.ToString());
#endregion
}
[TestMethod]
public void TestPreserveSpace_ChangeRequired()
{
XElement t_origional, t_afterPreserveSpace;
#region Doesn't start or end with a space, but has a space preserve attribute
// The test text element to check
t_origional = new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), "Hello I am a string");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual((new XElement(DocX.w + "t", "Hello I am a string")).ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Start with a space, but has no space preserve attribute
// The test text element to check
t_origional = new XElement(DocX.w + "t", " Hello I am a string");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual((new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " Hello I am a string")).ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Ends with a space, but has no space preserve attribute
// The test text element to check
t_origional = new XElement(DocX.w + "t", "Hello I am a string ");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual((new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), "Hello I am a string ")).ToString(), t_afterPreserveSpace.ToString());
#endregion
#region Starts and ends with a space, but has no space preserve attribute
// The test text element to check
t_origional = new XElement(DocX.w + "t", " Hello I am a string ");
t_afterPreserveSpace = t_origional;
Text.PreserveSpace(t_afterPreserveSpace);
Assert.AreEqual((new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " Hello I am a string ")).ToString(), t_afterPreserveSpace.ToString());
#endregion
}
[TestMethod, ExpectedException(typeof(ArgumentException))]
public void TestPreserveSpace_NotTOrDelTextElement()
{
XElement e = new XElement("NotTOrDelText");
Text.PreserveSpace(e);
}
}
}

+ 35
- 0
UnitTests/Properties/AssemblyInfo.cs Целия файл

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft IT")]
[assembly: AssemblyProduct("UnitTests")]
[assembly: AssemblyCopyright("Copyright © Microsoft IT 2009")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM componenets. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ccefa1fd-d3c3-4130-b7ff-a6962dfc1a98")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 192
- 0
UnitTests/SplitEditTests.cs Целия файл

@@ -0,0 +1,192 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using Novacode;
namespace UnitTests
{
/// <summary>
/// Summary description for SplitEditTests
/// </summary>
[TestClass]
public class SplitEditTests
{
public SplitEditTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void TestSplitEdit()
{
// The test text element to split
XElement run1 = new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "Hello"));
XElement run2 = new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " world"));
XElement edit = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), run1, run2);
Paragraph p = new Paragraph(edit);
#region Split at index 0
XElement[] splitEdit = p.SplitEdit(edit, 0, EditType.del);
Assert.IsNull(splitEdit[0]);
Assert.AreEqual(edit.ToString(), splitEdit[1].ToString());
#endregion
#region Split at index 1
/*
* Split the text at index 5.
* This will cause the left side of the split to end with a space and the right to start with a space.
*/
XElement[] splitEdit_indexOne = p.SplitEdit(edit, 1, EditType.del);
// The result I expect to get from splitRun_nearMiddle
XElement splitEdit_indexOne_left = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "H")));
XElement splitEdit_indexOne_right = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r",new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "ello")), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " world")));
// Check if my expectations have been met
Assert.AreEqual(splitEdit_indexOne_left.ToString(), splitEdit_indexOne[0].ToString());
Assert.AreEqual(splitEdit_indexOne_right.ToString(), splitEdit_indexOne[1].ToString());
#endregion
#region Split near the middle
/*
* Split the text at index 5.
* This will cause the left side of the split to end with a space and the right to start with a space.
*/
XElement[] splitEdit_nearMiddle = p.SplitEdit(edit, 5, EditType.del);
// The result I expect to get from splitRun_nearMiddle
XElement splitEdit_nearMiddle_left = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "Hello")));
XElement splitEdit_nearMiddle_right = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " world")));
// Check if my expectations have been met
Assert.AreEqual(splitEdit_nearMiddle_left.ToString(), splitEdit_nearMiddle[0].ToString());
Assert.AreEqual(splitEdit_nearMiddle_right.ToString(), splitEdit_nearMiddle[1].ToString());
#endregion
#region Split at index Length - 1
/*
* Split the text at index 5.
* This will cause the left side of the split to end with a space and the right to start with a space.
*/
XElement[] splitEdit_indexOneFromLength = p.SplitEdit(edit, Paragraph.GetElementTextLength(edit) - 1, EditType.del);
// The result I expect to get from splitRun_nearMiddle
XElement splitEdit_OneFromLength_left = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "Hello")), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " worl")));
XElement splitEdit_OneFromLength_right = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "d")));
// Check if my expectations have been met
Assert.AreEqual(splitEdit_OneFromLength_left.ToString(), splitEdit_indexOneFromLength[0].ToString());
Assert.AreEqual(splitEdit_OneFromLength_right.ToString(), splitEdit_indexOneFromLength[1].ToString());
#endregion
#region Split at index Length
XElement[] splitEdit_indexZero = p.SplitEdit(edit, Paragraph.GetElementTextLength(edit), EditType.del);
Assert.AreEqual(edit.ToString(), splitEdit_indexZero[0].ToString());
Assert.IsNull(splitEdit_indexZero[1]);
#endregion
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitEdit_IndexLessThanTextStartIndex()
{
// The test text element to split
XElement run1 = new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", "Hello"));
XElement run2 = new XElement(DocX.w + "r", new XElement(DocX.w + "rPr", new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0"))), new XElement(DocX.w + "t", new XAttribute(XNamespace.Xml + "space", "preserve"), " world"));
XElement edit = new XElement(DocX.w + "ins", new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), run1, run2);
Paragraph p = new Paragraph(edit);
/*
* Split r at a negative index.
* This will cause an argument out of range exception to be thrown.
*/
p.SplitEdit(edit, -1, EditType.del);
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitEdit_IndexGreaterThanTextEndIndex()
{
// The test text element to split
XElement run1 = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello") });
XElement run2 = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", new object[] { new XAttribute(XNamespace.Xml + "space", "preserve"), " world" }) });
XElement edit = new XElement(DocX.w + "ins", new object[] { new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), run1, run2 });
Paragraph p = new Paragraph(edit);
/*
* Split r at a negative index.
* This will cause an argument out of range exception to be thrown.
*/
p.SplitEdit(edit, Paragraph.GetElementTextLength(edit) + 1, EditType.del);
}
[TestMethod]
public void TestSplitEditOfLengthOne()
{
XElement edit = new XElement(DocX.w + "ins", new object[] { new XAttribute(DocX.w + "id", "0"), new XAttribute(DocX.w + "author", "t-cathco"), new XAttribute(DocX.w + "date", "2009-02-17T21:09:00Z"), new XElement(DocX.w + "r", new XElement(DocX.w + "tab"))});
Paragraph p = new Paragraph(edit);
XElement[] splitEditOfLengthOne;
#region Split before
splitEditOfLengthOne = p.SplitEdit(edit, 0, EditType.del);
// Check if my expectations have been met
Assert.AreEqual(edit.ToString(), splitEditOfLengthOne[0].ToString());
Assert.IsNull(splitEditOfLengthOne[1]);
#endregion
#region Split after
splitEditOfLengthOne = p.SplitEdit(edit, Paragraph.GetElementTextLength(edit), EditType.del);
// Check if my expectations have been met
Assert.IsNull(splitEditOfLengthOne[0]);
Assert.AreEqual(edit.ToString(), splitEditOfLengthOne[1].ToString());
#endregion
}
}
}

+ 185
- 0
UnitTests/SplitRunTests.cs Целия файл

@@ -0,0 +1,185 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Novacode;
using System.Xml.Linq;
namespace UnitTests
{
/// <summary>
/// Summary description for SplitRunTests
/// </summary>
[TestClass]
public class SplitRunTests
{
public SplitRunTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void TestSplitRun()
{
// The test text element to split
Run r = new Run(0, new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello world") }));
#region Split at index 0
/*
* Split r at index 0.
* This will cause the left side of the split to be null and the right side to be equal to r.
*/
XElement[] splitRun_indexZero = Run.SplitRun(r, 0);
// Check if my expectations have been met
Assert.IsNull(splitRun_indexZero[0]);
Assert.AreEqual(r.Xml.ToString(), splitRun_indexZero[1].ToString());
#endregion
#region Split at index 1
XElement[] splitRun_indexOne = Run.SplitRun(r, 1);
// The result I expect to get from splitRun_indexOne
XElement splitRun_indexOne_left = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "H") });
XElement splitRun_indexOne_right = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "ello world") });
// Check if my expectations have been met
Assert.AreEqual(splitRun_indexOne_left.ToString(), splitRun_indexOne[0].ToString());
Assert.AreEqual(splitRun_indexOne_right.ToString(), splitRun_indexOne[1].ToString());
#endregion
#region Split near the middle
/*
* Split the text at index 11.
* This will cause the left side of the split to end with a space and the right to start with a space.
*/
XElement[] splitRun_nearMiddle = Run.SplitRun(r, 5);
// The result I expect to get from splitRun_nearMiddle
XElement splitRun_nearMiddle_left = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello") });
XElement splitRun_nearMiddle_right = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", new object[] { new XAttribute(XNamespace.Xml + "space", "preserve"), " world" }) });
// Check if my expectations have been met
Assert.AreEqual(splitRun_nearMiddle_left.ToString(), splitRun_nearMiddle[0].ToString());
Assert.AreEqual(splitRun_nearMiddle_right.ToString(), splitRun_nearMiddle[1].ToString());
#endregion
#region Split at index Length - 1
XElement[] splitRun_indexOneFromLength = Run.SplitRun(r, Paragraph.GetElementTextLength(r.Xml) - 1);
// The result I expect to get from splitRun_indexOne
XElement splitRun_indexOneFromLength_left = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello worl") });
XElement splitRun_indexOneFromLength_right = new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "d") });
// Check if my expectations have been met
Assert.AreEqual(splitRun_indexOneFromLength_left.ToString(), splitRun_indexOneFromLength[0].ToString());
Assert.AreEqual(splitRun_indexOneFromLength_right.ToString(), splitRun_indexOneFromLength[1].ToString());
#endregion
#region Split at index Length
/*
* Split r at index Length.
* This will cause the left side of the split to equal to r and the right side to be null.
*/
XElement[] splitRun_indexLength = Run.SplitRun(r, Paragraph.GetElementTextLength(r.Xml));
// Check if my expectations have been met
Assert.AreEqual(r.Xml.ToString(), splitRun_indexLength[0].ToString());
Assert.IsNull(splitRun_indexLength[1]);
#endregion
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitRun_IndexLessThanTextStartIndex()
{
// The test text element to split
Run r = new Run(0, new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello world") }));
/*
* Split r at a negative index.
* This will cause an argument out of range exception to be thrown.
*/
Run.SplitRun(r, r.StartIndex - 1);
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitRun_IndexGreaterThanTextEndIndex()
{
// The test text element to split
Run r = new Run(0, new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "t", "Hello world") }));
/*
* Split r at a length + 1.
* This will cause an argument out of range exception to be thrown.
*/
Run.SplitRun(r, r.EndIndex + 1);
}
[TestMethod]
public void TestSplitRunOfLengthOne()
{
// The test text element to split
Run r = new Run(0, new XElement(DocX.w + "r", new object[] { new XElement(DocX.w + "rPr", new object[] { new XElement(DocX.w + "b"), new XElement(DocX.w + "i"), new XElement(DocX.w + "color", new XAttribute(DocX.w + "val", "7030A0")) }), new XElement(DocX.w + "br") }));
XElement[] splitRunOfLengthOne;
#region Split before
splitRunOfLengthOne = Run.SplitRun(r, r.StartIndex);
// Check if my expectations have been met
Assert.AreEqual(r.Xml.ToString(), splitRunOfLengthOne[0].ToString());
Assert.IsNull(splitRunOfLengthOne[1]);
#endregion
#region Split after
splitRunOfLengthOne = Run.SplitRun(r, r.EndIndex);
// Check if my expectations have been met
Assert.IsNull(splitRunOfLengthOne[0]);
Assert.AreEqual(r.Xml.ToString(), splitRunOfLengthOne[1].ToString());
#endregion
}
}
}

+ 183
- 0
UnitTests/SplitTextTests.cs Целия файл

@@ -0,0 +1,183 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Novacode;
using System.Xml.Linq;
namespace UnitTests
{
/// <summary>
/// This class tests the SplitText function of Novacode.Paragraph
/// </summary>
[TestClass]
public class SplitTextTests
{
public SplitTextTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void TestSplitText()
{
// The test text element to split
Text t = new Text(0, new XElement(DocX.w + "t", "Hello I am a string"));
#region Split at index 0
/*
* Split t at index 0.
* This will cause the left side of the split to be null and the right side to be equal to t.
*/
XElement[] splitText_indexZero = Text.SplitText(t, 0);
// Check if my expectations have been met
Assert.IsNull(splitText_indexZero[0]);
Assert.AreEqual(t.Xml.ToString(), splitText_indexZero[1].ToString());
#endregion
#region Split at index 1
XElement[] splitText_indexOne = Text.SplitText(t, 1);
// The result I expect to get from splitText1
XElement splitText_indexOne_left = new XElement(DocX.w + "t", "H");
XElement splitText_indexOne_right = new XElement(DocX.w + "t", "ello I am a string");
// Check if my expectations have been met
Assert.AreEqual(splitText_indexOne_left.ToString(), splitText_indexOne[0].ToString());
Assert.AreEqual(splitText_indexOne_right.ToString(), splitText_indexOne[1].ToString());
#endregion
#region Split near the middle causing starting and ending spaces
/*
* Split the text at index 11.
* This will cause the left side of the split to end with a space and the right to start with a space.
*/
XElement[] splitText_nearMiddle = Text.SplitText(t, 11);
// The result I expect to get from splitText1
XElement splitText_nearMiddle_left = new XElement(DocX.w + "t", new object[] { new XAttribute(XNamespace.Xml + "space", "preserve"), "Hello I am " });
XElement splitText_nearMiddle_right = new XElement(DocX.w + "t", new object[] { new XAttribute(XNamespace.Xml + "space", "preserve"), " a string" });
// Check if my expectations have been met
Assert.AreEqual(splitText_nearMiddle_left.ToString(), splitText_nearMiddle[0].ToString());
Assert.AreEqual(splitText_nearMiddle_right.ToString(), splitText_nearMiddle[1].ToString());
#endregion
#region Split at text.Value.Length - 1
XElement[] splitText_indexOneFromLength = Text.SplitText(t, t.Value.Length - 1);
// The result I expect to get from splitText1
XElement splitText_indexOneFromLength_left = new XElement(DocX.w + "t", "Hello I am a strin");
XElement splitText_indexOneFromLength_right = new XElement(DocX.w + "t", "g");
// Check if my expectations have been met
Assert.AreEqual(splitText_indexOneFromLength_left.ToString(), splitText_indexOneFromLength[0].ToString());
Assert.AreEqual(splitText_indexOneFromLength_right.ToString(), splitText_indexOneFromLength[1].ToString());
#endregion
#region Split at index text.Value.Length
/*
* Split the text at index text.Value.Length.
* This will cause the left side of the split to be equal to text and the right side to be null.
*/
XElement[] splitText_indexLength = Text.SplitText(t, t.Value.Length);
// Check if my expectations have been met
Assert.AreEqual(t.Xml.ToString(), splitText_indexLength[0].ToString());
Assert.IsNull(splitText_indexLength[1]);
#endregion
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitText_IndexLessThanTextStartIndex()
{
// The test text element to split
Text t = new Text(0, new XElement(DocX.w + "t", "Hello I am a string"));
/*
* Split t at a negative index.
* This will cause an argument out of range exception to be thrown.
*/
Text.SplitText(t, t.StartIndex - 1);
}
[TestMethod, ExpectedException(typeof(ArgumentOutOfRangeException))]
public void TestSplitText_IndexGreaterThanTextEndIndex()
{
// The test text element to split
Text t = new Text(0, new XElement(DocX.w + "t", "Hello I am a string"));
/*
* Split t at an index greater than its text length.
* This will cause an argument out of range exception to be thrown.
*/
Text.SplitText(t, t.EndIndex + 1);
}
[TestMethod]
public void TestSplitTextOfLengthOne()
{
// The test text element to split
Text t = new Text(0, new XElement(DocX.w + "tab"));
XElement[] splitTextOfLengthOne;
#region Split before
splitTextOfLengthOne = Text.SplitText(t, t.StartIndex);
// Check if my expectations have been met
Assert.AreEqual(t.Xml.ToString(), splitTextOfLengthOne[0].ToString());
Assert.IsNull(splitTextOfLengthOne[1]);
#endregion
#region Split after
splitTextOfLengthOne = Text.SplitText(t, t.EndIndex);
// Check if my expectations have been met
Assert.IsNull(splitTextOfLengthOne[0]);
Assert.AreEqual(t.Xml.ToString(), splitTextOfLengthOne[1].ToString());
#endregion
}
}
}

+ 70
- 0
UnitTests/UnitTests.csproj Целия файл

@@ -0,0 +1,70 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6E4A2A95-9A9A-4F8C-A68D-4950E3455700}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnitTests</RootNamespace>
<AssemblyName>UnitTests</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DocX, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DocX\bin\Debug\DocX.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="PreserveSpaceCheckTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplitEditTests.cs" />
<Compile Include="SplitRunTests.cs" />
<Compile Include="SplitTextTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="AuthoringTests.txt" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 10
- 0
UnitTests/UnitTests.csproj.vspscc Целия файл

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

Loading…
Отказ
Запис