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
Original file line number Diff line number Diff line change
Expand Up @@ -510,10 +510,9 @@ internal IAssertion CreateSliceValidator(ElementDefinitionNavigator root)
convertElementToSchema(schemaId + ":" + "condition", root)
: buildDiscriminatorCondition(slicing, root);

// Check for always true/false cases.
if (condition is IFixedResult ra)
throw new IncorrectElementDefinitionException($"Encountered an ElementDefinition {root.Current.ElementId} that always" +
$"results in {ra.FixedResult} for its discriminator(s) and therefore cannot be used as a slicing discriminator.");
// A condition that always succeeds (or always fails) makes the slice superfluous (it matches
// everything, or nothing), but that is not wrong, so it should not stop the schema from being
// built. The SliceValidator handles such a condition correctly as it is.

// If this is a normal slice, the constraints for the case to run are the constraints under this node.
// In the case of a discriminator-less match, the case condition itself was a full validation of all
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2024, Firely (info@fire.ly) and contributors
* See the file CONTRIBUTORS for details.
*
* This file is licensed under the BSD 3-Clause license
* available at https://github.com/FirelyTeam/firely-validator-api/blob/main/LICENSE
*/

using FluentAssertions;
using Hl7.Fhir.Model;
using Hl7.Fhir.Specification.Source;
using Hl7.Fhir.Specification.Terminology;
using System.Linq;
using Xunit;

namespace Firely.Fhir.Validation.Tests
{
public class SuperfluousSliceTests
{
private const string PROFILE_URL = "http://example.org/fhir/StructureDefinition/SuperfluousSliceTestProfile";

private static StructureDefinition profile(string type, params ElementDefinition[] differential) => new()
{
Url = PROFILE_URL,
Name = "SuperfluousSliceTestProfile",
Status = PublicationStatus.Draft,
FhirVersion = FHIRVersion.N4_0_1,
Kind = StructureDefinition.StructureDefinitionKind.Resource,
Abstract = false,
Type = type,
BaseDefinition = $"http://hl7.org/fhir/StructureDefinition/{type}",
Derivation = StructureDefinition.TypeDerivationRule.Constraint,
Differential = new StructureDefinition.DifferentialComponent { Element = differential.ToList() }
};

private static OperationOutcome validate(StructureDefinition sd, Resource instance)
{
var source = new SnapshotSource(new MultiResolver(new InMemoryProfileResolver(sd), ZipSource.CreateValidationSource()));
var validator = new Validator(source.AsAsync(), new LocalTerminologyService(source.AsAsync()));
return validator.Validate(instance, PROFILE_URL);
}

/// <summary>
/// A slice whose discriminator always succeeds (here: a 'profile' discriminator on an
/// element without any profiles) is superfluous, but not wrong. See issue #662.
/// </summary>
[Fact]
public void SuperfluousSliceShouldNotFailSchemaCompilation()
{
var sd = profile("Patient",
new ElementDefinition("Patient.name")
{
ElementId = "Patient.name",
Slicing = new ElementDefinition.SlicingComponent
{
Rules = ElementDefinition.SlicingRules.Open,
Discriminator =
[
new ElementDefinition.DiscriminatorComponent
{
Type = ElementDefinition.DiscriminatorType.Profile, Path = "$this"
}
]
}
},
new ElementDefinition("Patient.name")
{
ElementId = "Patient.name:only",
SliceName = "only",
Min = 0,
Max = "*"
});

var patient = new Patient { Name = [new HumanName { Family = "Kramer" }] };

var outcome = validate(sd, patient);

outcome.Success.Should().BeTrue(outcome.ToString());
}
}
}
Loading