diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab394d5..c424876 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,10 @@ on: jobs: build: - runs-on: windows-latest - + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] + runs-on: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v3 @@ -20,10 +22,12 @@ jobs: submodules: true fetch-depth: 0 - - name: Install .NET 7.0 - uses: actions/setup-dotnet@v3 + - name: Install .NET 6 & 8 + uses: actions/setup-dotnet@v4 with: - dotnet-version: '7.0.x' + dotnet-version: | + 6 + 8 - name: Build, Test, Pack, Publish shell: bash diff --git a/src/Tomlyn.Signed/Tomlyn.Signed.csproj b/src/Tomlyn.Signed/Tomlyn.Signed.csproj index eb9fbe7..ebad399 100644 --- a/src/Tomlyn.Signed/Tomlyn.Signed.csproj +++ b/src/Tomlyn.Signed/Tomlyn.Signed.csproj @@ -4,6 +4,7 @@ Tomlyn.Signed key.snk true + netstandard2.0;net6.0;net8.0 diff --git a/src/Tomlyn.Tests/AssertHelper.cs b/src/Tomlyn.Tests/AssertHelper.cs index 9a47806..ad0b6ab 100644 --- a/src/Tomlyn.Tests/AssertHelper.cs +++ b/src/Tomlyn.Tests/AssertHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Alexandre Mutel. All rights reserved. -// Licensed under the BSD-Clause 2 license. +// Licensed under the BSD-Clause 2 license. // See license.txt file in the project root for full license information. using System; @@ -27,5 +27,13 @@ public static string NormalizeEndOfLine(string text) { return text.Replace("\r\n", "\n"); } + + #if !NET5_0_OR_GREATER + public static string ReplaceLineEndings(this string text, string? newLine = null) + { + newLine ??= Environment.NewLine; + return text.Replace("\r\n", "\n").Replace("\n", newLine); + } + #endif } } \ No newline at end of file diff --git a/src/Tomlyn.Tests/FloatingRoundtripTests.cs b/src/Tomlyn.Tests/FloatingRoundtripTests.cs new file mode 100644 index 0000000..e06d7a3 --- /dev/null +++ b/src/Tomlyn.Tests/FloatingRoundtripTests.cs @@ -0,0 +1,90 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// Licensed under the BSD-Clause 2 license. +// See license.txt file in the project root for full license information. + +using NUnit.Framework; +using Tomlyn.Model; + +namespace Tomlyn.Tests +{ + [TestFixture] + public class FloatingRoundtripTests{ + + + [TestCase(0.0)] + [TestCase(-0.0)] + [TestCase(1.0)] + [TestCase(-1.0)] + [TestCase(double.PositiveInfinity)] + [TestCase(double.NegativeInfinity)] + [TestCase(double.NaN)] +#if NET8_0_OR_GREATER + [TestCase(double.NegativeZero)] +#endif + [TestCase(double.Epsilon)] + [TestCase(-double.Epsilon)] + // [TestCase(0.1)] - - These fail. Adjusting g16->g17 fixes some but not all. + // [TestCase(0.99)] + // [TestCase(0.3)] + // [TestCase(double.MinValue)] + // [TestCase(double.MaxValue)] + public void TestDoublesRoundtrip(double number) + { + // we want to increment f64 by the smallest possible value + // and verify it changes the serialized value + // IEEE 754 compliance means -0.0 and +0.0 are different + // special values +inf=inf, -inf, nan=+nan, -nan + var model = new TomlTable + { + ["float"] = (float)number, + ["double"] = number + }; + var toml = Toml.FromModel(model); + var parsed = Toml.Parse(toml); + var parsedDouble = (double)parsed.ToModel()["double"]; + var parsedFloat = (double)parsed.ToModel()["float"]; + Assert.True(number == parsedDouble || double.IsNaN(number), + $"(f64->str->f64) expected {number:g30} but got {parsedDouble:g30}. \nString form: \n{toml}"); + Assert.AreEqual(number, parsedDouble); + Assert.True((float)number == parsedFloat || double.IsNaN(number), + $"(f64->f32->str->f64->f32) expected {(float)number:g30} but got {parsedFloat:g30}. \nString form: \n{toml}"); + Assert.AreEqual((float)number, parsedFloat); + } + + [TestCase(0.0f)] + [TestCase(-0.0f)] + [TestCase(1.0f)] + [TestCase(-1.0f)] + [TestCase(float.PositiveInfinity)] + [TestCase(float.NegativeInfinity)] + [TestCase(float.NaN)] +#if NET8_0_OR_GREATER + [TestCase(float.NegativeZero)] +#endif + [TestCase(float.Epsilon)] + [TestCase(-float.Epsilon)] + // [TestCase(0.1f)] - These fail. Adjusting g16->g17 fixes them + // [TestCase(0.99f)] + // [TestCase(0.3f)] + // [TestCase(float.MinValue)] + // [TestCase(float.MaxValue)] + public void TestFloatsRoundtrip(float number) + { + var model = new TomlTable + { + ["float"] = number, + ["double"] = (double)number + }; + var toml = Toml.FromModel(model); + + var parsed = Toml.Parse(toml); + var parsedDouble = (double)parsed.ToModel()["double"]; + var parsedFloatAsDouble = (double)parsed.ToModel()["float"]; + Assert.True((double)number == parsedDouble || double.IsNaN(number), + $"(f32->f64->str->f64) expected double {(double)number:g64} but got double {parsedDouble:g64}. \nString form: \n{toml}"); + Assert.True(number == (float)parsedFloatAsDouble || double.IsNaN(number), + $"(f32->str->f64->f32) expected float {number:g64} but got float {(float)parsedFloatAsDouble:g64}. \nString form: \n{toml}"); + + } + } +} \ No newline at end of file diff --git a/src/Tomlyn.Tests/ModelTests/ReflectionModelTests.cs b/src/Tomlyn.Tests/ModelTests/ReflectionModelTests.cs index 6d41a2a..0a11d4d 100644 --- a/src/Tomlyn.Tests/ModelTests/ReflectionModelTests.cs +++ b/src/Tomlyn.Tests/ModelTests/ReflectionModelTests.cs @@ -94,8 +94,10 @@ public void TestPrimitives() Float64Value = 2.5, DateTime = new DateTime(1970, 1, 1), DateTimeOffset = new DateTimeOffset(1980, 1, 1, 0, 23, 1, TimeSpan.FromHours(-2)), +#if NET6_0_OR_GREATER DateOnly = new DateOnly(1970, 5, 27), TimeOnly = new TimeOnly(7, 32, 0, 999), +#endif TomlDateTime = new TomlDateTime(new DateTimeOffset(new DateTime(1990, 11, 15)), 0, TomlDateTimeKind.LocalDateTime) }; @@ -149,8 +151,10 @@ public void TestPrimitiveFields() Float64Value = 2.5, DateTime = new DateTime(1970, 1, 1), DateTimeOffset = new DateTimeOffset(1980, 1, 1, 0, 23, 1, TimeSpan.FromHours(-2)), +#if NET6_0_OR_GREATER DateOnly = new DateOnly(1970, 5, 27), TimeOnly = new TimeOnly(7, 32, 0, 999), +#endif TomlDateTime = new TomlDateTime(new DateTimeOffset(new DateTime(1990, 11, 15)), 0, TomlDateTimeKind.LocalDateTime) }; @@ -207,8 +211,10 @@ public void TestNullableValueTypes() Float64Value = 2.5, DateTime = new DateTime(1970, 1, 1), DateTimeOffset = new DateTimeOffset(1980, 1, 1, 0, 23, 1, TimeSpan.FromHours(-2)), +#if NET6_0_OR_GREATER DateOnly = new DateOnly(1970, 5, 27), TimeOnly = new TimeOnly(7, 32, 0, 999), +#endif TomlDateTime = new TomlDateTime(new DateTimeOffset(new DateTime(1990, 11, 15)), 0, TomlDateTimeKind.LocalDateTime) }; @@ -280,8 +286,10 @@ public void TestNullableValueTypeFields() Float64Value = 2.5, DateTime = new DateTime(1970, 1, 1), DateTimeOffset = new DateTimeOffset(1980, 1, 1, 0, 23, 1, TimeSpan.FromHours(-2)), +#if NET6_0_OR_GREATER DateOnly = new DateOnly(1970, 5, 27), TimeOnly = new TimeOnly(7, 32, 0, 999), +#endif TomlDateTime = new TomlDateTime(new DateTimeOffset(new DateTime(1990, 11, 15)), 0, TomlDateTimeKind.LocalDateTime) }; diff --git a/src/Tomlyn.Tests/Tomlyn.Tests.csproj b/src/Tomlyn.Tests/Tomlyn.Tests.csproj index db21535..efbcb03 100644 --- a/src/Tomlyn.Tests/Tomlyn.Tests.csproj +++ b/src/Tomlyn.Tests/Tomlyn.Tests.csproj @@ -1,9 +1,14 @@ - net7.0 + net6.0;net8.0;net48 + net6.0;net8.0 + + + false enable + latest @@ -11,6 +16,13 @@ + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tomlyn/Model/ModelToTomlTransform.cs b/src/Tomlyn/Model/ModelToTomlTransform.cs index 1f0df06..b9b0e82 100644 --- a/src/Tomlyn/Model/ModelToTomlTransform.cs +++ b/src/Tomlyn/Model/ModelToTomlTransform.cs @@ -104,7 +104,7 @@ private void WriteKey(string name) private string EscapeKey(string name) { if (string.IsNullOrWhiteSpace(name)) return $"\"{name.EscapeForToml()}\""; - + // A-Za-z0-9_- foreach (var c in name) { @@ -174,7 +174,6 @@ private bool VisitObject(ObjectDynamicAccessor accessor, object currentObject, b try { - // Pre-convert values to TOML values var convertToToml = _context.ConvertToToml; if (convertToToml != null) @@ -200,8 +199,8 @@ private bool VisitObject(ObjectDynamicAccessor accessor, object currentObject, b } // Sort primitive first - properties = properties.OrderBy(_ => _, - Comparer>.Create((left, right) => + properties = properties.OrderBy(p => p, + Comparer>.Create((left, right) => { var leftValue = left.Value; var rightValue = right.Value; diff --git a/src/Tomlyn/Tomlyn.csproj b/src/Tomlyn/Tomlyn.csproj index e1f5e32..4e68be5 100644 --- a/src/Tomlyn/Tomlyn.csproj +++ b/src/Tomlyn/Tomlyn.csproj @@ -2,6 +2,7 @@ Tomlyn + netstandard2.0;net6.0;net8.0 diff --git a/src/Tomlyn/Tomlyn.props b/src/Tomlyn/Tomlyn.props index ec129d2..b866f52 100644 --- a/src/Tomlyn/Tomlyn.props +++ b/src/Tomlyn/Tomlyn.props @@ -1,8 +1,8 @@ - netstandard2.0;net7.0 - 10.0 + + latest Tomlyn is a TOML parser, validator and authoring library for .NET. Alexandre Mutel Alexandre Mutel @@ -21,6 +21,12 @@ true true snupkg + + true + + + + @@ -35,6 +41,12 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/global.json b/src/global.json index aaf58f5..2ddda36 100644 --- a/src/global.json +++ b/src/global.json @@ -1,7 +1,7 @@ { - "sdk": { - "version": "7.0.100", - "rollForward": "latestMinor", - "allowPrerelease": false - } + "sdk": { + "version": "8.0.0", + "rollForward": "latestMinor", + "allowPrerelease": false + } } \ No newline at end of file