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
9 changes: 8 additions & 1 deletion Services/Iec61850ValueFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ public static string Format(object? value, string dataType, string unit)
if (TryExtractStructuredScalar(value, dataType, out var structuredScalar))
value = structuredScalar;

return FormatNormalizedValue(value, dataType, unit);
}

// Both entry points normalize any legacy structure exactly once before formatting.
// Keep the established generic and report-specific state vocabularies separate.
private static string FormatNormalizedValue(object? value, string dataType, string unit)
{
if (IsDbposDataType(dataType) && TryNormalizeDbpos(value, out var dbpos))
return FormatDbpos(dbpos);

Expand Down Expand Up @@ -74,7 +81,7 @@ public static string FormatReportProcessValue(
return boolean ? "True [1]" : "False [0]";
}

return Format(normalizedValue, dataType, unit);
return FormatNormalizedValue(normalizedValue, dataType, unit);
}

private static bool IsPositionSemantic(string dataType, string category, string reference)
Expand Down
27 changes: 27 additions & 0 deletions tests/ARSAS.Tests/Iec61850ValueFormatterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,33 @@ public void Format_Does_Not_Collapse_Indexed_Structure_When_Metadata_Is_Not_Nume
Assert.Equal(value, formatted);
}

[Theory]
[InlineData("Structure(3) {stVal=false, q=Quality{V=1,D=0}}", "Boolean", "", "Status", "IEDLD/GGIO1.Ind1.stVal", "False [0]")]
[InlineData("Structure(3) {stVal=2, q=Quality{V=1,D=0}}", "Dbpos", "", "Position", "IEDLD/CSWI1.Pos.stVal", "Close [10]")]
[InlineData("Structure(5) {[0]=12345, [1]=Quality{V=1,D=0}}", "Int64", "Wh", "Measurement", "IEDLD/MMXU1.Wh.instMag.i", "12345 Wh")]
public void FormatReportProcessValue_NormalizesLegacyScalarAndKeepsOperatorSemantics(
string value,
string dataType,
string unit,
string category,
string reference,
string expected)
{
Assert.Equal(expected,
Iec61850ValueFormatter.FormatReportProcessValue(
value, dataType, unit, category, reference));
}

[Fact]
public void FormatReportProcessValue_DoesNotCollapseIndexedStructureWithoutNumericMetadata()
{
const string value = "Structure(2) {[0]=12345, [1]=Quality{V=1,D=0}}";

Assert.Equal(value,
Iec61850ValueFormatter.FormatReportProcessValue(
value, "Structure", string.Empty, "Measurement", "IEDLD/GGIO1.Raw"));
}

[Fact]
public void Format_Does_Not_Collapse_NonStVal_Structures()
{
Expand Down
Loading