Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Schematron.Tests/Content/po-schema.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<pattern name="Basic data">
<rule context="po:customer">
<assert test="(@sex='Male' and @title='Mr') or (@sex='Female' and (@title='Mrs' or @title='Miss'))">
Attributes sex and title must have compatible values on element <name/>.
Attributes sex (<value-of select="@sex"/>) and title (<value-of select="@title"/>) must have compatible values on element <name/>.
</assert>
<report test="@customerId and @partnerId">
Both customerId and partnerId can't be present on element <name/>.
Expand Down
3 changes: 3 additions & 0 deletions src/Schematron.Tests/Schematron.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<Name>Schematron</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, this makes the project into a unit testable project.

</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
Expand Down
262 changes: 145 additions & 117 deletions src/Schematron.Tests/ValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,121 +8,149 @@
using Xunit;

namespace Schematron.Tests
{
public class ValidatorTests
{
const string XsdLocation = "./Content/po-schema.xsd";
const string XsdWithPartialSchemaLocation = "./Content/po-schema-with-schema-import.xsd";
const string XmlContentLocation = "./Content/po-instance.xml";
const string TargetNamespace = "http://example.com/po-schematron";

[Fact]
public void NewAddSchemaSignatureShouldNotBreakCode()
{
var validatorA = new Validator(OutputFormatting.XML);
validatorA.AddSchema(XmlReader.Create(XsdLocation));

var validatorB = new Validator(OutputFormatting.XML);
validatorB.AddSchema(TargetNamespace, XsdLocation);

var resultA = default(string);
var resultB = default(string);

try
{
var result = validatorA.Validate(XmlReader.Create(XmlContentLocation));
}
catch (ValidationException ex)
{
resultA = ex.Message;

System.Diagnostics.Debug.WriteLine(ex.Message);
}

try
{
var result = validatorB.Validate(XmlReader.Create(XmlContentLocation));
}
catch (ValidationException ex)
{
resultB = ex.Message;

Xunit.Assert.True(resultA == resultB);

System.Diagnostics.Debug.WriteLine(ex.Message);
}

}

[Fact]
public void ValidateShouldReturnSchematronValidationResultWhenSchematronConstraintsAreNotMet()
{
//Arrange
var validator = new Validator(OutputFormatting.XML);

//Act
validator.AddSchema(TargetNamespace, XsdLocation);

using (var doc = XmlReader.Create(XmlContentLocation))
{
var result = default(IXPathNavigable);

try
{
result = validator.Validate(doc);
}
catch (ValidationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);

var serializer = new XmlSerializer(typeof(Schematron.Serialization.SchematronValidationResultTempObjectModel.output));

using (var stream = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(ex.Message)))
using (var reader = XmlReader.Create(stream))
{
var obj = (Schematron.Serialization.SchematronValidationResultTempObjectModel.output)serializer.Deserialize(reader);

// Assert


Xunit.Assert.NotNull(obj);
Xunit.Assert.NotNull(obj.xml);
Xunit.Assert.NotNull(obj.schematron);
}
}
}
}

[Fact]
public void WhenUsingTheXmlReaderApproach_ToSupplyASchema_TypesFromImportsAreNotResolved()
{
// arrange
var validator = new Schematron.Validator();

// act, (assert)
Xunit.Assert.Throws<XmlSchemaException>(() => validator.AddSchema(XmlReader.Create(XsdWithPartialSchemaLocation)));
}

[Fact]
public void WhenUsingTheXmlSchemaSetBasedApproach_ToSupplyASchema_TypesFromImportsAreResolved()
{
// arrange
var validator = new Schematron.Validator();

var count = validator.XmlSchemas != null ? validator.XmlSchemas.Count : 0;

// act, (assert)
validator.AddSchema(TargetNamespace, XsdWithPartialSchemaLocation);

Xunit.Assert.True(validator.Schemas.Count == count + 1);

//var res = validator.Validate(XmlContentLocation);
}

//[Fact]
public void DoTheRawXmlValidation()
{
throw new NotImplementedException();
}
}
{
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting was changed by EditorConfig.

public class ValidatorTests
{
const string XsdLocation = "./Content/po-schema.xsd";
const string XsdWithPartialSchemaLocation = "./Content/po-schema-with-schema-import.xsd";
const string XmlContentLocation = "./Content/po-instance.xml";
const string TargetNamespace = "http://example.com/po-schematron";

[Fact]
public void NewAddSchemaSignatureShouldNotBreakCode()
{
var validatorA = new Validator(OutputFormatting.XML);
validatorA.AddSchema(XmlReader.Create(XsdLocation));

var validatorB = new Validator(OutputFormatting.XML);
validatorB.AddSchema(TargetNamespace, XsdLocation);

var resultA = default(string);
var resultB = default(string);

try
{
var result = validatorA.Validate(XmlReader.Create(XmlContentLocation));
}
catch (ValidationException ex)
{
resultA = ex.Message;

System.Diagnostics.Debug.WriteLine(ex.Message);
}

try
{
var result = validatorB.Validate(XmlReader.Create(XmlContentLocation));
}
catch (ValidationException ex)
{
resultB = ex.Message;

Xunit.Assert.True(resultA == resultB);

System.Diagnostics.Debug.WriteLine(ex.Message);
}

}

[Fact]
public void ValidateShouldReturnSchematronValidationResultWhenSchematronConstraintsAreNotMet()
{
//Arrange
var validator = new Validator(OutputFormatting.XML);

//Act
validator.AddSchema(TargetNamespace, XsdLocation);

using (var doc = XmlReader.Create(XmlContentLocation))
{
var result = default(IXPathNavigable);

try
{
result = validator.Validate(doc);
}
catch (ValidationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);

var serializer = new XmlSerializer(typeof(Schematron.Serialization.SchematronValidationResultTempObjectModel.output));

using (var stream = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(ex.Message)))
using (var reader = XmlReader.Create(stream))
{
var obj = (Schematron.Serialization.SchematronValidationResultTempObjectModel.output)serializer.Deserialize(reader);

// Assert


Xunit.Assert.NotNull(obj);
Xunit.Assert.NotNull(obj.xml);
Xunit.Assert.NotNull(obj.schematron);
}
}
}
}

[Fact]
public void WhenUsingTheXmlReaderApproach_ToSupplyASchema_TypesFromImportsAreNotResolved()
{
// arrange
var validator = new Schematron.Validator();

// act, (assert)
Xunit.Assert.Throws<XmlSchemaException>(() => validator.AddSchema(XmlReader.Create(XsdWithPartialSchemaLocation)));
}

[Fact]
public void WhenUsingTheXmlSchemaSetBasedApproach_ToSupplyASchema_TypesFromImportsAreResolved()
{
// arrange
var validator = new Schematron.Validator();

var count = validator.XmlSchemas != null ? validator.XmlSchemas.Count : 0;

// act, (assert)
validator.AddSchema(TargetNamespace, XsdWithPartialSchemaLocation);

Xunit.Assert.True(validator.Schemas.Count == count + 1);

//var res = validator.Validate(XmlContentLocation);
}

//[Fact]
public void DoTheRawXmlValidation()
{
throw new NotImplementedException();
}

[Fact]
public void SchematronValidationResultIncludesExpandedValueElements()
{
//Arrange
var validator = new Validator(OutputFormatting.XML);

//Act
validator.AddSchema(TargetNamespace, XsdLocation);

using (var doc = XmlReader.Create(XmlContentLocation))
{
var result = default(IXPathNavigable);

try
{
result = validator.Validate(doc);
}
catch (ValidationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
string expectedMessage = "<text>Attributes sex (Female) and title (Mr) must have compatible values on element customer.</text>";
Xunit.Assert.True(ex.Message.Contains(expectedMessage));
}
Xunit.Assert.Null(result);
}
}

}
}
70 changes: 70 additions & 0 deletions src/Schematron/Formatters/FormatterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,75 @@ public virtual void Format(SchemaCollection schemas, StringBuilder output)
public virtual void Format(StringBuilder output)
{
}

protected static StringBuilder FormatMessage(Test source, XPathNavigator context, string msg)
{
StringBuilder sb = new StringBuilder();
XPathExpression nameExpr;
XPathExpression selectExpr;

// As we move on, we have to append starting from the last point,
// skipping the <name> and <value-of> expressions: Substring(offset, name.Index - offset).
int offset = 0;

for (int i = 0; i < source.NameValueOfExpressions.Count; i++)
{
System.Text.RegularExpressions.Match name = source.NameValueOfExpressions[i];
nameExpr = source.NamePaths[i];
selectExpr = source.ValueOfSelects[i];

// Append the text without the expression.
sb.Append(msg.Substring(offset, name.Index - offset));

// Does the name element have a path attribute?
if (nameExpr != null)
{
nameExpr.SetContext(source.GetContext());

string result = null;
if (nameExpr.ReturnType == XPathResultType.NodeSet)
{
// It the result of the expression is a nodeset, we only get the element
// name of the first node, which is compatible with XSLT implementation.
XPathNodeIterator nodes = (XPathNodeIterator)context.Evaluate(nameExpr);
if (nodes.MoveNext())
result = nodes.Current.Name;
}
else
result = context.Evaluate(nameExpr) as string;

if (result != null)
sb.Append(result);
}
// Does the value-of element have a select attribute?
else if (selectExpr != null)
{
selectExpr.SetContext(source.GetContext());

string result = null;
if (selectExpr.ReturnType == XPathResultType.NodeSet)
{
XPathNodeIterator nodes = (XPathNodeIterator)context.Evaluate(selectExpr);
result = String.Empty;
while (nodes.MoveNext())
result += nodes.Current.Value;
}
else
result = context.Evaluate(selectExpr) as string;

if (result != null)
sb.Append(result);
}
// If there is no path or select expression, there is an empty <name> element.
else
sb.Append(context.Name);

offset = name.Index + name.Length;
}

sb.Append(msg.Substring(offset));
return sb;
}

}
}
2 changes: 1 addition & 1 deletion src/Schematron/Formatters/FormattingUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public static string GetNamespaceSummary(XPathNavigator context, Hashtable names
/// </summary>
public static string NormalizeString(string input)
{
// Account for enconded strings, such as &lt; (<) and &gt (>).
// Account for encoded strings, such as &lt; (<) and &gt (>).
return System.Web.HttpUtility.HtmlDecode(
_normalize.Replace(input, " ").Trim());
}
Expand Down
Loading