From 9f0ebdae42c52b12b7bc1f9f49f2e232df6865a1 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Thu, 4 Apr 2024 18:43:04 +0200 Subject: [PATCH 01/16] FsCheck.3.0.0-rc3 --- src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj index 5304e80..0592bab 100644 --- a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj +++ b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj @@ -22,7 +22,7 @@ - + From 347c44d023e112bfdbaa4e0f200e58d0233143d4 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:58:56 +0200 Subject: [PATCH 02/16] rc-1 --- src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj index 59cabc5..cfd126e 100644 --- a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj +++ b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj @@ -4,7 +4,7 @@ True $(MSBuildProjectName.Replace("AD", "AndreasDorfer")) False - 1.1.2 + 3.0.0-rc1 Andreas Dorfer Integrates FsCheck with MSTest. https://github.com/Andreas-Dorfer/fscheck-mstest From 4af74c958189960a66eadb104681deeedd7d419d Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:18:52 +0200 Subject: [PATCH 03/16] no build errors --- .../ConfigurationExtensions.cs | 28 ++++++++----- src/AD.FsCheck.MSTest/MSTestRunner.cs | 5 ++- .../PropertyAttribute.Invoke.cs | 1 + .../PropertyAttribute.Invoke.tt | 1 + src/AD.FsCheck.MSTest/PropertyAttribute.cs | 4 +- .../RunConfigurationExtensions.cs | 40 +++++++++++-------- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs index a0c925f..60b1f02 100644 --- a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs @@ -1,30 +1,36 @@ -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); } 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/PropertyAttribute.Invoke.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs index c40214e..f52faff 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; diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt index 0d3dc35..4e0b0e4 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; diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index e8ec1e6..1e84342 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -10,7 +10,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. @@ -136,7 +136,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)) diff --git a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs index 1d6b463..f02733b 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; @@ -18,30 +18,36 @@ public static IRunConfiguration OrElse(this IRunConfiguration config, IRunConfig config.QuietOnSuccess || @else.QuietOnSuccess); } - 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.MaxNbOfTest) + .WithMaxRejected(config.MaxNbOfFailedTests) + .WithStartSize(config.StartSize) + .WithEndSize(config.EndSize) + .WithReplay(OptionModule.OfObj(ToReplay(config.Replay))) + .WithQuietOnSuccess(config.QuietOnSuccess) + .WithRunner(runner); } From 650693df9d4cd2e6b0703595d21f6efbea96c965 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:29:58 +0200 Subject: [PATCH 04/16] no compile errors --- src/AD.FsCheck.MSTest.FsTests/VectorTest.fs | 4 ++-- .../Arbitraries.cs | 14 +++++-------- .../_usings.cs | 1 + ...axNbOfTest.cs => ClassAndMethodMaxTest.cs} | 16 +++++++------- .../ClassMaxNbOfTest.cs | 21 ------------------- src/AD.FsCheck.MSTest.Tests/ClassMaxTest.cs | 21 +++++++++++++++++++ src/AD.FsCheck.MSTest.Tests/DurationTest.cs | 2 +- .../MethodMaxNbOfTest.cs | 21 ------------------- src/AD.FsCheck.MSTest.Tests/MethodMaxTest.cs | 21 +++++++++++++++++++ src/AD.FsCheck.MSTest.Tests/VectorTest.cs | 4 ++-- .../VerbosePropertiesTest.cs | 8 +++---- src/AD.FsCheck.MSTest.Tests/VerboseTest.cs | 6 +++--- src/AD.FsCheck.MSTest/IRunConfiguration.cs | 4 ++-- src/AD.FsCheck.MSTest/PropertiesAttribute.cs | 6 +++--- src/AD.FsCheck.MSTest/PropertyAttribute.cs | 4 ++-- src/AD.FsCheck.MSTest/RunConfiguration.cs | 8 +++---- .../RunConfigurationExtensions.cs | 8 +++---- 17 files changed, 83 insertions(+), 86 deletions(-) rename src/AD.FsCheck.MSTest.Tests/{ClassAndMethodMaxNbOfTest.cs => ClassAndMethodMaxTest.cs} (50%) delete mode 100644 src/AD.FsCheck.MSTest.Tests/ClassMaxNbOfTest.cs create mode 100644 src/AD.FsCheck.MSTest.Tests/ClassMaxTest.cs delete mode 100644 src/AD.FsCheck.MSTest.Tests/MethodMaxNbOfTest.cs create mode 100644 src/AD.FsCheck.MSTest.Tests/MethodMaxTest.cs 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/Arbitraries.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs index fba3394..0278640 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs @@ -1,15 +1,11 @@ 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(IArbMap map) => 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))); + from100To200 => map.ArbFor().Shrinker(from100To200.Value).Where(value => value >= 100 && value <= 200).Select(value => new From100To200(value))); - [AssemblyInitialize] - public static void Initialize(TestContext _) - { - Arb.Register(); - } + public static IArbMap Merge(IArbMap arbMap) => arbMap + .MergeArbFactory(From100To200); } \ No newline at end of file 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/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/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/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/IRunConfiguration.cs b/src/AD.FsCheck.MSTest/IRunConfiguration.cs index bf1ae73..5ba822f 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. diff --git a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs index f338fe9..9d76e49 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; diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index 1e84342..dc0c5cb 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -33,10 +33,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; diff --git a/src/AD.FsCheck.MSTest/RunConfiguration.cs b/src/AD.FsCheck.MSTest/RunConfiguration.cs index e48d8cd..f184d50 100644 --- a/src/AD.FsCheck.MSTest/RunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/RunConfiguration.cs @@ -3,16 +3,16 @@ /// /// 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. public record RunConfiguration( - int MaxNbOfTest, - int MaxNbOfFailedTests, + int MaxTest, + int MaxRejected, int StartSize, int EndSize, string? Replay, diff --git a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs index f02733b..cf6d4d9 100644 --- a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs @@ -9,8 +9,8 @@ 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, @@ -43,8 +43,8 @@ public static IRunConfiguration OrElse(this IRunConfiguration config, IRunConfig } public static Config ToConfiguration(this IRunConfiguration config, IRunner runner) => Config.Default - .WithMaxTest(config.MaxNbOfTest) - .WithMaxRejected(config.MaxNbOfFailedTests) + .WithMaxTest(config.MaxTest) + .WithMaxRejected(config.MaxRejected) .WithStartSize(config.StartSize) .WithEndSize(config.EndSize) .WithReplay(OptionModule.OfObj(ToReplay(config.Replay))) From 98c073387d9ff2073afd4f3d05821a641817567a Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:45:41 +0200 Subject: [PATCH 05/16] ArbitraryFactory property --- src/AD.FsCheck.MSTest/ConfigurationExtensions.cs | 3 ++- src/AD.FsCheck.MSTest/IRunConfiguration.cs | 5 +++++ src/AD.FsCheck.MSTest/PropertiesAttribute.cs | 3 +++ src/AD.FsCheck.MSTest/PropertyAttribute.cs | 3 +++ src/AD.FsCheck.MSTest/RunConfiguration.cs | 4 +++- src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs | 3 ++- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs index 60b1f02..71312f1 100644 --- a/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/ConfigurationExtensions.cs @@ -32,5 +32,6 @@ public static IRunConfiguration ToRunConfiguration(this Config configuration) => configuration.EndSize, 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 5ba822f..1673a60 100644 --- a/src/AD.FsCheck.MSTest/IRunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/IRunConfiguration.cs @@ -39,4 +39,9 @@ public interface IRunConfiguration /// Suppresses the output from the test if the test is successful. /// bool QuietOnSuccess { get; } + + /// + /// The Arbitrary factories to use for this test method. + /// + Type[] ArbitraryFactory { get;} } diff --git a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs index 9d76e49..61afd08 100644 --- a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs @@ -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[] ArbitraryFactory { get; set; } = []; + /// public override TestMethodAttribute? GetTestMethodAttribute(TestMethodAttribute? testMethodAttribute) { diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index dc0c5cb..fd5f366 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -53,6 +53,9 @@ public PropertyAttribute(string displayName) : base(displayName) /// public bool QuietOnSuccess { get; set; } + /// + public Type[] ArbitraryFactory { get; set; } = []; + /// public override MSTestResult[] Execute(ITestMethod testMethod) { diff --git a/src/AD.FsCheck.MSTest/RunConfiguration.cs b/src/AD.FsCheck.MSTest/RunConfiguration.cs index f184d50..ad5403b 100644 --- a/src/AD.FsCheck.MSTest/RunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/RunConfiguration.cs @@ -10,6 +10,7 @@ /// 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 factories to use for this test method. public record RunConfiguration( int MaxTest, int MaxRejected, @@ -17,4 +18,5 @@ public record RunConfiguration( int EndSize, string? Replay, bool Verbose, - bool QuietOnSuccess) : IRunConfiguration; + bool QuietOnSuccess, + Type[] ArbitraryFactory) : IRunConfiguration; diff --git a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs index cf6d4d9..28d0ecc 100644 --- a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs @@ -15,7 +15,8 @@ public static IRunConfiguration OrElse(this IRunConfiguration config, IRunConfig config.EndSize > -1 ? config.EndSize : @else.EndSize, config.Replay ?? @else.Replay, config.Verbose || @else.Verbose, - config.QuietOnSuccess || @else.QuietOnSuccess); + config.QuietOnSuccess || @else.QuietOnSuccess, + [.. config.ArbitraryFactory, .. @else.ArbitraryFactory]); } static Replay? ToReplay(string? replayString) From fac7b03cc65c3e98265fe8a2f4637755a48de69d Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:43:31 +0200 Subject: [PATCH 06/16] invoke with ArbMap --- .../PropertyAttribute.Invoke.cs | 30 ++++++++++--------- .../PropertyAttribute.Invoke.tt | 28 +++++++++++------ src/AD.FsCheck.MSTest/PropertyAttribute.cs | 7 +++-- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs index f52faff..9f538f7 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs @@ -8,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(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 4e0b0e4..6b076e9 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt @@ -11,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(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 fd5f366..d74f419 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using FsCheck.Fluent; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -152,11 +153,13 @@ bool Invoke(object[] values) return testResult.Outcome == UnitTestOutcome.Passed; } + var arbMap = ArbMap.Default; + var invokeInfo = methodInfo.MakeGenericMethod(parameters.Select(_ => _.ParameterType).ToArray()); try { #pragma warning disable CS8974 // Converting method group to non-delegate type - ((Property)invokeInfo.Invoke(null, [Invoke])!).Check(fsCheckConfig); + ((Property)invokeInfo.Invoke(null, [arbMap, Invoke])!).Check(fsCheckConfig); #pragma warning restore CS8974 // Converting method group to non-delegate type runException = ex; return true; From d961ea50f9ece9e7b8b192b32473fd03a32dee53 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:08:14 +0200 Subject: [PATCH 07/16] ArbFactory --- .../From100To200Tests.cs | 2 +- .../PropertyAttribute.Invoke.cs | 2 +- .../PropertyAttribute.Invoke.tt | 2 +- src/AD.FsCheck.MSTest/PropertyAttribute.cs | 39 ++++++++++++++++--- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/From100To200Tests.cs index 6bff8c8..2524dfe 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(ArbitraryFactory = [typeof(Arbitraries)])] public void IsInRange(From100To200 x) { Assert.IsTrue(x.Value >= 100); diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs index 9f538f7..a75ea3c 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.cs @@ -13,7 +13,7 @@ public partial class PropertyAttribute static readonly MethodInfo Invoke1MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke1), BindingFlags.Static | BindingFlags.NonPublic)!; static Property Invoke1(IArbMap arbMap, Func method) => - Prop.ForAll(v => method(new object[] { v! })); + Prop.ForAll(arbMap.ArbFor(), v => method(new object[] { v! })); static readonly MethodInfo Invoke2MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke2), BindingFlags.Static | BindingFlags.NonPublic)!; diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt index 6b076e9..154fe93 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.Invoke.tt @@ -16,7 +16,7 @@ public partial class PropertyAttribute static readonly MethodInfo Invoke1MethodInfo = typeof(PropertyAttribute).GetMethod(nameof(Invoke1), BindingFlags.Static | BindingFlags.NonPublic)!; static Property Invoke1(IArbMap arbMap, Func method) => - Prop.ForAll(v => method(new object[] { v! })); + Prop.ForAll(arbMap.ArbFor(), v => method(new object[] { v! })); <# string types = "T1"; diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index d74f419..f7a931b 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -1,4 +1,5 @@ using FsCheck.Fluent; +using System.Collections.Concurrent; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -109,10 +110,12 @@ 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)) + var arbMap = ArbMap.Default; + if (TryInvoke(testMethod, fsCheckConfig, BuildArbMap(combined), out var runException, out var errorMsg)) { var runResult = runner.Result!; runResult.TestFailureException = runException; @@ -140,7 +143,7 @@ public override MSTestResult[] Execute(ITestMethod testMethod) return results; } - bool TryInvoke(ITestMethod testMethod, Config fsCheckConfig, out Exception? runException, [NotNullWhen(false)] out string? errorMsg) + bool TryInvoke(ITestMethod testMethod, Config fsCheckConfig, IArbMap arbMap, out Exception? runException, [NotNullWhen(false)] out string? errorMsg) { var parameters = testMethod.ParameterTypes; if (TryGetInvokeMethodInfo(parameters.Length, out var methodInfo, out errorMsg)) @@ -153,8 +156,6 @@ bool Invoke(object[] values) return testResult.Outcome == UnitTestOutcome.Passed; } - var arbMap = ArbMap.Default; - var invokeInfo = methodInfo.MakeGenericMethod(parameters.Select(_ => _.ParameterType).ToArray()); try { @@ -172,4 +173,32 @@ bool Invoke(object[] values) runException = default; return false; } + + static readonly ConcurrentDictionary assemblyConfigurations = []; + + static IRunConfiguration? GetAssemblyConfiguration(Type? type) => + type is null ? null : + assemblyConfigurations.GetOrAdd(type.Assembly, assembly => assembly.GetCustomAttribute()); + + static IArbMap BuildArbMap(IRunConfiguration runConfiguration) + { + var arbMap = ArbMap.Default; + + foreach (var factoryType in runConfiguration.ArbitraryFactory) + { + var merge = factoryType.GetMethod("Merge", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod); + if (merge is null || + merge.IsGenericMethod || + merge.ReturnType != typeof(IArbMap)) continue; + var parameter = merge.GetParameters(); + if (parameter.Length != 1 || + parameter[0].ParameterType != typeof(IArbMap)) continue; + + var next = (IArbMap)merge.Invoke(null, [arbMap])!; + if (next is null) continue; + arbMap = next; + } + + return arbMap; + } } From d2f4e970e47a6f33e003b225e7b7a4eab088f9ec Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:19:29 +0200 Subject: [PATCH 08/16] test fix --- src/AD.FsCheck.MSTest.Tests/InvokeErrorTest.cs | 2 +- src/AD.FsCheck.MSTest/PropertyAttribute.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index f7a931b..c1cc33c 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -167,7 +167,7 @@ bool Invoke(object[] values) } catch (TargetInvocationException invokeEx) { - errorMsg = invokeEx.InnerException?.Message ?? invokeEx.Message; + errorMsg = invokeEx.InnerException?.InnerException?.Message ?? invokeEx.InnerException?.Message ?? invokeEx.Message; } } runException = default; From 3fcbe9d5980ba21662486db1d66eebed9b31cf9f Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:21:55 +0200 Subject: [PATCH 09/16] test fix --- src/AD.FsCheck.MSTest.Tests/PropertiesReplayTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)")); } } From d47aca10ab858cf829cf66d0e43604721beb827e Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:23:41 +0200 Subject: [PATCH 10/16] test fix --- src/AD.FsCheck.MSTest.Tests/PropertyReplayTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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)")); } } From e581dd6ed9a0ff97f74882e4912b28c888031d27 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:24:52 +0200 Subject: [PATCH 11/16] test fix --- src/AD.FsCheck.MSTest.Tests/ReplayPrecedenceTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)")); } } From 2c6cc830ae7e8b3ee858f11b4d53995ee8cd08b8 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:25:19 +0200 Subject: [PATCH 12/16] format --- src/AD.FsCheck.MSTest/IRunConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AD.FsCheck.MSTest/IRunConfiguration.cs b/src/AD.FsCheck.MSTest/IRunConfiguration.cs index 1673a60..97a4f1b 100644 --- a/src/AD.FsCheck.MSTest/IRunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/IRunConfiguration.cs @@ -43,5 +43,5 @@ public interface IRunConfiguration /// /// The Arbitrary factories to use for this test method. /// - Type[] ArbitraryFactory { get;} + Type[] ArbitraryFactory { get; } } From 3b51061f9450898cf45504c0afa6a6fd8508aa23 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:34:35 +0200 Subject: [PATCH 13/16] test fix --- src/AD.FsCheck.MSTest.Tests/ParametersTest.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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] From a973175fd53943b41b07e7f2493c3676290c4ba1 Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:46:09 +0200 Subject: [PATCH 14/16] fix --- src/AD.FsCheck.MSTest/PropertyAttribute.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index c1cc33c..0e71ddd 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -114,7 +114,6 @@ public override MSTestResult[] Execute(ITestMethod testMethod) var combined = this.OrElse(Parent).OrElse(assemblyConfig).OrElse(Default); MSTestRunner runner = new(combined.Verbose, combined.QuietOnSuccess); var fsCheckConfig = combined.ToConfiguration(runner); - var arbMap = ArbMap.Default; if (TryInvoke(testMethod, fsCheckConfig, BuildArbMap(combined), out var runException, out var errorMsg)) { var runResult = runner.Result!; From f0f4ddddb722727a37bf4efe9f7adbe09a3018cd Mon Sep 17 00:00:00 2001 From: Andreas Dorfer <41114919+Andreas-Dorfer@users.noreply.github.com> Date: Thu, 25 Apr 2024 19:13:15 +0200 Subject: [PATCH 15/16] ArbitraryFactory -> Arbitrary --- .../Arbitraries.cs | 9 ++---- .../From100To200Tests.cs | 2 +- .../AD.FsCheck.MSTest.csproj | 2 +- src/AD.FsCheck.MSTest/IRunConfiguration.cs | 4 +-- src/AD.FsCheck.MSTest/PropertiesAttribute.cs | 2 +- src/AD.FsCheck.MSTest/PropertyAttribute.cs | 30 +++---------------- src/AD.FsCheck.MSTest/RunConfiguration.cs | 4 +-- .../RunConfigurationExtensions.cs | 5 ++-- 8 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs index 0278640..89df08c 100644 --- a/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs +++ b/src/AD.FsCheck.MSTest.Tests.Arbitraries/Arbitraries.cs @@ -2,10 +2,7 @@ namespace AD.FsCheck.MSTest.Tests.Arbitraries; public static class Arbitraries { - public static Arbitrary From100To200(IArbMap map) => Arb.From( + public static Arbitrary From100To200(Arbitrary intArb) => Arb.From( Gen.Choose(100, 200).Select(value => new From100To200(value)), - from100To200 => map.ArbFor().Shrinker(from100To200.Value).Where(value => value >= 100 && value <= 200).Select(value => new From100To200(value))); - - public static IArbMap Merge(IArbMap arbMap) => arbMap - .MergeArbFactory(From100To200); -} \ 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 2524dfe..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(ArbitraryFactory = [typeof(Arbitraries)])] + [Property(Arbitrary = [typeof(Arbitraries)])] public void IsInRange(From100To200 x) { Assert.IsTrue(x.Value >= 100); diff --git a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj index cfd126e..17b28d7 100644 --- a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj +++ b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj @@ -4,7 +4,7 @@ True $(MSBuildProjectName.Replace("AD", "AndreasDorfer")) False - 3.0.0-rc1 + 3.0.0-rc1.1 Andreas Dorfer Integrates FsCheck with MSTest. https://github.com/Andreas-Dorfer/fscheck-mstest diff --git a/src/AD.FsCheck.MSTest/IRunConfiguration.cs b/src/AD.FsCheck.MSTest/IRunConfiguration.cs index 97a4f1b..4c14f2e 100644 --- a/src/AD.FsCheck.MSTest/IRunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/IRunConfiguration.cs @@ -41,7 +41,7 @@ public interface IRunConfiguration bool QuietOnSuccess { get; } /// - /// The Arbitrary factories to use for this test method. + /// The Arbitrary instances to use for this test method. /// - Type[] ArbitraryFactory { get; } + Type[] Arbitrary{ get; } } diff --git a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs index 61afd08..947f190 100644 --- a/src/AD.FsCheck.MSTest/PropertiesAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertiesAttribute.cs @@ -30,7 +30,7 @@ public class PropertiesAttribute : TestClassAttribute, IRunConfiguration public bool QuietOnSuccess { get; set; } /// - public Type[] ArbitraryFactory { get; set; } = []; + public Type[] Arbitrary { get; set; } = []; /// public override TestMethodAttribute? GetTestMethodAttribute(TestMethodAttribute? testMethodAttribute) diff --git a/src/AD.FsCheck.MSTest/PropertyAttribute.cs b/src/AD.FsCheck.MSTest/PropertyAttribute.cs index 0e71ddd..b8a1136 100644 --- a/src/AD.FsCheck.MSTest/PropertyAttribute.cs +++ b/src/AD.FsCheck.MSTest/PropertyAttribute.cs @@ -56,7 +56,7 @@ public PropertyAttribute(string displayName) : base(displayName) public bool QuietOnSuccess { get; set; } /// - public Type[] ArbitraryFactory { get; set; } = []; + public Type[] Arbitrary { get; set; } = []; /// public override MSTestResult[] Execute(ITestMethod testMethod) @@ -114,7 +114,7 @@ public override MSTestResult[] Execute(ITestMethod testMethod) 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, BuildArbMap(combined), out var runException, out var errorMsg)) + if (TryInvoke(testMethod, fsCheckConfig, out var runException, out var errorMsg)) { var runResult = runner.Result!; runResult.TestFailureException = runException; @@ -142,7 +142,7 @@ public override MSTestResult[] Execute(ITestMethod testMethod) return results; } - bool TryInvoke(ITestMethod testMethod, Config fsCheckConfig, IArbMap arbMap, 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)) @@ -159,7 +159,7 @@ bool Invoke(object[] values) try { #pragma warning disable CS8974 // Converting method group to non-delegate type - ((Property)invokeInfo.Invoke(null, [arbMap, 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; @@ -178,26 +178,4 @@ bool Invoke(object[] values) static IRunConfiguration? GetAssemblyConfiguration(Type? type) => type is null ? null : assemblyConfigurations.GetOrAdd(type.Assembly, assembly => assembly.GetCustomAttribute()); - - static IArbMap BuildArbMap(IRunConfiguration runConfiguration) - { - var arbMap = ArbMap.Default; - - foreach (var factoryType in runConfiguration.ArbitraryFactory) - { - var merge = factoryType.GetMethod("Merge", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod); - if (merge is null || - merge.IsGenericMethod || - merge.ReturnType != typeof(IArbMap)) continue; - var parameter = merge.GetParameters(); - if (parameter.Length != 1 || - parameter[0].ParameterType != typeof(IArbMap)) continue; - - var next = (IArbMap)merge.Invoke(null, [arbMap])!; - if (next is null) continue; - arbMap = next; - } - - return arbMap; - } } diff --git a/src/AD.FsCheck.MSTest/RunConfiguration.cs b/src/AD.FsCheck.MSTest/RunConfiguration.cs index ad5403b..92ea8f8 100644 --- a/src/AD.FsCheck.MSTest/RunConfiguration.cs +++ b/src/AD.FsCheck.MSTest/RunConfiguration.cs @@ -10,7 +10,7 @@ /// 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 factories to use for this test method. +/// The Arbitrary instances to use for this test method. public record RunConfiguration( int MaxTest, int MaxRejected, @@ -19,4 +19,4 @@ public record RunConfiguration( string? Replay, bool Verbose, bool QuietOnSuccess, - Type[] ArbitraryFactory) : IRunConfiguration; + Type[] Arbitrary) : IRunConfiguration; diff --git a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs index 28d0ecc..7501ed4 100644 --- a/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs +++ b/src/AD.FsCheck.MSTest/RunConfigurationExtensions.cs @@ -16,7 +16,7 @@ public static IRunConfiguration OrElse(this IRunConfiguration config, IRunConfig config.Replay ?? @else.Replay, config.Verbose || @else.Verbose, config.QuietOnSuccess || @else.QuietOnSuccess, - [.. config.ArbitraryFactory, .. @else.ArbitraryFactory]); + [.. config.Arbitrary, .. @else.Arbitrary]); } static Replay? ToReplay(string? replayString) @@ -50,5 +50,6 @@ public static Config ToConfiguration(this IRunConfiguration config, IRunner runn .WithEndSize(config.EndSize) .WithReplay(OptionModule.OfObj(ToReplay(config.Replay))) .WithQuietOnSuccess(config.QuietOnSuccess) - .WithRunner(runner); + .WithRunner(runner) + .WithArbitrary(config.Arbitrary); } From 344cb5c069fdfeaad01afec43a38778564448d58 Mon Sep 17 00:00:00 2001 From: Alan Horne Date: Wed, 11 Sep 2024 12:00:01 -0500 Subject: [PATCH 16/16] Added netstandard2.0 to target frameworks. (#18) Co-authored-by: Alan Horne --- .../AD.FsCheck.MSTest.csproj | 4 +- src/AD.FsCheck.MSTest/IsExternalInit.cs | 10 + src/AD.FsCheck.MSTest/NullableAttributes.cs | 199 ++++++++++++++++++ 3 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/AD.FsCheck.MSTest/IsExternalInit.cs create mode 100644 src/AD.FsCheck.MSTest/NullableAttributes.cs diff --git a/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj b/src/AD.FsCheck.MSTest/AD.FsCheck.MSTest.csproj index 17b28d7..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 - 3.0.0-rc1.1 + 3.0.0-rc1.2 Andreas Dorfer Integrates FsCheck with MSTest. https://github.com/Andreas-Dorfer/fscheck-mstest 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/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; } + } +}