Scand.StormPetrel.Generator 1.0.0

Prefix Reserved
dotnet add package Scand.StormPetrel.Generator --version 1.0.0                
NuGet\Install-Package Scand.StormPetrel.Generator -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Scand.StormPetrel.Generator" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Scand.StormPetrel.Generator --version 1.0.0                
#r "nuget: Scand.StormPetrel.Generator, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Scand.StormPetrel.Generator as a Cake Addin
#addin nuget:?package=Scand.StormPetrel.Generator&version=1.0.0

// Install Scand.StormPetrel.Generator as a Cake Tool
#tool nuget:?package=Scand.StormPetrel.Generator&version=1.0.0                

Scand Storm Petrel Generator

Scand Storm Petrel Generator

Overview<a name="overview"></a>

.NET Incremental Generator that creates modified copies of unit and/or integration tests to update expected baselines in original tests, automating baseline creation and accelerating test development.

Primary Use Cases<a name="primary-use-cases"></a>

Enabler: Auto-Generate CalculatorTestStormPetrel.AddTestStormPetrel<a name="use-case-enabler"></a>

Given

Calculator class with a bug introduced by the buggyDelta variable:

public class Calculator
{
    public static AddResult Add(int a, int b)
    {
        var buggyDelta = 1;
        var result = a + b + buggyDelta;
        return new AddResult
        {
            Value = result,
            ValueAsHexString = "0x" + result.ToString("x"),
        };
    }
}

public class AddResult
{
    public int Value { get; set; }
    public string ValueAsHexString { get; set; } = string.Empty;
}

And its corresponding test with an expected baseline that matches the Calculator.Add buggy behavior:

public class CalculatorTest
{
    [Xunit.Fact]
    public void AddTest()
    {
        //Arrange
        // incorrect `expected` baseline value will be overwritten with correct `actual` value
        // after manual execution of auto-generated AddTestStormPetrel test.
        var expected = new AddResult
        {
            Value = 5, //incorrect value example
            ValueAsHexString = "0x5"
        };

        //Act
        var actual = Calculator.Add(2, 2);

        //Assert
        actual.Should().BeEquivalentTo(expected);
    }
}
When

The developer configures the test project with StormPetrel.Generator as per the Getting Started.

Then

A new test method, CalculatorTestStormPetrel.AddTestStormPetrel, is generated. This method is a specially modified copy of the original CalculatorTest.AddTest to overwrite its expected baseline.

Overwrite CalculatorTest.AddTest expected baseline <a name="use-case-overwrite-baseline"></a>

Given

CalculatorTestStormPetrel.AddTestStormPetrel is auto-generated after enabling Storm Petrel functionality.

When

The developer fixes buggyDelta to 0 and executes CalculatorTestStormPetrel.AddTestStormPetrel test.

Then

CalculatorTest.AddTest code is populated with correct expected baseline value, i.e. its code becomes

public class CalculatorTest
{
    [Xunit.Fact]
    public void AddTest()
    {
        //Arrange
        // incorrect `expected` baseline value will be overwritten with correct `actual` value
        // after manual execution of auto-generated AddTestStormPetrel test.
        var expected = new AddResult
        {
            Value = 4,
            ValueAsHexString = "0x4"
        };

        //Act
        var actual = Calculator.Add(2, 2);

        //Assert
        actual.Should().BeEquivalentTo(expected);
    }
}
So that

The developer should only review expected baseline changes (no manual modification) what typically saves development time.

Overwrite CalculatorTestTheory.AddTestGetExpected expected baseline method<a name="use-case-overwrite-baseline-get-expected-method"></a>

Given

CalculatorTestTheory.AddTest test below with

  • multiple use cases;
  • AddTestGetExpected static method call returning incorrect expected baselines based on arguments;
  • AddTestGetExpected method possible variations per its comments.
public class CalculatorTestTheory
{
    [Xunit.Theory]
    [Xunit.InlineData(1, 5)]
    [Xunit.InlineData(2, 2)]
    [Xunit.InlineData(2, 3)]
    public void AddTest(int a, int b)
    {
        //Arrange
        var expected = AddTestGetExpected(a, b);

        //Act
        var actual = Calculator.Add(a, b);

        //Assert
        actual.Should().BeEquivalentTo(expected);
    }

    /// <summary>
    /// Possible variations of AddTestGetExpected static method are:
    /// - Method body may have pattern matches within pattern matches.
    /// - Method body may have `switch` and/or `if` expressions with return statements returning expected baselines.
    /// - The method may be placed in another class and/or file.
    /// </summary>
    private static AddResult AddTestGetExpected(int a, int b) => (a, b) switch
    {
        (1, 5) => new AddResult(), // should be overwritten with correct expected baseline after
                                   // CalculatorTestTheoryStormPetrel.AddTestStormPetrel execution
        (2, 2) => new AddResult(),
        (2, 3) => new AddResult(),
        _ => throw new InvalidOperationException(),
    };
}
When

The developer executes CalculatorTestTheoryStormPetrel.AddTestStormPetrel test.

Then

CalculatorTestTheory.AddTestGetExpected code is populated with correct expected baseline values, i.e. its code becomes

private static AddResult AddTestGetExpected(int a, int b) => (a, b) switch
{
    (1, 5) => new AddResult
    {
        Value = 6,
        ValueAsHexString = "0x6"
    }, //should be overwritten with correct expected baseline
    (2, 2) => new AddResult
    {
        Value = 4,
        ValueAsHexString = "0x4"
    },
    (2, 3) => new AddResult
    {
        Value = 5,
        ValueAsHexString = "0x5"
    },
    _ => throw new InvalidOperationException(),
};
So that

The developer should only review expected baseline changes (no manual modification) what typically saves development time.

Use Case Variations<a name="use-case-variations"></a>

  • Expected variable expression is static property assignment. See <a href="Test.Integration.XUnit/PropertyTest.cs">PropertyTest.cs</a> for more details.
  • Expected expression is test method argument what comes from test attribute (Xunit.InlineData or other) argument value. See <a href="Test.Integration.XUnit/AttributesTest.cs">AttributesTest.cs</a> for more details.

Getting Started<a name="getting-started"></a>

To utilize the StormPetrel tests, add the following NuGet Package references to your test project:

  • Scand.StormPetrel.Generator.
  • Object to C# code dumper. Represents actual test instance as C# code. See DumperExpression in Configuration for more details.
    • Option A. VarDump. Must be referenced in the case of StormPetrel.Generator default configuration (no appsettings.StormPetrel.json file in the test project). May be additionally configured.
    • Option B. ObjectDumper.NET. May be referenced and configured.
    • Option C. Custom implementation of IGeneratorDumper interface. May be developed and configured.

Configuration<a name="configuration"></a>

The StormPetrel Generator introduces several interfaces and classes to the Scand.StormPetrel.Generator.TargetProject namespace of the test project. These can be utilized alongside an optional JSON file to customize the rewriting of expected baselines. Key interfaces and classes include:

  • IGenerator, Generator;
  • IGeneratorBackuper, GeneratorBackuper;
  • IGeneratorDumper, GeneratorDumper;
  • IGeneratorRewriter, GeneratorRewriter.

Optionally appsettings.StormPetrel.json file (its Build Action should be C# analyzer additional file) can be added to a test project to configure Storm Petrel functionality. The file changes are applied on the fly and can have the following settings:

{
  "TargetProjectGeneratorExpression": "...", // [optional] string, configures the default `Generator`. An expression for the `IGenerator` instance.
  "GeneratorConfig":             // [optional] object to configure `Generator` behavior.
  {
    "BackuperExpression": "...", // [optional] string, instantiates `GeneratorBackuper` by default. An expression for the `IGeneratorBackuper` instance. Set to 'null' to skip creating backup files.
    "DumperExpression": "...",   // [optional] string, instantiates `GeneratorDumper` by default. An expression for the `IGeneratorDumper` instance. `GeneratorDumper` references [VarDump](https://www.nuget.org/packages/VarDump) stuff. Use
                                 // - "new Scand.StormPetrel.Generator.TargetProject.GeneratorDumper(CustomCSharpDumperProvider.GetCSharpDumper())" to have `VarDump` with custom options. Need to implement `CustomCSharpDumperProvider.GetCSharpDumper()` method in this case.
                                 // - "new Scand.StormPetrel.Generator.TargetProject.GeneratorObjectDumper()" expression for `GeneratorObjectDumper` instance which references [ObjectDumper.NET](https://github.com/thomasgalliker/ObjectDumper) stuff.
                                 // - "new Scand.StormPetrel.Generator.TargetProject.GeneratorObjectDumper(CustomOptionsProvider.GetDumpOptions())" to have `ObjectDumper.NET` with custom options. Need to implement `CustomOptionsProvider.GetDumpOptions()` method in this case.
                                 // - "new CustomClassImplementingIGeneratorDumper()" or similar expression to have totally custom implementation of dumping of an instance to C# code.
    "RewriterExpression": "..."  // [optional] string, instantiates `GeneratorRewriter` by default. An expression for the `IGeneratorRewriter` instance.
  },
  "IsDisabled": false,           // [optional] boolean, false is by default. Indicates whether the generator should create 'StormPetrel' classes.
                                 // Even if set to 'false', the generator still adds classes like 'IGeneratorDumper', 'GeneratorDumper' to avoid test project compilation failures
                                 // in the case when custom classes uses them.
  "IgnoreFilePathRegex": "...",  // [optional] string, empty by default. Regular Expression to exclude certain paths from 'StormPetrel' class generation.
  "Serilog": "...",              // [optional] Logging configuration using Serilog (https://github.com/serilog/serilog-settings-configuration?tab=readme-ov-file#serilogsettingsconfiguration--).
                                 // Defaults to logging warnings to the test project's Logs folder. Set to 'null' to disable logging.
                                 // Use the '{StormPetrelRootPath}' token to indicate the target test project root path.
  "TestVariablePairConfigs": [   // [optional] array of objects. Configures naming pairs for actual/expected variables to generate correct expected baselines.
    {
      "ActualVarNameTokenRegex": "[Aa]{1}ctual",     // Default configuration object. Assumes variable pair names like (expected, actual), (myExpected, myActual), (expectedOne, actualOne), (ExpectedTwo, ActualTwo), etc.
      "ExpectedVarNameTokenRegex": "[Ee]{1}xpected", // Corresponds to the `ActualVarNameTokenRegex` for pairing.
    }
  ]
}

Supported Software<a name="supported-software"></a>

Test Frameworks<a name="supported-test-frameworks"></a>

  • <a href="https://xunit.net/">xUnit</a>
  • <a href="https://nunit.org/">NUnit</a>
  • <a href="https://github.com/microsoft/testfx/">MSTest</a>

.NET Versions<a name="supported-net-versions"></a>

  • .NET Standard 2.0+
  • .NET 8.0+
  • .NET Framework 4.6.2+

References<a name="references"></a>

At SCAND, we specialize in building advanced .NET solutions to help businesses develop new or modernize their legacy applications. If you need help getting started with Storm Petrel or support with implementation, we're ready to assist. Whether you're refactoring or rewriting, our team can help solve any challenges you might face. Visit our page to learn more, or reach out for hands-on guidance.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 69 9/10/2024

Initial release.