Skip to content

Commit

Permalink
Merge pull request #181 from FirelyTeam/feature/141-improve-error-rep…
Browse files Browse the repository at this point in the history
…ort-narrative-validation

Added new txt-1 and txt-2 validation components
  • Loading branch information
mmsmits authored Aug 17, 2023
2 parents e91ef96 + 8a31e23 commit 5f7c693
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public IEnumerable<IAssertion> Build(ElementDefinitionNavigator nav, ElementConv
{
"ele-1" => new FhirEle1Validator(),
"ext-1" => new FhirExt1Validator(),
"txt-1" => new FhirTxt1Validator(),
"txt-2" => new FhirTxt2Validator(),
_ => null
};
}
Expand Down
68 changes: 68 additions & 0 deletions src/Firely.Fhir.Validation/Impl/FhirTxt1Validator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2022, Firely (info@fire.ly) - All Rights Reserved
* Proprietary and confidential. Unauthorized copying of this file,
* via any medium is strictly prohibited.
*/

using Hl7.Fhir.ElementModel;
using Hl7.Fhir.Model;
using Hl7.Fhir.Support;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Runtime.Serialization;

namespace Firely.Fhir.Validation
{
/// <summary>
/// Represents the hand-coded version of the equivalent <see cref="FhirPathValidator"/> running invariant "ext-1".
/// </summary>
[DataContract]
public class FhirTxt1Validator : InvariantValidator
{
/// <inheritdoc/>
public override string Key => "txt-1";

/// <inheritdoc/>
public override OperationOutcome.IssueSeverity? Severity => OperationOutcome.IssueSeverity.Error;

/// <inheritdoc/>
public override bool BestPractice => false;

/// <inheritdoc/>
public override string? HumanDescription => "The narrative SHALL contain only the basic html formatting elements and attributes described in chapters 7-11 (except section 4 of chapter 9) and 15 of the HTML 4.0 standard, <a> elements (either name or href), images and internally contained style attributes";

/// <inheritdoc/>
protected override (bool, ResultReport?) RunInvariant(ITypedElement input, ValidationContext vc, ValidationState _)
{
// Original expression: "expression": "htmlChecks()"

if (input.Value is null) return (false, null);

switch (input.Value)
{
case string value:
{
var result = XHtml.IsValidNarrativeXhtml(input.Value.ToString(), out var errors);

if (result)
{
return (true, null);
}
else
{
var issues = errors.Select(e => new IssueAssertion(Issue.XSD_VALIDATION_ERROR, e));
return (false, new ResultReport(ValidationResult.Failure, issues));
}
}
default:
return (false, new ResultReport(ValidationResult.Failure,
new IssueAssertion(Issue.CONTENT_ELEMENT_INVALID_PRIMITIVE_VALUE,
$"Narrative should be of type string, but is of type ({input.Value.GetType()})")));

}
}

/// <inheritdoc/>
public override JToken ToJson() => new JProperty("FastInvariant-txt1", new JObject());
}
}
42 changes: 42 additions & 0 deletions src/Firely.Fhir.Validation/Impl/FhirTxt2Validator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2022, Firely (info@fire.ly) - All Rights Reserved
* Proprietary and confidential. Unauthorized copying of this file,
* via any medium is strictly prohibited.
*/

using Hl7.Fhir.ElementModel;
using Hl7.Fhir.Model;
using Newtonsoft.Json.Linq;
using System.Runtime.Serialization;

namespace Firely.Fhir.Validation
{
/// <summary>
/// Represents the hand-coded version of the equivalent <see cref="FhirPathValidator"/> running invariant "ext-1".
/// </summary>
[DataContract]
public class FhirTxt2Validator : InvariantValidator
{
/// <inheritdoc/>
public override string Key => "txt-2";

/// <inheritdoc/>
public override OperationOutcome.IssueSeverity? Severity => OperationOutcome.IssueSeverity.Error;

/// <inheritdoc/>
public override bool BestPractice => false;

/// <inheritdoc/>
public override string? HumanDescription => "The narrative SHALL have some non-whitespace content";

/// <inheritdoc/>
protected override (bool, ResultReport?) RunInvariant(ITypedElement input, ValidationContext vc, ValidationState _)
{
//Check whether the narrative contains non-whitespace content.
return (!string.IsNullOrWhiteSpace(input.Value.ToString()), null);
}

/// <inheritdoc/>
public override JToken ToJson() => new JProperty("FastInvariant-txt2", new JObject());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,15 @@ public void HandcodedFPConstraintsTest()
new()
{
Key = "ext-1"
}
},
new()
{
Key = "txt-1"
},
new()
{
Key = "txt-2"
},

}
};
Expand All @@ -62,11 +70,13 @@ public void HandcodedFPConstraintsTest()

var result = _sut.Build(nav, ElementConversionMode.Full);
var builders = result.Should()
.HaveCount(2).And
.HaveCount(4).And
.AllBeAssignableTo<InvariantValidator>().Which;

builders.First().Should().BeOfType<FhirEle1Validator>();
builders.Skip(1).First().Should().BeOfType<FhirExt1Validator>();
builders.Skip(2).First().Should().BeOfType<FhirTxt1Validator>();
builders.Skip(3).First().Should().BeOfType<FhirTxt2Validator>();
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,31 @@ public void ValidateExtensionCardinality()
results = patientSchema!.Validate(patient.ToTypedElement(), _fixture.NewValidationContext());
results.IsSuccessful.Should().Be(true, because: "extensions have the correct cardinality");
}

[Fact]
public void ValidateNarrativeInvariants()
{
var justWhiteSpace = new Narrative
{
Status = Narrative.NarrativeStatus.Additional,
Div = " "
};

var invalidHtml = new Narrative
{
Status = Narrative.NarrativeStatus.Additional,
Div = "<div xmlns=\"http://www.w3.org/1999/xhtml\"><script> document.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\"; </script></div>"
};

var narrativeSchema = _fixture.SchemaResolver.GetSchema("http://hl7.org/fhir/StructureDefinition/Narrative");

var results = narrativeSchema!.Validate(justWhiteSpace.ToTypedElement(), _fixture.NewValidationContext());
results.IsSuccessful.Should().Be(false, "Instance failed constraint txt-2 \"The narrative SHALL have some non-whitespace content\"");

results = narrativeSchema!.Validate(invalidHtml.ToTypedElement(), _fixture.NewValidationContext());
results.IsSuccessful.Should().Be(false, "The element 'div' in namespace 'http://www.w3.org/1999/xhtml' has invalid child element 'script' in namespace 'http://www.w3.org/1999/xhtml'. List of possible elements expected: 'p, h1, h2, h3, h4, h5, h6, div, ul, ol, dl, pre, hr, blockquote, address, table, a, br, span, bdo, map, img, tt, i, b, big, small, em, strong, dfn, code, q, samp, kbd, var, cite, abbr, acronym, sub, sup' in namespace 'http://www.w3.org/1999/xhtml'.");

}
}
}

0 comments on commit 5f7c693

Please sign in to comment.