Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ internal static ValueSet.ContainsComponent ToContainsComponent(this CodeSystem.C
if (inactiveProperty?.Value is FhirBoolean isInactive)
newContains.Inactive = isInactive.Value;

#if !STU3
#if !(STU3 || R4)
if (source.Property.Any())
{
newContains.Property = source.Property.Select(p => new ValueSet.ConceptPropertyComponent { Code = p.Code, Value = p.Value }).ToList();
Expand Down
49 changes: 49 additions & 0 deletions src/Hl7.Fhir.Specification.Shared.Tests/Source/TerminologyTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using Hl7.Fhir.Model;
using Hl7.Fhir.Rest;
using Hl7.Fhir.Serialization;
using Hl7.Fhir.Specification.Source;
using Hl7.Fhir.Specification.Terminology;
using Hl7.Fhir.Validation;
Expand Down Expand Up @@ -762,6 +763,54 @@ void expandAction(string url)
}
}

/// <summary>
/// Test for issue with ValueSet expansion causing NullReferenceException during serialization
/// when the expansion contains property field that doesn't exist in R4/R4B.
/// The Property field in ValueSet.expansion.contains was introduced in R5.
/// Uses item-type ValueSet which has properties in R5.
/// </summary>
[Fact]
public async Tasks.Task ExpandedValueSetShouldSerializeSuccessfully()
{
var server = new LocalTerminologyService(_resolver);
var parameters = new Parameters()
{
Parameter = new List<Parameters.ParameterComponent>
{
new Parameters.ParameterComponent()
{
Name = "url",
Value = new FhirUri("http://hl7.org/fhir/ValueSet/item-type"),
},
},
};

var resource = await server.Expand(parameters);

// This should not throw a NullReferenceException
var json = resource.ToJson();

// Verify the expansion was successful
Assert.NotNull(json);
Assert.NotEmpty(json);
var valueSet = resource as ValueSet;
Assert.NotNull(valueSet);
Assert.True(valueSet.HasExpansion);
Assert.True(valueSet.Expansion.Contains.Any());

#if R5 || R6
// In R5 and R6, verify that the Property element is correctly set in the expansion
// when the CodeSystem has properties defined. The item-type CodeSystem has the
// "notSelectable" property defined for some concepts (e.g., "question").
var containsWithProperties = valueSet.Expansion.Contains
.Where(c => c.Property != null && c.Property.Any())
.ToList();

// The item-type ValueSet should have at least one concept with properties in R5+
Assert.NotEmpty(containsWithProperties);
#endif
}

[Fact]
public void TestValidateCodeParametersCode()
{
Expand Down