diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cfbb4da9..36938403 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -197,13 +197,10 @@ jobs: steps: # No checkout here, so no global.json to read: this job only pushes the verified packages # and any SDK of the line can do that. Bump it with global.json when the line moves. - # `dotnet-quality: preview` is there only because 11.0.x has no GA build yet for setup-dotnet to - # resolve. Drop it at .NET 11 GA, in the change that moves global.json to the GA SDK. - name: Setup .NET uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: 11.0.x - dotnet-quality: preview # Publishes exactly what was verified — the packages are not rebuilt here. - name: Download packages diff --git a/CHANGELOG.md b/CHANGELOG.md index 2581d599..1a750aa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ The first preview of the 11 line: the same public API as 10.0.0, on .NET 11. Not ### Breaking -- All four packages target `net11.0` and need the .NET 11 runtime, one target framework per line; the EF Core packages reference EF Core 11 and `Npgsql.EntityFrameworkCore.PostgreSQL` 11 (release candidates while .NET 11 is in preview). PostgreSQL 16 or later, as in 10.x. +- All four packages target `net11.0` and need the .NET 11 runtime, one target framework per line; the EF Core packages reference EF Core 11 and `Npgsql.EntityFrameworkCore.PostgreSQL` 11 (`11.0.0-rc.3`, which pins EF Core to rc.3, until Npgsql ships 11.0.0). PostgreSQL 16 or later, as in 10.x. - Ranges: `RangeAgg()` and `RangeIntersectAgg()` skip a `null` range or set, as `range_agg` and `range_intersect_agg` skip a NULL row. With a `null` after another range, `RangeIntersectAgg()` returned `empty`, or threw after `(,)`, and `RangeAgg()` threw unless an input was `(,)` ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-rangeagg-and-rangeintersectagg-over-null-ranges)). - Ranges: `RangeSet.From`, a collection expression and `RangeSet.Create` throw `ArgumentException` for a `null` range, where they built a set holding `null`, whose `IsEmpty()` was `false`. `Union` and `Except` called on a `null` range throw too ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#keep-null-out-of-a-range-set)). - Ranges: a predicate called on a `null` range, or given a `null` range or set, returns `false`, as a query does over a NULL column. `Contains(Empty)`, `IsContainedBy((,))` and `(,).Contains(null)` returned `true`, and `Contains(T)` and a `null` set operand threw ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-predicates-over-a-null-range-or-a-null-column)). diff --git a/docs/efcore.md b/docs/efcore.md index 5e2e18fc..4807b68b 100644 --- a/docs/efcore.md +++ b/docs/efcore.md @@ -384,7 +384,7 @@ Good to know: - **Migrations and `EnsureCreated()` both create the key.** It is part of EF Core's own model, so no extra registration is needed. -Everything in this section was run against PostgreSQL 18 with Npgsql 11.0.0-rc.2, over a `DateRange`, +Everything in this section was run against PostgreSQL 18 with Npgsql 11.0.0-rc.3, over a `DateRange`, a `RangeSet`, a `TimeRange` and a `YearMonthRange` column for the key, and a `DateRange` column for the foreign key. diff --git a/global.json b/global.json index 9eb43a98..e26c590b 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "11.0.100-rc.2.26504.105", + "version": "11.0.100", "rollForward": "latestFeature" } } diff --git a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CHANGELOG.md b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CHANGELOG.md index e98a8985..b776b54b 100644 --- a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CHANGELOG.md +++ b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CHANGELOG.md @@ -9,7 +9,7 @@ The first preview of the 11 line: the same public API as 10.0.0, on .NET 11, EF ### Breaking -- Targets `net11.0` and references `Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime` 11 (a release candidate while .NET 11 is in preview). PostgreSQL 16 or later, as in 10.x. +- Targets `net11.0` and references `Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime` 11 (`11.0.0-rc.3` until Npgsql ships 11.0.0). PostgreSQL 16 or later, as in 10.x. - EF Core: `LowerBound()` and `UpperBound()` of a NodaTime range or multirange column, `YearMonthRange` included, are `NULL` in a query for an empty value and on an unbounded side, as in memory. So `== null` selects those rows, where it selected none on a required column, and `?? fallback` returns the fallback, where the row was missing ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-bound-comparisons-with-null-in-queries)). - EF Core: a range, multirange or value set predicate over a NULL column is `false`, so its negation keeps the row, as EF Core does for `string` and `string[]`. `!b.Period.Overlaps(p)` dropped the NULL rows, and a projected predicate threw ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-predicates-over-a-null-range-or-a-null-column)). - EF Core: `Contains(T)` on a range or multirange is `false` in a query when the element is NULL: a column of a missing child in an outer join, or a nullable column read with `.Value`. Its negation dropped the row, and a projection threw ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-predicates-over-a-null-range-or-a-null-column)). diff --git a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.csproj b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.csproj index e70774dc..7152ab86 100644 --- a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.csproj +++ b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.csproj @@ -24,7 +24,7 @@ The full range algebra translates from LINQ to SQL exactly as for the BCL-based - + diff --git a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CHANGELOG.md b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CHANGELOG.md index 53a7551d..922afdce 100644 --- a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CHANGELOG.md +++ b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CHANGELOG.md @@ -9,7 +9,7 @@ The first preview of the 11 line: the same public API as 10.0.0, on .NET 11, EF ### Breaking -- Targets `net11.0` and references EF Core 11 and `Npgsql.EntityFrameworkCore.PostgreSQL` 11 (release candidates while .NET 11 is in preview). PostgreSQL 16 or later, as in 10.x. +- Targets `net11.0` and references EF Core 11 and `Npgsql.EntityFrameworkCore.PostgreSQL` 11 (`11.0.0-rc.3`, which pins EF Core to rc.3, until Npgsql ships 11.0.0). PostgreSQL 16 or later, as in 10.x. - EF Core: `EFCore.ComplexIndexes.PostgreSQL` 5.x stays on EF Core 10 and can't be installed beside the 11 packages. Its EF Core 11 successor, `CodoMetis.EFCore.SchemaKit.PostgreSQL`, isn't on NuGet yet ([CaffeinatedCoder/EFCore.ComplexIndexes#38](https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/issues/38)). For exclusion constraints until then, stay on 10.x or add the constraint with explicit SQL. Temporal keys are Npgsql's own on EF Core 11 ([Exclusion constraints](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/efcore.md#reject-overlapping-rows-with-an-exclusion-constraint)). - EF Core: `LowerBound()` and `UpperBound()` in a query are `NULL` for an empty range or set and on an unbounded side, as in memory. So `== null` selects those rows, where it selected none on a required column, and `?? fallback` returns the fallback, where the row was missing ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-bound-comparisons-with-null-in-queries)). - EF Core: a range, multirange or value set predicate over a NULL column is `false`, so its negation keeps the row, as EF Core does for `string` and `string[]`. `!b.Period.Overlaps(p)` dropped the NULL rows, and a projected predicate threw ([Migration](https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/main/docs/migration.md#check-predicates-over-a-null-range-or-a-null-column)). diff --git a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CodoMetis.ValueRanges.EFCore.PostgreSQL.csproj b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CodoMetis.ValueRanges.EFCore.PostgreSQL.csproj index a8e8eb3c..b92789a7 100644 --- a/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CodoMetis.ValueRanges.EFCore.PostgreSQL.csproj +++ b/src/CodoMetis.ValueRanges.EFCore.PostgreSQL/CodoMetis.ValueRanges.EFCore.PostgreSQL.csproj @@ -30,7 +30,7 @@ v6 also maps the value set types to native PostgreSQL arrays (StringSet to text[ - + diff --git a/src/CodoMetis.ValueRanges/Core/IValueSetFactory.cs b/src/CodoMetis.ValueRanges/Core/IValueSetFactory.cs index de046d0e..b819ab2f 100644 --- a/src/CodoMetis.ValueRanges/Core/IValueSetFactory.cs +++ b/src/CodoMetis.ValueRanges/Core/IValueSetFactory.cs @@ -138,7 +138,8 @@ static bool ISpanParsable.TryParse(ReadOnlySpan s, IFormatProvider? // NoInlining: ILCompiler 11 inlines this default into the instantiating thunk of the shared-generic // interface, where the receiver is typed as the thunk's module type, so the cast of `this` fails and // the thunk is compiled to a trap (SIGTRAP, exit 133) in a net11.0 Native AOT consumer — measured on - // 11.0.100-rc.2.26504.105 (#291, #299, #315, dotnet/runtime#136073). Every set family also overrides + // 11.0.100-rc.2.26504.105, and again on 11.0.100: the fix is in dotnet/runtime's main, and its backport + // (dotnet/runtime#136148) is not in 11.0.0 (#291, #299, #315, #532, dotnet/runtime#136073). Every set family also overrides // IFormattable.ToString itself, which is what keeps the trap out of a compiled consumer today; the // attribute keeps a family that forgets the override from trapping. The range default (IRangeFactory) did not trap in // the same publish, which prints range text through it, so it is left alone. diff --git a/test/CodoMetis.ValueRanges.AspNetCore.Tests/CodoMetis.ValueRanges.AspNetCore.Tests.csproj b/test/CodoMetis.ValueRanges.AspNetCore.Tests/CodoMetis.ValueRanges.AspNetCore.Tests.csproj index 08fbc3e1..2c293d68 100644 --- a/test/CodoMetis.ValueRanges.AspNetCore.Tests/CodoMetis.ValueRanges.AspNetCore.Tests.csproj +++ b/test/CodoMetis.ValueRanges.AspNetCore.Tests/CodoMetis.ValueRanges.AspNetCore.Tests.csproj @@ -13,9 +13,9 @@ - - - + + + diff --git a/test/CodoMetis.ValueRanges.Conventions.Tests/CodoMetis.ValueRanges.Conventions.Tests.csproj b/test/CodoMetis.ValueRanges.Conventions.Tests/CodoMetis.ValueRanges.Conventions.Tests.csproj index e33bdb2b..bc400f85 100644 --- a/test/CodoMetis.ValueRanges.Conventions.Tests/CodoMetis.ValueRanges.Conventions.Tests.csproj +++ b/test/CodoMetis.ValueRanges.Conventions.Tests/CodoMetis.ValueRanges.Conventions.Tests.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests.csproj b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests.csproj index d02d4254..88ff4fc3 100644 --- a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests.csproj +++ b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.InfinityDisabled.IntegrationTests.csproj @@ -20,7 +20,7 @@ - + diff --git a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests.csproj b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests.csproj index cf46bb80..f6541919 100644 --- a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests.csproj +++ b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests.csproj @@ -9,7 +9,7 @@ - + - + @@ -82,7 +82,7 @@ --> - + diff --git a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests.csproj b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests.csproj index a426f8cb..84ef8379 100644 --- a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests.csproj +++ b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests.csproj b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests.csproj index 0457380f..9a19a31d 100644 --- a/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests.csproj +++ b/test/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests.csproj @@ -9,12 +9,12 @@ - + - + diff --git a/test/CodoMetis.ValueRanges.NodaTime.Tests/CodoMetis.ValueRanges.NodaTime.Tests.csproj b/test/CodoMetis.ValueRanges.NodaTime.Tests/CodoMetis.ValueRanges.NodaTime.Tests.csproj index d64b5e8a..913c798f 100644 --- a/test/CodoMetis.ValueRanges.NodaTime.Tests/CodoMetis.ValueRanges.NodaTime.Tests.csproj +++ b/test/CodoMetis.ValueRanges.NodaTime.Tests/CodoMetis.ValueRanges.NodaTime.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/CodoMetis.ValueRanges.Tests/CodoMetis.ValueRanges.Tests.csproj b/test/CodoMetis.ValueRanges.Tests/CodoMetis.ValueRanges.Tests.csproj index 4dc71a0d..10e6f653 100644 --- a/test/CodoMetis.ValueRanges.Tests/CodoMetis.ValueRanges.Tests.csproj +++ b/test/CodoMetis.ValueRanges.Tests/CodoMetis.ValueRanges.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/CodoMetis.ValueRanges.Tests/ParserResilienceTests.cs b/test/CodoMetis.ValueRanges.Tests/ParserResilienceTests.cs index 8a704818..9eb80df0 100644 --- a/test/CodoMetis.ValueRanges.Tests/ParserResilienceTests.cs +++ b/test/CodoMetis.ValueRanges.Tests/ParserResilienceTests.cs @@ -23,40 +23,52 @@ public sealed class ParserResilienceTests // Each entry: a name, and the hostile text. Rejection is expected for most; a few are valid and // must simply not be slow (whitespace flood, huge but well-formed sets). - public static IEnumerable HostileRangeLiterals() => - [ - ["digit run of a million characters", $"[{new string('1', Size)},2]"], - ["a million opening brackets", new string('[', Size)], - ["a million characters of garbage bound", $"[{new string('x', Size)},1]"], - ["a million characters of whitespace", $"{new string(' ', Size)}[1,2]"], - ["a million quotes inside the bound", $"[\"{new string('"', Size)},2]"], - ["a million backslashes inside quotes", $"[\"{new string('\\', Size)}\",2]"], - ["a million commas", $"[{new string(',', Size)}]"], - ]; - - public static IEnumerable HostileSetLiterals() => - [ - ["two hundred thousand ranges", "{" + string.Join(",", Enumerable.Range(0, 200_000).Select(i => $"[{i * 2},{i * 2 + 1}]")) + "}"], - ["two hundred thousand identical ranges", "{" + string.Join(",", Enumerable.Repeat("[1,10]", 200_000)) + "}"], - ["a million nested brackets", "{" + new string('[', Size) + "}"], - ["a million characters, never closed", "{" + new string('[', Size)], - ]; - - public static IEnumerable HostileArrayLiterals() => - [ - ["two hundred thousand elements", "{" + string.Join(",", Enumerable.Range(0, 200_000).Select(i => $"e{i}")) + "}"], - ["a million escaped quotes in one element", "{\"" + string.Concat(Enumerable.Repeat("\\\"", Size / 2)) + "\"}"], - ["an unterminated quoted element", "{\"" + new string('a', Size)], - ["an unterminated escape", "{\"" + new string('a', Size) + "\\"], - ["a million commas", "{" + new string(',', Size) + "}"], - ["one element of a million characters", "{" + new string('a', Size) + "}"], - ]; + // + // A row carries only the name, and the test builds its text from it. A row's arguments travel in + // every message the test host sends about that row, so with the text as an argument one results + // message was 20 MB, and vstest.console in SDK 11.0.100 did not get through it in ten minutes: `dotnet test` + // ran at full CPU after the last test had passed (#535). SDK 11.0.100-rc.2 read it in seconds. + private static readonly Dictionary> RangeLiterals = new() + { + ["digit run of a million characters"] = () => $"[{new string('1', Size)},2]", + ["a million opening brackets"] = () => new string('[', Size), + ["a million characters of garbage bound"] = () => $"[{new string('x', Size)},1]", + ["a million characters of whitespace"] = () => $"{new string(' ', Size)}[1,2]", + ["a million quotes inside the bound"] = () => $"[\"{new string('"', Size)},2]", + ["a million backslashes inside quotes"] = () => $"[\"{new string('\\', Size)}\",2]", + ["a million commas"] = () => $"[{new string(',', Size)}]", + }; + + public static IEnumerable HostileRangeLiterals() => RangeLiterals.Keys.Select(name => new object[] { name }); + + private static readonly Dictionary> SetLiterals = new() + { + ["two hundred thousand ranges"] = () => "{" + string.Join(",", Enumerable.Range(0, 200_000).Select(i => $"[{i * 2},{i * 2 + 1}]")) + "}", + ["two hundred thousand identical ranges"] = () => "{" + string.Join(",", Enumerable.Repeat("[1,10]", 200_000)) + "}", + ["a million nested brackets"] = () => "{" + new string('[', Size) + "}", + ["a million characters, never closed"] = () => "{" + new string('[', Size), + }; + + public static IEnumerable HostileSetLiterals() => SetLiterals.Keys.Select(name => new object[] { name }); + + private static readonly Dictionary> ArrayLiterals = new() + { + ["two hundred thousand elements"] = () => "{" + string.Join(",", Enumerable.Range(0, 200_000).Select(i => $"e{i}")) + "}", + ["a million escaped quotes in one element"] = () => "{\"" + string.Concat(Enumerable.Repeat("\\\"", Size / 2)) + "\"}", + ["an unterminated quoted element"] = () => "{\"" + new string('a', Size), + ["an unterminated escape"] = () => "{\"" + new string('a', Size) + "\\", + ["a million commas"] = () => "{" + new string(',', Size) + "}", + ["one element of a million characters"] = () => "{" + new string('a', Size) + "}", + }; + + public static IEnumerable HostileArrayLiterals() => ArrayLiterals.Keys.Select(name => new object[] { name }); // ---- bounded time, documented failure modes ------------------------------------------------ [TestMethod, DynamicData(nameof(HostileRangeLiterals)), Timeout(10_000)] - public void RangeParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name, string input) + public void RangeParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name) { + var input = RangeLiterals[name](); AssertRejectedOrParsed(() => Int32Range.Parse(input, null)); AssertRejectedOrParsed(() => DecimalRange.Parse(input, null)); AssertRejectedOrParsed(() => DateTimeRange.Parse(input, null)); @@ -65,15 +77,17 @@ public void RangeParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string nam } [TestMethod, DynamicData(nameof(HostileSetLiterals)), Timeout(10_000)] - public void RangeSetParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name, string input) + public void RangeSetParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name) { + var input = SetLiterals[name](); AssertRejectedOrParsed(() => RangeSet.Parse(input, null)); Assert.IsFalse(Throws(() => RangeSet.TryParse(input, null, out _)), "RangeSet.TryParse threw on hostile input."); } [TestMethod, DynamicData(nameof(HostileArrayLiterals)), Timeout(10_000)] - public void SetParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name, string input) + public void SetParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name) { + var input = ArrayLiterals[name](); AssertRejectedOrParsed(() => StringSet.Parse(input, null)); AssertRejectedOrParsed(() => Int32Set.Parse(input, null)); Assert.IsFalse(Throws(() => StringSet.TryParse(input, null, out _)), "StringSet.TryParse threw on hostile input."); @@ -81,8 +95,9 @@ public void SetParse_HostileInput_IsAcceptedOrRejectedInBoundedTime(string name, } [TestMethod, DynamicData(nameof(HostileRangeLiterals)), Timeout(10_000)] - public void JsonRead_HostileRangeString_IsAcceptedOrRejectedInBoundedTime(string name, string input) + public void JsonRead_HostileRangeString_IsAcceptedOrRejectedInBoundedTime(string name) { + var input = RangeLiterals[name](); var payload = JsonSerializer.Serialize(input); AssertRejectedOrParsed(() => JsonSerializer.Deserialize(payload, Json), typeof(JsonException)); AssertRejectedOrParsed(() => JsonSerializer.Deserialize>(payload, Json), typeof(JsonException));