From f706840d5de335916f88530eff3e61152eb7fbec Mon Sep 17 00:00:00 2001 From: codex Date: Mon, 10 Aug 2026 15:42:18 +0300 Subject: [PATCH] fix: preserve legacy settings decimal semantics --- .../src/PRecAnnot.Core/ProductionSettingsContract.cs | 7 ++++++- .../ProductionSettingsContractTests.cs | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ProductionSettingsContract.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ProductionSettingsContract.cs index dba6d36..c97fa36 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ProductionSettingsContract.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ProductionSettingsContract.cs @@ -37,7 +37,7 @@ public sealed record ProductionSettingsContract( var setLayer = root.Element("SetLayer")?.Attribute("name")?.Value; if (string.IsNullOrWhiteSpace(setLayer)) throw Invalid("SetLayer.name"); var plusLength = root.Element("PlusLengthNO")?.Attribute("value")?.Value; - double? parsedPlusLength = double.TryParse(plusLength, NumberStyles.Float, CultureInfo.InvariantCulture, out var plus) ? plus : null; + double? parsedPlusLength = TryParseLegacyNumber(plusLength, out var plus) ? plus : null; return new( copy, layers, @@ -55,6 +55,11 @@ public sealed record ProductionSettingsContract( } private static int? ParseInt(XElement value, string name) => int.TryParse(value.Attribute(name)?.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed) ? parsed : null; + private static bool TryParseLegacyNumber(string? value, out double parsed) + { + if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out parsed)) return true; + return double.TryParse(value?.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out parsed); + } private static string Required(XElement? value, string name, bool allowEmpty = false) => value?.Attribute(name) is { Value: var result } && (allowEmpty || !string.IsNullOrWhiteSpace(result)) ? result : throw Invalid(name); private static InvalidDataException Invalid(string field) => new("PRODUCTION_SETTINGS_INVALID:" + field); } diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ProductionSettingsContractTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ProductionSettingsContractTests.cs index c749ac9..766b809 100644 --- a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ProductionSettingsContractTests.cs +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ProductionSettingsContractTests.cs @@ -35,4 +35,12 @@ public sealed class ProductionSettingsContractTests var exception = Assert.Throws(() => ProductionSettingsContract.Parse(xml)); Assert.Equal("PRODUCTION_SETTINGS_INVALID:layer", exception.Message); } + + [Fact] + public void ParsesLegacyCommaDecimalPlusLength() + { + const string xml = "
"; + var result = ProductionSettingsContract.Parse(xml); + Assert.Equal(1.5, result.FixedSupportPlusLength); + } }