From c9bcef19632745bcbb77f0961b6a4322015d5b6a Mon Sep 17 00:00:00 2001 From: nkosi23 Date: Wed, 11 Dec 2024 17:19:35 +0100 Subject: [PATCH] Made the test suite great again. Improved separation between F# test cases and C# test cases to avoid breaking other tests due to differences with the serializer used (newtonsoft has limited support for discriminated unions). --- .../Acceptance/Support/DefaultQueryFixture.cs | 18 +++-------- .../Acceptance/Support/LinqTestContext.cs | 16 ++++++++-- .../Acceptance/Support/TargetSchemaFixture.cs | 17 +++++++++-- .../Acceptance/where_clauses_fsharp.cs | 4 +-- src/LinqTests/Operators/is_one_of_operator.cs | 8 ++--- src/Marten.Testing/Documents/Target.cs | 30 ++++++++++++------- 6 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/LinqTests/Acceptance/Support/DefaultQueryFixture.cs b/src/LinqTests/Acceptance/Support/DefaultQueryFixture.cs index 8c07a9eb6f..873e926025 100644 --- a/src/LinqTests/Acceptance/Support/DefaultQueryFixture.cs +++ b/src/LinqTests/Acceptance/Support/DefaultQueryFixture.cs @@ -25,14 +25,14 @@ public DefaultQueryFixture() .Duplicate(x => x.NumberArray); }); - FSharpFriendlyStore = ProvisionStore("linq_querying", options => + FSharpFriendlyStore = ProvisionStore("fsharp_linq_querying", options => { options.RegisterFSharpOptionValueTypes(); var serializerOptions = JsonFSharpOptions.Default().WithUnwrapOption().ToJsonSerializerOptions(); options.UseSystemTextJsonForSerialization(serializerOptions); - }); + }, isFsharpTest: true); - FSharpFriendlyStoreWithDuplicatedField = ProvisionStore("duplicate_fields", options => + FSharpFriendlyStoreWithDuplicatedField = ProvisionStore("fsharp_duplicated_fields", options => { options.Schema.For() .Duplicate(x => x.Number) @@ -47,7 +47,7 @@ public DefaultQueryFixture() options.RegisterFSharpOptionValueTypes(); var serializerOptions = JsonFSharpOptions.Default().WithUnwrapOption().ToJsonSerializerOptions(); options.UseSystemTextJsonForSerialization(serializerOptions); - }); + }, isFsharpTest: true); SystemTextJsonStore = ProvisionStore("stj_linq", o => { @@ -65,13 +65,3 @@ public DefaultQueryFixture() public DocumentStore Store { get; set; } } -public static class DefaultQueryFixtureExtensions -{ - public static void UseFSharp(this DocumentStore store) - { - var o = store.Options; - o.RegisterFSharpOptionValueTypes(); - var serializerOptions = JsonFSharpOptions.Default().WithUnwrapOption().ToJsonSerializerOptions(); - o.UseSystemTextJsonForSerialization(serializerOptions); - } -} diff --git a/src/LinqTests/Acceptance/Support/LinqTestContext.cs b/src/LinqTests/Acceptance/Support/LinqTestContext.cs index 1c5d80a8de..e4fcef9afd 100644 --- a/src/LinqTests/Acceptance/Support/LinqTestContext.cs +++ b/src/LinqTests/Acceptance/Support/LinqTestContext.cs @@ -103,17 +103,27 @@ public static IEnumerable GetDescriptions() return _descriptions.Select(x => new object[] { x }); } - protected async Task assertTestCase(string description, IDocumentStore store) + protected async Task assertTestCaseWithDocuments(string description, IDocumentStore store, Target[] documents) { var index = _descriptions.IndexOf(description); var testCase = testCases[index]; await using var session = store.QuerySession(); - var logger = new TestOutputMartenLogger(TestOutput); + session.Logger = logger; - await testCase.Compare(session, Fixture.Documents, logger); + await testCase.Compare(session, documents, logger); + } + + protected Task assertTestCase(string description, IDocumentStore store) + { + return assertTestCaseWithDocuments(description, store, Fixture.Documents); + } + + protected Task assertFSharpTestCase(string description, IDocumentStore store) + { + return assertTestCaseWithDocuments(description, store, Fixture.FSharpDocuments); } } diff --git a/src/LinqTests/Acceptance/Support/TargetSchemaFixture.cs b/src/LinqTests/Acceptance/Support/TargetSchemaFixture.cs index 8248c38575..b0c83b1086 100644 --- a/src/LinqTests/Acceptance/Support/TargetSchemaFixture.cs +++ b/src/LinqTests/Acceptance/Support/TargetSchemaFixture.cs @@ -9,7 +9,12 @@ namespace LinqTests.Acceptance.Support; public abstract class TargetSchemaFixture: IDisposable { + /* + * Newtonsoft.Json does not support saving Discriminated Unions unwrapped (included f# options) which causes serialization-related errors. + * We must therefore only include F# data in F#-related tests to avoid false negatives. + */ public readonly Target[] Documents = Target.GenerateRandomData(1000).ToArray(); + public readonly Target[] FSharpDocuments = Target.GenerateRandomData(1000, includeFSharpUnionTypes: true).ToArray(); private readonly IList _stores = new List(); @@ -21,7 +26,7 @@ public void Dispose() } } - internal DocumentStore ProvisionStore(string schema, Action configure = null) + internal DocumentStore ProvisionStore(string schema, Action configure = null, bool isFsharpTest = false) { var store = DocumentStore.For(x => { @@ -33,7 +38,15 @@ internal DocumentStore ProvisionStore(string schema, Action config store.Advanced.Clean.CompletelyRemoveAll(); - store.BulkInsert(Documents); + + if (isFsharpTest) + { + store.BulkInsert(FSharpDocuments); + } + else + { + store.BulkInsert(Documents); + } _stores.Add(store); diff --git a/src/LinqTests/Acceptance/where_clauses_fsharp.cs b/src/LinqTests/Acceptance/where_clauses_fsharp.cs index 00f8b73d6b..9498390f97 100644 --- a/src/LinqTests/Acceptance/where_clauses_fsharp.cs +++ b/src/LinqTests/Acceptance/where_clauses_fsharp.cs @@ -36,13 +36,13 @@ static where_clauses_fsharp() [MemberData(nameof(GetDescriptions))] public Task run_query(string description) { - return assertTestCase(description, Fixture.FSharpFriendlyStore); + return assertFSharpTestCase(description, Fixture.FSharpFriendlyStore); } [Theory] [MemberData(nameof(GetDescriptions))] public Task with_duplicated_fields(string description) { - return assertTestCase(description, Fixture.FSharpFriendlyStoreWithDuplicatedField); + return assertFSharpTestCase(description, Fixture.FSharpFriendlyStoreWithDuplicatedField); } } diff --git a/src/LinqTests/Operators/is_one_of_operator.cs b/src/LinqTests/Operators/is_one_of_operator.cs index 81f0e7dec2..7e113e865b 100644 --- a/src/LinqTests/Operators/is_one_of_operator.cs +++ b/src/LinqTests/Operators/is_one_of_operator.cs @@ -156,7 +156,7 @@ public void can_query_against_fsharp_guid_option_array_with_unwrapped_guid(Func< private void can_query_against_array(Func>> isOneOf, Func select) { - var targets = Target.GenerateRandomData(100).ToArray(); + var targets = Target.GenerateRandomData(100, true).ToArray(); theStore.BulkInsert(targets); var validValues = targets.Select(select).Distinct().Take(3).ToArray(); @@ -201,7 +201,7 @@ private void can_query_against_array_with_not_operator( Func select ) { - var targets = Target.GenerateRandomData(100).ToArray(); + var targets = Target.GenerateRandomData(100, true).ToArray(); theStore.BulkInsert(targets); var validValues = targets.Select(select).Distinct().Take(3).ToArray(); @@ -240,7 +240,7 @@ public void can_query_against_fsharp_guid_option_list(Func(Func, Expression>> isOneOf, Func select) { - var targets = Target.GenerateRandomData(100).ToArray(); + var targets = Target.GenerateRandomData(100, true).ToArray(); theStore.BulkInsert(targets); var validValues = targets.Select(select).Distinct().Take(3).ToList(); @@ -288,7 +288,7 @@ private void can_query_against_list_with_not_operator( Func select ) { - var targets = Target.GenerateRandomData(100).ToArray(); + var targets = Target.GenerateRandomData(100, true).ToArray(); theStore.BulkInsert(targets); var validValues = targets.Select(select).Distinct().Take(3).ToList(); diff --git a/src/Marten.Testing/Documents/Target.cs b/src/Marten.Testing/Documents/Target.cs index 5c7fc54ded..1c9dd017ac 100644 --- a/src/Marten.Testing/Documents/Target.cs +++ b/src/Marten.Testing/Documents/Target.cs @@ -32,28 +32,32 @@ public class Target "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" }; - public static IEnumerable GenerateRandomData(int number) + public static IEnumerable GenerateRandomData(int number, bool includeFSharpUnionTypes = false) { var i = 0; while (i < number) { - yield return Random(true); + yield return Random(true, includeFSharpUnionTypes); i++; } } - public static Target Random(bool deep = false) + public static Target Random(bool deep = false, bool includeFSharpUnionTypes = false) { var target = new Target(); target.String = _strings[_random.Next(0, 10)]; - target.FSharpGuidOption = new FSharpOption(Guid.NewGuid()); - target.FSharpIntOption = new FSharpOption(_random.Next(0, 10)); - target.FSharpDateOption = new FSharpOption(DateTime.Now); - target.FSharpDateTimeOffsetOption = new FSharpOption(new DateTimeOffset(DateTime.UtcNow)); - target.FSharpDecimalOption = new FSharpOption(_random.Next(0, 10)); - target.FSharpLongOption = new FSharpOption(_random.Next(0, 10)); - target.FSharpStringOption = new FSharpOption(_strings[_random.Next(0, 10)]); + + if (includeFSharpUnionTypes) + { + target.FSharpGuidOption = new FSharpOption(Guid.NewGuid()); + target.FSharpIntOption = new FSharpOption(_random.Next(0, 10)); + target.FSharpDateOption = new FSharpOption(DateTime.Now); + target.FSharpDateTimeOffsetOption = new FSharpOption(new DateTimeOffset(DateTime.UtcNow)); + target.FSharpDecimalOption = new FSharpOption(_random.Next(0, 10)); + target.FSharpLongOption = new FSharpOption(_random.Next(0, 10)); + target.FSharpStringOption = new FSharpOption(_strings[_random.Next(0, 10)]); + } target.PaddedString = " " + target.String + " "; target.AnotherString = _otherStrings[_random.Next(0, 10)]; @@ -107,6 +111,7 @@ public static Target Random(bool deep = false) target.HowLong = TimeSpan.FromSeconds(target.Long); target.Date = DateTime.Today.AddDays(_random.Next(-10000, 10000)); + target.DateOffset = new DateTimeOffset(DateTime.Today.AddDays(_random.Next(-10000, 10000))); if (value > 15) { @@ -213,6 +218,11 @@ public Target() public TimeSpan HowLong { get; set; } } +public class FSharpTarget: Target +{ + +} + public class Address { public Address()