Skip to content

Commit

Permalink
handle and testing missing optional values
Browse files Browse the repository at this point in the history
  • Loading branch information
MWO1024 committed Dec 11, 2024
1 parent afbe20a commit 6d657aa
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private Document ParseFrom(OutgoingMessageHeader header, IReadOnlyCollection<str
activityRecord.OriginalTransactionIdReferenceId?.Value,
activityRecord.Product,
activityRecord.QuantityMeasureUnit.Code,
activityRecord.RegistrationDateTime.ToString(),
activityRecord.RegistrationDateTime?.ToString(),
new Period(
activityRecord.Resolution.Code,
new TimeInterval(
Expand All @@ -100,7 +100,7 @@ private Document ParseFrom(OutgoingMessageHeader header, IReadOnlyCollection<str
header.SenderId,
header.SenderRole,
TypeCode,
meteredDataForMeasurementPoints));
meteredDataForMeasurementPoints.Count == 0 ? null : meteredDataForMeasurementPoints));
}
}

Expand All @@ -120,7 +120,7 @@ internal class MeteredDateForMeasurementPoint(
string senderId,
string senderRole,
string typeCode,
IReadOnlyCollection<MeteredDataForMeasurementPoint> meteredDataForMeasurementPoints)
IReadOnlyCollection<MeteredDataForMeasurementPoint>? meteredDataForMeasurementPoints)
{
[JsonPropertyName("mRID")]
public string MessageId { get; init; } = messageId;
Expand Down Expand Up @@ -150,17 +150,19 @@ internal class MeteredDateForMeasurementPoint(
public ValueObject<string> Type { get; init; } = ValueObject<string>.Create(typeCode);

[JsonPropertyName("Series")]
public IReadOnlyCollection<MeteredDataForMeasurementPoint> MeteredDataForMeasurementPoints { get; init; } = meteredDataForMeasurementPoints;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IReadOnlyCollection<MeteredDataForMeasurementPoint>? MeteredDataForMeasurementPoints { get; init; } =
meteredDataForMeasurementPoints;
}

internal class MeteredDataForMeasurementPoint(
string transactionId,
string marketEvaluationPointNumber,
string marketEvaluationPointType,
string? originalTransactionIdReferenceId,
string product,
string? product,
string quantityMeasureUnit,
string registrationDateTime,
string? registrationDateTime,
Period period)
{
[JsonPropertyName("mRID")]
Expand All @@ -177,13 +179,15 @@ internal class MeteredDataForMeasurementPoint(
public string? OriginalTransactionIdReferenceId { get; init; } = originalTransactionIdReferenceId; //TODO: what does this field represent?

[JsonPropertyName("product")]
public string Product { get; init; } = product;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Product { get; init; } = product;

[JsonPropertyName("quantity_Measure_Unit.name")]
public ValueObject<string> QuantityMeasureUnit { get; init; } = ValueObject<string>.Create(quantityMeasureUnit);

[JsonPropertyName("registration_DateAndOrTime.dateTime")]
public string RegistrationDateTime { get; init; } = registrationDateTime;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? RegistrationDateTime { get; init; } = registrationDateTime;

[JsonPropertyName("Period")]
public Period Period { get; init; } = period;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,43 @@ protected override async Task WriteMarketActivityRecordsAsync(
XNamespace @namespace = "urn:ediel.org:measure:notifyvalidatedmeasuredata:0:1";
foreach (var activityRecord in ParseFrom<MeteredDateForMeasurementPointMarketActivityRecord>(marketActivityPayloads))
{
var seriesElement = new XElement(
@namespace + "Series",
new XElement(@namespace + "mRID", activityRecord.TransactionId.Value),
new XElement(
var seriesElement = new XElement(@namespace + "Series");
seriesElement.Add(new XElement(@namespace + "mRID", activityRecord.TransactionId.Value));

if (activityRecord.OriginalTransactionIdReferenceId is not null)
{
seriesElement.Add(
new XElement(
@namespace + "originalTransactionIDReference_Series.mRID",
activityRecord.OriginalTransactionIdReferenceId?.Value),
activityRecord.OriginalTransactionIdReferenceId?.Value));
}

seriesElement.Add(
new XElement(
@namespace + "marketEvaluationPoint.mRID",
new XAttribute("codingScheme", "A10"),
activityRecord.MarketEvaluationPointNumber),
new XElement(@namespace + "marketEvaluationPoint.type", activityRecord.MarketEvaluationPointType),
new XElement(@namespace + "registration_DateAndOrTime.dateTime", activityRecord.RegistrationDateTime),
new XElement(@namespace + "product", activityRecord.Product),
new XElement(@namespace + "quantity_Measure_Unit.name", activityRecord.QuantityMeasureUnit.Code),
activityRecord.MarketEvaluationPointNumber));

seriesElement.Add(
new XElement(@namespace + "marketEvaluationPoint.type", activityRecord.MarketEvaluationPointType));

if (activityRecord.RegistrationDateTime is not null)
{
seriesElement.Add(
new XElement(
@namespace + "registration_DateAndOrTime.dateTime",
activityRecord.RegistrationDateTime));
}

if (activityRecord.Product is not null)
{
seriesElement.Add(new XElement(@namespace + "product", activityRecord.Product));
}

seriesElement.Add(
new XElement(@namespace + "quantity_Measure_Unit.name", activityRecord.QuantityMeasureUnit.Code));

seriesElement.Add(
new XElement(
@namespace + "Period",
new XElement(@namespace + "resolution", activityRecord.Resolution.Code),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public sealed record MeteredDateForMeasurementPointMarketActivityRecord(
string MarketEvaluationPointNumber,
string MarketEvaluationPointType,
TransactionId? OriginalTransactionIdReferenceId,
string Product,
string? Product,
MeasurementUnit QuantityMeasureUnit,
Instant RegistrationDateTime,
Instant? RegistrationDateTime,
Resolution Resolution,
Instant StartedDateTime,
Instant EndedDateTime,
Expand Down
14 changes: 14 additions & 0 deletions source/Tests/Factories/MeteredDateForMeasurementPointBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,18 @@ public MeteredDateForMeasurementPointMarketActivityRecord BuildMeteredDataForMea
SampleData.EndedDateTime,
SampleData.Points);
}

public MeteredDateForMeasurementPointMarketActivityRecord BuildMinimalMeteredDataForMeasurementPoint() =>
new(
SampleData.TransactionId,
SampleData.MeteringPointNumber,
SampleData.MeteringPointType,
null,
null,
SampleData.QuantityMeasureUnit,
null,
SampleData.Resolution,
SampleData.StartedDateTime,
SampleData.EndedDateTime,
SampleData.MinimalPoints);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public IAssertMeteredDateForMeasurementPointDocumentDocument MessageIdExists()
return this;
}

public IAssertMeteredDateForMeasurementPointDocumentDocument HasNoSeriesElements()
{
_root.TryGetProperty("Series", out _).Should().BeFalse("property 'Series' should not be present");
return this;
}

public IAssertMeteredDateForMeasurementPointDocumentDocument HasBusinessReason(string expectedBusinessReasonCode)
{
Assert.Equal(expectedBusinessReasonCode, _root.GetProperty("process.processType").GetProperty("value").ToString());
Expand Down Expand Up @@ -360,7 +366,10 @@ public async Task<IAssertMeteredDateForMeasurementPointDocumentDocument> Documen
{
var schema = await _schemas.GetSchemaAsync<JsonSchema>("NOTIFYVALIDATEDMEASUREDATA", "0", CancellationToken.None).ConfigureAwait(false);
var validationResult = IsValid(_document, schema!);
validationResult.IsValid.Should().BeTrue(string.Join("\n", validationResult.Errors));
validationResult.IsValid.Should()
.BeTrue(
$"the following errors were unexpected:\n\n{string.Join("\n", validationResult.Errors)}\n\nfor the document\n\n{_document.RootElement}");

return this;
}

Expand All @@ -370,31 +379,28 @@ public async Task<IAssertMeteredDateForMeasurementPointDocumentDocument> Documen
var result = schema.Evaluate(jsonDocument, new EvaluationOptions() { OutputFormat = OutputFormat.Hierarchical, });
if (result.IsValid == false)
{
errors.Add(FindErrorsForInvalidEvaluation(result));
errors.AddRange(FindErrorsForInvalidEvaluation(result).Where(e => !string.IsNullOrEmpty(e)));
}

return (result.IsValid, errors);
}

private string FindErrorsForInvalidEvaluation(EvaluationResults result)
private IEnumerable<string> FindErrorsForInvalidEvaluation(EvaluationResults result)
{
if (!result.IsValid)
var errors = new List<string>();

if (result is { IsValid: false, Errors: not null })
{
foreach (var detail in result.Details)
{
return FindErrorsForInvalidEvaluation(detail);
}
var propertyName = result.InstanceLocation.ToString();
errors.AddRange(result.Errors.Select(error => $"{propertyName}: {error}"));
}

if (!result.HasErrors || result.Errors == null) return string.Empty;

var propertyName = result.InstanceLocation.ToString();
foreach (var error in result.Errors)
foreach (var detail in result.Details)
{
return $"{propertyName}: {error}";
errors.AddRange(FindErrorsForInvalidEvaluation(detail));
}

return string.Empty;
return errors;
}

private JsonElement GetTimeSeriesElement(int seriesIndex) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public IAssertMeteredDateForMeasurementPointDocumentDocument MessageIdExists()
return this;
}

public IAssertMeteredDateForMeasurementPointDocumentDocument HasNoSeriesElements()
{
_documentAsserter.IsNotPresent("Series[1]");
return this;
}

public IAssertMeteredDateForMeasurementPointDocumentDocument HasBusinessReason(string expectedBusinessReasonCode)
{
_documentAsserter.HasValue("process.processType", expectedBusinessReasonCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public interface IAssertMeteredDateForMeasurementPointDocumentDocument
{
IAssertMeteredDateForMeasurementPointDocumentDocument MessageIdExists();

IAssertMeteredDateForMeasurementPointDocumentDocument HasNoSeriesElements();

IAssertMeteredDateForMeasurementPointDocumentDocument HasBusinessReason(string expectedBusinessReasonCode);

IAssertMeteredDateForMeasurementPointDocumentDocument HasSenderId(string expectedSenderId, string expectedSchemeCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class MeteredDateForMeasurementPointDocumentWriterTests(DocumentValidatio
[Theory]
[InlineData(nameof(DocumentFormat.Xml))]
[InlineData(nameof(DocumentFormat.Json))]
public async Task Can_create_notifyValidatedMeasureData_document(string documentFormat)
public async Task Can_create_maximal_notifyValidatedMeasureData_document(string documentFormat)
{
// Arrange
var messageBuilder = _meteredDateForMeasurementPointBuilder;
Expand Down Expand Up @@ -85,23 +85,102 @@ await AssertDocument(document, DocumentFormat.FromName(documentFormat))
.DocumentIsValidAsync();
}

[Theory]
[InlineData(nameof(DocumentFormat.Xml))]
[InlineData(nameof(DocumentFormat.Json))]
public async Task Can_create_minimal_series_notifyValidatedMeasureData_document(string documentFormat)
{
// Arrange
var messageBuilder = _meteredDateForMeasurementPointBuilder;

// Act
var document = await WriteDocument(
messageBuilder.BuildHeader(),
messageBuilder.BuildMinimalMeteredDataForMeasurementPoint(),
DocumentFormat.FromName(documentFormat));

// Assert
using var assertionScope = new AssertionScope();
await AssertDocument(document, DocumentFormat.FromName(documentFormat))
.MessageIdExists()
.HasBusinessReason(SampleData.BusinessReason.Code)
.HasSenderId(SampleData.SenderActorNumber, "A10")
.HasSenderRole(SampleData.SenderActorRole)
.HasReceiverId(SampleData.ReceiverActorNumber, "A10")
.HasReceiverRole(SampleData.ReceiverActorRole)
.HasTimestamp(SampleData.TimeStamp.ToString())
.HasTransactionId(1, SampleData.TransactionId)
.HasMeteringPointNumber(1, SampleData.MeteringPointNumber, "A10")
.HasMeteringPointType(1, SampleData.MeteringPointType)
.HasOriginalTransactionIdReferenceId(1, null)
.HasProduct(1, null)
.HasQuantityMeasureUnit(1, SampleData.QuantityMeasureUnit.Code)
.HasRegistrationDateTime(1, null)
.HasResolution(1, SampleData.Resolution.Code)
.HasStartedDateTime(
1,
SampleData.StartedDateTime.ToString("yyyy-MM-dd'T'HH:mm'Z'", CultureInfo.InvariantCulture))
.HasEndedDateTime(
1,
SampleData.EndedDateTime.ToString("yyyy-MM-dd'T'HH:mm'Z'", CultureInfo.InvariantCulture))
.HasPoints(
1,
SampleData.MinimalPoints.Select(
p => new AssertPointDocumentFieldsInput(
new RequiredPointDocumentFields(p.Position),
OptionalPointDocumentFields.NoOptionalFields()))
.ToList())
.DocumentIsValidAsync();
}

[Theory]
[InlineData(nameof(DocumentFormat.Xml))]
[InlineData(nameof(DocumentFormat.Json))]
public async Task Can_create_no_series_notifyValidatedMeasureData_document(string documentFormat)
{
// Arrange
var messageBuilder = _meteredDateForMeasurementPointBuilder;

// Act
var document = await WriteDocument(
messageBuilder.BuildHeader(),
null,
DocumentFormat.FromName(documentFormat));

// Assert
using var assertionScope = new AssertionScope();
await AssertDocument(document, DocumentFormat.FromName(documentFormat))
.MessageIdExists()
.HasBusinessReason(SampleData.BusinessReason.Code)
.HasSenderId(SampleData.SenderActorNumber, "A10")
.HasSenderRole(SampleData.SenderActorRole)
.HasReceiverId(SampleData.ReceiverActorNumber, "A10")
.HasReceiverRole(SampleData.ReceiverActorRole)
.HasTimestamp(SampleData.TimeStamp.ToString())
.HasNoSeriesElements()
.DocumentIsValidAsync();
}

private Task<MarketDocumentStream> WriteDocument(
OutgoingMessageHeader header,
MeteredDateForMeasurementPointMarketActivityRecord meteredDateForMeasurementPointMarketActivityRecord,
MeteredDateForMeasurementPointMarketActivityRecord? meteredDateForMeasurementPointMarketActivityRecord,
DocumentFormat documentFormat)
{
var records = _parser.From(meteredDateForMeasurementPointMarketActivityRecord);
var records = meteredDateForMeasurementPointMarketActivityRecord is null
? null
: _parser.From(meteredDateForMeasurementPointMarketActivityRecord);

if (documentFormat == DocumentFormat.Xml)
{
return new MeteredDateForMeasurementPointCimXmlDocumentWriter(_parser).WriteAsync(header, new[] { records });
return new MeteredDateForMeasurementPointCimXmlDocumentWriter(_parser)
.WriteAsync(header, records is null ? [] : [records]);
}

var serviceProvider = new ServiceCollection().AddJavaScriptEncoder().BuildServiceProvider();
return new MeteredDateForMeasurementPointCimJsonDocumentWriter(
_parser,
serviceProvider.GetRequiredService<JavaScriptEncoder>())
.WriteAsync(header, [records], CancellationToken.None);
.WriteAsync(header, records is null ? [] : [records], CancellationToken.None);
}

private IAssertMeteredDateForMeasurementPointDocumentDocument AssertDocument(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,7 @@ internal static class SampleData
new(6, "A02", null),
};

public static IReadOnlyList<PointActivityRecord> MinimalPoints => [new(2, null, null)];

#endregion
}

0 comments on commit 6d657aa

Please sign in to comment.