diff --git a/.github/workflows/verify-generated.yml b/.github/workflows/verify-generated.yml new file mode 100644 index 0000000..5b4f142 --- /dev/null +++ b/.github/workflows/verify-generated.yml @@ -0,0 +1,48 @@ +name: Verify Generated Files + +# Source-generator output under Semantics.Quantities/Generated/ is committed to the +# repo (EmitCompilerGeneratedFiles=true). This job rebuilds and fails if the committed +# files are stale, so a generated file can never drift from its generator. +# +# NOTE: this is a standalone workflow on purpose — dotnet.yml is centrally synced from a +# shared template across ktsu repos, so a step added there would be overwritten. If this +# check belongs in the shared KtsuBuild pipeline long-term, move it there and delete this. + +on: + pull_request: + paths-ignore: ["**.md"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: verify-generated-${{ github.ref }} + cancel-in-progress: true + +jobs: + verify-generated: + name: Generated files up to date + # windows-latest so git's autocrlf matches the committed CRLF line endings and the + # diff doesn't flag end-of-line differences. + runs-on: windows-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "10.0.x" + + - name: Build (regenerates source-generator output into Generated/) + run: dotnet build Semantics.Quantities/Semantics.Quantities.csproj -c Release + + - name: Fail if generated files are stale + shell: bash + run: | + if ! git diff --exit-code -- 'Semantics.Quantities/Generated/'; then + echo "::error::Generated files are out of date. Run 'dotnet build Semantics.Quantities/Semantics.Quantities.csproj' and commit the changes under Semantics.Quantities/Generated/." + exit 1 + fi diff --git a/Semantics.Paths/Semantics.Paths.csproj b/Semantics.Paths/Semantics.Paths.csproj index 426ab04..e498fea 100644 --- a/Semantics.Paths/Semantics.Paths.csproj +++ b/Semantics.Paths/Semantics.Paths.csproj @@ -2,7 +2,7 @@ - net10.0;net9.0;net8.0;net7.0;net6.0;net5.0;netstandard2.0;netstandard2.1 + net10.0;net9.0;net8.0;netstandard2.0;netstandard2.1 $(NoWarn);CA1716;CA2225;IDE0032;CA1866;CA2249;IDE0056;IDE0057 diff --git a/Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.UnitsGenerator/Units.g.cs b/Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.UnitsGenerator/Units.g.cs index 1b1e59a..ea08567 100644 --- a/Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.UnitsGenerator/Units.g.cs +++ b/Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.UnitsGenerator/Units.g.cs @@ -5422,9 +5422,6 @@ public static class Units{ /// Singleton FaradPerMeter instance. public static readonly FaradPerMeter FaradPerMeter = new FaradPerMeter(); - /// Singleton FootPerSecond instance. - public static readonly FootPerSecond FootPerSecond = new FootPerSecond(); - /// Singleton Foot instance. public static readonly Foot Foot = new Foot(); @@ -5434,6 +5431,9 @@ public static class Units{ /// Singleton FootLambert instance. public static readonly FootLambert FootLambert = new FootLambert(); + /// Singleton FootPerSecond instance. + public static readonly FootPerSecond FootPerSecond = new FootPerSecond(); + /// Singleton Gallon instance. public static readonly Gallon Gallon = new Gallon(); diff --git a/Semantics.Quantities/Semantics.Quantities.csproj b/Semantics.Quantities/Semantics.Quantities.csproj index 12e8d9d..0deb3f1 100644 --- a/Semantics.Quantities/Semantics.Quantities.csproj +++ b/Semantics.Quantities/Semantics.Quantities.csproj @@ -2,7 +2,7 @@ - net10.0;net9.0;net8.0;net7.0 + net10.0;net9.0;net8.0 $(NoWarn);CA1716;CA2225;KTSU0003;IDE0032 true Generated diff --git a/Semantics.Strings/Semantics.Strings.csproj b/Semantics.Strings/Semantics.Strings.csproj index 04d2585..4b57fd6 100644 --- a/Semantics.Strings/Semantics.Strings.csproj +++ b/Semantics.Strings/Semantics.Strings.csproj @@ -2,7 +2,7 @@ - net10.0;net9.0;net8.0;net7.0;net6.0;net5.0;netstandard2.0;netstandard2.1 + net10.0;net9.0;net8.0;netstandard2.0;netstandard2.1 $(NoWarn);CA1716;CA1866;CA2249;IDE0057 diff --git a/Semantics.Test/Quantities/VectorQuantityTests.cs b/Semantics.Test/Quantities/VectorQuantityTests.cs index 13499a5..a8d3087 100644 --- a/Semantics.Test/Quantities/VectorQuantityTests.cs +++ b/Semantics.Test/Quantities/VectorQuantityTests.cs @@ -165,13 +165,11 @@ public void Speed_Plus_Speed_Returns_Speed() } // ------------------------------------------------------------- V0 - V0 - // Locked design decision in #52: V0 - V0 should return the same V0 of T.Abs(a - b). - // Generator currently emits unsigned subtraction via the SemanticQuantity base, which - // can produce a negative magnitude. Tracked as a follow-up. + // #52: V0 - V0 returns the same V0 of T.Abs(a - b). The generated derived operator + // wins overload resolution over PhysicalQuantity's plain (signable) subtraction. [TestMethod] - [Ignore("Locked in #52: V0 - V0 should return the same V0 of T.Abs(a - b). Generator currently emits unsigned subtraction.")] - public void Mass_Minus_Mass_Returns_Absolute_Difference_Pending52() + public void Mass_Minus_Mass_Returns_Absolute_Difference() { Mass a = Mass.FromKilogram(3.0); Mass b = Mass.FromKilogram(5.0); @@ -180,20 +178,18 @@ public void Mass_Minus_Mass_Returns_Absolute_Difference_Pending52() } // ---------------------------------------------------- V0 non-negativity - // Tracked in #50: factories on Vector0 quantities should reject negative inputs - // with ArgumentException. The current generator does not emit guards. + // #50: factories on Vector0 quantities reject negative inputs with ArgumentException + // via Vector0Guards.EnsureNonNegative (the guard runs after unit conversion). [TestMethod] - [Ignore("Tracked in #50: V0 factories should reject negative inputs.")] - public void Speed_From_Negative_Throws_Pending50() + public void Speed_From_Negative_Throws() { _ = Assert.ThrowsExactly( () => Speed.FromMeterPerSecond(-1.0)); } [TestMethod] - [Ignore("Tracked in #50: V0 factories should reject negative inputs.")] - public void Mass_From_Negative_Throws_Pending50() + public void Mass_From_Negative_Throws() { _ = Assert.ThrowsExactly( () => Mass.FromKilogram(-1.0)); diff --git a/docs/migration-guide-2.0.md b/docs/migration-guide-2.0.md index 0ebdd8d..7e2dfad 100644 --- a/docs/migration-guide-2.0.md +++ b/docs/migration-guide-2.0.md @@ -214,6 +214,10 @@ different dimensions throws `ArgumentException`; equality across dimensions is | audio-engineering `Percent` | the `Percent` **unit** on the Dimensionless dimension: `Ratio.FromPercent(50)` and `ratio.In(Units.Percent)` | | audio-engineering `Gain` record struct | `Gain` is now a generated semantic overload of `Ratio` (a record class, non-negative, widens implicitly to `Ratio`); `Unity`, `Silence`, the `Decibels` conversions, and `*` live in a partial | +## Target frameworks + +The out-of-support runtimes `net5.0`, `net6.0`, and `net7.0` were dropped — `System.Text.Json` 10 (and friends) no longer ship assets for them. `ktsu.Semantics.Quantities` now targets `net8.0`–`net10.0` (it requires `INumber`, so it has no `netstandard` target). `Semantics.Strings` and `Semantics.Paths` target `net8.0`–`net10.0` plus `netstandard2.0`/`netstandard2.1`, so consumers on older runtimes still resolve via `netstandard`. + ## What didn't change - `Semantics.Strings` and `Semantics.Paths` — same namespaces, same types; @@ -224,7 +228,6 @@ different dimensions throws `ArgumentException`; equality across dimensions is through the generated `Ratio`, and (for the logarithmic ones) are generated from `logarithmic.json`. `Percent` became a unit and `Gain` a generated `Ratio` overload — see the removed-APIs table. -- Target frameworks: `net7.0` through `net10.0`. - Quantities remain generic over the numeric storage type (`where T : struct, INumber`). - `UnitSystem` and `UnitConversionException` keep their names and meaning.