diff --git a/src/AD.FsCheck.MSTest.FsTests/AD.FsCheck.MSTest.FsTests.fsproj b/src/AD.FsCheck.MSTest.FsTests/AD.FsCheck.MSTest.FsTests.fsproj index 437a85c..b967ac8 100644 --- a/src/AD.FsCheck.MSTest.FsTests/AD.FsCheck.MSTest.FsTests.fsproj +++ b/src/AD.FsCheck.MSTest.FsTests/AD.FsCheck.MSTest.FsTests.fsproj @@ -13,8 +13,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/AD.FsCheck.MSTest.FsTests/VectorTest.fs b/src/AD.FsCheck.MSTest.FsTests/VectorTest.fs index 3952b0d..3ffeb4d 100644 --- a/src/AD.FsCheck.MSTest.FsTests/VectorTest.fs +++ b/src/AD.FsCheck.MSTest.FsTests/VectorTest.fs @@ -12,7 +12,7 @@ with static member (+) (a, b) = { X = a.X + b.X; Y = a.Y + b.Y } module Vector = let plusIdentity = { X = 0; Y = 0} -[] +[] type VectorTest () = [] @@ -39,7 +39,7 @@ type VectorSerializationTest () = return vector } - [] + [] member _.```Serialize and deserialize`` expected : Task = task { let! data = expected |> serialize let! actual = data |> deserialize diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/AD.FsCheck.MSTest.Tests.Arbitraries.csproj b/src/AD.FsCheck.MSTest.Tests.Arbitraries/AD.FsCheck.MSTest.Tests.Arbitraries.csproj index b1bd4ca..d7f0490 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/AD.FsCheck.MSTest.Tests.Arbitraries.csproj +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/AD.FsCheck.MSTest.Tests.Arbitraries.csproj @@ -1,4 +1,4 @@ - + false @@ -11,8 +11,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs index fba3394..89df08c 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs @@ -1,15 +1,8 @@ namespace AD.FsCheck.MSTest.Tests.Arbitraries; -[TestClass] -public sealed class Arbitraries +public static class Arbitraries { - public static Arbitrary From100To200Arbitrary() => Arb.From( + public static Arbitrary From100To200(Arbitrary intArb) => Arb.From( Gen.Choose(100, 200).Select(value => new From100To200(value)), - from100To200 => Arb.Shrink(from100To200.Value).Where(value => value >= 100 && value <= 200).Select(value => new From100To200(value))); - - [AssemblyInitialize] - public static void Initialize(TestContext _) - { - Arb.Register(); - } -} \ No newline at end of file + from100To200 => intArb.Shrinker(from100To200.Value).Where(value => value >= 100 && value <= 200).Select(value => new From100To200(value))); +} diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs index 6bff8c8..5eb4a31 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs @@ -3,7 +3,7 @@ [TestClass] public sealed class From100To200Tests { - [Property] + [Property(Arbitrary = [typeof(Arbitraries)])] public void IsInRange(From100To200 x) { Assert.IsTrue(x.Value >= 100); diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/_usings.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/_usings.cs index a753791..81ece07 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/_usings.cs +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/_usings.cs @@ -1 +1,2 @@ global using FsCheck; +global using FsCheck.Fluent; diff --git a/src/AD.FsCheck.MSTest.Tests/AD.FsCheck.MSTest.Tests.csproj b/src/AD.FsCheck.MSTest.Tests/AD.FsCheck.MSTest.Tests.csproj index f9f5d0b..96b48d3 100644 --- a/src/AD.FsCheck.MSTest.Tests/AD.FsCheck.MSTest.Tests.csproj +++ b/src/AD.FsCheck.MSTest.Tests/AD.FsCheck.MSTest.Tests.csproj @@ -7,8 +7,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxNbOfTest.cs b/src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxTest.cs similarity index 50% rename from src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxNbOfTest.cs rename to src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxTest.cs index 263972d..65e131d 100644 --- a/src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxNbOfTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/ClassAndMethodMaxTest.cs @@ -2,13 +2,13 @@ #pragma warning disable IDE0060 // Remove unused parameter -[Properties(MaxNbOfTest = ClassMaxNbOfTest)] -public sealed class ClassAndMethodMaxNbOfTest : CommandLineTest +[Properties(MaxTest = ClassMaxTest)] +public sealed class ClassAndMethodMaxTest : CommandLineTest { - const int ClassMaxNbOfTest = 20; - const int MethodMaxNbOfTest = 30; + const int ClassMaxTest = 20; + const int MethodMaxTest = 30; - public ClassAndMethodMaxNbOfTest() : base(nameof(ClassAndMethodMaxNbOfTest)) + public ClassAndMethodMaxTest() : base(nameof(ClassAndMethodMaxTest)) { } [CommandLineProperty] @@ -16,14 +16,14 @@ public void Class_is_inherited(int a) { } [TestMethod] - public async Task Class_is_inherited_test() => AreEqual(ClassMaxNbOfTest, await AssertSuccess(nameof(Class_is_inherited))); + public async Task Class_is_inherited_test() => AreEqual(ClassMaxTest, await AssertSuccess(nameof(Class_is_inherited))); - [CommandLineProperty(MaxNbOfTest = MethodMaxNbOfTest)] + [CommandLineProperty(MaxTest = MethodMaxTest)] public void Method_overrides_class(int a) { } [TestMethod] - public async Task Method_overrides_class_test() => AreEqual(MethodMaxNbOfTest, await AssertSuccess(nameof(Method_overrides_class))); + public async Task Method_overrides_class_test() => AreEqual(MethodMaxTest, await AssertSuccess(nameof(Method_overrides_class))); } #pragma warning restore IDE0060 // Remove unused parameter diff --git a/src/AD.FsCheck.MSTest.Tests/ClassMaxNbOfTest.cs b/src/AD.FsCheck.MSTest.Tests/ClassMaxNbOfTest.cs deleted file mode 100644 index 56b06a1..0000000 --- a/src/AD.FsCheck.MSTest.Tests/ClassMaxNbOfTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace AD.FsCheck.MSTest.Tests; - -#pragma warning disable IDE0060 // Remove unused parameter - -[Properties(MaxNbOfTest = MaxNbOfTest)] -public sealed class ClassMaxNbOfTest : CommandLineTest -{ - const int MaxNbOfTest = 20; - - public ClassMaxNbOfTest() : base(nameof(ClassMaxNbOfTest)) - { } - - [CommandLineProperty] - public void Method(int a) - { } - - [TestMethod] - public async Task Method_test() => AreEqual(MaxNbOfTest, await AssertSuccess(nameof(Method))); -} - -#pragma warning restore IDE0060 // Remove unused parameter diff --git a/src/AD.FsCheck.MSTest.Tests/ClassMaxTest.cs b/src/AD.FsCheck.MSTest.Tests/ClassMaxTest.cs new file mode 100644 index 0000000..5cbd1f3 --- /dev/null +++ b/src/AD.FsCheck.MSTest.Tests/ClassMaxTest.cs @@ -0,0 +1,21 @@ +namespace AD.FsCheck.MSTest.Tests; + +#pragma warning disable IDE0060 // Remove unused parameter + +[Properties(MaxTest = MaxTest)] +public sealed class ClassMaxTest : CommandLineTest +{ + const int MaxTest = 20; + + public ClassMaxTest() : base(nameof(ClassMaxTest)) + { } + + [CommandLineProperty] + public void Method(int a) + { } + + [TestMethod] + public async Task Method_test() => AreEqual(MaxTest, await AssertSuccess(nameof(Method))); +} + +#pragma warning restore IDE0060 // Remove unused parameter diff --git a/src/AD.FsCheck.MSTest.Tests/DurationTest.cs b/src/AD.FsCheck.MSTest.Tests/DurationTest.cs index 4877dcb..cf03b3a 100644 --- a/src/AD.FsCheck.MSTest.Tests/DurationTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/DurationTest.cs @@ -9,7 +9,7 @@ public sealed class DurationTest : CommandLineTest public DurationTest() : base(nameof(DurationTest)) { } - [Property(MaxNbOfTest = NbOfTest)] + [Property(MaxTest = NbOfTest)] public async Task Duration(int _) => await Task.Delay(Yield); [TestMethod] diff --git a/src/AD.FsCheck.MSTest.Tests/InvokeErrorTest.cs b/src/AD.FsCheck.MSTest.Tests/InvokeErrorTest.cs index 6bc4725..30d7855 100644 --- a/src/AD.FsCheck.MSTest.Tests/InvokeErrorTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/InvokeErrorTest.cs @@ -18,7 +18,7 @@ public void CannotGenerate(NotGeneratable _) public async Task CannotGenerate_test() { var msg = await Run(nameof(CannotGenerate), Fetch.StdErr); - AreEqual($"The type {typeof(NotGeneratable).FullName} is not handled automatically by FsCheck. Consider using another type or writing and registering a generator for it.", + AreEqual($"The type {typeof(NotGeneratable).FullName} is not handled automatically by FsCheck. Consider using another type or writing a generator for it.", msg); } } diff --git a/src/AD.FsCheck.MSTest.Tests/MethodMaxNbOfTest.cs b/src/AD.FsCheck.MSTest.Tests/MethodMaxNbOfTest.cs deleted file mode 100644 index 13990db..0000000 --- a/src/AD.FsCheck.MSTest.Tests/MethodMaxNbOfTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace AD.FsCheck.MSTest.Tests; - -#pragma warning disable IDE0060 // Remove unused parameter - -[TestClass] -public sealed class MethodMaxNbOfTest : CommandLineTest -{ - const int MaxNbOfTest = 30; - - public MethodMaxNbOfTest() : base(nameof(MethodMaxNbOfTest)) - { } - - [CommandLineProperty(MaxNbOfTest = MaxNbOfTest)] - public void Method(int a) - { } - - [TestMethod] - public async Task Method_test() => AreEqual(MaxNbOfTest, await AssertSuccess(nameof(Method))); -} - -#pragma warning restore IDE0060 // Remove unused parameter diff --git a/src/AD.FsCheck.MSTest.Tests/MethodMaxTest.cs b/src/AD.FsCheck.MSTest.Tests/MethodMaxTest.cs new file mode 100644 index 0000000..14f80ec --- /dev/null +++ b/src/AD.FsCheck.MSTest.Tests/MethodMaxTest.cs @@ -0,0 +1,21 @@ +namespace AD.FsCheck.MSTest.Tests; + +#pragma warning disable IDE0060 // Remove unused parameter + +[TestClass] +public sealed class MethodMaxTest : CommandLineTest +{ + const int MaxTest = 30; + + public MethodMaxTest() : base(nameof(MethodMaxTest)) + { } + + [CommandLineProperty(MaxTest = MaxTest)] + public void Method(int a) + { } + + [TestMethod] + public async Task Method_test() => AreEqual(MaxTest, await AssertSuccess(nameof(Method))); +} + +#pragma warning restore IDE0060 // Remove unused parameter diff --git a/src/AD.FsCheck.MSTest.Tests/ParametersTest.cs b/src/AD.FsCheck.MSTest.Tests/ParametersTest.cs index f933f33..33fea07 100644 --- a/src/AD.FsCheck.MSTest.Tests/ParametersTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/ParametersTest.cs @@ -37,7 +37,7 @@ public void One_parameter(int a) #region Two [CommandLineProperty] - public void Two_parameters(int a, int b) + public void Two_parameters(int a, string b) { } [TestMethod] @@ -48,7 +48,7 @@ public void Two_parameters(int a, int b) #region Three [CommandLineProperty] - public void Three_parameters(int a, int b, int c) + public void Three_parameters(int a, string b, Guid c) { } [TestMethod] @@ -59,7 +59,7 @@ public void Three_parameters(int a, int b, int c) #region Four [CommandLineProperty] - public void Four_parameters(int a, int b, int c, int d) + public void Four_parameters(int a, string b, Guid c, double d) { } [TestMethod] @@ -70,7 +70,7 @@ public void Four_parameters(int a, int b, int c, int d) #region Five [CommandLineProperty] - public void Five_parameters(int a, int b, int c, int d, int e) + public void Five_parameters(int a, string b, Guid c, double d, decimal e) { } [TestMethod] @@ -81,7 +81,7 @@ public void Five_parameters(int a, int b, int c, int d, int e) #region Six [CommandLineProperty] - public void Six_parameters(int a, int b, int c, int d, int e, int f) + public void Six_parameters(int a, string b, Guid c, double d, decimal e, byte f) { } [TestMethod] @@ -92,7 +92,7 @@ public void Six_parameters(int a, int b, int c, int d, int e, int f) #region Seven [CommandLineProperty] - public void Seven_parameters(int a, int b, int c, int d, int e, int f, int g) + public void Seven_parameters(int a, string b, Guid c, double d, decimal e, byte f, DateTime g) { } [TestMethod] @@ -103,7 +103,7 @@ public void Seven_parameters(int a, int b, int c, int d, int e, int f, int g) #region Eight [CommandLineProperty] - public void Eight_parameters(int a, int b, int c, int d, int e, int f, int g, int h) + public void Eight_parameters(int a, string b, Guid c, double d, decimal e, byte f, DateTime g, char h) { } [TestMethod] diff --git a/src/AD.FsCheck.MSTest.Tests/PropertiesReplayTest.cs b/src/AD.FsCheck.MSTest.Tests/PropertiesReplayTest.cs index 88052e6..bab5e87 100644 --- a/src/AD.FsCheck.MSTest.Tests/PropertiesReplayTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/PropertiesReplayTest.cs @@ -1,6 +1,6 @@ namespace AD.FsCheck.MSTest.Tests; -[Properties(Replay = "1561428431,297099475")] +[Properties(Replay = "10333802694858096737,13365262137747244545")] public sealed class PropertiesReplayTest : CommandLineTest { public PropertiesReplayTest() : base(nameof(PropertiesReplayTest)) @@ -13,6 +13,6 @@ public PropertiesReplayTest() : base(nameof(PropertiesReplayTest)) public async Task Prop_test() { var msg = await Run(nameof(Prop), Fetch.StdErr); - IsTrue(msg.StartsWith("Falsifiable, after 28 tests (1 shrink) (StdGen (1561428431,297099475))")); + IsTrue(msg.StartsWith("Falsifiable, after 20 tests (2 shrinks) (10333802694858096737,13365262137747244545)")); } } diff --git a/src/AD.FsCheck.MSTest.Tests/PropertyReplayTest.cs b/src/AD.FsCheck.MSTest.Tests/PropertyReplayTest.cs index c1e97e9..1652ef6 100644 --- a/src/AD.FsCheck.MSTest.Tests/PropertyReplayTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/PropertyReplayTest.cs @@ -6,19 +6,19 @@ public sealed class PropertyReplayTest : CommandLineTest public PropertyReplayTest() : base(nameof(PropertyReplayTest)) { } - [CommandLineProperty(Replay = "1561428431,297099475")] + [CommandLineProperty(Replay = "1358818329932720880,1613334182980143787")] public void Prop1(int a) => IsTrue(a < 17); [TestMethod] public async Task Prop1_test() => await Run(nameof(Prop1)); - [CommandLineProperty(Replay = " 1561428431 , 297099475 ")] + [CommandLineProperty(Replay = " 1358818329932720880 , 1613334182980143787 ")] public void Prop2(int a) => IsTrue(a < 17); [TestMethod] public async Task Prop2_test() => await Run(nameof(Prop2)); - [CommandLineProperty(Replay = "(1561428431,297099475)")] + [CommandLineProperty(Replay = "(1358818329932720880,1613334182980143787)")] public void Prop3(int a) => IsTrue(a < 17); [TestMethod] @@ -27,6 +27,6 @@ public PropertyReplayTest() : base(nameof(PropertyReplayTest)) async Task Run(string testName) { var msg = await Run(testName, Fetch.StdErr); - IsTrue(msg.StartsWith("Falsifiable, after 28 tests (1 shrink) (StdGen (1561428431,297099475))")); + IsTrue(msg.StartsWith("Falsifiable, after 25 tests (3 shrinks) (1358818329932720880,1613334182980143787)")); } } diff --git a/src/AD.FsCheck.MSTest.Tests/ReplayPrecedenceTest.cs b/src/AD.FsCheck.MSTest.Tests/ReplayPrecedenceTest.cs index c91e4a1..ce13cca 100644 --- a/src/AD.FsCheck.MSTest.Tests/ReplayPrecedenceTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/ReplayPrecedenceTest.cs @@ -6,13 +6,13 @@ public sealed class ReplayPrecedenceTest : CommandLineTest public ReplayPrecedenceTest() : base(nameof(ReplayPrecedenceTest)) { } - [CommandLineProperty(Replay = "1561428431,297099475")] + [CommandLineProperty(Replay = "5195330141687306492,9724345478383734501")] public void Prop(int a) => IsTrue(a < 17); [TestMethod] public async Task Prop_test() { var msg = await Run(nameof(Prop), Fetch.StdErr); - IsTrue(msg.StartsWith("Falsifiable, after 28 tests (1 shrink) (StdGen (1561428431,297099475))")); + IsTrue(msg.StartsWith("Falsifiable, after 21 tests (2 shrinks) (5195330141687306492,9724345478383734501)")); } } diff --git a/src/AD.FsCheck.MSTest.Tests/VectorTest.cs b/src/AD.FsCheck.MSTest.Tests/VectorTest.cs index 7444d14..a982b65 100644 --- a/src/AD.FsCheck.MSTest.Tests/VectorTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/VectorTest.cs @@ -7,7 +7,7 @@ public record Vector(int X, int Y) public static Vector PlusIdentity { get; } = new(0, 0); } -[Properties(MaxNbOfTest = 1000)] +[Properties(MaxTest = 1000)] public sealed class VectorTest { [Property] @@ -23,7 +23,7 @@ public sealed class VectorTest [TestClass] public sealed class VectorSerializationTest { - [Property(MaxNbOfTest = 10)] + [Property(MaxTest = 10)] public async Task Serialize_and_deserialize(Vector expected) { var actual = await Deserialize(await Serialize(expected)); diff --git a/src/AD.FsCheck.MSTest.Tests/VerbosePropertiesTest.cs b/src/AD.FsCheck.MSTest.Tests/VerbosePropertiesTest.cs index a373c0f..5c2d7cb 100644 --- a/src/AD.FsCheck.MSTest.Tests/VerbosePropertiesTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/VerbosePropertiesTest.cs @@ -1,9 +1,9 @@ namespace AD.FsCheck.MSTest.Tests; -[Properties(MaxNbOfTest = MaxNbOfTest, Verbose = true)] +[Properties(MaxTest = MaxTest, Verbose = true)] public sealed class VerbosePropertiesTest : CommandLineTest { - const int MaxNbOfTest = 20; + const int MaxTest = 20; public VerbosePropertiesTest() : base(nameof(VerbosePropertiesTest)) { } @@ -12,13 +12,13 @@ public VerbosePropertiesTest() : base(nameof(VerbosePropertiesTest)) public void Verbose(int a, int b) => AreEqual(a + b, b + a); [TestMethod] - public async Task Verbose_test() => await Test(nameof(Verbose), MaxNbOfTest + 1); + public async Task Verbose_test() => await Test(nameof(Verbose), MaxTest + 1); [CommandLineProperty(Verbose = false)] public void NotVerbose(int a, int b) => AreEqual(a + b, b + a); [TestMethod] - public async Task NotVerbose_test() => await Test(nameof(NotVerbose), MaxNbOfTest + 1); + public async Task NotVerbose_test() => await Test(nameof(NotVerbose), MaxTest + 1); //when 'Verbose' is set to true for the class, it cannot be set to false for a single property async Task Test(string testName, int expectedLines) diff --git a/src/AD.FsCheck.MSTest.Tests/VerboseTest.cs b/src/AD.FsCheck.MSTest.Tests/VerboseTest.cs index 3f5eb6e..ccf776e 100644 --- a/src/AD.FsCheck.MSTest.Tests/VerboseTest.cs +++ b/src/AD.FsCheck.MSTest.Tests/VerboseTest.cs @@ -1,9 +1,9 @@ namespace AD.FsCheck.MSTest.Tests; -[Properties(MaxNbOfTest = MaxNbOfTest)] +[Properties(MaxTest = MaxTest)] public sealed class VerboseTest : CommandLineTest { - const int MaxNbOfTest = 20; + const int MaxTest = 20; public VerboseTest() : base(nameof(VerboseTest)) { } @@ -12,7 +12,7 @@ public VerboseTest() : base(nameof(VerboseTest)) public void Verbose(int a, int b) => AreEqual(a + b, b + a); [TestMethod] - public async Task Verbose_test() => await Test(nameof(Verbose), MaxNbOfTest + 1); + public async Task Verbose_test() => await Test(nameof(Verbose), MaxTest + 1); [CommandLineProperty] public void NotVerbose(int a, int b) => AreEqual(a + b, b + a); diff --git a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj index e381348..9e35fc1 100644 --- a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj +++ b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj @@ -1,10 +1,12 @@  + + netstandard2.0;net8.0 True $(MSBuildProjectName.Replace("AD", "AndreasDorfer")) False - 1.1.2 + 3.0.0-rc1.2 Andreas Dorfer Integrates FsCheck with MSTest. https://github.com/Andreas-Dorfer/fscheck-mstest @@ -22,8 +24,8 @@ - - + + diff --git a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs index a0c925f..71312f1 100644 --- a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs @@ -1,30 +1,37 @@ -using static FsCheck.Random; +using Microsoft.FSharp.Core; namespace AD.FsCheck.MSTest; /// -/// Extension methods for . +/// Extension methods for . /// public static class ConfigurationExtensions { - static string? FromStdGen(StdGen? stdGen) + static string? FromReplay(Replay? replay) { - if (stdGen is null) return null; - return $"{stdGen.Item1},{stdGen.Item2}"; + if (replay is null) return null; + var replayString = $"{replay.Rnd.Seed},{replay.Rnd.Gamma}"; + var size = OptionModule.ToNullable(replay.Size); + if (size is not null) + { + replayString += $",{size.Value}"; + } + return replayString; } /// - /// Converts a to a . + /// Converts a to a . /// - /// The to convert. + /// The to convert. /// The created . - public static IRunConfiguration ToRunConfiguration(this Configuration configuration) => + public static IRunConfiguration ToRunConfiguration(this Config configuration) => new RunConfiguration( - configuration.MaxNbOfTest, - configuration.MaxNbOfFailedTests, + configuration.MaxTest, + configuration.MaxRejected, configuration.StartSize, configuration.EndSize, - FromStdGen(configuration.Replay), + FromReplay(OptionModule.ToObj(configuration.Replay)), false, //Verbose cannot be inferred from a Configuration - configuration.QuietOnSuccess); + configuration.QuietOnSuccess, + []); } diff --git a/src/AD.FsCheck.MSTest/IRunConfiguration.cs b/src/AD.FsCheck.MSTest/IRunConfiguration.cs index bf1ae73..4c14f2e 100644 --- a/src/AD.FsCheck.MSTest/IRunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/IRunConfiguration.cs @@ -8,12 +8,12 @@ public interface IRunConfiguration /// /// The maximum number of tests that are run. /// - int MaxNbOfTest { get; } + int MaxTest { get; } /// /// The maximum number of tests where values are rejected. /// - int MaxNbOfFailedTests { get; } + int MaxRejected { get; } /// /// The size to use for the first test. @@ -39,4 +39,9 @@ public interface IRunConfiguration /// Suppresses the output from the test if the test is successful. /// bool QuietOnSuccess { get; } + + /// + /// The Arbitrary instances to use for this test method. + /// + Type[] Arbitrary{ get; } } diff --git a/src/AD.FsCheck.MSTest/IsExternalInit.cs b/src/AD.FsCheck.MSTest/IsExternalInit.cs new file mode 100644 index 0000000..f11b0fd --- /dev/null +++ b/src/AD.FsCheck.MSTest/IsExternalInit.cs @@ -0,0 +1,10 @@ +// from https://github.com/dotnet/runtime/blob/48ae96799fa048302d5e323cee204ae7fbb4edde/src/tasks/Common/IsExternalInit.cs + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + internal sealed class IsExternalInit { } +} \ No newline at end of file diff --git a/src/AD.FsCheck.MSTest/MSTestRunner.cs b/src/AD.FsCheck.MSTest/MSTestRunner.cs index b4b8115..6a261de 100644 --- a/src/AD.FsCheck.MSTest/MSTestRunner.cs +++ b/src/AD.FsCheck.MSTest/MSTestRunner.cs @@ -34,12 +34,13 @@ public void OnShrink(FSharpList args, FSharpFunc, str public void OnFinished(string name, FsCheckResult testResult) => Result = testResult switch { - FsCheckResult.True => new() + FsCheckResult.Passed => new() { Outcome = MSTestOutcome.Passed, LogOutput = quietOnSuccess ? null : log.Append(Runner.onFinishedToString("", testResult)).ToString() }, - FsCheckResult.False => new() + FsCheckResult.Exhausted or + FsCheckResult.Failed => new() { Outcome = MSTestOutcome.Failed, LogError = log.Append(Runner.onFinishedToString("", testResult)).ToString() diff --git a/src/AD.FsCheck.MSTest/NullableAttributes.cs b/src/AD.FsCheck.MSTest/NullableAttributes.cs new file mode 100644 index 0000000..89e85d7 --- /dev/null +++ b/src/AD.FsCheck.MSTest/NullableAttributes.cs @@ -0,0 +1,199 @@ +// from https://github.com/dotnet/runtime/blob/48ae96799fa048302d5e323cee204ae7fbb4edde/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis +{ +#if !NETSTANDARD2_1 && !NETCOREAPP3_0_OR_GREATER + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +#endif + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = [member]; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated field or property member will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = [member]; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated field and property members will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} diff --git a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs index f338fe9..947f190 100644 --- a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs @@ -3,14 +3,14 @@ /// /// Set common configuration for all properties within this class. /// -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] public class PropertiesAttribute : TestClassAttribute, IRunConfiguration { /// - public int MaxNbOfTest { get; set; } = -1; + public int MaxTest { get; set; } = -1; /// - public int MaxNbOfFailedTests { get; set; } = -1; + public int MaxRejected { get; set; } = -1; /// public int StartSize { get; set; } = -1; @@ -29,6 +29,9 @@ public class PropertiesAttribute : TestClassAttribute, IRunConfiguration /// When you set to true, it cannot be set to false for individual properties. public bool QuietOnSuccess { get; set; } + /// + public Type[] Arbitrary { get; set; } = []; + /// public override TestMethodAttribute? GetTestMethodAttribute(TestMethodAttribute? testMethodAttribute) { diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs index c40214e..a75ea3c 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs @@ -1,5 +1,6 @@ // This file was generated from 'PropertyAttribute.Invoke.tt'. #nullable enable +using FsCheck.Fluent; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -7,40 +8,42 @@ namespace AD.FsCheck.MSTest; public partial class PropertyAttribute { + static Property Combine(IArbMap arbMap, Func action) => Prop.ForAll(arbMap.ArbFor(), action); + static readonly MethodInfo Invoke1MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke1), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke1(Func method) => - Prop.ForAll(values => method(new object[] { values! })); + static Property Invoke1(IArbMap arbMap, Func method) => + Prop.ForAll(arbMap.ArbFor(), v => method(new object[] { v! })); static readonly MethodInfo Invoke2MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke2), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke2(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2! })); + static Property Invoke2(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke1(arbMap, values => method([v!, values[0]!]))); static readonly MethodInfo Invoke3MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke3), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke3(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2!, values.Item3! })); + static Property Invoke3(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke2(arbMap, values => method([v!, values[0]!, values[1]]))); static readonly MethodInfo Invoke4MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke4), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke4(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2!, values.Item3!, values.Item4! })); + static Property Invoke4(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke3(arbMap, values => method([v!, values[0]!, values[1], values[2]]))); static readonly MethodInfo Invoke5MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke5), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke5(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2!, values.Item3!, values.Item4!, values.Item5! })); + static Property Invoke5(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke4(arbMap, values => method([v!, values[0]!, values[1], values[2], values[3]]))); static readonly MethodInfo Invoke6MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke6), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke6(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2!, values.Item3!, values.Item4!, values.Item5!, values.Item6! })); + static Property Invoke6(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke5(arbMap, values => method([v!, values[0]!, values[1], values[2], values[3], values[4]]))); static readonly MethodInfo Invoke7MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke7), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke7(Func method) => - Prop.ForAll>(values => method(new object[] { values.Item1!, values.Item2!, values.Item3!, values.Item4!, values.Item5!, values.Item6!, values.Item7! })); + static Property Invoke7(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke6(arbMap, values => method([v!, values[0]!, values[1], values[2], values[3], values[4], values[5]]))); bool TryGetInvokeMethodInfo(int count, [NotNullWhen(true)] out MethodInfo? methodInfo, [NotNullWhen(false)] out string? errorMsg) { diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt index 0d3dc35..154fe93 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt @@ -3,6 +3,7 @@ <#const int count = 7; #> // This file was generated from 'PropertyAttribute.Invoke.tt'. #nullable enable +using FsCheck.Fluent; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -10,27 +11,37 @@ namespace AD.FsCheck.MSTest; public partial class PropertyAttribute { + static Property Combine(IArbMap arbMap, Func action) => Prop.ForAll(arbMap.ArbFor(), action); + + static readonly MethodInfo Invoke1MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke1), BindingFlags.Static | BindingFlags.NonPublic)!; + + static Property Invoke1(IArbMap arbMap, Func method) => + Prop.ForAll(arbMap.ArbFor(), v => method(new object[] { v! })); + <# string types = "T1"; -string typesTuple = "T1"; -string values = "values!"; +string values = ""; for(int i = 1; i <= count; i++) { + if(i > 1) + { #> static readonly MethodInfo Invoke<#= i #>MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke<#= i #>), BindingFlags.Static | BindingFlags.NonPublic)!; - static Property Invoke<#= i #><<#= types #>>(Func method) => - Prop.ForAll<<#= typesTuple #>>(values => method(new object[] { <#= values #> })); + static Property Invoke<#= i #><<#= types #>>(IArbMap arbMap, Func method) => + Combine(arbMap, v => Invoke<#= i - 1 #><<#= types.Replace("T1, ", "") #>>(arbMap, values => method([v!, <#= values #>]))); <# + } + types += ", T" + (i + 1).ToString(); if(i == 1) { - values = "values.Item1!"; + values = "values[0]!"; + } + else + { + values += ", values[" + (i - 1) + "]"; } - - types += ", T" + (i + 1).ToString(); - typesTuple = "Tuple<" + types + ">"; - values += ", values.Item" + (i + 1).ToString() + "!"; } #> bool TryGetInvokeMethodInfo(int count, [NotNullWhen(true)] out MethodInfo? methodInfo, [NotNullWhen(false)] out string? errorMsg) diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index e8ec1e6..b8a1136 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -1,4 +1,6 @@ -using System.Diagnostics; +using FsCheck.Fluent; +using System.Collections.Concurrent; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -10,7 +12,7 @@ namespace AD.FsCheck.MSTest; [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public partial class PropertyAttribute : TestMethodAttribute, IRunConfiguration { - static readonly IRunConfiguration DefaultRunConfiguration = Configuration.Quick.ToRunConfiguration(); + static readonly IRunConfiguration DefaultRunConfiguration = Config.Quick.ToRunConfiguration(); /// /// Initializes a new instance of the class. @@ -33,10 +35,10 @@ public PropertyAttribute(string displayName) : base(displayName) internal PropertiesAttribute? Parent { get; set; } /// - public int MaxNbOfTest { get; set; } = -1; + public int MaxTest { get; set; } = -1; /// - public int MaxNbOfFailedTests { get; set; } = -1; + public int MaxRejected { get; set; } = -1; /// public int StartSize { get; set; } = -1; @@ -53,6 +55,9 @@ public PropertyAttribute(string displayName) : base(displayName) /// public bool QuietOnSuccess { get; set; } + /// + public Type[] Arbitrary { get; set; } = []; + /// public override MSTestResult[] Execute(ITestMethod testMethod) { @@ -105,7 +110,8 @@ public override MSTestResult[] Execute(ITestMethod testMethod) if (initializeCleanupException is null) { - var combined = this.OrElse(Parent).OrElse(Default); + var assemblyConfig = GetAssemblyConfiguration(testMethod.MethodInfo.DeclaringType); + var combined = this.OrElse(Parent).OrElse(assemblyConfig).OrElse(Default); MSTestRunner runner = new(combined.Verbose, combined.QuietOnSuccess); var fsCheckConfig = combined.ToConfiguration(runner); if (TryInvoke(testMethod, fsCheckConfig, out var runException, out var errorMsg)) @@ -136,7 +142,7 @@ public override MSTestResult[] Execute(ITestMethod testMethod) return results; } - bool TryInvoke(ITestMethod testMethod, Configuration fsCheckConfig, out Exception? runException, [NotNullWhen(false)] out string? errorMsg) + bool TryInvoke(ITestMethod testMethod, Config fsCheckConfig, out Exception? runException, [NotNullWhen(false)] out string? errorMsg) { var parameters = testMethod.ParameterTypes; if (TryGetInvokeMethodInfo(parameters.Length, out var methodInfo, out errorMsg)) @@ -153,17 +159,23 @@ bool Invoke(object[] values) try { #pragma warning disable CS8974 // Converting method group to non-delegate type - ((Property)invokeInfo.Invoke(null, [Invoke])!).Check(fsCheckConfig); + ((Property)invokeInfo.Invoke(null, [fsCheckConfig.ArbMap, Invoke])!).Check(fsCheckConfig); #pragma warning restore CS8974 // Converting method group to non-delegate type runException = ex; return true; } catch (TargetInvocationException invokeEx) { - errorMsg = invokeEx.InnerException?.Message ?? invokeEx.Message; + errorMsg = invokeEx.InnerException?.InnerException?.Message ?? invokeEx.InnerException?.Message ?? invokeEx.Message; } } runException = default; return false; } + + static readonly ConcurrentDictionary assemblyConfigurations = []; + + static IRunConfiguration? GetAssemblyConfiguration(Type? type) => + type is null ? null : + assemblyConfigurations.GetOrAdd(type.Assembly, assembly => assembly.GetCustomAttribute()); } diff --git a/src/AD.FsCheck.MSTest/RunConfiguration.cs b/src/AD.FsCheck.MSTest/RunConfiguration.cs index e48d8cd..92ea8f8 100644 --- a/src/AD.FsCheck.MSTest/RunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/RunConfiguration.cs @@ -3,18 +3,20 @@ /// /// Configures how an FsCheck test is run. /// -/// The maximum number of tests that are run. -/// The maximum number of tests where values are rejected. +/// The maximum number of tests that are run. +/// The maximum number of tests where values are rejected. /// The size to use for the first test. /// The size to use for the last test. /// If set, the seed to use to start testing. /// Output all generated arguments. /// Suppresses the output from the test if the test is successful. +/// The Arbitrary instances to use for this test method. public record RunConfiguration( - int MaxNbOfTest, - int MaxNbOfFailedTests, + int MaxTest, + int MaxRejected, int StartSize, int EndSize, string? Replay, bool Verbose, - bool QuietOnSuccess) : IRunConfiguration; + bool QuietOnSuccess, + Type[] Arbitrary) : IRunConfiguration; diff --git a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs index 1d6b463..7501ed4 100644 --- a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs @@ -1,4 +1,4 @@ -using static FsCheck.Random; +using Microsoft.FSharp.Core; namespace AD.FsCheck.MSTest; @@ -9,39 +9,47 @@ public static IRunConfiguration OrElse(this IRunConfiguration config, IRunConfig if (@else is null) return config; return new RunConfiguration( - config.MaxNbOfTest > -1 ? config.MaxNbOfTest : @else.MaxNbOfTest, - config.MaxNbOfFailedTests > -1 ? config.MaxNbOfFailedTests : @else.MaxNbOfFailedTests, + config.MaxTest > -1 ? config.MaxTest : @else.MaxTest, + config.MaxRejected > -1 ? config.MaxRejected : @else.MaxRejected, config.StartSize > -1 ? config.StartSize : @else.StartSize, config.EndSize > -1 ? config.EndSize : @else.EndSize, config.Replay ?? @else.Replay, config.Verbose || @else.Verbose, - config.QuietOnSuccess || @else.QuietOnSuccess); + config.QuietOnSuccess || @else.QuietOnSuccess, + [.. config.Arbitrary, .. @else.Arbitrary]); } - static StdGen? ToStdGen(string? replay) + static Replay? ToReplay(string? replayString) { - if (replay is null) return null; + if (replayString is null) return null; - var items = replay.TrimStart('(').TrimEnd(')').Split(','); - if (items.Length != 2) return null; + var items = replayString.TrimStart('(').TrimEnd(')').Split(','); + if (items.Length < 2 || items.Length > 3) return null; for (int i = 0; i < items.Length; i++) { items[i] = items[i].Trim(); } - if (!(int.TryParse(items[0], out var item1) && int.TryParse(items[1], out var item2))) return null; - return StdGen.NewStdGen(item1, item2); + if (!(ulong.TryParse(items[0], out var seed) && ulong.TryParse(items[1], out var gamma))) return null; + + int? size = null; + if (items.Length == 3) + { + if (!int.TryParse(items[2], out var value)) return null; + size = value; + } + + return new(new(seed, gamma), OptionModule.OfNullable(size)); } - public static Configuration ToConfiguration(this IRunConfiguration config, IRunner runner) => new() - { - MaxNbOfTest = config.MaxNbOfTest, - MaxNbOfFailedTests = config.MaxNbOfFailedTests, - StartSize = config.StartSize, - EndSize = config.EndSize, - Replay = ToStdGen(config.Replay), - QuietOnSuccess = config.QuietOnSuccess, - Runner = runner - }; + public static Config ToConfiguration(this IRunConfiguration config, IRunner runner) => Config.Default + .WithMaxTest(config.MaxTest) + .WithMaxRejected(config.MaxRejected) + .WithStartSize(config.StartSize) + .WithEndSize(config.EndSize) + .WithReplay(OptionModule.OfObj(ToReplay(config.Replay))) + .WithQuietOnSuccess(config.QuietOnSuccess) + .WithRunner(runner) + .WithArbitrary(config.Arbitrary); }