diff --git a/.editorconfig b/.editorconfig
index 8738748..175c36f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -42,7 +42,7 @@ indent_size = 4
generated_code = true
# XML project files
-[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,nativeproj,locproj}]
+[*.{slnx,csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,nativeproj,locproj}]
indent_size = 2
# Xml build files
diff --git a/.github/template-sync.yml b/.github/template-sync.yml
deleted file mode 100644
index 23f98f8..0000000
--- a/.github/template-sync.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-# Every time I update this file without changing the content, I increment this counter.
-# Counter: 2
-
-files:
- - "!**/*"
- - ".commitlintrc"
- - ".csharpierignore"
- - ".gitattributes"
- - ".gitignore"
- - ".mcp.json"
- - "AGENTS.md"
- - "GitVersion.yml"
- - "global.json"
- - "nuget.config"
- - "renovate.json"
- - "testEnvironments.json"
- - ".github/CODEOWNERS"
- - ".github/copilot-instructions.md"
- - ".github/dependabot.yml"
- - ".github/FUNDING.yml"
- - ".github/release-drafter.yml"
- - ".github/instructions/**/*"
- - ".github/ISSUE_TEMPLATE/**/*"
- - ".github/PULL_REQUEST_TEMPLATE/**/*"
- - ".github/workflows/update-license.yml"
- - ".vscode/**/*"
- - "decisions/**/*"
- - "templates/**/*"
-
- # you probably want to exclude these files:
- - "!.github/workflows/dependabot-merge.yml"
- - "!.github/workflows/template-sync.yml"
- - "!.github/template-sync.yml"
diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml
index 03fd106..e09d494 100644
--- a/.github/workflows/cicd.yml
+++ b/.github/workflows/cicd.yml
@@ -28,9 +28,13 @@ jobs:
all:
if: github.run_id != 1
name: Build & Tests
- uses: dailydevops/pipelines/.github/workflows/build-dotnet-single.yml@cb37352bc6f2f8b723d966d5d879625d3dd5413b # 1.3.13
+ uses: dailydevops/pipelines/.github/workflows/build-dotnet-matrix.yml@cb37352bc6f2f8b723d966d5d879625d3dd5413b # 1.3.13
with:
+ disableTestsOnLinux: false
+ disableTestsOnMacOs: false
+ disableTestsOnWindows: false
dotnetLogging: ${{ inputs.dotnet-logging }}
dotnetVersion: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
+ failFast: false
solution: ./ProjectBuilders.slnx
secrets: inherit
diff --git a/.github/workflows/template-sync.yml b/.github/workflows/template-sync.yml
deleted file mode 100644
index 7214288..0000000
--- a/.github/workflows/template-sync.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Update template files
-
-on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
- workflow_dispatch:
-
-permissions:
- contents: write
-
-jobs:
- template-sync:
- if: github.actor != 'dependabot[bot]' && github.repository == 'dailydevops/dotnet-template'
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
-
- - uses: ahmadnassri/action-template-repository-sync@3dbe8f75504de32c7dab84dd6820b94ba9e98708 # v2.6.10
- with:
- github-token: ${{ secrets.TEMPLATE_SYNC }}
- dry-run: false
- skip-ci: true
diff --git a/Directory.Build.props b/Directory.Build.props
index c6df64b..c2cec22 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,15 +1,16 @@
$(MSBuildProjectName)
-
-
-
+ Allows you to create a temporary .NET project with all possible settings and few bells and whistles.
+ https://github.com/dailydevops/projectbuilders.git
+ https://github.com/dailydevops/projectbuilders
$(RepositoryUrl)/releases
-
- 2024
+ test;projectbuilder
+ 2025
+
-
- net8.0
+ net8.0;net9.0;net10.0
+ net8.0;net9.0;net10.0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index e074cbc..ff3d083 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -12,4 +12,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/ProjectBuilders.slnx b/ProjectBuilders.slnx
index ba788ff..3c1d8cc 100644
--- a/ProjectBuilders.slnx
+++ b/ProjectBuilders.slnx
@@ -1,2 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.ProjectBuilders.TUnit/NetEvolve.ProjectBuilders.TUnit.csproj b/src/NetEvolve.ProjectBuilders.TUnit/NetEvolve.ProjectBuilders.TUnit.csproj
new file mode 100644
index 0000000..396d36b
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders.TUnit/NetEvolve.ProjectBuilders.TUnit.csproj
@@ -0,0 +1,12 @@
+
+
+ $(ProjectTargetFrameworks)
+ NetEvolve.ProjectBuilders
+
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.ProjectBuilders.TUnit/TemporaryDirectory.cs b/src/NetEvolve.ProjectBuilders.TUnit/TemporaryDirectory.cs
new file mode 100644
index 0000000..009d74f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders.TUnit/TemporaryDirectory.cs
@@ -0,0 +1,89 @@
+namespace NetEvolve.ProjectBuilders;
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+using TUnit.Core.Interfaces;
+
+///
+/// Represents a temporary directory that is automatically created and cleaned up for TUnit tests.
+///
+///
+///
+/// This class serves as a TUnit-specific adapter around
+/// to provide seamless integration with TUnit's test lifecycle management. It implements both
+/// for automatic initialization and
+/// for automatic cleanup.
+///
+///
+/// The temporary directory is automatically:
+///
+/// - Created before test execution via
+/// - Cleaned up and deleted after test completion via
+/// - Placed in a unique location to avoid conflicts between parallel test executions
+///
+///
+///
+/// Provides directory and file management methods through ,
+/// including directory creation, file creation, and path resolution.
+///
+///
+/// Usage example in TUnit tests:
+///
+/// [ClassDataSource<TemporaryDirectory>]
+/// public class MyTests(TemporaryDirectory directory)
+/// {
+/// [Test]
+/// public async Task TestCreateFile()
+/// {
+/// using var stream = directory.CreateFile("test.txt");
+/// stream.WriteAsync(new byte[] { 1, 2, 3 }, 0, 3);
+///
+/// string fullPath = directory.GetFilePath("test.txt");
+/// Assert.That(File.Exists(fullPath));
+/// }
+///
+/// [Test]
+/// public void TestCreateDirectory()
+/// {
+/// var subDir = directory.CreateDirectory("subdirectory");
+/// Assert.That(Directory.Exists(Path.Combine(directory.FullPath, "subdirectory")));
+/// }
+/// }
+///
+///
+///
+///
+///
+///
+public sealed class TemporaryDirectory : ITemporaryDirectoryBuilder, IAsyncInitializer
+{
+ private readonly TemporaryDirectoryBuilder _directory = new();
+
+ ///
+ public string FullPath => _directory.FullPath;
+
+ ///
+ public ValueTask CreateAsync(CancellationToken cancellationToken = default) =>
+ _directory.CreateAsync(cancellationToken);
+
+ ///
+ public ISubdirectoryBuilder CreateDirectory(string directoryName) => _directory.CreateDirectory(directoryName);
+
+ ///
+ public Stream CreateFile(string fileName) => _directory.CreateFile(fileName);
+
+ ///
+ public async Task DisposeAsync() => await _directory.DisposeAsync().ConfigureAwait(false);
+
+ ///
+ public string GetFilePath(string fileName) => _directory.GetFilePath(fileName);
+
+ ///
+ async Task IAsyncInitializer.InitializeAsync() => await _directory.CreateAsync().ConfigureAwait(false);
+
+ ///
+ async ValueTask IAsyncDisposable.DisposeAsync() => await DisposeAsync().ConfigureAwait(false);
+}
diff --git a/src/NetEvolve.ProjectBuilders.XUnit/NetEvolve.ProjectBuilders.XUnit.csproj b/src/NetEvolve.ProjectBuilders.XUnit/NetEvolve.ProjectBuilders.XUnit.csproj
new file mode 100644
index 0000000..335dd64
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders.XUnit/NetEvolve.ProjectBuilders.XUnit.csproj
@@ -0,0 +1,12 @@
+
+
+ $(ProjectTargetFrameworks)
+ NetEvolve.ProjectBuilders
+
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.ProjectBuilders.XUnit/TemporaryDirectoryFixture.cs b/src/NetEvolve.ProjectBuilders.XUnit/TemporaryDirectoryFixture.cs
new file mode 100644
index 0000000..9f31703
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders.XUnit/TemporaryDirectoryFixture.cs
@@ -0,0 +1,125 @@
+namespace NetEvolve.ProjectBuilders;
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+using Xunit;
+
+///
+/// Represents a temporary directory fixture that is automatically created and cleaned up for xUnit tests.
+///
+///
+///
+/// This class serves as an xUnit-specific adapter around
+/// to provide seamless integration with xUnit's test lifecycle management through the fixture pattern.
+/// It implements for automatic initialization and cleanup.
+///
+///
+/// The temporary directory is automatically:
+///
+/// - Created before test execution via
+/// - Cleaned up and deleted after test completion via
+/// - Placed in a unique location to avoid conflicts between parallel test executions
+///
+///
+///
+/// Provides directory and file management methods through ,
+/// including directory creation, file creation, and path resolution.
+///
+///
+/// Works with xUnit class fixtures and collection fixtures for flexible test lifecycle management.
+///
+///
+/// Class fixture usage example:
+///
+/// public class MyTests : IClassFixture<TemporaryDirectoryFixture>
+/// {
+/// private readonly TemporaryDirectoryFixture _directory;
+///
+/// public MyTests(TemporaryDirectoryFixture directory)
+/// {
+/// _directory = directory;
+/// }
+///
+/// [Fact]
+/// public void TestCreateFile()
+/// {
+/// // Directory is automatically initialized before this test runs
+/// using var stream = _directory.CreateFile("test.txt");
+/// var fullPath = _directory.GetFilePath("test.txt");
+/// Assert.True(File.Exists(fullPath));
+/// // Directory is automatically cleaned up after this test completes
+/// }
+/// }
+///
+///
+///
+/// Collection fixture usage example:
+///
+/// [CollectionDefinition("Temporary Directory Collection")]
+/// public class TemporaryDirectoryCollection : ICollectionFixture<TemporaryDirectoryFixture>
+/// {
+/// }
+///
+/// [Collection("Temporary Directory Collection")]
+/// public class MyTests
+/// {
+/// private readonly TemporaryDirectoryFixture _directory;
+///
+/// public MyTests(TemporaryDirectoryFixture directory)
+/// {
+/// _directory = directory;
+/// }
+///
+/// [Fact]
+/// public void TestOne()
+/// {
+/// // Directory is shared across all tests in the collection
+/// using var stream = _directory.CreateFile("test1.txt");
+/// }
+///
+/// [Fact]
+/// public void TestTwo()
+/// {
+/// // Same directory instance from TestOne
+/// using var stream = _directory.CreateFile("test2.txt");
+/// }
+/// }
+///
+///
+///
+///
+///
+///
+///
+public sealed class TemporaryDirectoryFixture : ITemporaryDirectoryBuilder, IAsyncLifetime
+{
+ private readonly TemporaryDirectoryBuilder _directory = new();
+
+ ///
+ public string FullPath => _directory.FullPath;
+
+ ///
+ public ValueTask CreateAsync(CancellationToken cancellationToken = default) =>
+ _directory.CreateAsync(cancellationToken);
+
+ ///
+ public ISubdirectoryBuilder CreateDirectory(string directoryName) => _directory.CreateDirectory(directoryName);
+
+ ///
+ public Stream CreateFile(string fileName) => _directory.CreateFile(fileName);
+
+ ///
+ public async Task DisposeAsync() => await _directory.DisposeAsync().ConfigureAwait(false);
+
+ ///
+ public string GetFilePath(string fileName) => _directory.GetFilePath(fileName);
+
+ ///
+ async ValueTask IAsyncLifetime.InitializeAsync() => await _directory.CreateAsync().ConfigureAwait(false);
+
+ ///
+ async ValueTask IAsyncDisposable.DisposeAsync() => await DisposeAsync().ConfigureAwait(false);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IFileBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IFileBuilder.cs
new file mode 100644
index 0000000..42774ee
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IFileBuilder.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Represents a generic file builder interface for creating project files.
+///
+///
+///
+/// This interface serves as a base abstraction for all file builders in the project.
+/// It extends to provide async creation and disposal capabilities
+/// for file-based objects used in the project building process.
+///
+///
+/// Implementations of this interface are responsible for creating specific types of files,
+/// such as project files (.csproj, .vbproj) and configuration files (global.json).
+///
+///
+///
+///
+///
+public interface IFileBuilder : IObjectBuilder { }
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IGlobalJsonBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IGlobalJsonBuilder.cs
new file mode 100644
index 0000000..0bb7059
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IGlobalJsonBuilder.cs
@@ -0,0 +1,78 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Represents a builder for creating and configuring global.json SDK configuration files.
+///
+///
+///
+/// This interface provides a fluent API for building global.json files that configure
+/// the .NET SDK version and roll-forward behavior for a project or directory tree.
+///
+///
+/// The global.json file is used to:
+///
+/// - Pin a specific .NET SDK version for the project
+/// - Configure SDK roll-forward policies
+/// - Allow or disallow prerelease SDK versions
+///
+///
+///
+/// See for more information.
+///
+///
+///
+public interface IGlobalJsonBuilder : IFileBuilder
+{
+ ///
+ /// Configures whether prerelease SDK versions are allowed for this project.
+ ///
+ ///
+ /// When set to , the .NET SDK resolution will consider prerelease
+ /// versions that match the specified major, minor, and patch versions. The default is
+ /// , which restricts to released SDK versions only.
+ ///
+ ///
+ /// to allow prerelease SDK versions; otherwise.
+ ///
+ /// The current instance of the for fluent chaining.
+ IGlobalJsonBuilder SetAllowPrerelease(bool allowPrerelease);
+
+ ///
+ /// Sets the roll-forward behavior for SDK version resolution.
+ ///
+ ///
+ /// The roll-forward policy determines how the SDK resolves versions when the exact
+ /// specified version is not available. Different policies allow rolling forward to
+ /// different release levels (patch, feature, minor, or major).
+ ///
+ ///
+ /// The roll-forward policy to apply. For example,
+ /// allows rolling forward to the latest patch and feature level within the same major.minor version.
+ ///
+ /// The current instance of the for fluent chaining.
+ ///
+ IGlobalJsonBuilder SetRollForward(RollForward rollForward);
+
+ ///
+ /// Sets the .NET SDK version to use for this project or directory tree.
+ ///
+ ///
+ /// The version string should be in semantic versioning format, for example "8.0.204" or "10.0.100".
+ /// This version becomes the preferred SDK version for all dotnet commands executed in this
+ /// directory and its subdirectories (unless overridden by nested global.json files).
+ ///
+ ///
+ /// The SDK version as a string (e.g., "8.0.204", "10.0.100").
+ /// Must not be , empty, or whitespace.
+ ///
+ /// The current instance of the for fluent chaining.
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ /// Thrown when is empty or whitespace.
+ ///
+ IGlobalJsonBuilder SetRuntimeSdk(string runtimeVersion);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroup.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroup.cs
new file mode 100644
index 0000000..fb11471
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroup.cs
@@ -0,0 +1,42 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.Collections.ObjectModel;
+
+///
+/// Represents an ItemGroup element in an MSBuild project file.
+///
+///
+///
+/// The ItemGroup is one of the fundamental building blocks in MSBuild project files. It contains
+/// items that represent inputs to the build process, such as package references, project references,
+/// framework references, and other file-based items.
+///
+///
+/// Each item in the group can have various attributes and properties that influence how the
+/// build system processes it. Items can be conditional using the Condition attribute.
+///
+///
+/// See for more information.
+///
+///
+public interface IItemGroup
+{
+ ///
+ /// Gets a read-only collection of items in this item group.
+ ///
+ /// A read-only collection of objects.
+ ReadOnlyCollection Items { get; }
+
+ ///
+ /// Adds a new item of the specified type to this item group.
+ ///
+ ///
+ /// The type of the item to add. Must be a non-abstract class implementing
+ /// with a public parameterless constructor.
+ ///
+ ///
+ /// The newly created and added item instance.
+ ///
+ T Add()
+ where T : class, IItemGroupItem, new();
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroupItem.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroupItem.cs
new file mode 100644
index 0000000..0578f08
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IItemGroupItem.cs
@@ -0,0 +1,83 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Helpers;
+
+///
+/// Represents an item element within an ItemGroup in an MSBuild project file.
+///
+///
+///
+/// Item group items are the fundamental units of information that get passed to MSBuild tasks.
+/// Each item can represent various types of project content such as package references,
+/// project references, assembly references, or source code files.
+///
+///
+/// Items have metadata that can be set through properties, and they support conditional evaluation
+/// through the Condition attribute and organizational grouping through the Label attribute.
+///
+///
+/// See for more information.
+///
+///
+public interface IItemGroupItem
+{
+ ///
+ /// Gets the name (element type) of the item group item.
+ ///
+ ///
+ /// The name determines the type of item within the project. Common names include:
+ ///
+ /// - PackageReference - NuGet package dependencies
+ /// - ProjectReference - Local project dependencies
+ /// - Reference - Assembly references
+ /// - FrameworkReference - Built-in framework references
+ ///
+ ///
+ /// The item type name as a string.
+ string Name { get; }
+
+ ///
+ /// Gets the optional condition that must evaluate to true for this item to be included.
+ ///
+ ///
+ /// This allows for conditional inclusion of items based on project properties, target frameworks,
+ /// platforms, or other build conditions. When , the item is always included.
+ ///
+ /// A condition string (e.g., "'$(TargetFramework)' == 'net8.0'"), or if no condition is set.
+ string? Condition => null;
+
+ ///
+ /// Gets the optional label for organizing and identifying related items.
+ ///
+ ///
+ /// Labels are optional tags that can be used to organize items logically or identify groups
+ /// of related items. They don't affect the build process but can be useful for documentation
+ /// and organization of complex project files.
+ ///
+ /// A descriptive label string, or if no label is set.
+ string? Label => null;
+
+ ///
+ /// Gets the value to include in the item.
+ ///
+ ///
+ ///
+ /// The Include attribute specifies what the item refers to. For package references, this would be
+ /// the package name; for project references, it would be the project file path; for file items,
+ /// it would be the file path pattern.
+ ///
+ ///
+ /// Wildcards and property references (e.g., $(SomeProperty)) are typically supported depending
+ /// on the item type.
+ ///
+ ///
+ /// The include value as a string, typically a package name or file path.
+ string? Include { get; }
+
+ ///
+ /// Converts this item group item to its XML representation.
+ ///
+ /// An representing the MSBuild item element with all its attributes and metadata.
+ XElement GetXElement();
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IObjectBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IObjectBuilder.cs
new file mode 100644
index 0000000..781ce89
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IObjectBuilder.cs
@@ -0,0 +1,45 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+///
+/// Represents the base abstraction for all object builders in the project creation pipeline.
+///
+///
+///
+/// This interface defines the core contract for objects that can create and manage
+/// file system artifacts asynchronously. All builders in the library implement this interface
+/// to ensure consistent lifecycle management and resource cleanup.
+///
+///
+/// Implementations are expected to provide proper resource disposal through the inherited
+/// interface, ensuring that all created temporary files and
+/// directories are properly cleaned up.
+///
+///
+public interface IObjectBuilder : IAsyncDisposable
+{
+ ///
+ /// Gets the full path of the created object in the file system.
+ ///
+ /// An absolute path to the object being built.
+ string FullPath { get; }
+
+ ///
+ /// Asynchronously creates the object and writes it to the file system.
+ ///
+ ///
+ /// This method is responsible for all I/O operations required to persist the object
+ /// to the file system. Implementations should be exception-safe and properly handle
+ /// cancellation tokens.
+ ///
+ ///
+ /// A token that can be used to request cancellation of the creation operation.
+ ///
+ ///
+ /// A representing the asynchronous operation.
+ ///
+ ValueTask CreateAsync(CancellationToken cancellationToken = default);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IProjectBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IProjectBuilder.cs
new file mode 100644
index 0000000..3ee8f5f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IProjectBuilder.cs
@@ -0,0 +1,127 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System;
+using System.IO;
+
+///
+/// Represents a builder for creating and configuring MSBuild project files.
+///
+///
+///
+/// This interface provides a fluent API for constructing .NET project files (both .csproj and .vbproj).
+/// It allows configuration of project SDK, target frameworks, properties, and item references in a
+/// type-safe, programmatic manner.
+///
+///
+/// The builder manages two main sections of a project file:
+///
+/// - PropertyGroup: Defines build properties like TargetFramework, Nullable, Configuration
+/// - ItemGroup: Defines project items like PackageReference, ProjectReference, FrameworkReference
+///
+///
+///
+/// Usage example:
+///
+/// var builder = factory.AddFileBuilder<IProjectBuilder, ProjectBuilder>(
+/// new ProjectBuilder(directory, "test.csproj")
+/// );
+/// builder
+/// .SetProjectSdk("Microsoft.NET.Sdk")
+/// .WithTargetFramework(TargetFramework.Net8)
+/// .WithNullable(NullableOptions.Enable);
+///
+///
+///
+///
+public interface IProjectBuilder : IFileBuilder
+{
+ ///
+ /// Creates a file in the project directory.
+ ///
+ ///
+ /// This method allows creation of additional files alongside the project file, such as
+ /// source code files, configuration files, or other project resources.
+ ///
+ /// The name of the file to create (e.g., "Program.cs", "appsettings.json").
+ ///
+ /// A writeable to the created file. The caller must dispose this stream.
+ ///
+ Stream CreateFile(string fileName);
+
+ ///
+ /// Gets or adds an item group item of the specified type.
+ ///
+ ///
+ ///
+ /// If an item of the specified type already exists in the ItemGroup, it is returned.
+ /// Otherwise, a new item of that type is created and added.
+ ///
+ ///
+ /// This method is useful for ensuring only one instance of a particular item type exists,
+ /// such as a single TargetFramework property.
+ ///
+ ///
+ ///
+ /// The type of the item to get or add. Must implement and
+ /// have a public parameterless constructor.
+ ///
+ ///
+ /// The existing or newly created item of type .
+ ///
+ T GetOrAddItemGroupItem()
+ where T : class, IItemGroupItem, new();
+
+ ///
+ /// Gets or adds a property group item of the specified type.
+ ///
+ ///
+ ///
+ /// If a property of the specified type already exists in the PropertyGroup, it is returned.
+ /// Otherwise, a new property of that type is created and added.
+ ///
+ ///
+ /// This method is useful for ensuring only one instance of a particular property type exists,
+ /// such as a single TargetFramework or Nullable property.
+ ///
+ ///
+ ///
+ /// The type of the property to get or add. Must implement and
+ /// have a public parameterless constructor.
+ ///
+ ///
+ /// The existing or newly created property of type .
+ ///
+ T GetOrAddPropertyGroupItem()
+ where T : class, IPropertyGroupItem, new();
+
+ ///
+ /// Sets the SDK used by the project file.
+ ///
+ ///
+ ///
+ /// The SDK attribute on the Project element determines which build system and tools are used.
+ /// Common values include:
+ ///
+ /// - Microsoft.NET.Sdk - Standard .NET Console, Class Library, ASP.NET Core applications
+ /// - Microsoft.NET.Sdk.Web - ASP.NET Core web applications
+ /// - Microsoft.NET.Sdk.WindowsDesktop - WPF and Windows Forms applications
+ ///
+ ///
+ ///
+ /// If the SDK has already been set, calling this method overwrites the previous value.
+ ///
+ ///
+ ///
+ /// The SDK identifier (e.g., "Microsoft.NET.Sdk"). Must not be , empty, or whitespace.
+ ///
+ ///
+ /// The current instance of for fluent chaining.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ /// Thrown when is empty or contains only whitespace.
+ ///
+ IProjectBuilder SetProjectSdk(string sdk);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IProjectFactory.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IProjectFactory.cs
new file mode 100644
index 0000000..4464651
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IProjectFactory.cs
@@ -0,0 +1,193 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Models.Output;
+
+///
+/// Provides a fluent API for creating, configuring, and building .NET projects for testing.
+///
+///
+///
+/// This interface is the primary entry point for the ProjectBuilders library. It enables
+/// the creation of test projects with specific configurations, from basic structure to complex
+/// multi-framework setups with custom properties and references.
+///
+///
+/// The factory manages the complete lifecycle:
+///
+/// - Creating a temporary, isolated directory structure
+/// - Adding and configuring project files (C#, VB.NET)
+/// - Adding configuration files (global.json)
+/// - Setting environment variables for build execution
+/// - Executing dotnet build and restore commands
+/// - Capturing and analyzing SARIF diagnostic output
+///
+///
+///
+/// Usage example:
+///
+/// using var factory = ProjectFactory.Create();
+/// factory
+/// .AddCSharpProject(pb => pb
+/// .WithDefaults()
+/// .WithTargetFramework(TargetFramework.Net8))
+/// .AddGlobalJson(configure: gb => gb.WithDefaults())
+/// .AddEnvironmentVariable("MYVAR", "myvalue");
+///
+/// var result = await factory.BuildAsync();
+/// if (result.HasErrors())
+/// {
+/// foreach (var error in result.Results.Where(r => r.Level == "error"))
+/// {
+/// Console.WriteLine($"{error.RuleId}: {error.Message}");
+/// }
+/// }
+///
+///
+///
+///
+public interface IProjectFactory : IAsyncDisposable
+{
+ ///
+ /// Adds or updates an environment variable for project execution.
+ ///
+ ///
+ ///
+ /// Environment variables set through this method are passed to the dotnet build and restore
+ /// commands when the project is built. If the variable already exists, its value is updated.
+ ///
+ ///
+ /// Some variables are pre-configured for test execution (CI, DOTNET_CLI_TELEMETRY_OPTOUT, etc.)
+ /// and can be overridden with this method.
+ ///
+ ///
+ ///
+ /// The name of the environment variable. Must not be or whitespace.
+ ///
+ ///
+ /// The value of the environment variable. Can be to set the variable
+ /// without a value, or any string value.
+ ///
+ /// The current instance for fluent chaining.
+ ///
+ /// Thrown when is , empty, or whitespace.
+ ///
+ IProjectFactory AddEnvironmentVariable(string name, string? value);
+
+ ///
+ /// Adds multiple environment variables for project execution at once.
+ ///
+ ///
+ ///
+ /// This is a convenience method for adding multiple environment variables in a single call.
+ /// It's equivalent to calling multiple times.
+ ///
+ ///
+ /// If any variable already exists, it is updated with the new value.
+ ///
+ ///
+ ///
+ /// An array of key-value pairs representing environment variables to add.
+ /// Must not be . Individual values can be .
+ ///
+ /// The current instance for fluent chaining.
+ IProjectFactory AddEnvironmentVariables(params KeyValuePair[] variables);
+
+ ///
+ /// Adds a custom file builder to the project factory.
+ ///
+ ///
+ ///
+ /// This extensibility point allows registration of custom implementations
+ /// to support specialized file generation beyond the built-in C#/VB.NET projects and global.json files.
+ ///
+ ///
+ /// All registered builders are created when is called.
+ /// Attempting to add the same builder instance twice throws an exception.
+ ///
+ ///
+ ///
+ /// The interface type that the builder implements. Should be or a derived interface.
+ ///
+ ///
+ /// The concrete implementation type. Must implement .
+ ///
+ ///
+ /// The configured builder instance to register. Must not be .
+ ///
+ ///
+ /// The builder instance cast to , allowing for further
+ /// configuration or fluent chaining.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ /// Thrown when the builder instance has already been registered.
+ ///
+ TInterface AddFileBuilder(TImplementation builder)
+ where TInterface : IFileBuilder
+ where TImplementation : class, TInterface;
+
+ ///
+ /// Creates the entire project structure, executes the build, and returns the SARIF diagnostic output.
+ ///
+ ///
+ ///
+ /// This method orchestrates the complete build process:
+ ///
+ /// - Creates all registered file builders (projects, configuration files, etc.)
+ /// - Executes dotnet restore to restore NuGet packages
+ /// - Executes dotnet build with optional additional arguments
+ /// - Captures build output and diagnostic information
+ /// - Parses the generated SARIF file for diagnostic results
+ /// - Enriches SARIF results with diagnostic information from build output
+ ///
+ ///
+ ///
+ /// At least one project builder must be registered before calling this method, otherwise
+ /// an is thrown.
+ ///
+ ///
+ ///
+ /// Optional command-line arguments to pass to the dotnet build command. Can be
+ /// or empty to use default build behavior. Examples: "/p:Configuration=Release", "/p:Platform=x64".
+ ///
+ ///
+ /// A token to observe while waiting for the build operation to complete. Allows cancellation
+ /// of long-running builds.
+ ///
+ ///
+ /// A that returns an containing
+ /// the parsed SARIF diagnostic information from the build, including any errors or warnings.
+ ///
+ ///
+ /// Thrown when no project builders have been registered or no project file has been added.
+ ///
+ ///
+ /// Thrown when the build operation is cancelled via the cancellation token.
+ ///
+ ValueTask BuildAsync(string[]? args = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Gets the temporary directory builder used by this factory.
+ ///
+ ///
+ ///
+ /// This directory serves as the root for all project files, configuration files, and other
+ /// outputs created during the project building process. It's automatically created when the
+ /// first file is created and cleaned up when the factory is disposed.
+ ///
+ ///
+ /// Direct access to the directory builder allows advanced scenarios where custom files need
+ /// to be created or managed outside the standard builder pattern.
+ ///
+ ///
+ ///
+ /// An representing the temporary directory for this factory.
+ ///
+ ISubdirectoryBuilder DirectoryBuilder { get; }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroup.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroup.cs
new file mode 100644
index 0000000..8b092c7
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroup.cs
@@ -0,0 +1,42 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.Collections.ObjectModel;
+
+///
+/// Represents a PropertyGroup element in an MSBuild project file.
+///
+///
+///
+/// PropertyGroup elements contain project properties that define build behavior and metadata.
+/// Properties are key-value pairs that configure the build system, affect compilation, and
+/// control the packaging and deployment of projects.
+///
+///
+/// Common properties include TargetFramework, Configuration, Nullable, AssemblyVersion,
+/// and many others that influence how projects are built and packaged.
+///
+///
+/// See for more information.
+///
+///
+public interface IPropertyGroup
+{
+ ///
+ /// Gets a read-only collection of properties in this property group.
+ ///
+ /// A read-only collection of objects.
+ ReadOnlyCollection Items { get; }
+
+ ///
+ /// Adds a new property of the specified type to this property group.
+ ///
+ ///
+ /// The type of the property to add. Must be a non-abstract class implementing
+ /// with a public parameterless constructor.
+ ///
+ ///
+ /// The newly created and added property instance.
+ ///
+ T Add()
+ where T : class, IPropertyGroupItem, new();
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItem.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItem.cs
new file mode 100644
index 0000000..ffe4a69
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItem.cs
@@ -0,0 +1,100 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.Linq;
+using Microsoft.Extensions.Primitives;
+
+///
+/// Represents a property element within a PropertyGroup in an MSBuild project file.
+///
+///
+///
+/// Properties are name-value pairs that control build behavior. Unlike items, properties are
+/// scalar values (though they can contain semicolon-separated lists). Properties affect how
+/// the compiler is invoked, what frameworks are targeted, and many other aspects of the build.
+///
+///
+/// Properties can be conditional, labeled for organization, and can reference other properties
+/// or environment variables using MSBuild syntax $(PropertyName).
+///
+///
+/// See for more information.
+///
+///
+public interface IPropertyGroupItem
+{
+ ///
+ /// Gets the name of the property.
+ ///
+ ///
+ /// The property name is the element type in the project file. Examples include
+ /// TargetFramework, Nullable, Configuration, AssemblyVersion, and many others.
+ ///
+ /// The property name as a string.
+ string Name { get; }
+
+ ///
+ /// Gets the values assigned to this property.
+ ///
+ ///
+ ///
+ /// Although most properties have a single value, this interface supports multiple values
+ /// which are typically separated by semicolons when serialized to the project file.
+ ///
+ ///
+ /// Empty or unset values are represented by .
+ ///
+ ///
+ /// A collection representing the property values.
+ StringValues Values { get; }
+
+ ///
+ /// Gets the optional condition that must evaluate to true for this property to be set.
+ ///
+ ///
+ /// This allows for conditional property assignment based on project properties, target frameworks,
+ /// platforms, or other build conditions. When , the property is always set.
+ ///
+ /// A condition string, or if no condition is set.
+ string? Condition => null;
+
+ ///
+ /// Gets the optional label for organizing and identifying related properties.
+ ///
+ ///
+ /// Labels are optional tags that can be used to organize properties logically. They don't
+ /// affect the build process but can be useful for documentation and organization of complex
+ /// project files.
+ ///
+ /// A descriptive label string, or if no label is set.
+ string? Label => null;
+
+ ///
+ /// Gets a value indicating whether the property is null or has no values.
+ ///
+ ///
+ /// A property is considered null or empty if its Values collection is empty or contains
+ /// only whitespace, indicating that the property has not been assigned a meaningful value.
+ ///
+ ///
+ /// if the property has no values or only empty values;
+ /// if the property contains at least one non-empty value.
+ ///
+ bool IsNullOrEmpty => StringValues.IsNullOrEmpty(Values);
+
+ ///
+ /// Gets the value of the property as a single semicolon-delimited string.
+ ///
+ ///
+ ///
+ /// If the property contains multiple values, they are joined with semicolons to create
+ /// a single string representation suitable for use in the project file.
+ ///
+ ///
+ /// Duplicate values are removed when joining, ensuring each distinct value appears only once.
+ ///
+ ///
+ ///
+ /// A semicolon-delimited string of property values, or an empty string if the property has no values.
+ ///
+ string GetValue() => string.Join(';', Values.Distinct());
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItemOfT.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItemOfT.cs
new file mode 100644
index 0000000..ac50506
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IPropertyGroupItemOfT.cs
@@ -0,0 +1,58 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Represents a strongly-typed property element in a PropertyGroup that supports value mutation.
+///
+/// The type of values this property accepts.
+///
+///
+/// This generic interface extends to provide methods for setting
+/// property values in a type-safe manner. Implementations enforce validation and type conversions
+/// appropriate for the specific property type.
+///
+///
+/// For example, implements this interface with
+/// to ensure only valid target framework values are set.
+///
+///
+///
+public interface IPropertyGroupItem : IPropertyGroupItem
+{
+ ///
+ /// Sets the value of the property to a single value.
+ ///
+ ///
+ ///
+ /// CAUTION: This method overwrites any existing values. If you need to append rather than
+ /// replace, use instead or consider the property's append semantics.
+ ///
+ ///
+ /// The value is converted to the appropriate string representation for storage in the project file.
+ ///
+ ///
+ ///
+ /// The value to set. The method should handle appropriately based on
+ /// the implementation and property type.
+ ///
+ void SetValue(T value);
+
+ ///
+ /// Sets the values of the property to multiple values.
+ ///
+ ///
+ ///
+ /// CAUTION: This method overwrites any existing values. Multiple values are typically
+ /// stored as semicolon-separated entries in the project file.
+ ///
+ ///
+ /// Each value is converted to the appropriate string representation for storage.
+ ///
+ ///
+ ///
+ /// An array of values to set. Must not be . Empty array results in
+ /// clearing all values from the property.
+ ///
+ void SetValues(T[] values);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/IReference.cs b/src/NetEvolve.ProjectBuilders/Abstractions/IReference.cs
new file mode 100644
index 0000000..262b3af
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/IReference.cs
@@ -0,0 +1,104 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.Collections.Generic;
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Represents an item that provides lookup paths for resolving referenced packages or projects.
+///
+///
+///
+/// This interface extends to add the concept of lookup paths,
+/// which are file system directories where the referenced item's metadata (like .nuspec files)
+/// can be found. This is used during test setup to locate and process package or project references.
+///
+///
+/// Implementations include and ,
+/// which provide paths for locating NuGet package specifications and project files respectively.
+///
+///
+///
+///
+///
+///
+public interface IReference : IItemGroupItem
+{
+ ///
+ bool GeneratePathProperty { get; }
+
+ ///
+ /// Gets the collection of directory paths used for lookup operations.
+ ///
+ ///
+ ///
+ /// These paths are used to locate referenced resources such as NuGet packages or project files.
+ /// For project references, paths might include both the .nuspec file location and the project file path.
+ ///
+ ///
+ /// The default implementation returns an empty collection, allowing subclasses to override with
+ /// appropriate paths based on their reference type.
+ ///
+ ///
+ ///
+ /// An enumerable of absolute file system paths where referenced resources can be found.
+ /// Returns an empty enumeration if no lookup paths are applicable.
+ ///
+ IEnumerable LookUpPaths => [];
+
+ ///
+ /// Gets the optional alias name(s) to use for referencing this reference in code.
+ ///
+ ///
+ ///
+ /// Aliases allow you to reference the same assembly using different names to avoid naming conflicts.
+ /// Multiple aliases can be specified by separating them with commas.
+ ///
+ ///
+ /// See for more information on extern aliases.
+ ///
+ ///
+ /// A comma-separated list of alias names, or if no aliases are defined.
+ string? Aliases { get; }
+
+ ///
+ /// Gets the asset types to include from this reference.
+ ///
+ ///
+ ///
+ /// Controls which assets from the package are included in the build. When , all assets are included by default.
+ ///
+ ///
+ /// See for more information.
+ ///
+ ///
+ /// A flags enumeration of values, or to include all assets.
+ ReferenceAssets? IncludeAssets { get; }
+
+ ///
+ /// Gets the asset types to exclude from this reference.
+ ///
+ ///
+ ///
+ /// Controls which assets from the package are excluded from the build. Takes precedence over .
+ ///
+ ///
+ /// See for more information.
+ ///
+ ///
+ /// A flags enumeration of values, or to not exclude any assets.
+ ReferenceAssets? ExcludeAssets { get; }
+
+ ///
+ /// Gets the asset types that flow privately and are not exposed to dependent projects.
+ ///
+ ///
+ ///
+ /// Controls which assets from the package do not flow to consuming projects. Commonly used with analyzer packages or build tools.
+ ///
+ ///
+ /// See for more information.
+ ///
+ ///
+ /// A flags enumeration of values, or to allow all assets to flow.
+ ReferenceAssets? PrivateAssets { get; }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/ISubdirectoryBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/ISubdirectoryBuilder.cs
new file mode 100644
index 0000000..3eec812
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/ISubdirectoryBuilder.cs
@@ -0,0 +1,89 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using System.IO;
+
+///
+/// Represents a builder for creating and managing subdirectories and files within a directory hierarchy.
+///
+///
+///
+/// This interface extends to provide methods for creating subdirectories
+/// and files within a parent directory. It manages a portion of the file system hierarchy used by
+/// the project building process.
+///
+///
+/// Implementations support nested directory creation, file creation with stream access, and path queries
+/// to help manage the directory structure during test project building.
+///
+///
+///
+///
+public interface ISubdirectoryBuilder : IObjectBuilder
+{
+ ///
+ /// Creates a subdirectory within this directory.
+ ///
+ ///
+ ///
+ /// This method creates a new subdirectory hierarchy under the current directory and returns
+ /// a builder for that subdirectory, allowing for nested directory creation and manipulation.
+ ///
+ ///
+ /// The method supports fluent chaining to create multiple nested levels or perform operations
+ /// on the created subdirectory.
+ ///
+ ///
+ ///
+ /// The name of the subdirectory to create. Must not be , empty, or contain only whitespace.
+ /// Can be a simple name (e.g., "subdir") or a relative path (e.g., "parent/child").
+ ///
+ ///
+ /// An for the newly created subdirectory, supporting fluent chaining.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ /// Thrown when is empty, contains only whitespace characters,
+ /// or the subdirectory already exists.
+ ///
+ ISubdirectoryBuilder CreateDirectory(string directoryName);
+
+ ///
+ /// Creates a file in this directory.
+ ///
+ ///
+ ///
+ /// This method creates a new file in the directory and returns a writeable stream for writing content.
+ /// The stream must be disposed after writing to ensure proper file closure and flushing.
+ ///
+ ///
+ /// If a file with the same name already exists, an exception is thrown to prevent accidental overwriting.
+ ///
+ ///
+ /// The name of the file to create. Must not be or empty.
+ ///
+ /// A writeable to the newly created file. The caller is responsible for
+ /// disposing this stream after writing.
+ ///
+ ///
+ /// Thrown when a file with the specified name already exists in this directory.
+ ///
+ Stream CreateFile(string fileName);
+
+ ///
+ /// Gets the full path of a file in this directory.
+ ///
+ ///
+ ///
+ /// This method constructs the absolute path to a file without creating it. It's useful for
+ /// reading or referencing files after they've been created.
+ ///
+ ///
+ /// The returned path is absolute and suitable for use with standard File I/O operations.
+ ///
+ ///
+ /// The name of the file to get the path for. Must not be or empty.
+ /// The absolute path to the file.
+ string GetFilePath(string fileName);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/ITemporaryDirectoryBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/ITemporaryDirectoryBuilder.cs
new file mode 100644
index 0000000..5da7244
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/ITemporaryDirectoryBuilder.cs
@@ -0,0 +1,25 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+using NetEvolve.ProjectBuilders.Builders;
+
+///
+/// Represents a temporary directory builder for creating isolated, auto-cleaning temporary directories.
+///
+///
+///
+/// This interface extends to provide specialized behavior
+/// for managing temporary directories that are automatically created and cleaned up after use.
+///
+///
+/// Temporary directories created through this interface are:
+///
+/// - Created in the system's temporary folder with unique identifiers
+/// - Isolated from other test execution contexts
+/// - Automatically deleted when disposed, ensuring clean test environments
+/// - Protected against file system pollution and leftover test artifacts
+///
+///
+///
+///
+///
+public interface ITemporaryDirectoryBuilder : ISubdirectoryBuilder { }
diff --git a/src/NetEvolve.ProjectBuilders/Abstractions/ITestPackageBuilder.cs b/src/NetEvolve.ProjectBuilders/Abstractions/ITestPackageBuilder.cs
new file mode 100644
index 0000000..8e26271
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Abstractions/ITestPackageBuilder.cs
@@ -0,0 +1,44 @@
+namespace NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Represents a test package builder that creates NuGet packages from referenced project sources.
+///
+///
+///
+/// This interface enables the automatic creation of NuGet packages from project references,
+/// which are then made available during the test project build process. This capability is
+/// essential for validating how projects behave when consuming their own packages or dependencies.
+///
+///
+/// The package builder:
+///
+/// - Accepts paths to project files or .nuspec specifications
+/// - Packages them as NuGet packages with a test version (999.999.999)
+/// - Makes them available to the build process via a configured NuGet source
+/// - Handles platform-specific tooling (nuget.exe on Windows, nuget CLI on other platforms)
+///
+///
+///
+///
+public interface ITestPackageBuilder : IObjectBuilder
+{
+ ///
+ /// Sets the file system paths to projects or specifications used to create test packages.
+ ///
+ ///
+ ///
+ /// This method can be called multiple times to accumulate package paths. The method is
+ /// thread-safe through internal locking to ensure thread-safe operations during the
+ /// creation phase.
+ ///
+ ///
+ /// Duplicate paths are automatically handled and will not be processed twice. Empty or
+ /// whitespace paths are silently ignored.
+ ///
+ ///
+ ///
+ /// An array of absolute paths to .nuspec files or project files that should be packaged.
+ /// Must not be . Array elements that are empty or whitespace are ignored.
+ ///
+ void SetPackagePaths(string[] packagePaths);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilder.cs b/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilder.cs
new file mode 100644
index 0000000..7292507
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilder.cs
@@ -0,0 +1,130 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System.IO;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Builds global.json SDK configuration files with fluent API support.
+///
+///
+///
+/// This class implements to provide a convenient way to create
+/// global.json configuration files that specify SDK versions and roll-forward policies for
+/// .NET projects.
+///
+///
+/// The generated global.json file follows the .NET SDK global.json format and includes:
+///
+/// - SDK version specification
+/// - Prerelease version allowance configuration
+/// - Roll-forward policy selection
+///
+///
+///
+/// See for detailed information
+/// on global.json file format and options.
+///
+///
+///
+///
+internal sealed class GlobalJsonBuilder : IGlobalJsonBuilder
+{
+ private const string FileName = "global.json";
+ private readonly ISubdirectoryBuilder _directory;
+
+ private bool? _allowPrerelease;
+ private RollForward? _rollForward;
+ private string _runtimeVersion;
+
+ public string FullPath => Path.Combine(_directory.FullPath, FileName);
+
+ ///
+ public IGlobalJsonBuilder SetAllowPrerelease(bool allowPrerelease)
+ {
+ _allowPrerelease = allowPrerelease;
+
+ return this;
+ }
+
+ ///
+ public IGlobalJsonBuilder SetRollForward(RollForward rollForward)
+ {
+ _rollForward = rollForward;
+
+ return this;
+ }
+
+ ///
+ public IGlobalJsonBuilder SetRuntimeSdk(string runtimeVersion)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(runtimeVersion);
+
+ _runtimeVersion = runtimeVersion;
+
+ return this;
+ }
+
+ internal GlobalJsonBuilder(ISubdirectoryBuilder directory, string runtimeVersion)
+ {
+ _directory = directory;
+ _runtimeVersion = runtimeVersion;
+ }
+
+ public async ValueTask CreateAsync(CancellationToken cancellationToken = default)
+ {
+ var document = CreateDocument();
+
+ var file = _directory.CreateFile(FileName);
+ await using (file.ConfigureAwait(false))
+ {
+ await JsonSerializer
+ .SerializeAsync(file, document, Constants.JsonSettings, cancellationToken)
+ .ConfigureAwait(false);
+ }
+ }
+
+ private JsonObject CreateDocument()
+ {
+ // https://learn.microsoft.com/en-us/dotnet/core/tools/global-json
+ var sdk = new JsonObject { ["version"] = _runtimeVersion };
+
+ if (_allowPrerelease.HasValue)
+ {
+ sdk["allowPrerelease"] = _allowPrerelease.Value;
+ }
+
+ var rollForward = RollForwardToString(_rollForward);
+
+ if (rollForward is not null)
+ {
+ sdk["rollForward"] = rollForward;
+ }
+
+ var node = new JsonObject { ["sdk"] = sdk };
+
+ return node;
+ }
+
+ private static string? RollForwardToString(RollForward? value) =>
+ value switch
+ {
+ RollForward.Patch => "patch",
+ RollForward.Feature => "feature",
+ RollForward.Minor => "minor",
+ RollForward.Major => "major",
+ RollForward.LatestPatch => "latestPatch",
+ RollForward.LatestFeature => "latestFeature",
+ RollForward.LatestMinor => "latestMinor",
+ RollForward.LatestMajor => "latestMajor",
+ RollForward.Disable => "disable",
+ _ => null,
+ };
+
+ public ValueTask DisposeAsync() => ValueTask.CompletedTask;
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilderExtensions.cs b/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilderExtensions.cs
new file mode 100644
index 0000000..28136a9
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/GlobalJsonBuilderExtensions.cs
@@ -0,0 +1,47 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Provides extension methods for to simplify common configurations.
+///
+///
+/// This static class provides convenience methods for applying standard global.json configurations,
+/// such as default settings that are commonly used in test projects.
+///
+public static class GlobalJsonBuilderExtensions
+{
+ ///
+ /// Applies default configuration to the global.json builder.
+ ///
+ ///
+ ///
+ /// This method applies the following defaults:
+ ///
+ /// - SDK version:
+ /// - Allow prerelease: false
+ /// - Roll-forward policy:
+ ///
+ ///
+ ///
+ /// These defaults are suitable for most test scenarios where you want to use the default
+ /// SDK version and allow rolling forward to newer patch and feature versions within the same major.minor.
+ ///
+ ///
+ /// The global.json builder to configure. Must not be .
+ /// The builder instance for fluent chaining.
+ ///
+ /// Thrown when is .
+ ///
+ public static IGlobalJsonBuilder WithDefaults(this IGlobalJsonBuilder builder)
+ {
+ Argument.ThrowIfNull(builder);
+
+ return builder
+ .SetRuntimeSdk(Constants.RuntimeSdkDefault)
+ .SetAllowPrerelease(false)
+ .SetRollForward(RollForward.LatestMinor);
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilder.cs b/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilder.cs
new file mode 100644
index 0000000..1f52f51
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilder.cs
@@ -0,0 +1,175 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Helpers;
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Builds MSBuild project files (.csproj, .vbproj) with fluent API support.
+///
+///
+///
+/// This internal class implements to provide programmatic creation
+/// of .NET project files with proper XML structure. It manages property groups and item groups
+/// that configure the project's build behavior.
+///
+///
+/// The generated project file includes:
+///
+/// - Project SDK specification (e.g., Microsoft.NET.Sdk)
+/// - PropertyGroup elements for build configuration
+/// - ItemGroup elements for package and project references
+/// - Proper XML formatting with indentation
+///
+///
+///
+/// The class automatically initializes with default error logging configuration for SARIF v2.1 output,
+/// which captures build diagnostics during the build process.
+///
+///
+///
+///
+internal sealed class ProjectBuilder : IProjectBuilder
+{
+ private readonly ISubdirectoryBuilder _directory;
+
+ private readonly Dictionary _projectAttributes;
+
+ internal ItemGroup ItemGroup { get; }
+ internal PropertyGroup PropertyGroup { get; }
+
+ private readonly string _projectName;
+ private const string NameProjectAttributeSdk = "Sdk";
+
+ public string FullPath => Path.Combine(_directory.FullPath, _projectName);
+
+ internal ProjectBuilder(ISubdirectoryBuilder directory, string projectExtension)
+ {
+ _directory = directory;
+
+ _projectName = projectExtension;
+ _projectAttributes = new Dictionary(StringComparer.Ordinal)
+ {
+ { NameProjectAttributeSdk, "Microsoft.NET.Sdk" },
+ };
+
+ PropertyGroup = new PropertyGroup();
+ PropertyGroup.Add("ErrorLog", $"{Constants.OutputFileName},version=2.1");
+ ItemGroup = new ItemGroup();
+ }
+
+ ///
+ public ValueTask CreateAsync(CancellationToken cancellationToken = default)
+ {
+ var document = CreateDocument();
+
+ using var file = _directory.CreateFile(_projectName);
+ using var writer = XmlWriter.Create(file, Constants.XmlSettings);
+
+ document.WriteTo(writer);
+
+ return ValueTask.CompletedTask;
+ }
+
+ ///
+ public Stream CreateFile(string fileName) => _directory.CreateFile(fileName);
+
+ ///
+ public T GetOrAddItemGroupItem()
+ where T : class, IItemGroupItem, new()
+ {
+ var item = ItemGroup.Items.OfType().FirstOrDefault() ?? ItemGroup.Add();
+ return item;
+ }
+
+ ///
+ public T GetOrAddPropertyGroupItem()
+ where T : class, IPropertyGroupItem, new()
+ {
+ var item = PropertyGroup.Items.OfType().FirstOrDefault() ?? PropertyGroup.Add();
+ return item;
+ }
+
+ ///
+ public IProjectBuilder SetProjectSdk(string sdk)
+ {
+ var currentValue = _projectAttributes[NameProjectAttributeSdk];
+ if (!currentValue.Equals(sdk, StringComparison.Ordinal))
+ {
+ _projectAttributes[NameProjectAttributeSdk] = sdk;
+ }
+
+ return this;
+ }
+
+ public ValueTask DisposeAsync() => ValueTask.CompletedTask;
+
+ private XDocument CreateDocument()
+ {
+ var project = new XElement("Project");
+
+ foreach (var attributePair in _projectAttributes)
+ {
+ project.SetAttributeValue(attributePair.Key, attributePair.Value);
+ }
+
+ AppendPropertyGroups(project);
+ AppendItemGroups(project);
+
+ return new XDocument(null, project);
+ }
+
+ private void AppendItemGroups(XElement project)
+ {
+ if (ItemGroup.Items.Count == 0)
+ {
+ return;
+ }
+
+ var result = new XElement("ItemGroup");
+
+ foreach (var item in ItemGroup.Items)
+ {
+ var element = item.GetXElement();
+ result.Add(element);
+ }
+
+ project.Add(result);
+ }
+
+ private void AppendPropertyGroups(XElement project)
+ {
+ if (PropertyGroup.Items.Count == 0)
+ {
+ return;
+ }
+
+ var result = new XElement("PropertyGroup");
+
+ foreach (var item in PropertyGroup.Items)
+ {
+ var value = item.GetValue();
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ continue;
+ }
+
+ var element = new XElement(item.Name, value);
+
+ element.SetAttributeValue("Condition", item.Condition);
+ element.SetAttributeValue("Label", item.Label);
+
+ result.Add(element);
+ }
+
+ project.Add(result);
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilderExtensions.cs b/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilderExtensions.cs
new file mode 100644
index 0000000..90b42af
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/ProjectBuilderExtensions.cs
@@ -0,0 +1,298 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System;
+using System.IO;
+using System.Text;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Models;
+
+///
+/// Provides extension methods for to simplify project configuration.
+///
+///
+///
+/// This static class provides convenient methods for configuring project properties and adding
+/// source code files to projects. All methods use the fluent API pattern for chaining.
+///
+///
+/// These extensions cover common scenarios like setting target frameworks, configuring nullable
+/// reference handling, and adding C# or VB.NET source files.
+///
+///
+public static class ProjectBuilderExtensions
+{
+ ///
+ /// Adds a C# source file to the project.
+ ///
+ ///
+ ///
+ /// This method creates a .cs file in the project with the specified content.
+ /// The file name extension is automatically added if not present.
+ ///
+ ///
+ /// The content is encoded as UTF-8 before writing to the file.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to add the file to. Must not be .
+ ///
+ /// The name of the file to create (e.g., "Program", "Class1").
+ /// Must not be , empty, or whitespace.
+ ///
+ ///
+ /// The C# source code content to write to the file.
+ /// Must not be , empty, or whitespace.
+ ///
+ ///
+ /// Thrown when , , or is .
+ ///
+ ///
+ /// Thrown when or is empty or whitespace.
+ ///
+ public static void AddCSharpFile(this T builder, string fileName, string content)
+ where T : class, IProjectBuilder
+ {
+ Argument.ThrowIfNull(builder);
+ Argument.ThrowIfNullOrWhiteSpace(fileName);
+ Argument.ThrowIfNullOrWhiteSpace(content);
+
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ using var file = projectBuilder.CreateFile($"{Path.GetFileNameWithoutExtension(fileName)}.cs");
+ file.Write(Encoding.UTF8.GetBytes(content).AsSpan());
+ }
+ }
+
+ ///
+ /// Adds a VB.NET source file to the project.
+ ///
+ ///
+ ///
+ /// This method creates a .vb file in the project with the specified content.
+ /// The file name extension is automatically added if not present.
+ ///
+ ///
+ /// The content is encoded as UTF-8 before writing to the file.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to add the file to. Must not be .
+ ///
+ /// The name of the file to create (e.g., "Program", "Class1").
+ /// Must not be , empty, or whitespace.
+ ///
+ ///
+ /// The VB.NET source code content to write to the file.
+ /// Must not be , empty, or whitespace.
+ ///
+ ///
+ /// Thrown when , , or is .
+ ///
+ ///
+ /// Thrown when or is empty or whitespace.
+ ///
+ public static void AddVBFile(this T builder, string fileName, string content)
+ where T : class, IProjectBuilder
+ {
+ Argument.ThrowIfNull(builder);
+ Argument.ThrowIfNullOrWhiteSpace(fileName);
+ Argument.ThrowIfNullOrWhiteSpace(content);
+
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ using var file = projectBuilder.CreateFile($"{Path.GetFileNameWithoutExtension(fileName)}.vb");
+ file.Write(Encoding.UTF8.GetBytes(content).AsSpan());
+ }
+ }
+
+ ///
+ /// Applies default project configuration settings.
+ ///
+ ///
+ ///
+ /// This method applies the following defaults:
+ ///
+ /// - Target framework: .NET 8
+ /// - Nullable reference types: Enabled
+ ///
+ ///
+ ///
+ /// These are reasonable defaults for modern .NET development and test projects.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to configure. Must not be .
+ /// The builder instance for fluent chaining.
+ ///
+ /// Thrown when is .
+ ///
+ public static T WithDefaults(this T builder)
+ where T : class, IProjectBuilder
+ {
+ Argument.ThrowIfNull(builder);
+
+ return builder.WithTargetFramework(TargetFramework.Net8).WithNullable(NullableOptions.Enable);
+ }
+
+ ///
+ /// Sets the Nullable property in the project file.
+ ///
+ ///
+ ///
+ /// The Nullable property controls how the C# compiler handles nullable reference types.
+ /// This property is typically set at the project level to apply nullable reference semantics
+ /// to all code in the project.
+ ///
+ ///
+ /// CAUTION: This method overwrites any existing value for the Nullable property.
+ ///
+ ///
+ /// See
+ /// for more information on nullable contexts.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to configure. Must not be .
+ /// The nullable reference option to set.
+ /// The builder instance for fluent chaining.
+ public static T WithNullable(this T builder, NullableOptions nullable)
+ where T : class, IProjectBuilder
+ {
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ var propertyItem = projectBuilder.GetOrAddPropertyGroupItem();
+ propertyItem.SetValue(nullable);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Sets the target framework for the project.
+ ///
+ ///
+ ///
+ /// The target framework determines which .NET runtime and APIs are available for the project.
+ /// Common values include .NET 5, 6, 7, 8, and preview versions.
+ ///
+ ///
+ /// CAUTION: This method overwrites any existing target framework setting.
+ /// Use for multi-targeting.
+ ///
+ ///
+ /// See
+ /// for detailed information on target frameworks.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to configure. Must not be .
+ ///
+ /// The target framework to set. For example, ,
+ /// , or custom frameworks created with .
+ ///
+ /// The builder instance for fluent chaining.
+ public static T WithTargetFramework(this T builder, TargetFramework targetFramework)
+ where T : class, IProjectBuilder
+ {
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ var propertyItem = projectBuilder.GetOrAddPropertyGroupItem();
+
+ propertyItem.SetValue(targetFramework);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Sets multiple target frameworks for the project (multi-targeting).
+ ///
+ ///
+ ///
+ /// Multi-targeting allows a single project to build against multiple target frameworks.
+ /// The build process creates separate assemblies for each framework.
+ ///
+ ///
+ /// CAUTION: This method overwrites any existing target framework settings.
+ ///
+ ///
+ /// See
+ /// for guidance on multi-targeting strategies.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to configure. Must not be .
+ ///
+ /// One or more target frameworks to set. For example, ,
+ /// , and .
+ ///
+ /// The builder instance for fluent chaining.
+ public static T WithTargetFrameworks(this T builder, params TargetFramework[] targetFrameworks)
+ where T : class, IProjectBuilder
+ {
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ var propertyItem = projectBuilder.GetOrAddPropertyGroupItem();
+
+ propertyItem.SetValues(targetFrameworks);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Adds a NuGet package reference to the project.
+ ///
+ ///
+ ///
+ /// This method adds a PackageReference item to the project, enabling the project to consume
+ /// a NuGet package and its dependencies. Package references are the modern way to manage
+ /// dependencies in .NET projects.
+ ///
+ ///
+ /// See for more information.
+ ///
+ ///
+ /// The type of the project builder.
+ /// The project builder to add the package reference to. Must not be .
+ /// The package ID of the NuGet package to reference. Must not be or empty.
+ /// The optional version of the package to reference. When , uses centrally managed version or latest version.
+ /// The optional version override for the package. Overrides centrally managed versions.
+ /// When , generates a property containing the path to the package. Default is .
+ /// The optional comma-separated list of alias names for the reference. See .
+ /// The optional asset types to include from the package. When , all assets are included.
+ /// The optional asset types to exclude from the package. Takes precedence over .
+ /// The optional asset types that should not flow to consuming projects. Commonly used for analyzers and build tools.
+ /// The builder instance for fluent chaining.
+ /// Thrown when is or whitespace.
+ public static T AddPackageReference(
+ this T builder,
+ string name,
+ string? version = null,
+ string? versionOverride = null,
+ bool generatePathProperty = false,
+ string? aliases = null,
+ ReferenceAssets? includeAssets = null,
+ ReferenceAssets? excludeAssets = null,
+ ReferenceAssets? privateAssets = null
+ )
+ where T : class, IProjectBuilder
+ {
+ Argument.ThrowIfNullOrWhiteSpace(name);
+
+ if (builder is ProjectBuilder projectBuilder)
+ {
+ var item = projectBuilder.GetOrAddItemGroupItem();
+ item.Include = name;
+ item.Version = string.IsNullOrWhiteSpace(version) ? null : version;
+ item.VersionOverride = string.IsNullOrWhiteSpace(versionOverride) ? null : versionOverride;
+ item.GeneratePathProperty = generatePathProperty;
+ item.Aliases = aliases;
+ item.IncludeAssets = includeAssets;
+ item.ExcludeAssets = excludeAssets;
+ item.PrivateAssets = privateAssets;
+ }
+ return builder;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/ProjectFactoryExtensions.cs b/src/NetEvolve.ProjectBuilders/Builders/ProjectFactoryExtensions.cs
new file mode 100644
index 0000000..d08c540
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/ProjectFactoryExtensions.cs
@@ -0,0 +1,180 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Provides extension methods for to simplify project creation.
+///
+///
+///
+/// This static class provides convenient factory methods for creating the most common project types:
+/// C# projects, VB.NET projects, and global.json configuration files.
+///
+///
+/// Each method uses the fluent API pattern and accepts optional configuration actions for
+/// further customization of the created builders.
+///
+///
+[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "As designed.")]
+public static class ProjectFactoryExtensions
+{
+ ///
+ /// Adds a C# project to the factory.
+ ///
+ ///
+ ///
+ /// This method creates a C# project file (.csproj) with default configuration and registers it
+ /// with the factory. The created project can be further configured using the optional configuration action.
+ ///
+ ///
+ /// The project is configured to use the Microsoft.NET.Sdk by default.
+ ///
+ ///
+ ///
+ /// The factory object to which the project will be added. Must not be .
+ ///
+ ///
+ /// An optional configuration action that receives the for the
+ /// created project, allowing for customization. Can be to skip configuration.
+ ///
+ ///
+ /// The factory object for fluent method chaining.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ ///
+ /// factory.AddCSharpProject(pb => pb
+ /// .WithDefaults()
+ /// .WithTargetFramework(TargetFramework.Net8)
+ /// .AddCSharpFile("Program.cs", "// Hello World"));
+ ///
+ ///
+ public static IProjectFactory AddCSharpProject(
+ this IProjectFactory factory,
+ Action? configure = null
+ )
+ {
+ ArgumentNullException.ThrowIfNull(factory);
+
+ var builder = factory.AddFileBuilder(
+ new ProjectBuilder(factory.DirectoryBuilder, Constants.CSharpProjectFileName)
+ );
+
+ configure?.Invoke(builder);
+
+ return factory;
+ }
+
+ ///
+ /// Adds a global.json SDK configuration file to the factory.
+ ///
+ ///
+ ///
+ /// This method creates a global.json file that specifies the .NET SDK version and roll-forward
+ /// policy for the project. The file is registered with the factory and can be further customized.
+ ///
+ ///
+ /// The global.json file is useful for ensuring all developers and CI/CD systems use the same
+ /// SDK version when building the project.
+ ///
+ ///
+ /// See for more information.
+ ///
+ ///
+ ///
+ /// The factory object to which the file will be added. Must not be .
+ ///
+ ///
+ /// The .NET SDK version to specify in the global.json file. Defaults to
+ /// if not provided. Must not be , empty, or whitespace.
+ ///
+ ///
+ /// An optional configuration action that receives the for the
+ /// created file, allowing for customization. Can be to skip configuration.
+ ///
+ ///
+ /// The factory object for fluent method chaining.
+ ///
+ ///
+ /// Thrown when or is .
+ ///
+ ///
+ /// Thrown when is empty or contains only whitespace.
+ ///
+ ///
+ ///
+ /// factory.AddGlobalJson(
+ /// runtimeVersion: "8.0.204",
+ /// configure: gb => gb
+ /// .SetAllowPrerelease(false)
+ /// .SetRollForward(RollForward.LatestMinor));
+ ///
+ ///
+ public static IProjectFactory AddGlobalJson(
+ this IProjectFactory factory,
+ string runtimeVersion = Constants.RuntimeSdkDefault,
+ Action? configure = null
+ )
+ {
+ ArgumentNullException.ThrowIfNull(factory);
+ Argument.ThrowIfNullOrWhiteSpace(runtimeVersion);
+
+ var builder = factory.AddFileBuilder(
+ new GlobalJsonBuilder(factory.DirectoryBuilder, runtimeVersion)
+ );
+
+ configure?.Invoke(builder);
+
+ return factory;
+ }
+
+ ///
+ /// Adds a VB.NET project to the factory.
+ ///
+ ///
+ ///
+ /// This method creates a VB.NET project file (.vbproj) with default configuration and registers it
+ /// with the factory. The created project can be further configured using the optional configuration action.
+ ///
+ ///
+ /// The project is configured to use the Microsoft.NET.Sdk by default.
+ ///
+ ///
+ ///
+ /// The factory object to which the project will be added. Must not be .
+ ///
+ ///
+ /// An optional configuration action that receives the for the
+ /// created project, allowing for customization. Can be to skip configuration.
+ ///
+ ///
+ /// The factory object for fluent method chaining.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ ///
+ /// factory.AddVBProject(pb => pb
+ /// .WithDefaults()
+ /// .WithTargetFramework(TargetFramework.Net8));
+ ///
+ ///
+ public static IProjectFactory AddVBProject(this IProjectFactory factory, Action? configure = null)
+ {
+ ArgumentNullException.ThrowIfNull(factory);
+
+ var builder = factory.AddFileBuilder(
+ new ProjectBuilder(factory.DirectoryBuilder, Constants.VBNetProjectFileName)
+ );
+
+ configure?.Invoke(builder);
+
+ return factory;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/ReferenceExtensions.cs b/src/NetEvolve.ProjectBuilders/Builders/ReferenceExtensions.cs
new file mode 100644
index 0000000..f11aef3
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/ReferenceExtensions.cs
@@ -0,0 +1,24 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Models;
+
+internal static class ReferenceExtensions
+{
+ public static XElement ToXElement(this IReference item)
+ {
+ var element = new XElement(item.Name);
+
+ element.SetAttributeValue("Include", item.Include);
+ element.SetAttributeValue("Condition", item.Condition);
+ element.SetAttributeValue("Label", item.Label);
+ element.SetAttributeValue("GeneratePathProperty", item.GeneratePathProperty ? true : null);
+
+ element.SetElementValue("IncludeAssets", item.IncludeAssets.GetValue());
+ element.SetElementValue("ExcludeAssets", item.ExcludeAssets.GetValue());
+ element.SetElementValue("PrivateAssets", item.PrivateAssets.GetValue());
+
+ return element;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/SubdirectoryBuilder.cs b/src/NetEvolve.ProjectBuilders/Builders/SubdirectoryBuilder.cs
new file mode 100644
index 0000000..7444848
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/SubdirectoryBuilder.cs
@@ -0,0 +1,75 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Manages subdirectories and file creation within a directory hierarchy.
+///
+///
+///
+/// This internal class implements to provide file system
+/// operations for creating and managing subdirectories and files during project building.
+///
+///
+/// Each instance wraps a and provides methods to:
+///
+/// - Create nested subdirectories
+/// - Create new files with stream access
+/// - Query file paths
+///
+///
+///
+/// Unlike , this class does not provide automatic cleanup.
+/// It is typically used to represent subdirectories within a temporary directory that will be
+/// cleaned up by its parent.
+///
+///
+///
+///
+///
+internal sealed class SubdirectoryBuilder : ISubdirectoryBuilder
+{
+ private readonly DirectoryInfo _directory;
+
+ ///
+ public string FullPath => _directory.FullName;
+
+ internal SubdirectoryBuilder(DirectoryInfo directory) => _directory = directory;
+
+ ///
+ public ValueTask CreateAsync(CancellationToken cancellationToken = default) => ValueTask.CompletedTask;
+
+ ///
+ public ISubdirectoryBuilder CreateDirectory(string directoryName)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(directoryName);
+
+ return new SubdirectoryBuilder(_directory.CreateSubdirectory(directoryName));
+ }
+
+ ///
+ public Stream CreateFile(string fileName)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(fileName);
+
+ var fileInfo = new FileInfo(Path.Combine(_directory.FullName, fileName));
+
+ if (fileInfo.Exists)
+ {
+ throw new ArgumentException($"File with name `{fileName}` already exists.", nameof(fileName));
+ }
+
+ return fileInfo.Create();
+ }
+
+ ///
+ public ValueTask DisposeAsync() => ValueTask.CompletedTask;
+
+ ///
+ public string GetFilePath(string fileName) => Path.Combine(FullPath, fileName);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/TemporaryDirectoryBuilder.cs b/src/NetEvolve.ProjectBuilders/Builders/TemporaryDirectoryBuilder.cs
new file mode 100644
index 0000000..fb79d9d
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/TemporaryDirectoryBuilder.cs
@@ -0,0 +1,133 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Creates and manages temporary directories with automatic cleanup.
+///
+///
+///
+/// This internal class implements to provide isolated,
+/// auto-cleaning temporary directories for project building and testing. Each instance creates
+/// a unique directory in the system's temporary folder.
+///
+///
+/// The builder:
+///
+/// - Creates a unique directory using for isolation
+/// - Provides file and subdirectory creation capabilities
+/// - Automatically deletes the entire directory hierarchy when disposed
+/// - Handles exceptions during cleanup gracefully
+///
+///
+///
+/// The automatic cleanup ensures that test artifacts don't pollute the file system, even if exceptions occur
+/// during the build process. This is essential for maintaining clean test environments.
+///
+///
+///
+///
+///
+internal sealed class TemporaryDirectoryBuilder : ITemporaryDirectoryBuilder
+{
+ private readonly DirectoryInfo _directory;
+ private bool _disposedValue;
+
+ ///
+ public string FullPath => _directory.FullName;
+
+ ///
+ public ISubdirectoryBuilder CreateDirectory(string directoryName)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(directoryName);
+
+ return new SubdirectoryBuilder(_directory.CreateSubdirectory(directoryName));
+ }
+
+ ///
+ public Stream CreateFile(string fileName)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(fileName);
+
+ if (!_directory.Exists)
+ {
+ _directory.Create();
+ }
+
+ var fileInfo = new FileInfo(Path.Combine(_directory.FullName, fileName));
+
+ if (fileInfo.Exists)
+ {
+ throw new ArgumentException($"File with name `{fileName}` already exists.", nameof(fileName));
+ }
+
+ return fileInfo.Create();
+ }
+
+ ///
+ public string GetFilePath(string fileName)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(fileName);
+ return Path.Combine(FullPath, fileName);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TemporaryDirectoryBuilder()
+ {
+ var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
+ _directory = new DirectoryInfo(directoryPath);
+ }
+
+ ///
+ public ValueTask DisposeAsync() => DisposeAsync(true);
+
+ private async ValueTask DisposeAsync(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ await DeleteDiretoryAsync(_directory).ConfigureAwait(false);
+ }
+
+ _disposedValue = true;
+ }
+ }
+
+ private static async ValueTask DeleteDiretoryAsync(DirectoryInfo directory)
+ {
+ try
+ {
+ await Parallel
+ .ForEachAsync(
+ directory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly),
+ async (dir, _) => await DeleteDiretoryAsync(dir).ConfigureAwait(false)
+ )
+ .ConfigureAwait(false);
+
+ directory.Delete(true);
+ }
+ catch (Exception)
+ {
+ // Ignore, because we are using this while testing.
+ }
+ }
+
+ ///
+ public ValueTask CreateAsync(CancellationToken cancellationToken = default)
+ {
+ if (!_directory.Exists)
+ {
+ _directory.Create();
+ }
+
+ return ValueTask.CompletedTask;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Builders/TestPackageBuilder.cs b/src/NetEvolve.ProjectBuilders/Builders/TestPackageBuilder.cs
new file mode 100644
index 0000000..eb02f6f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Builders/TestPackageBuilder.cs
@@ -0,0 +1,154 @@
+namespace NetEvolve.ProjectBuilders.Builders;
+
+using CliWrap;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Helpers;
+
+///
+/// Builds NuGet packages from project specifications for testing purposes.
+///
+///
+///
+/// This internal class implements to create NuGet packages
+/// from project files or .nuspec specifications. It uses the nuget.exe tool (or the nuget CLI)
+/// to package referenced projects as test packages with a fixed version (999.999.999).
+///
+///
+/// The class features:
+///
+/// - Thread-safe package creation with semaphore-based locking
+/// - Platform-specific tooling (nuget.exe on Windows, nuget CLI on others)
+/// - Automatic downloading of nuget.exe if needed
+/// - Deduplication of package paths to avoid redundant processing
+///
+///
+///
+///
+///
+internal sealed class TestPackageBuilder : ITestPackageBuilder
+{
+ private readonly Guid _identifier = Guid.NewGuid();
+ private TemporaryDirectoryBuilder? _nugetFolder;
+ private readonly ISubdirectoryBuilder _directoy;
+ private bool _isInitialized;
+ private static readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
+ private readonly HashSet _packagePaths = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ public string FullPath => _directoy.FullPath;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The output directory where created NuGet packages will be stored.
+ ///
+ internal TestPackageBuilder(ISubdirectoryBuilder directory) => _directoy = directory;
+
+ ///
+ public async ValueTask CreateAsync(CancellationToken cancellationToken = default)
+ {
+ await _lock.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ if (_isInitialized)
+ {
+ return;
+ }
+
+ await _directoy.CreateAsync(cancellationToken).ConfigureAwait(false);
+ var cliWrap = await GetCliWrapAsync(cancellationToken).ConfigureAwait(false);
+
+ foreach (var packagePath in _packagePaths)
+ {
+ string[] args =
+ [
+ "pack",
+ packagePath,
+ "-ForceEnglishOutput",
+ "-Version",
+ "999.999.999", // To prevent version conflicts during testing
+ "-OutputDirectory",
+ _directoy.FullPath,
+ ];
+
+ _ = await cliWrap.WithArguments(args).ExecuteAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ _isInitialized = true;
+ }
+ finally
+ {
+ _ = _lock.Release();
+ }
+ }
+
+ public void SetPackagePaths(string[] packagePaths)
+ {
+ Argument.ThrowIfNull(packagePaths);
+
+ foreach (var packagePath in packagePaths.Where(x => !string.IsNullOrWhiteSpace(x)))
+ {
+ _ = _packagePaths.Add(packagePath);
+ }
+ }
+
+ private async ValueTask GetCliWrapAsync(CancellationToken cancellationToken)
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ var exe = await GetNuGetExeAsync(cancellationToken).ConfigureAwait(false);
+
+ return Cli.Wrap(exe!);
+ }
+
+ return Cli.Wrap("nuget");
+ }
+
+ private async ValueTask GetNuGetExeAsync(CancellationToken cancellationToken)
+ {
+ if (_nugetFolder is null)
+ {
+ _nugetFolder = new TemporaryDirectoryBuilder();
+ await _nugetFolder.CreateAsync(cancellationToken).ConfigureAwait(false);
+ }
+
+ var fileName = $"nuget-{_identifier:N}.exe";
+ var filePath = Path.Combine(_nugetFolder.FullPath, fileName);
+ if (!File.Exists(filePath))
+ {
+#pragma warning disable S1075 // URIs should not be hardcoded
+ await DownloadNuGetClientAsync(
+ "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe",
+ fileName,
+ cancellationToken
+ )
+ .ConfigureAwait(false);
+#pragma warning restore S1075 // URIs should not be hardcoded
+ }
+
+ return filePath;
+ }
+
+ private async Task DownloadNuGetClientAsync(string url, string fileName, CancellationToken cancellationToken)
+ {
+ using var downloadStream = await SharedHttpClient
+ .Instance.GetStreamAsync(new Uri(url, UriKind.Absolute), cancellationToken)
+ .ConfigureAwait(false);
+ using var fileStream = _nugetFolder!.CreateFile(fileName);
+
+ await downloadStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ await _directoy.DisposeAsync().ConfigureAwait(false);
+ if (_nugetFolder is not null)
+ {
+ await _nugetFolder.DisposeAsync().ConfigureAwait(false);
+ }
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Constants.cs b/src/NetEvolve.ProjectBuilders/Constants.cs
new file mode 100644
index 0000000..accf8a8
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Constants.cs
@@ -0,0 +1,74 @@
+namespace NetEvolve.ProjectBuilders;
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Xml;
+
+///
+/// Contains internal constants used throughout the NetEvolve.ProjectBuilders library.
+///
+///
+/// This static class defines configuration constants for SDK versions, command names,
+/// project file names, and default serialization settings for XML and JSON output.
+///
+internal static class Constants
+{
+ ///
+ /// Default runtime SDK version (8.0.204).
+ ///
+ public const string RuntimeSdkDefault = "8.0.204";
+
+ ///
+ /// Long-term support runtime SDK version (10.0.100).
+ ///
+ public const string RuntimeSdkLTS = "10.0.100";
+
+ ///
+ /// The dotnet build command name.
+ ///
+ public const string CommandBuild = "build";
+
+ ///
+ /// The dotnet restore command name.
+ ///
+ public const string CommandRestore = "restore";
+
+ ///
+ /// The default C# project file name for testing.
+ ///
+ public const string CSharpProjectFileName = "test.csproj";
+
+ ///
+ /// The default VB.NET project file name for testing.
+ ///
+ public const string VBNetProjectFileName = "test.vbproj";
+
+ ///
+ /// The default SARIF output file name for diagnostic results.
+ ///
+ public const string OutputFileName = "result.sarif";
+
+#pragma warning disable IDE1006 // Naming Styles
+ ///
+ /// Default XML writer settings for project file generation.
+ /// Omits the XML declaration, enables indentation with 2-space characters.
+ ///
+ public static readonly XmlWriterSettings XmlSettings = new XmlWriterSettings
+ {
+ OmitXmlDeclaration = true,
+ Indent = true,
+ IndentChars = " ",
+ };
+
+ ///
+ /// Default JSON serialization options for SARIF output and global.json files.
+ /// Enables pretty-printing and omits properties with default values.
+ ///
+ public static readonly JsonSerializerOptions JsonSettings = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
+ };
+
+#pragma warning restore IDE1006 // Naming Styles
+}
diff --git a/src/NetEvolve.ProjectBuilders/Helpers/SharedHttpClient.cs b/src/NetEvolve.ProjectBuilders/Helpers/SharedHttpClient.cs
new file mode 100644
index 0000000..40636e3
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Helpers/SharedHttpClient.cs
@@ -0,0 +1,155 @@
+namespace NetEvolve.ProjectBuilders.Helpers;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+///
+/// Provides a shared, reusable HttpClient instance with automatic retry logic for resilient HTTP operations.
+///
+///
+///
+/// This static utility class manages a singleton instance that's optimized for
+/// use throughout the ProjectBuilders library. It implements exponential backoff retry logic to handle
+/// transient failures gracefully.
+///
+///
+/// The client is configured with:
+///
+/// - Connection pooling with 1-minute idle timeout
+/// - 1-minute connection lifetime limit
+/// - Up to 5 automatic retries for transient failures
+/// - Exponential backoff delays (200ms, 400ms, 600ms, 800ms, 1000ms)
+/// - Respect for Retry-After headers
+///
+///
+///
+/// This pattern ensures:
+///
+/// - Efficient connection reuse
+/// - Resilience against transient network failures
+/// - No unnecessary DNS lookups
+/// - Proper handling of rate limiting and server errors
+///
+///
+///
+internal static class SharedHttpClient
+{
+ private static readonly Lazy _instance = new(
+ CreateHttpClient,
+ LazyThreadSafetyMode.ExecutionAndPublication
+ );
+
+ ///
+ /// Gets the shared singleton HttpClient instance.
+ ///
+ ///
+ ///
+ /// This instance is lazily initialized on first access and reused throughout the application lifetime.
+ /// It should never be disposed by callers.
+ ///
+ ///
+ /// The shared HttpClient instance configured with retry logic and connection pooling.
+ public static HttpClient Instance { get; } = _instance.Value;
+
+ [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "As designed.")]
+ private static HttpClient CreateHttpClient()
+ {
+ var socketHandler = new SocketsHttpHandler()
+ {
+ PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1),
+ PooledConnectionLifetime = TimeSpan.FromMinutes(1),
+ };
+
+ return new HttpClient(new HttpRetryMessageHandler(socketHandler), disposeHandler: true);
+ }
+
+ ///
+ /// Provides automatic retry logic with exponential backoff for transient HTTP failures.
+ ///
+ ///
+ ///
+ /// This delegating handler intercepts HTTP requests and automatically retries them up to 5 times
+ /// when transient failures occur. It respects the Retry-After header from the server if present.
+ ///
+ ///
+ /// Retryable conditions:
+ ///
+ /// - 500+ status codes (server errors)
+ /// - 408 Request Timeout
+ /// - 429 Too Many Requests
+ /// - HttpRequestException (network failures)
+ /// - TaskCanceledException (timeouts, not explicit cancellation)
+ ///
+ ///
+ ///
+ private sealed class HttpRetryMessageHandler(HttpMessageHandler handler) : DelegatingHandler(handler)
+ {
+ private const int MaxRetries = 5;
+
+ protected override async Task SendAsync(
+ HttpRequestMessage request,
+ CancellationToken cancellationToken
+ )
+ {
+ for (var i = 1; i <= MaxRetries; i++)
+ {
+ var delay = TimeSpan.FromMilliseconds(i * 200);
+ HttpResponseMessage? result = null;
+
+ try
+ {
+ result = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
+ if (
+ !ValidAttemp(i)
+ && (
+ result.StatusCode >= HttpStatusCode.InternalServerError
+ || result.StatusCode is HttpStatusCode.RequestTimeout or HttpStatusCode.TooManyRequests
+ )
+ )
+ {
+ if (result.Headers.RetryAfter is { Date: { } date })
+ {
+ delay = date - DateTimeOffset.UtcNow;
+ }
+ else if (result.Headers.RetryAfter is { Delta: { } delta })
+ {
+ delay = delta;
+ }
+
+ result.Dispose();
+ }
+ else
+ {
+ return result;
+ }
+ }
+ catch (HttpRequestException)
+ {
+ result?.Dispose();
+ if (ValidAttemp(i))
+ {
+ throw;
+ }
+ }
+ catch (TaskCanceledException ex) when (ex.CancellationToken != cancellationToken) // catch "The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing"
+ {
+ result?.Dispose();
+ if (ValidAttemp(i))
+ {
+ throw;
+ }
+ }
+
+ await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
+ }
+
+ throw new InvalidOperationException("The code should not reach this point.");
+ }
+
+ private static bool ValidAttemp(int i) => i >= MaxRetries;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/FrameworkReferenceItem.cs b/src/NetEvolve.ProjectBuilders/Models/FrameworkReferenceItem.cs
new file mode 100644
index 0000000..3d0304f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/FrameworkReferenceItem.cs
@@ -0,0 +1,48 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+
+///
+/// Represents a FrameworkReference item in a project file's ItemGroup.
+///
+///
+///
+/// Framework references are built-in references to .NET framework assemblies that are included
+/// with the SDK. Examples include System.Net.Http, System.Reflection, and other standard libraries.
+///
+///
+/// Framework references use the "FrameworkReference" element in project files and are different
+/// from Package References (NuGet packages) or Project References (other projects).
+///
+///
+///
+///
+///
+internal sealed record FrameworkReferenceItem : IReference
+{
+ ///
+ public string Name => "FrameworkReference";
+
+ ///
+ public string Include { get; } = default!;
+
+ ///
+ public bool GeneratePathProperty { get; set; }
+
+ ///
+ public ReferenceAssets? IncludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? ExcludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? PrivateAssets { get; set; }
+
+ ///
+ public string? Aliases { get; set; }
+
+ ///
+ public XElement GetXElement() => this.ToXElement();
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/ItemGroup.cs b/src/NetEvolve.ProjectBuilders/Models/ItemGroup.cs
new file mode 100644
index 0000000..750a1c1
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/ItemGroup.cs
@@ -0,0 +1,43 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Manages a collection of items within a project file's ItemGroup element.
+///
+///
+///
+/// This internal class implements to provide a mutable collection of
+/// project items such as package references, project references, and framework references.
+///
+///
+/// The class stores items in an internal list and exposes them as a read-only collection to
+/// prevent external modification of the collection structure while building the project file.
+///
+///
+///
+///
+internal sealed record ItemGroup : IItemGroup
+{
+ private readonly List _items;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ItemGroup() => _items = [];
+
+ ///
+ public ReadOnlyCollection Items => _items.AsReadOnly();
+
+ ///
+ public T Add()
+ where T : class, IItemGroupItem, new()
+ {
+ var item = new T();
+ _items.Add(item);
+
+ return item;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/NullableItem.cs b/src/NetEvolve.ProjectBuilders/Models/NullableItem.cs
new file mode 100644
index 0000000..e8a0571
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/NullableItem.cs
@@ -0,0 +1,54 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using Microsoft.Extensions.Primitives;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Represents the <Nullable> property in a project file.
+///
+///
+///
+/// This class implements to provide type-safe configuration
+/// of the Nullable property in .NET projects. The Nullable property controls how the C# compiler
+/// handles nullable reference types.
+///
+///
+/// Valid values are defined by the enum:
+///
+/// - Enable: Full nullable reference type checking
+/// - Disable: Disables nullable reference type checking
+/// - Warnings: Only warnings for potential null reference issues
+/// - Annotations: Only tracks null dereference locations
+///
+///
+///
+/// See
+/// for detailed information on nullable contexts.
+///
+///
+///
+///
+internal sealed record NullableItem : IPropertyGroupItem
+{
+ ///
+ public string Name => "Nullable";
+
+ ///
+ public StringValues Values { get; internal set; }
+
+ ///
+ public void SetValue(NullableOptions value) => Values = ConvertValue(value);
+
+ ///
+ public void SetValues(NullableOptions[] values) { }
+
+ private static StringValues ConvertValue(NullableOptions value) =>
+ value switch
+ {
+ NullableOptions.Enable => "enable",
+ NullableOptions.Disable => "disable",
+ NullableOptions.Warnings => "warnings",
+ NullableOptions.Annotations => "annotations",
+ _ => null,
+ };
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/NullableOptions.cs b/src/NetEvolve.ProjectBuilders/Models/NullableOptions.cs
new file mode 100644
index 0000000..f4cd1d3
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/NullableOptions.cs
@@ -0,0 +1,33 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+///
+/// Specifies the nullable context options for a SDK-based project.
+///
+///
+public enum NullableOptions
+{
+ ///
+ /// This value will be ignored.
+ ///
+ None = 0,
+
+ ///
+ /// The compiler enables all null reference analysis and all language features.
+ ///
+ Enable,
+
+ ///
+ /// The code is nullable-oblivious. Disable matches the behavior before nullable reference types were enabled, except the new syntax produces warnings instead of errors.
+ ///
+ Disable,
+
+ ///
+ /// The compiler performs all null analysis and emits warnings when code might dereference .
+ ///
+ Warnings,
+
+ ///
+ /// The compiler doesn't emit warnings when code might dereference , or when you assign a maybe-null expression to a non-nullable variable.
+ ///
+ Annotations,
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/Output/OutputFile.cs b/src/NetEvolve.ProjectBuilders/Models/Output/OutputFile.cs
new file mode 100644
index 0000000..0fbf0a8
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/Output/OutputFile.cs
@@ -0,0 +1,184 @@
+namespace NetEvolve.ProjectBuilders.Models.Output;
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+///
+/// Represents the root object of a SARIF (Static Analysis Results Format) output file.
+///
+///
+///
+/// This class models the top-level structure of a SARIF v2.1 compliant JSON file that contains
+/// diagnostic results from static analysis tools like the .NET compiler and analyzers. SARIF is
+/// a standard format for reporting analysis results across different tools.
+///
+///
+/// The OutputFile aggregates multiple instances and provides convenient
+/// methods to query the complete set of results across all runs, enabling unified analysis result
+/// processing regardless of how the results are logically organized.
+///
+///
+/// For more information about SARIF format, see
+/// .
+///
+///
+public sealed class OutputFile
+{
+ ///
+ /// Gets the list of analysis runs included in this SARIF output file.
+ ///
+ ///
+ ///
+ /// Each run typically represents a single invocation of an analyzer tool. Multiple runs may be
+ /// present if results from different tools or tool invocations are aggregated.
+ ///
+ ///
+ /// Use to retrieve all results across all runs in a single collection.
+ ///
+ ///
+ /// A list of objects, each containing results from a single analysis run.
+ [JsonPropertyName("runs")]
+ [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "As designed.")]
+ public List Runs { get; init; } = default!;
+
+ private List? _results;
+
+ ///
+ /// Gets a combined list of all results from all runs in the file.
+ ///
+ ///
+ ///
+ /// This property flattens the result hierarchy, combining all objects
+ /// from all instances into a single collection. This is convenient for
+ /// unified result processing without manually iterating through runs.
+ ///
+ ///
+ /// The result list is cached after first access for performance.
+ ///
+ ///
+ ///
+ /// A list containing all results from all runs. Returns an empty list if no runs contain results.
+ ///
+ [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "As designed.")]
+ public List Results
+ {
+ get
+ {
+ if (_results is null)
+ {
+ _results =
+ Runs?.SelectMany(r =>
+ {
+ if (r.Results is null)
+ {
+ return [];
+ }
+ return r.Results;
+ })
+ .ToList() ?? [];
+ }
+
+ return _results;
+ }
+ }
+
+ ///
+ /// Determines whether any results in the file have an error severity level.
+ ///
+ ///
+ ///
+ /// Errors represent the most severe type of diagnostic issue, typically indicating a problem
+ /// that must be fixed before the build succeeds.
+ ///
+ ///
+ /// This method examines all results across all runs. Use to
+ /// check for specific rule violations.
+ ///
+ ///
+ ///
+ /// if any result has level "error"; otherwise, .
+ ///
+ public bool HasErrors() => Results.Exists(r => r.Level == "error");
+
+ ///
+ /// Determines whether any error results match the specified rule ID.
+ ///
+ ///
+ ///
+ /// Use this method to check for specific rule violations. Rules are identified by rule IDs
+ /// that correspond to analyzer rules, compiler warnings, or code style violations.
+ ///
+ ///
+ /// Example: Checking for "CS1002" for C# compiler errors or "CA1050" for design guidelines.
+ ///
+ ///
+ ///
+ /// The rule identifier to search for. Typically follows patterns like "CS1234" for compiler errors
+ /// or "CA5000" for code analysis rules.
+ ///
+ ///
+ /// if any result has level "error" and matches the specified rule ID;
+ /// otherwise, .
+ ///
+ public bool HasError(string ruleId) => Results.Exists(r => r.Level == "error" && r.RuleId == ruleId);
+
+ ///
+ /// Determines whether the results contain no errors or warnings.
+ ///
+ ///
+ ///
+ /// Returns if all results have severity levels other than "error" or "warning"
+ /// (typically "note" or "none"), or if there are no results at all.
+ ///
+ ///
+ /// This is useful for determining if a build has any actionable issues.
+ ///
+ ///
+ ///
+ /// if no results have "error" or "warning" severity;
+ /// otherwise, .
+ ///
+ public bool HasNoErrorsOrWarnings() => Results.TrueForAll(r => r.Level is not "error" and not "warning");
+
+ ///
+ /// Determines whether any results in the file have a warning severity level.
+ ///
+ ///
+ ///
+ /// Warnings represent issues that should be addressed but do not necessarily prevent the build
+ /// from succeeding. The treatment of warnings depends on project settings.
+ ///
+ ///
+ /// This method examines all results across all runs. Use to
+ /// check for specific warning rules.
+ ///
+ ///
+ ///
+ /// if any result has level "warning"; otherwise, .
+ ///
+ public bool HasWarnings() => Results.Exists(r => r.Level == "warning");
+
+ ///
+ /// Determines whether any warning results match the specified rule ID.
+ ///
+ ///
+ ///
+ /// Use this method to check for specific warning rules. This is useful for suppressing or
+ /// validating particular categories of warnings.
+ ///
+ ///
+ /// Example: Checking for "CS0618" for obsolete member usage warnings or "CA1014" for
+ /// assembly-level warnings.
+ ///
+ ///
+ ///
+ /// The rule identifier to search for.
+ ///
+ ///
+ /// if any result has level "warning" and matches the specified rule ID;
+ /// otherwise, .
+ ///
+ public bool HasWarning(string ruleId) => Results.Exists(r => r.Level == "warning" && r.RuleId == ruleId);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/Output/OutputRun.cs b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRun.cs
new file mode 100644
index 0000000..1cf62a5
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRun.cs
@@ -0,0 +1,47 @@
+namespace NetEvolve.ProjectBuilders.Models.Output;
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json.Serialization;
+
+///
+/// Represents a single analysis run within a SARIF output file.
+///
+///
+///
+/// This class models a single run of an analysis tool, containing all results produced by that
+/// invocation. In a typical SARIF file, there is often one run per analysis tool or tool invocation,
+/// but SARIF supports multiple runs within a single file to aggregate results from different tools
+/// or different invocation parameters.
+///
+///
+/// The run contains a list of objects, each representing a diagnostic
+/// issue discovered during the analysis. Results include information such as the rule that was violated,
+/// the severity level, and descriptive messages.
+///
+///
+/// For more information about SARIF run objects, see
+/// .
+///
+///
+public sealed class OutputRun
+{
+ ///
+ /// Gets the list of results produced by this analysis run.
+ ///
+ ///
+ ///
+ /// Each result represents a single diagnostic issue found during analysis. Results contain
+ /// information such as the rule ID, severity level, location in source code, and descriptive messages.
+ ///
+ ///
+ /// This property may be if the analysis run produced no results.
+ ///
+ ///
+ ///
+ /// A list of objects, or if no results were produced.
+ ///
+ [JsonPropertyName("results")]
+ [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "As designed.")]
+ public List? Results { get; init; }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResult.cs b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResult.cs
new file mode 100644
index 0000000..85d721f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResult.cs
@@ -0,0 +1,89 @@
+namespace NetEvolve.ProjectBuilders.Models.Output;
+
+using System.Text.Json.Serialization;
+
+///
+/// Represents a single diagnostic result from a SARIF analysis run.
+///
+///
+///
+/// This class models a SARIF result object, which contains information about a single issue discovered
+/// during static analysis. Each result represents one diagnostic violation, warning, or informational
+/// message produced by the analysis tool.
+///
+///
+/// Results include three primary pieces of information:
+///
+/// - : The identifier of the rule that was violated
+/// - : The severity level ("error", "warning", "note", etc.)
+/// - : Descriptive information about the issue
+///
+///
+///
+/// Typical rule IDs include C# compiler error codes (e.g., "CS1002"), code analysis rules (e.g., "CA5000"),
+/// or analyzer-specific diagnostic IDs. The level determines how the issue should be treated during the build.
+///
+///
+public sealed class OutputRunResult
+{
+ ///
+ /// Gets the identifier of the rule that was violated or the diagnostic code.
+ ///
+ ///
+ ///
+ /// This identifies which rule, warning code, or diagnostic the result pertains to. Common formats include:
+ ///
+ /// - C# Compiler: "CS1234" (e.g., "CS1002" for missing semicolon)
+ /// - Code Analysis: "CA5000" (e.g., "CA1050" for design rules)
+ /// - Analyzers: Custom identifiers (e.g., "NETANALYZER001")
+ ///
+ ///
+ ///
+ /// The rule identifier string, or if not available.
+ [JsonPropertyName("ruleId")]
+ public string? RuleId { get; set; }
+
+ ///
+ /// Gets the severity level of this result.
+ ///
+ ///
+ ///
+ /// Specifies the importance and actionability of the result. Standard SARIF severity levels include:
+ ///
+ /// - "error": The most severe level, indicating a problem that must be addressed
+ /// - "warning": An issue that should be addressed but may not prevent the build
+ /// - "note": Informational message, usually non-blocking
+ /// - "none": No severity classification
+ ///
+ ///
+ ///
+ /// The interpretation of error vs. warning severity is context-specific and may be influenced by
+ /// project settings (e.g., "treat warnings as errors").
+ ///
+ ///
+ /// The severity level string ("error", "warning", "note", "none", etc.), or if not specified.
+ [JsonPropertyName("level")]
+ public string? Level { get; set; }
+
+ ///
+ /// Gets the message containing details about the result.
+ ///
+ ///
+ ///
+ /// The message provides human-readable details about the diagnostic issue, including the nature
+ /// of the problem, why it matters, and often suggestions for remediation.
+ ///
+ ///
+ /// An object containing the message text, or if no message is available.
+ [JsonPropertyName("message")]
+ public OutputRunResultMessage? Message { get; set; }
+
+ ///
+ /// Returns a formatted string representation of this result.
+ ///
+ ///
+ /// The format is "{Level}:{RuleId} {Message}", making it suitable for display in build output or logs.
+ ///
+ /// A formatted string in the pattern "error:CS1002 Missing semicolon".
+ public override string ToString() => $" {Level}:{RuleId} {Message}";
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResultMessage.cs b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResultMessage.cs
new file mode 100644
index 0000000..ee3832a
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/Output/OutputRunResultMessage.cs
@@ -0,0 +1,55 @@
+namespace NetEvolve.ProjectBuilders.Models.Output;
+
+using System.Text.Json.Serialization;
+
+///
+/// Represents the message content of a SARIF diagnostic result.
+///
+///
+///
+/// This class wraps the text of a diagnostic message within a SARIF result. In full SARIF documents,
+/// messages can be complex objects with formatting, location information, and references to markdown-formatted
+/// strings. However, this implementation focuses on the plain text message content.
+///
+///
+/// The message provides human-readable information about the diagnostic issue, explaining what was
+/// detected and often providing context or suggestions for fixing the issue.
+///
+///
+/// Example messages:
+///
+/// - "The type initializer threw an exception."
+/// - "Using directive is unnecessary."
+/// - "Variable 'x' is assigned but its value is never used"
+///
+///
+///
+public sealed class OutputRunResultMessage
+{
+ ///
+ /// Gets the plain text content of the diagnostic message.
+ ///
+ ///
+ ///
+ /// This contains the textual description of the diagnostic issue in a human-readable format.
+ /// The message may include context about where the issue was detected and suggestions for remediation.
+ ///
+ ///
+ /// The text may be empty or if the result has no textual message content.
+ ///
+ ///
+ ///
+ /// The message text as a string, or if the message content is not available.
+ ///
+ [JsonPropertyName("text")]
+ public string? Text { get; set; }
+
+ ///
+ /// Returns the text content of this message.
+ ///
+ ///
+ /// Returns an empty string if the text is or whitespace to ensure clean output.
+ ///
+ /// The message text, or an empty string if the text is or whitespace.
+ public override string ToString() => string.IsNullOrWhiteSpace(Text) ? string.Empty : Text;
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/PackageReferenceItem.cs b/src/NetEvolve.ProjectBuilders/Models/PackageReferenceItem.cs
new file mode 100644
index 0000000..0eff96c
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/PackageReferenceItem.cs
@@ -0,0 +1,80 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Reflection.Emit;
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Helpers;
+
+///
+/// Represents a PackageReference item in a project file's ItemGroup.
+///
+///
+///
+/// Package references represent NuGet package dependencies in a project. They specify the
+/// external packages that the project depends on for compilation and runtime.
+///
+///
+/// Package references use the "PackageReference" element in project files and are the modern
+/// way to manage NuGet dependencies in SDK-style projects (as opposed to the older packages.config format).
+///
+///
+/// The Include attribute typically contains the package name, optionally followed by a version specifier.
+///
+///
+///
+///
+///
+internal sealed record PackageReferenceItem : IReference
+{
+ ///
+ public string Name => "PackageReference";
+
+ ///
+ ///
+ /// For package references, this typically contains the NuGet package name, such as "Newtonsoft.Json"
+ /// or "Serilog".
+ ///
+ public string? Include { get; set; }
+
+ ///
+ public bool GeneratePathProperty { get; set; }
+
+ ///
+ public ReferenceAssets? IncludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? ExcludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? PrivateAssets { get; set; }
+
+ public string? Version { get; set; }
+
+ public string? VersionOverride
+ {
+ get;
+ set
+ {
+ field = value;
+
+ if (!string.IsNullOrWhiteSpace(field))
+ {
+ Version = null;
+ }
+ }
+ }
+
+ ///
+ public string? Aliases { get; set; }
+
+ public XElement GetXElement()
+ {
+ var element = this.ToXElement();
+
+ element.SetAttributeValue("Version", Version);
+ element.SetAttributeValue("VersionOverride", VersionOverride);
+
+ return element;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/ProjectReferenceItem.cs b/src/NetEvolve.ProjectBuilders/Models/ProjectReferenceItem.cs
new file mode 100644
index 0000000..2e5c119
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/ProjectReferenceItem.cs
@@ -0,0 +1,75 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Xml.Linq;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+
+///
+/// Represents a ProjectReference item in a project file's ItemGroup.
+///
+///
+///
+/// Project references represent dependencies on other projects within the same solution or
+/// local file system. They enable projects to reference each other's compiled outputs and
+/// ensure proper build ordering.
+///
+///
+/// Project references use the "ProjectReference" element in project files and include
+/// the relative path to the referenced project file.
+///
+///
+/// The Include attribute contains the path to the referenced project file, and the LookUpPaths
+/// property provides paths for locating the project's outputs and specifications.
+///
+///
+///
+///
+///
+internal sealed record ProjectReferenceItem : IReference
+{
+ ///
+ public string Name => "ProjectReference";
+
+ ///
+ ///
+ /// For project references, this contains the relative path to the referenced project file,
+ /// such as "../OtherProject/OtherProject.csproj".
+ ///
+ public string Include { get; } = default!;
+
+ ///
+ public bool GeneratePathProperty { get; set; }
+
+ ///
+ public ReferenceAssets? IncludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? ExcludeAssets { get; set; }
+
+ ///
+ public ReferenceAssets? PrivateAssets { get; set; }
+
+ ///
+ public string? Aliases { get; set; }
+
+ ///
+ ///
+ /// Returns paths for both the .nuspec file (if the project is packaged as a NuGet) and
+ /// the project file itself, enabling the test package builder to locate and process them.
+ ///
+ public IEnumerable LookUpPaths
+ {
+ get
+ {
+ yield return Path.ChangeExtension(FullPath, ".nuspec");
+ yield return FullPath;
+ }
+ }
+
+ private string FullPath => Path.GetFullPath(Include);
+
+ ///
+ public XElement GetXElement() => this.ToXElement();
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/PropertyGroup.cs b/src/NetEvolve.ProjectBuilders/Models/PropertyGroup.cs
new file mode 100644
index 0000000..cb37883
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/PropertyGroup.cs
@@ -0,0 +1,65 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Manages a collection of properties within a project file's PropertyGroup element.
+///
+///
+///
+/// This internal class implements to provide a mutable collection of
+/// project properties that configure build behavior, project metadata, and other settings.
+///
+///
+/// The class supports both typed property items (via the generic Add method) and dynamic properties
+/// (via the internal Add method with key-value pairs). Properties are stored in an internal list
+/// and exposed as a read-only collection to prevent external modification.
+///
+///
+///
+///
+internal sealed record PropertyGroup : IPropertyGroup
+{
+ private readonly List _items;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PropertyGroup() => _items = [];
+
+ ///
+ public ReadOnlyCollection Items => _items.AsReadOnly();
+
+ ///
+ /// Adds a dynamic property with a key-value pair.
+ ///
+ ///
+ /// This internal method allows adding simple string-valued properties without needing
+ /// a dedicated typed class. It's used for straightforward properties that don't require
+ /// special handling.
+ ///
+ /// The property name. Must not be or whitespace.
+ /// The property value. Can be for empty properties.
+ ///
+ /// Thrown when is , empty, or whitespace.
+ ///
+ internal void Add(string key, string? value)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(key);
+
+ _items.Add(new PropertyGroupItem(key, value));
+ }
+
+ ///
+ public T Add()
+ where T : class, IPropertyGroupItem, new()
+ {
+ var item = new T();
+ _items.Add(item);
+
+ return item;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/PropertyGroupItem.cs b/src/NetEvolve.ProjectBuilders/Models/PropertyGroupItem.cs
new file mode 100644
index 0000000..c74ad1f
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/PropertyGroupItem.cs
@@ -0,0 +1,53 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using Microsoft.Extensions.Primitives;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Represents a simple property element in a project file's PropertyGroup.
+///
+///
+///
+/// This internal class implements to provide storage for
+/// a simple named property with one or more values. It's used for straightforward properties
+/// that don't require special type conversion or handling.
+///
+///
+/// This class is typically instantiated by the method
+/// when adding dynamic properties to a property group.
+///
+///
+///
+///
+internal sealed record PropertyGroupItem : IPropertyGroupItem
+{
+ ///
+ /// Gets the name of the property.
+ ///
+ ///
+ /// This is the property name as it appears in the project file XML element.
+ ///
+ /// The property name, typically capitalized per MSBuild conventions (e.g., "OutputPath", "AssemblyName").
+ public string Name { get; }
+
+ ///
+ /// Gets the values of the property.
+ ///
+ ///
+ /// Although most properties have a single value, this field can contain multiple values
+ /// if needed, stored as a StringValues collection.
+ ///
+ /// A StringValues object representing the property value(s).
+ public StringValues Values { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The property name.
+ /// The property value.
+ public PropertyGroupItem(string key, string? value)
+ {
+ Name = key;
+ Values = value;
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/ReferenceAssets.cs b/src/NetEvolve.ProjectBuilders/Models/ReferenceAssets.cs
new file mode 100644
index 0000000..dd92209
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/ReferenceAssets.cs
@@ -0,0 +1,68 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+///
+/// Represents the types of assets that can be controlled in a package or project reference.
+///
+///
+///
+/// This flags enumeration is used with ,
+/// , and
+/// to control which assets from a NuGet package are included, excluded, or kept private.
+///
+///
+/// See for more information.
+///
+///
+[Flags]
+public enum ReferenceAssets
+{
+ ///
+ /// No assets are included or referenced.
+ ///
+ None = 0,
+
+ ///
+ /// Assets in the lib folder that are used during compilation.
+ ///
+ Compile = 1 << 0,
+
+ ///
+ /// Assets in the lib and runtimes folders that are copied to the output directory.
+ ///
+ Runtime = 1 << 1,
+
+ ///
+ /// Assets in the contentFiles folder that are available to the project.
+ ///
+ ContentFiles = 1 << 2,
+
+ ///
+ /// Assets in the build folder, including MSBuild props and targets files.
+ ///
+ Build = 1 << 3,
+
+ ///
+ /// Assets in the buildMultitargeting folder used for cross-targeting scenarios.
+ ///
+ BuildMultiTargeting = 1 << 4,
+
+ ///
+ /// Assets in the buildTransitive folder that flow transitively to consuming projects.
+ ///
+ BuildTransitive = 1 << 5,
+
+ ///
+ /// Roslyn analyzer assemblies in the analyzers folder.
+ ///
+ Analyzers = 1 << 6,
+
+ ///
+ /// Native assets in the native folder.
+ ///
+ Native = 1 << 7,
+
+ ///
+ /// All asset types combined.
+ ///
+ All = Compile | Runtime | ContentFiles | Build | BuildMultiTargeting | BuildTransitive | Analyzers | Native,
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/ReferenceAssetsExtensions.cs b/src/NetEvolve.ProjectBuilders/Models/ReferenceAssetsExtensions.cs
new file mode 100644
index 0000000..7457961
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/ReferenceAssetsExtensions.cs
@@ -0,0 +1,25 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+internal static class ReferenceAssetsExtensions
+{
+ public static string? GetValue(this ReferenceAssets? assets)
+ {
+ if (assets is null || assets == ReferenceAssets.None)
+ {
+ return null;
+ }
+
+ if (assets == ReferenceAssets.All)
+ {
+ return "all";
+ }
+
+#pragma warning disable CA1308 // Normalize strings to uppercase
+ var parts = Enum.GetValues()
+ .Where(a => a != ReferenceAssets.None && assets.Value.HasFlag(a))
+ .Select(a => a.ToString().ToLowerInvariant());
+#pragma warning restore CA1308 // Normalize strings to uppercase
+
+ return string.Join(';', parts);
+ }
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/RollForward.cs b/src/NetEvolve.ProjectBuilders/Models/RollForward.cs
new file mode 100644
index 0000000..f7b140a
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/RollForward.cs
@@ -0,0 +1,163 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+///
+/// Specifies the roll-forward policy for a .NET SDK version selection.
+///
+///
+///
+/// This enumeration controls how the .NET runtime resolves an SDK version when the exact specified version
+/// is not available. The policy determines the level of flexibility in accepting newer versions within
+/// various version component bounds (major, minor, feature band, patch).
+///
+///
+/// Roll-forward policies are typically specified in global.json files to control SDK version selection
+/// during project builds. Each policy represents a different strategy for handling version mismatches:
+/// strict (Disable), exact-with-fallback (Patch), and progressive looser matching policies (Feature, Minor, Major).
+///
+///
+/// See for
+/// official documentation on SDK roll-forward policies.
+///
+///
+public enum RollForward
+{
+ ///
+ /// Disables forward rolling; no policy is applied.
+ ///
+ ///
+ /// This value indicates that SDK version selection will not attempt to use an alternative version.
+ /// The specified version must be found or the command will fail.
+ ///
+ None = 0,
+
+ ///
+ /// Uses the highest installed .NET SDK with a version greater than or equal to the specified version across all components.
+ ///
+ ///
+ ///
+ /// This is the most permissive policy, accepting any newer version regardless of major version bumps.
+ /// It's suitable when you want the latest available SDK functionality without any version constraints.
+ ///
+ ///
+ /// Example: For specified version 5.0.0, this policy accepts 5.0.5, 6.0.0, 7.1.3, etc.
+ ///
+ ///
+ LatestMajor = 1,
+
+ ///
+ /// Uses the highest installed minor, feature band, and patch version matching the specified major version.
+ ///
+ ///
+ ///
+ /// Allows upgrades within the same major version line but not to a different major version.
+ /// Suitable for long-term support releases where you want to stay within a major version family.
+ ///
+ ///
+ /// Example: For specified version 5.0.0, this policy accepts 5.3.8 but not 6.0.0.
+ ///
+ ///
+ LatestMinor = 2,
+
+ ///
+ /// Uses the highest installed feature band and patch version matching the specified major and minor version.
+ ///
+ ///
+ ///
+ /// Allows upgrades within the same major.minor version but not to different minor versions.
+ /// Provides more control than LatestMinor for environments with stricter version requirements.
+ ///
+ ///
+ /// Example: For specified version 5.0.0, this policy accepts 5.0.8 but not 5.1.0.
+ ///
+ ///
+ LatestFeature = 3,
+
+ ///
+ /// Uses the latest installed patch version matching the specified major, minor, and feature band.
+ ///
+ ///
+ ///
+ /// The most conservative upgrade policy, allowing only patch-level updates.
+ /// Recommended for production environments where version stability is critical.
+ ///
+ ///
+ /// Example: For specified version 5.0.0, this policy accepts 5.0.8 but not 5.0.0-preview.
+ ///
+ ///
+ LatestPatch = 4,
+
+ ///
+ /// Rolls forward from the specified version through feature bands, then minor versions, then major versions.
+ ///
+ ///
+ ///
+ /// This policy allows the most aggressive roll-forward behavior. Starting with the specified version,
+ /// it searches for higher patch levels in the feature band, then higher feature bands in the minor version,
+ /// then higher minor versions in the major version, and finally rolls forward to higher major versions.
+ ///
+ ///
+ /// Use this when compatibility across major versions is acceptable and you want automatic upgrades to the latest available SDK.
+ ///
+ ///
+ Major = 5,
+
+ ///
+ /// Rolls forward from the specified version through feature bands and minor versions within the same major version.
+ ///
+ ///
+ ///
+ /// Similar to Major but stops at major version boundaries, never rolling forward to a different major version.
+ /// This is useful for staying within a major version family while allowing flexibility for minor upgrades.
+ ///
+ ///
+ /// Example: For specified version 5.0.100, rolls forward through 5.0.x → 5.1.x → 5.2.x but not to 6.x.
+ ///
+ ///
+ Minor = 6,
+
+ ///
+ /// Rolls forward from the specified version through feature bands within the same major and minor version.
+ ///
+ ///
+ ///
+ /// Restricts roll-forward to feature band upgrades only, never allowing minor or major version changes.
+ /// This is suitable for environments requiring tight version control within a minor version line.
+ ///
+ ///
+ /// Example: For specified version 5.0.100, rolls forward through 5.0.100 → 5.0.200 → 5.0.300 but not to 5.1.x.
+ ///
+ ///
+ Feature = 7,
+
+ ///
+ /// Uses the specified version, rolling forward only to the latest patch level if the exact version is not available.
+ ///
+ ///
+ ///
+ /// A conservative policy that tries to use the exact specified version first, then falls back to higher patch levels
+ /// but never to different minor, feature band, or major versions.
+ ///
+ ///
+ /// This is the legacy default behavior from earlier .NET SDK versions and provides a good balance
+ /// between stability and flexibility.
+ ///
+ ///
+ /// Example: For specified version 5.0.100, accepts 5.0.100 or higher (5.0.101, 5.0.105, etc.) but not 5.0.99 or 5.1.x.
+ ///
+ ///
+ Patch = 8,
+
+ ///
+ /// Requires an exact version match; no roll-forward is allowed.
+ ///
+ ///
+ ///
+ /// The most restrictive policy. The specified version must be installed, or the command will fail.
+ /// No automatic version resolution or fallback mechanisms are applied.
+ ///
+ ///
+ /// Use this policy in strictly controlled environments where reproducible builds with exact versions are essential.
+ ///
+ ///
+ Disable = 9,
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/TargetFramework.cs b/src/NetEvolve.ProjectBuilders/Models/TargetFramework.cs
new file mode 100644
index 0000000..518b6a2
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/TargetFramework.cs
@@ -0,0 +1,717 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using NetEvolve.Arguments;
+
+///
+/// Represents a .NET target framework moniker and provides predefined constants for common frameworks.
+///
+///
+///
+/// This readonly struct encapsulates information about a .NET target framework, including its name,
+/// value (moniker), and optional platform specification. The library provides predefined instances
+/// for all official .NET frameworks from .NET 5 through .NET 10, including platform-specific variants.
+///
+///
+/// Target frameworks determine which .NET runtime and APIs are available for a project. The framework
+/// is specified in project files via the TargetFramework (single) or TargetFrameworks (multiple) property.
+///
+///
+/// Features:
+///
+/// - Predefined constants for all official .NET frameworks and versions
+/// - Support for platform-specific frameworks (iOS, Android, Browser, etc.)
+/// - Extensibility via the method for custom frameworks
+/// - Immutable readonly struct for value semantics
+///
+///
+///
+/// See for
+/// comprehensive information on .NET target frameworks and
+/// for platform-specific framework monikers.
+///
+///
+[SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "As designed")]
+public readonly record struct TargetFramework
+{
+ ///
+ /// Gets the programmatic name of the target framework.
+ ///
+ ///
+ /// This is the name used as a property identifier, typically matching the C# property name
+ /// (e.g., "Net8", "Net9Android").
+ ///
+ /// The framework name as a string.
+ public string Name { get; }
+
+ ///
+ /// Gets the framework moniker string used in project files.
+ ///
+ ///
+ ///
+ /// This is the value that appears in the TargetFramework or TargetFrameworks property in .csproj files.
+ /// Examples: "net5.0", "net8.0", "net9.0-android", "net10.0-ios".
+ ///
+ ///
+ /// The value follows the .NET Target Framework Moniker (TFM) format defined by Microsoft.
+ ///
+ ///
+ /// The target framework moniker string.
+ public string Value { get; }
+
+ ///
+ /// Gets the platform this framework targets, if platform-specific.
+ ///
+ ///
+ ///
+ /// For cross-platform frameworks like "net8.0", this is .
+ /// For platform-specific frameworks like "net8.0-android", this indicates the target platform.
+ ///
+ ///
+ /// Platform-specific frameworks include mobile (Android, iOS, tvOS, macOS, Mac Catalyst),
+ /// web (Browser/WebAssembly), and desktop (Windows) platforms.
+ ///
+ ///
+ /// The , or for cross-platform frameworks.
+ public TargetPlatform? Platform { get; }
+
+ private TargetFramework(string name, string value, TargetPlatform? platform)
+ {
+ Name = name;
+ Value = value;
+ Platform = platform;
+ }
+
+ private static readonly HashSet _values = [];
+ internal static TargetFramework[] Values => [.. _values];
+
+ ///
+ /// Creates a custom target framework instance.
+ ///
+ ///
+ ///
+ /// This method allows definition of custom or future target frameworks not included in the
+ /// predefined set. Each unique combination of name and value can be registered once; attempting
+ /// to register a duplicate throws an exception.
+ ///
+ ///
+ /// The custom framework is registered in a global registry and can be retrieved alongside
+ /// the predefined frameworks.
+ ///
+ ///
+ ///
+ /// The programmatic name for the framework (e.g., "Net5", "CustomFramework").
+ /// Must not be , empty, or whitespace.
+ ///
+ ///
+ /// The moniker string for the framework (e.g., "net5.0", "custom1.0").
+ /// Must not be , empty, or whitespace and should follow TFM conventions.
+ ///
+ ///
+ /// The platform, if any, that this framework is specific to. Can be
+ /// for cross-platform frameworks. Defaults to .
+ ///
+ ///
+ /// A new instance representing the created framework.
+ ///
+ ///
+ /// Thrown when or is .
+ ///
+ ///
+ /// Thrown when or is empty or whitespace,
+ /// or when a framework with the same name and value is already registered.
+ ///
+ public static TargetFramework Create(string name, string value, TargetPlatform? platform = null)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(name);
+ Argument.ThrowIfNullOrWhiteSpace(value);
+
+ var targetFramework = new TargetFramework(name, value, platform);
+
+ if (!_values.Add(targetFramework))
+ {
+ throw new ArgumentException("TargetFramework already registered.", nameof(name));
+ }
+
+ return targetFramework;
+ }
+
+ ///
+ ///
+ /// Returns the framework moniker string (e.g., "net8.0").
+ ///
+ public override string ToString() => Value;
+
+ ///
+ /// Gets the target framework for .NET 5.
+ ///
+ ///
+ /// .NET 5 is a legacy LTS framework. Consider using newer versions for new projects.
+ ///
+ /// The TargetFramework instance for "net5.0".
+ public static TargetFramework Net5 { get; } = Create(nameof(Net5), "net5.0");
+
+ ///
+ /// Gets the target framework for .NET 5 on Android.
+ ///
+ ///
+ /// Used for Android mobile applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-android".
+ public static TargetFramework Net5Android { get; } =
+ Create(nameof(Net5Android), "net5.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 5 on Browser (Blazor WebAssembly).
+ ///
+ ///
+ /// Used for Blazor WebAssembly applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-browser".
+ public static TargetFramework Net5Browser { get; } =
+ Create(nameof(Net5Browser), "net5.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 5 on iOS.
+ ///
+ ///
+ /// Used for iOS mobile applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-ios".
+ public static TargetFramework Net5iOS { get; } = Create(nameof(Net5iOS), "net5.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 5 on Mac Catalyst.
+ ///
+ ///
+ /// Used for Mac Catalyst applications (iOS apps running on macOS) targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-maccatalyst".
+ public static TargetFramework Net5MacCatalyst { get; } =
+ Create(nameof(Net5MacCatalyst), "net5.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 5 on macOS.
+ ///
+ ///
+ /// Used for desktop applications targeting .NET 5 APIs on macOS.
+ ///
+ /// The TargetFramework instance for "net5.0-macos".
+ public static TargetFramework Net5MacOs { get; } = Create(nameof(Net5MacOs), "net5.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 5 on Tizen.
+ ///
+ ///
+ /// Used for Tizen-based applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-tizen".
+ public static TargetFramework Net5Tizen { get; } = Create(nameof(Net5Tizen), "net5.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 5 on tvOS.
+ ///
+ ///
+ /// Used for Apple TV applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-tvos".
+ public static TargetFramework Net5tvOS { get; } = Create(nameof(Net5tvOS), "net5.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 5 on Windows.
+ ///
+ ///
+ /// Used for Windows desktop applications targeting .NET 5 APIs.
+ ///
+ /// The TargetFramework instance for "net5.0-windows".
+ public static TargetFramework Net5Windows { get; } =
+ Create(nameof(Net5Windows), "net5.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET 6.
+ ///
+ ///
+ /// .NET 6 is an LTS (Long-Term Support) framework released in November 2021.
+ ///
+ /// The TargetFramework instance for "net6.0".
+ public static TargetFramework Net6 { get; } = Create(nameof(Net6), "net6.0");
+
+ ///
+ /// Gets the target framework for .NET 6 on Android.
+ ///
+ /// The TargetFramework instance for "net6.0-android".
+ public static TargetFramework Net6Android { get; } =
+ Create(nameof(Net6Android), "net6.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 6 on Browser (Blazor WebAssembly).
+ ///
+ /// The TargetFramework instance for "net6.0-browser".
+ public static TargetFramework Net6Browser { get; } =
+ Create(nameof(Net6Browser), "net6.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 6 on iOS.
+ ///
+ /// The TargetFramework instance for "net6.0-ios".
+ public static TargetFramework Net6iOS { get; } = Create(nameof(Net6iOS), "net6.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 6 on Mac Catalyst.
+ ///
+ /// The TargetFramework instance for "net6.0-maccatalyst".
+ public static TargetFramework Net6MacCatalyst { get; } =
+ Create(nameof(Net6MacCatalyst), "net6.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 6 on macOS.
+ ///
+ /// The TargetFramework instance for "net6.0-macos".
+ public static TargetFramework Net6MacOs { get; } = Create(nameof(Net6MacOs), "net6.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 6 on Tizen.
+ ///
+ /// The TargetFramework instance for "net6.0-tizen".
+ public static TargetFramework Net6Tizen { get; } = Create(nameof(Net6Tizen), "net6.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 6 on tvOS.
+ ///
+ /// The TargetFramework instance for "net6.0-tvos".
+ public static TargetFramework Net6tvOS { get; } = Create(nameof(Net6tvOS), "net6.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 6 on Windows.
+ ///
+ /// The TargetFramework instance for "net6.0-windows".
+ public static TargetFramework Net6Windows { get; } =
+ Create(nameof(Net6Windows), "net6.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET 7.
+ ///
+ ///
+ /// .NET 7 was released in November 2022 and entered maintenance mode in May 2023.
+ ///
+ /// The TargetFramework instance for "net7.0".
+ public static TargetFramework Net7 { get; } = Create(nameof(Net7), "net7.0");
+
+ ///
+ /// Gets the target framework for .NET 7 on Android.
+ ///
+ /// The TargetFramework instance for "net7.0-android".
+ public static TargetFramework Net7Android { get; } =
+ Create(nameof(Net7Android), "net7.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 7 on Browser (Blazor WebAssembly).
+ ///
+ /// The TargetFramework instance for "net7.0-browser".
+ public static TargetFramework Net7Browser { get; } =
+ Create(nameof(Net7Browser), "net7.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 7 on iOS.
+ ///
+ /// The TargetFramework instance for "net7.0-ios".
+ public static TargetFramework Net7iOS { get; } = Create(nameof(Net7iOS), "net7.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 7 on Mac Catalyst.
+ ///
+ /// The TargetFramework instance for "net7.0-maccatalyst".
+ public static TargetFramework Net7MacCatalyst { get; } =
+ Create(nameof(Net7MacCatalyst), "net7.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 7 on macOS.
+ ///
+ /// The TargetFramework instance for "net7.0-macos".
+ public static TargetFramework Net7MacOs { get; } = Create(nameof(Net7MacOs), "net7.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 7 on Tizen.
+ ///
+ /// The TargetFramework instance for "net7.0-tizen".
+ public static TargetFramework Net7Tizen { get; } = Create(nameof(Net7Tizen), "net7.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 7 on tvOS.
+ ///
+ /// The TargetFramework instance for "net7.0-tvos".
+ public static TargetFramework Net7tvOS { get; } = Create(nameof(Net7tvOS), "net7.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 7 on Windows.
+ ///
+ /// The TargetFramework instance for "net7.0-windows".
+ public static TargetFramework Net7Windows { get; } =
+ Create(nameof(Net7Windows), "net7.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET 8.
+ ///
+ ///
+ /// .NET 8 is an LTS (Long-Term Support) framework released in November 2023.
+ ///
+ /// The TargetFramework instance for "net8.0".
+ public static TargetFramework Net8 { get; } = Create(nameof(Net8), "net8.0");
+
+ ///
+ /// Gets the target framework for .NET 8 on Android.
+ ///
+ /// The TargetFramework instance for "net8.0-android".
+ public static TargetFramework Net8Android { get; } =
+ Create(nameof(Net8Android), "net8.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 8 on Browser (Blazor WebAssembly).
+ ///
+ /// The TargetFramework instance for "net8.0-browser".
+ public static TargetFramework Net8Browser { get; } =
+ Create(nameof(Net8Browser), "net8.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 8 on iOS.
+ ///
+ /// The TargetFramework instance for "net8.0-ios".
+ public static TargetFramework Net8iOS { get; } = Create(nameof(Net8iOS), "net8.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 8 on Mac Catalyst.
+ ///
+ /// The TargetFramework instance for "net8.0-maccatalyst".
+ public static TargetFramework Net8MacCatalyst { get; } =
+ Create(nameof(Net8MacCatalyst), "net8.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 8 on macOS.
+ ///
+ /// The TargetFramework instance for "net8.0-macos".
+ public static TargetFramework Net8MacOs { get; } = Create(nameof(Net8MacOs), "net8.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 8 on Tizen.
+ ///
+ /// The TargetFramework instance for "net8.0-tizen".
+ public static TargetFramework Net8Tizen { get; } = Create(nameof(Net8Tizen), "net8.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 8 on tvOS.
+ ///
+ /// The TargetFramework instance for "net8.0-tvos".
+ public static TargetFramework Net8tvOS { get; } = Create(nameof(Net8tvOS), "net8.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 8 on Windows.
+ ///
+ /// The TargetFramework instance for "net8.0-windows".
+ public static TargetFramework Net8Windows { get; } =
+ Create(nameof(Net8Windows), "net8.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET 9.
+ ///
+ ///
+ /// .NET 9 was released in November 2024 and is a current release.
+ ///
+ /// The TargetFramework instance for "net9.0".
+ public static TargetFramework Net9 { get; } = Create(nameof(Net9), "net9.0");
+
+ ///
+ /// Gets the target framework for .NET 9 on Android.
+ ///
+ /// The TargetFramework instance for "net9.0-android".
+ public static TargetFramework Net9Android { get; } =
+ Create(nameof(Net9Android), "net9.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 9 on Browser (Blazor WebAssembly).
+ ///
+ /// The TargetFramework instance for "net9.0-browser".
+ public static TargetFramework Net9Browser { get; } =
+ Create(nameof(Net9Browser), "net9.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 9 on iOS.
+ ///
+ /// The TargetFramework instance for "net9.0-ios".
+ public static TargetFramework Net9iOS { get; } = Create(nameof(Net9iOS), "net9.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 9 on Mac Catalyst.
+ ///
+ /// The TargetFramework instance for "net9.0-maccatalyst".
+ public static TargetFramework Net9MacCatalyst { get; } =
+ Create(nameof(Net9MacCatalyst), "net9.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 9 on macOS.
+ ///
+ /// The TargetFramework instance for "net9.0-macos".
+ public static TargetFramework Net9MacOs { get; } = Create(nameof(Net9MacOs), "net9.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 9 on Tizen.
+ ///
+ /// The TargetFramework instance for "net9.0-tizen".
+ public static TargetFramework Net9Tizen { get; } = Create(nameof(Net9Tizen), "net9.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 9 on tvOS.
+ ///
+ /// The TargetFramework instance for "net9.0-tvos".
+ public static TargetFramework Net9tvOS { get; } = Create(nameof(Net9tvOS), "net9.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 9 on Windows.
+ ///
+ /// The TargetFramework instance for "net9.0-windows".
+ public static TargetFramework Net9Windows { get; } =
+ Create(nameof(Net9Windows), "net9.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET 10.
+ ///
+ ///
+ /// .NET 10 is an LTS (Long-Term Support) framework released in November 2025.
+ ///
+ /// The TargetFramework instance for "net10.0".
+ public static TargetFramework Net10 { get; } = Create(nameof(Net10), "net10.0");
+
+ ///
+ /// Gets the target framework for .NET 10 on Android.
+ ///
+ /// The TargetFramework instance for "net10.0-android".
+ public static TargetFramework Net10Android { get; } =
+ Create(nameof(Net10Android), "net10.0-android", TargetPlatform.Android);
+
+ ///
+ /// Gets the target framework for .NET 10 on Browser (Blazor WebAssembly).
+ ///
+ /// The TargetFramework instance for "net10.0-browser".
+ public static TargetFramework Net10Browser { get; } =
+ Create(nameof(Net10Browser), "net10.0-browser", TargetPlatform.Browser);
+
+ ///
+ /// Gets the target framework for .NET 10 on iOS.
+ ///
+ /// The TargetFramework instance for "net10.0-ios".
+ public static TargetFramework Net10iOS { get; } = Create(nameof(Net10iOS), "net10.0-ios", TargetPlatform.iOS);
+
+ ///
+ /// Gets the target framework for .NET 10 on Mac Catalyst.
+ ///
+ /// The TargetFramework instance for "net10.0-maccatalyst".
+ public static TargetFramework Net10MacCatalyst { get; } =
+ Create(nameof(Net10MacCatalyst), "net10.0-maccatalyst", TargetPlatform.MacCatalyst);
+
+ ///
+ /// Gets the target framework for .NET 10 on macOS.
+ ///
+ /// The TargetFramework instance for "net10.0-macos".
+ public static TargetFramework Net10MacOs { get; } =
+ Create(nameof(Net10MacOs), "net10.0-macos", TargetPlatform.MacOs);
+
+ ///
+ /// Gets the target framework for .NET 10 on Tizen.
+ ///
+ /// The TargetFramework instance for "net10.0-tizen".
+ public static TargetFramework Net10Tizen { get; } =
+ Create(nameof(Net10Tizen), "net10.0-tizen", TargetPlatform.Tizen);
+
+ ///
+ /// Gets the target framework for .NET 10 on tvOS.
+ ///
+ /// The TargetFramework instance for "net10.0-tvos".
+ public static TargetFramework Net10tvOS { get; } = Create(nameof(Net10tvOS), "net10.0-tvos", TargetPlatform.tvOS);
+
+ ///
+ /// Gets the target framework for .NET 10 on Windows.
+ ///
+ /// The TargetFramework instance for "net10.0-windows".
+ public static TargetFramework Net10Windows { get; } =
+ Create(nameof(Net10Windows), "net10.0-windows", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Standard 1.0.
+ ///
+ ///
+ /// .NET Standard 1.0 is a legacy framework specification. Use newer .NET versions for new projects.
+ ///
+ /// The TargetFramework instance for "netstandard1.0".
+ public static TargetFramework NetStandard1_0 { get; } = Create(nameof(NetStandard1_0), "netstandard1.0");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.1.
+ ///
+ /// The TargetFramework instance for "netstandard1.1".
+ public static TargetFramework NetStandard1_1 { get; } = Create(nameof(NetStandard1_1), "netstandard1.1");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.2.
+ ///
+ /// The TargetFramework instance for "netstandard1.2".
+ public static TargetFramework NetStandard1_2 { get; } = Create(nameof(NetStandard1_2), "netstandard1.2");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.3.
+ ///
+ /// The TargetFramework instance for "netstandard1.3".
+ public static TargetFramework NetStandard1_3 { get; } = Create(nameof(NetStandard1_3), "netstandard1.3");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.4.
+ ///
+ /// The TargetFramework instance for "netstandard1.4".
+ public static TargetFramework NetStandard1_4 { get; } = Create(nameof(NetStandard1_4), "netstandard1.4");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.5.
+ ///
+ /// The TargetFramework instance for "netstandard1.5".
+ public static TargetFramework NetStandard1_5 { get; } = Create(nameof(NetStandard1_5), "netstandard1.5");
+
+ ///
+ /// Gets the target framework for .NET Standard 1.6.
+ ///
+ /// The TargetFramework instance for "netstandard1.6".
+ public static TargetFramework NetStandard1_6 { get; } = Create(nameof(NetStandard1_6), "netstandard1.6");
+
+ ///
+ /// Gets the target framework for .NET Standard 2.0.
+ ///
+ ///
+ /// .NET Standard 2.0 is widely supported and still used for cross-platform library compatibility.
+ ///
+ /// The TargetFramework instance for "netstandard2.0".
+ public static TargetFramework NetStandard2_0 { get; } = Create(nameof(NetStandard2_0), "netstandard2.0");
+
+ ///
+ /// Gets the target framework for .NET Standard 2.1.
+ ///
+ ///
+ /// .NET Standard 2.1 is the final version of the .NET Standard specification.
+ ///
+ /// The TargetFramework instance for "netstandard2.1".
+ public static TargetFramework NetStandard2_1 { get; } = Create(nameof(NetStandard2_1), "netstandard2.1");
+
+ ///
+ /// Gets the target framework for .NET Core 1.0.
+ ///
+ ///
+ /// .NET Core 1.0 is a legacy framework. Migrate to modern .NET versions for new projects.
+ ///
+ /// The TargetFramework instance for "netcoreapp1.0".
+ public static TargetFramework NetCoreApp1_0 { get; } = Create(nameof(NetCoreApp1_0), "netcoreapp1.0");
+
+ ///
+ /// Gets the target framework for .NET Core 1.1.
+ ///
+ /// The TargetFramework instance for "netcoreapp1.1".
+ public static TargetFramework NetCoreApp1_1 { get; } = Create(nameof(NetCoreApp1_1), "netcoreapp1.1");
+
+ ///
+ /// Gets the target framework for .NET Core 2.0.
+ ///
+ /// The TargetFramework instance for "netcoreapp2.0".
+ public static TargetFramework NetCoreApp2_0 { get; } = Create(nameof(NetCoreApp2_0), "netcoreapp2.0");
+
+ ///
+ /// Gets the target framework for .NET Core 2.1.
+ ///
+ ///
+ /// .NET Core 2.1 is a legacy LTS framework. Consider upgrading to .NET 6 or later.
+ ///
+ /// The TargetFramework instance for "netcoreapp2.1".
+ public static TargetFramework NetCoreApp2_1 { get; } = Create(nameof(NetCoreApp2_1), "netcoreapp2.1");
+
+ ///
+ /// Gets the target framework for .NET Core 2.2.
+ ///
+ /// The TargetFramework instance for "netcoreapp2.2".
+ public static TargetFramework NetCoreApp2_2 { get; } = Create(nameof(NetCoreApp2_2), "netcoreapp2.2");
+
+ ///
+ /// Gets the target framework for .NET Core 3.0.
+ ///
+ /// The TargetFramework instance for "netcoreapp3.0".
+ public static TargetFramework NetCoreApp3_0 { get; } = Create(nameof(NetCoreApp3_0), "netcoreapp3.0");
+
+ ///
+ /// Gets the target framework for .NET Core 3.1.
+ ///
+ ///
+ /// .NET Core 3.1 is a legacy LTS framework with support ending in December 2022. Migrate to .NET 6 or later.
+ ///
+ /// The TargetFramework instance for "netcoreapp3.1".
+ public static TargetFramework NetCoreApp3_1 { get; } = Create(nameof(NetCoreApp3_1), "netcoreapp3.1");
+
+ ///
+ /// Gets the target framework for .NET Framework 4.6.
+ ///
+ ///
+ /// .NET Framework 4.6 is a legacy desktop-only framework. Migrate to modern .NET for new projects.
+ ///
+ /// The TargetFramework instance for "net46".
+ public static TargetFramework NetFramework4_6 { get; } =
+ Create(nameof(NetFramework4_6), "net46", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.6.1.
+ ///
+ /// The TargetFramework instance for "net461".
+ public static TargetFramework NetFramework4_6_1 { get; } =
+ Create(nameof(NetFramework4_6_1), "net461", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.6.2.
+ ///
+ /// The TargetFramework instance for "net462".
+ public static TargetFramework NetFramework4_6_2 { get; } =
+ Create(nameof(NetFramework4_6_2), "net462", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.7.
+ ///
+ /// The TargetFramework instance for "net47".
+ public static TargetFramework NetFramework4_7 { get; } =
+ Create(nameof(NetFramework4_7), "net47", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.7.1.
+ ///
+ /// The TargetFramework instance for "net471".
+ public static TargetFramework NetFramework4_7_1 { get; } =
+ Create(nameof(NetFramework4_7_1), "net471", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.7.2.
+ ///
+ /// The TargetFramework instance for "net472".
+ public static TargetFramework NetFramework4_7_2 { get; } =
+ Create(nameof(NetFramework4_7_2), "net472", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.8.
+ ///
+ ///
+ /// .NET Framework 4.8 is the final major version of the .NET Framework. Migrate to modern .NET for new projects.
+ ///
+ /// The TargetFramework instance for "net48".
+ public static TargetFramework NetFramework4_8 { get; } =
+ Create(nameof(NetFramework4_8), "net48", TargetPlatform.Windows);
+
+ ///
+ /// Gets the target framework for .NET Framework 4.8.1.
+ ///
+ ///
+ /// .NET Framework 4.8.1 is a minor update to .NET Framework 4.8, released in 2023 for specific scenarios.
+ ///
+ /// The TargetFramework instance for "net481".
+ public static TargetFramework NetFramework4_8_1 { get; } =
+ Create(nameof(NetFramework4_8_1), "net481", TargetPlatform.Windows);
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/TargetFrameworkItem.cs b/src/NetEvolve.ProjectBuilders/Models/TargetFrameworkItem.cs
new file mode 100644
index 0000000..4e815dd
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/TargetFrameworkItem.cs
@@ -0,0 +1,86 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+using System.Linq;
+using Microsoft.Extensions.Primitives;
+using NetEvolve.ProjectBuilders.Abstractions;
+
+///
+/// Represents a target framework property group item for a project file.
+///
+///
+///
+/// This internal record implements for managing target framework
+/// specifications in MSBuild project files. It provides an abstraction over the MSBuild properties
+/// TargetFramework (for single framework) and TargetFrameworks (for multiple frameworks).
+///
+///
+/// The property name automatically switches between "TargetFramework" and "TargetFrameworks" based on
+/// the number of configured frameworks:
+///
+/// - Single framework: Uses "TargetFramework" property
+/// - Multiple frameworks: Uses "TargetFrameworks" property (semicolon-delimited)
+///
+///
+///
+/// Example in project file:
+///
+///
+/// <TargetFramework>net8.0</TargetFramework>
+///
+///
+/// <TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
+///
+///
+///
+internal sealed record TargetFrameworkItem : IPropertyGroupItem
+{
+ ///
+ /// Gets the MSBuild property name based on the number of frameworks.
+ ///
+ ///
+ /// Returns "TargetFramework" for a single framework or "TargetFrameworks" for multiple frameworks.
+ /// This automatic selection ensures compatibility with MSBuild project file semantics.
+ ///
+ ///
+ /// TargetFramework if one framework is configured; otherwise, TargetFrameworks.
+ ///
+ public string Name => Values.Count > 1 ? "TargetFrameworks" : "TargetFramework";
+
+ ///
+ /// Gets or sets the target framework values as a semicolon-delimited string collection.
+ ///
+ ///
+ /// Framework values are stored as framework monikers (e.g., "net8.0", "net8.0-android").
+ /// Multiple frameworks are joined with semicolons when serialized to the project file.
+ ///
+ /// The collection of framework moniker strings.
+ public StringValues Values { get; internal set; }
+
+ ///
+ /// Sets a single target framework.
+ ///
+ ///
+ /// This method replaces all existing frameworks with a single specified framework.
+ /// The framework moniker is extracted from the value.
+ ///
+ /// The framework to set as the target.
+ public void SetValue(TargetFramework value) => Values = value.Value;
+
+ ///
+ /// Adds multiple target frameworks to the current collection.
+ ///
+ ///
+ ///
+ /// This method appends additional frameworks to any existing frameworks rather than replacing them.
+ /// The frameworks are stored as a semicolon-delimited collection for MSBuild compatibility.
+ ///
+ ///
+ /// Multiple frameworks enable multi-targeting, allowing a single project to produce binaries for
+ /// several frameworks simultaneously. The build system compiles code for each framework, allowing
+ /// framework-specific conditional compilation via preprocessor symbols.
+ ///
+ ///
+ /// An array of frameworks to add.
+ public void SetValues(TargetFramework[] values) =>
+ Values = StringValues.Concat(Values, values.Select(x => x.Value).ToArray());
+}
diff --git a/src/NetEvolve.ProjectBuilders/Models/TargetPlatform.cs b/src/NetEvolve.ProjectBuilders/Models/TargetPlatform.cs
new file mode 100644
index 0000000..26cb5de
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/Models/TargetPlatform.cs
@@ -0,0 +1,109 @@
+namespace NetEvolve.ProjectBuilders.Models;
+
+///
+/// Specifies the target platform for a .NET application or library.
+///
+///
+///
+/// This enumeration represents the operating system or runtime platform that a .NET project targets.
+/// Platform-specific target frameworks allow developers to create applications optimized for specific
+/// platforms while potentially sharing common code through multi-targeting.
+///
+///
+/// Platforms are typically specified in target framework monikers (TFM) as suffixes, such as
+/// "net8.0-android", "net8.0-ios", or "net8.0-browser". The combination of framework and platform
+/// determines which APIs and runtime features are available.
+///
+///
+/// See
+/// for more information on platform-specific target frameworks.
+///
+///
+public enum TargetPlatform
+{
+ ///
+ /// No platform restriction; the framework is cross-platform.
+ ///
+ ///
+ /// This value indicates the framework runs on all platforms without platform-specific targeting.
+ /// Examples include standard .NET frameworks like "net8.0" used for general-purpose libraries.
+ ///
+ None = 0,
+
+ ///
+ /// Windows desktop or server platform.
+ ///
+ ///
+ /// Used for Windows-specific applications including desktop applications, Windows Forms,
+ /// WPF, and Windows service projects. Also applies to .NET Framework applications.
+ ///
+ Windows,
+
+ ///
+ /// Android mobile platform.
+ ///
+ ///
+ /// Targets Android devices via .NET MAUI or Xamarin.Android. Enables development of Android
+ /// mobile applications using C# and .NET libraries.
+ ///
+ Android,
+
+ ///
+ /// Apple iOS mobile platform.
+ ///
+ ///
+ /// Targets Apple iPhone and iPad devices via .NET MAUI or Xamarin.iOS. Enables development of
+ /// native iOS applications using C# and .NET libraries.
+ ///
+ iOS,
+
+ ///
+ /// Mac Catalyst platform (iOS apps running on macOS).
+ ///
+ ///
+ /// Targets iPad applications running on Mac via Mac Catalyst technology. Allows iOS applications
+ /// to run on macOS with desktop-optimized interfaces.
+ ///
+ MacCatalyst,
+
+ ///
+ /// Apple macOS desktop platform.
+ ///
+ ///
+ /// Targets Apple Macintosh computers running macOS. Used for Mac desktop applications via
+ /// .NET MAUI or native macOS frameworks. Also includes support for creating command-line tools.
+ ///
+ MacOs,
+
+ ///
+ /// Apple tvOS platform (Apple TV).
+ ///
+ ///
+ /// Targets Apple TV devices. Enables development of applications for Apple TV set-top boxes
+ /// using C# and .NET libraries.
+ ///
+ tvOS,
+
+ ///
+ /// Samsung Tizen platform.
+ ///
+ ///
+ /// Targets devices running Samsung Tizen OS, including smart TVs and wearables. Support is
+ /// community-maintained and may be limited compared to other major platforms.
+ ///
+ Tizen,
+
+ ///
+ /// Browser platform using WebAssembly (Blazor).
+ ///
+ ///
+ ///
+ /// Targets web browsers via Blazor WebAssembly (WASM) technology. Enables C# code to run
+ /// directly in browsers with near-native performance through WebAssembly.
+ ///
+ ///
+ /// Differs from server-side Blazor which runs on the server; WASM provides client-side execution.
+ ///
+ ///
+ Browser,
+}
diff --git a/src/NetEvolve.ProjectBuilders/NetEvolve.ProjectBuilders.csproj b/src/NetEvolve.ProjectBuilders/NetEvolve.ProjectBuilders.csproj
new file mode 100644
index 0000000..abbd55a
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/NetEvolve.ProjectBuilders.csproj
@@ -0,0 +1,21 @@
+
+
+ $(ProjectTargetFrameworks)
+ NetEvolve.ProjectBuilders
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.ProjectBuilders/ProjectFactory.cs b/src/NetEvolve.ProjectBuilders/ProjectFactory.cs
new file mode 100644
index 0000000..6f17942
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/ProjectFactory.cs
@@ -0,0 +1,367 @@
+namespace NetEvolve.ProjectBuilders;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using CliWrap;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using NetEvolve.Arguments;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models.Output;
+
+///
+/// Provides fluent API to create, configure, and build .NET projects for testing purposes.
+///
+///
+///
+/// This class is the primary entry point for the ProjectBuilders library. It implements the
+/// fluent API pattern to allow convenient creation of test projects with various configurations,
+/// such as C#, VB.NET, and global.json files.
+///
+///
+/// The factory manages the complete lifecycle of test project creation, including:
+///
+/// - Creating temporary directories for isolated testing
+/// - Building project files with custom properties and item groups
+/// - Executing dotnet build and restore commands
+/// - Capturing and analyzing SARIF diagnostic output
+/// - Managing environment variables for build execution
+///
+///
+///
+/// Usage example:
+///
+/// using var factory = ProjectFactory.Create();
+/// factory
+/// .AddCSharpProject(pb => pb.WithDefaults())
+/// .AddGlobalJson(configure: gb => gb.WithDefaults());
+/// var result = await factory.BuildAsync();
+///
+///
+///
+///
+///
+public sealed partial class ProjectFactory : IProjectFactory
+{
+ /* language=regex */
+ private const string RulesFilterPattern = @"(NU|NEP)\d{4}";
+
+ private readonly ILogger _logger;
+ private readonly ITestPackageBuilder? _testPackageBuilder;
+ private readonly ISubdirectoryBuilder _tempDirectory;
+ private bool _disposedValue;
+ private readonly List _output;
+
+ internal Dictionary EnvironmentVariables { get; init; }
+ internal HashSet ObjectBuilders { get; init; }
+
+ ///
+ /// Gets the directory builder for the temporary directory used by this factory.
+ ///
+ ///
+ /// This directory serves as the root for all project files, subdirectories, and outputs
+ /// created during the test project building process.
+ ///
+ ///
+ public ISubdirectoryBuilder DirectoryBuilder => _tempDirectory;
+
+ private static readonly string[] _newLineSeparator = ["\r\n", "\r", "\n"];
+
+ internal ProjectFactory(
+ ITestPackageBuilder? testPackageBuilder,
+ ISubdirectoryBuilder? directory,
+ ILogger? logger
+ )
+ {
+ _logger = logger ?? NullLogger.Instance;
+ _testPackageBuilder = testPackageBuilder;
+ _tempDirectory = directory ?? new TemporaryDirectoryBuilder();
+ _output = [];
+
+ EnvironmentVariables = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "CI", null },
+ { "DOTNET_CLI_TELEMETRY_OPTOUT", "true" },
+ { "DOTNET_NOLOGO", "true" },
+ { "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true" },
+ { "GITHUB_ACTIONS", null },
+ };
+ ObjectBuilders = [];
+ }
+
+ ///
+ /// Creates a new instance of . Use the fluent API to build a project.
+ ///
+ ///
+ /// The test package builder to use.
+ ///
+ ///
+ /// The directory builder to use.
+ ///
+ ///
+ /// The logger to use. If not provided, a will be used.
+ ///
+ ///
+ /// A new instance of .
+ ///
+ public static IProjectFactory Create(
+ ITestPackageBuilder? testPackageBuilder = null,
+ ISubdirectoryBuilder? directory = null,
+ ILogger? logger = null
+ ) => new ProjectFactory(testPackageBuilder, directory, logger);
+
+ ///
+ public IProjectFactory AddEnvironmentVariable(string name, string? value)
+ {
+ Argument.ThrowIfNullOrWhiteSpace(name);
+ Argument.ThrowIfNullOrWhiteSpace(value);
+
+ if (!EnvironmentVariables.TryAdd(name, value))
+ {
+ EnvironmentVariables[name] = value;
+ }
+
+ return this;
+ }
+
+ ///
+ public IProjectFactory AddEnvironmentVariables(params KeyValuePair[] variables)
+ {
+ Argument.ThrowIfNull(variables);
+
+ foreach (var variable in variables)
+ {
+ _ = AddEnvironmentVariable(variable.Key, variable.Value);
+ }
+
+ return this;
+ }
+
+ ///
+ public TInterface AddFileBuilder(TImplementation builder)
+ where TInterface : IFileBuilder
+ where TImplementation : class, TInterface
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ if (!ObjectBuilders.Add(builder))
+ {
+ throw new ArgumentException("`builder` already registered.", nameof(builder));
+ }
+
+ return builder;
+ }
+
+ ///
+ public async ValueTask BuildAsync(string[]? args = null, CancellationToken cancellationToken = default)
+ {
+ if (ObjectBuilders.Count == 0)
+ {
+ throw new ArgumentException("No file builders were added.");
+ }
+
+ if (!ObjectBuilders.OfType().Any())
+ {
+ throw new ArgumentException("No project builder were added.");
+ }
+
+ // Create temporary directory for testing
+ await _tempDirectory.CreateAsync(cancellationToken).ConfigureAwait(false);
+
+ if (_testPackageBuilder is not null)
+ {
+ var lookupPaths = ObjectBuilders
+ .OfType()
+ .Select(x => x.ItemGroup.Items)
+ .OfType()
+ .SelectMany(x => x.LookUpPaths)
+ .Distinct()
+ .ToArray();
+
+ if (lookupPaths.Length > 0)
+ {
+ _testPackageBuilder.SetPackagePaths(lookupPaths);
+
+ // Prepare nuget packages for testings
+ await _testPackageBuilder.CreateAsync(cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ await Parallel
+ .ForEachAsync(
+ ObjectBuilders,
+ cancellationToken,
+ async (file, token) => await file.CreateAsync(token).ConfigureAwait(false)
+ )
+ .ConfigureAwait(false);
+
+ var result = await ExecuteDotNetCommandAsync([Constants.CommandRestore, "-v", "quiet"], cancellationToken)
+ .ConfigureAwait(false);
+
+ LogProcessExitCode(Constants.CommandRestore, result.ExitCode);
+
+ result = await ExecuteDotNetCommandAsync([Constants.CommandBuild, .. (args ?? [])], cancellationToken)
+ .ConfigureAwait(false);
+
+ LogProcessExitCode(Constants.CommandBuild, result.ExitCode);
+
+ var sarifBytes = await File.ReadAllBytesAsync(
+ _tempDirectory.GetFilePath(Constants.OutputFileName),
+ cancellationToken
+ )
+ .ConfigureAwait(false);
+
+ var sarif = JsonSerializer.Deserialize(sarifBytes)!;
+
+ EnrichSarifResults(sarif);
+
+ if (!sarif.HasNoErrorsOrWarnings())
+ {
+ LogSarifResult(string.Join('\n', sarif.Results.Select(x => x.ToString())));
+ }
+
+ return sarif;
+ }
+
+ private async Task ExecuteDotNetCommandAsync(
+ IEnumerable args,
+ CancellationToken cancellationToken
+ ) =>
+ await Cli.Wrap("dotnet")
+ .WithWorkingDirectory(_tempDirectory.FullPath)
+ .WithArguments(args)
+ .WithEnvironmentVariables(env =>
+ {
+ if (EnvironmentVariables.Count == 0)
+ {
+ return;
+ }
+
+ LogEnvironmentVariables();
+
+ foreach (var kvp in EnvironmentVariables)
+ {
+ LogEnvironmentVariable(kvp.Key, kvp.Value);
+ _ = env.Set(kvp.Key, kvp.Value);
+ }
+ })
+ .WithStandardOutputPipe(PipeTarget.ToDelegate(TrackStandardOutput))
+ .WithStandardErrorPipe(PipeTarget.ToDelegate(TrackErrorOutput))
+ .WithValidation(CommandResultValidation.None)
+ .ExecuteAsync(cancellationToken);
+
+ ///
+ /// Regular expression pattern used to extract diagnostic rule IDs from build output.
+ /// Matches patterns like "NU1234" or "NEP5678".
+ ///
+ ///
+ /// The pattern matches NuGet (NU) or NetEvolve.ProjectBuilders (NEP) diagnostic codes
+ /// followed by a four-digit number. This is used to filter and enrich SARIF output
+ /// with diagnostic information extracted from the dotnet build command output.
+ ///
+#if NET8_0_OR_GREATER
+ [GeneratedRegex(RulesFilterPattern, RegexOptions.Compiled)]
+ public static partial Regex RulesFilter();
+#else
+ public static Regex RulesFilter() => _rulesFilter;
+
+ private static readonly Regex _rulesFilter = new Regex(RulesFilterPattern, RegexOptions.Compiled);
+#endif
+
+ private void EnrichSarifResults(OutputFile? sarif)
+ {
+ if (_output.Count == 0 || sarif is null)
+ {
+ return;
+ }
+
+ var outputLines = _output
+ .SelectMany(x =>
+ x.Split(_newLineSeparator, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
+ )
+ .ToArray();
+ var filteredResults = new List();
+
+ foreach (var outputLine in outputLines)
+ {
+ var match = RulesFilter().Match(outputLine);
+ if (!match.Success)
+ {
+ continue;
+ }
+
+ var ruleId = match.Value.TrimEnd(':');
+ var previousColonIndex = outputLine.LastIndexOf(':', match.Index);
+ var ruleLevel = outputLine.Substring(previousColonIndex + 1, match.Index - previousColonIndex - 1).Trim();
+
+ var message = outputLine[(match.Index + match.Length + 1)..];
+
+ filteredResults.Add(
+ new OutputRunResult
+ {
+ RuleId = ruleId,
+ Level = ruleLevel,
+ Message = new OutputRunResultMessage { Text = message },
+ }
+ );
+ }
+
+ var distinctRules = filteredResults.DistinctBy(x => new { x.RuleId, x.Level }).ToList();
+ sarif.Runs.Add(new OutputRun { Results = distinctRules });
+ }
+
+ ///
+ public ValueTask DisposeAsync() => DisposeAsync(disposing: true);
+
+ private async ValueTask DisposeAsync(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ await Parallel
+ .ForEachAsync(ObjectBuilders, async (file, _) => await file.DisposeAsync().ConfigureAwait(false))
+ .ConfigureAwait(false);
+ }
+
+ _disposedValue = true;
+ }
+ }
+
+ private void TrackStandardOutput(string message)
+ {
+ LogStandardOutput(message);
+ _output.Add(message);
+ }
+
+ private void TrackErrorOutput(string message)
+ {
+ LogErrorOutput(message);
+ _output.Add(message);
+ }
+
+ [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "{Message}")]
+ private partial void LogStandardOutput(string message);
+
+ [LoggerMessage(EventId = 2, Level = LogLevel.Error, Message = "{Message}")]
+ private partial void LogErrorOutput(string message);
+
+ [LoggerMessage(EventId = 3, Level = LogLevel.Information, Message = "Process `{Name}` exit code: {ExitCode}")]
+ private partial void LogProcessExitCode(string name, int exitCode);
+
+ [LoggerMessage(EventId = 4, Level = LogLevel.Information, Message = "Result:\n{result}")]
+ private partial void LogSarifResult(string result);
+
+ [LoggerMessage(EventId = 5, Level = LogLevel.Debug, Message = "Environment Variables:")]
+ private partial void LogEnvironmentVariables();
+
+ [LoggerMessage(EventId = 6, Level = LogLevel.Debug, Message = " `{Key}`: `{Value}`")]
+ private partial void LogEnvironmentVariable(string key, string? value);
+}
diff --git a/src/NetEvolve.ProjectBuilders/README.md b/src/NetEvolve.ProjectBuilders/README.md
new file mode 100644
index 0000000..570f4e7
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/README.md
@@ -0,0 +1 @@
+Please give the customer a brief introduction about this library, and how to use it.
diff --git a/src/NetEvolve.ProjectBuilders/packages.lock.json b/src/NetEvolve.ProjectBuilders/packages.lock.json
new file mode 100644
index 0000000..867621b
--- /dev/null
+++ b/src/NetEvolve.ProjectBuilders/packages.lock.json
@@ -0,0 +1,239 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "CliWrap": {
+ "type": "Direct",
+ "requested": "[3.10.0, )",
+ "resolved": "3.10.0",
+ "contentHash": "Igph39WNImUFqQrpTeBDPafcCnM1u/8IooZHqMRF/5JdV5H78p+AbZkeYY1Nkz1WlbI/Gt2Hq/3rYh55jxRF9Q=="
+ },
+ "CSharpier.MsBuild": {
+ "type": "Direct",
+ "requested": "[1.2.1, )",
+ "resolved": "1.2.1",
+ "contentHash": "HolJfE0CR81eBFbYluoPxj3Kj6eQAeosVQ8QThw2NlTer1/2o8D6IxFhmRvZR8MkpgqAuvbO7WL90oudTYLGOw=="
+ },
+ "Microsoft.CodeAnalysis.BannedApiAnalyzers": {
+ "type": "Direct",
+ "requested": "[3.3.4, )",
+ "resolved": "3.3.4",
+ "contentHash": "0k2Jwpc8eq0hjOtX6TxRkHm9clkJ2PAQ3heEHgqIJZcsfdFosC/iyz18nsgTVDDWpID80rC7aiYK7ripx+Qndg=="
+ },
+ "Microsoft.CodeAnalysis.NetAnalyzers": {
+ "type": "Direct",
+ "requested": "[10.0.100, )",
+ "resolved": "10.0.100",
+ "contentHash": "uj9VuyvqylnNueJfU7u2PkI/hEMpZl8Wg9BXyI0eatNEldU5jDYPdwsM8aDL18+1oLovju25MiqOPaGRBnG72A=="
+ },
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.VisualStudio.Threading.Analyzers": {
+ "type": "Direct",
+ "requested": "[17.14.15, )",
+ "resolved": "17.14.15",
+ "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
+ },
+ "NetEvolve.Arguments": {
+ "type": "Direct",
+ "requested": "[2.0.17, )",
+ "resolved": "2.0.17",
+ "contentHash": "YjyDqJqlaVQZOzNrsTmENusTi+IOSPvS0qtwi5YiToHqn4OrddAohSF1taokEFbsBElxdxptNAJyiaDMhZteMg=="
+ },
+ "NetEvolve.Defaults": {
+ "type": "Direct",
+ "requested": "[1.4.81, )",
+ "resolved": "1.4.81",
+ "contentHash": "1P/7oZ6k188KaGLaMYVgT4BE/fGNr3wsMFWLyOU7BZE6PvrRovMU57brX/KU6h9sTZHC1r6mWLAljqtxTyR6/g==",
+ "dependencies": {
+ "NetEvolve.Defaults.Analyzer": "1.4.81"
+ }
+ },
+ "SonarAnalyzer.CSharp": {
+ "type": "Direct",
+ "requested": "[10.16.1.129956, )",
+ "resolved": "10.16.1.129956",
+ "contentHash": "XjMarxz00Xc+GD8JGYut1swL0RIw2iwfBhltEITsxsqC/MDLjK+8dk58fPYkS+YPwtdqzkU4VUuSqX3qrN2HYA=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ },
+ "NetEvolve.Defaults.Analyzer": {
+ "type": "Transitive",
+ "resolved": "1.4.81",
+ "contentHash": "SdgwEaqTdjpylQnCzTW3qWHlCJo8l/k5pVi1/wtu8zNq2RCmjKjdEwdzbqnuNZgq88O1kKk03eoC0QrBnLzf+w=="
+ }
+ },
+ "net8.0": {
+ "CliWrap": {
+ "type": "Direct",
+ "requested": "[3.10.0, )",
+ "resolved": "3.10.0",
+ "contentHash": "Igph39WNImUFqQrpTeBDPafcCnM1u/8IooZHqMRF/5JdV5H78p+AbZkeYY1Nkz1WlbI/Gt2Hq/3rYh55jxRF9Q=="
+ },
+ "CSharpier.MsBuild": {
+ "type": "Direct",
+ "requested": "[1.2.1, )",
+ "resolved": "1.2.1",
+ "contentHash": "HolJfE0CR81eBFbYluoPxj3Kj6eQAeosVQ8QThw2NlTer1/2o8D6IxFhmRvZR8MkpgqAuvbO7WL90oudTYLGOw=="
+ },
+ "Microsoft.CodeAnalysis.BannedApiAnalyzers": {
+ "type": "Direct",
+ "requested": "[3.3.4, )",
+ "resolved": "3.3.4",
+ "contentHash": "0k2Jwpc8eq0hjOtX6TxRkHm9clkJ2PAQ3heEHgqIJZcsfdFosC/iyz18nsgTVDDWpID80rC7aiYK7ripx+Qndg=="
+ },
+ "Microsoft.CodeAnalysis.NetAnalyzers": {
+ "type": "Direct",
+ "requested": "[10.0.100, )",
+ "resolved": "10.0.100",
+ "contentHash": "uj9VuyvqylnNueJfU7u2PkI/hEMpZl8Wg9BXyI0eatNEldU5jDYPdwsM8aDL18+1oLovju25MiqOPaGRBnG72A=="
+ },
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.VisualStudio.Threading.Analyzers": {
+ "type": "Direct",
+ "requested": "[17.14.15, )",
+ "resolved": "17.14.15",
+ "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
+ },
+ "NetEvolve.Arguments": {
+ "type": "Direct",
+ "requested": "[2.0.17, )",
+ "resolved": "2.0.17",
+ "contentHash": "YjyDqJqlaVQZOzNrsTmENusTi+IOSPvS0qtwi5YiToHqn4OrddAohSF1taokEFbsBElxdxptNAJyiaDMhZteMg=="
+ },
+ "NetEvolve.Defaults": {
+ "type": "Direct",
+ "requested": "[1.4.81, )",
+ "resolved": "1.4.81",
+ "contentHash": "1P/7oZ6k188KaGLaMYVgT4BE/fGNr3wsMFWLyOU7BZE6PvrRovMU57brX/KU6h9sTZHC1r6mWLAljqtxTyR6/g==",
+ "dependencies": {
+ "NetEvolve.Defaults.Analyzer": "1.4.81"
+ }
+ },
+ "SonarAnalyzer.CSharp": {
+ "type": "Direct",
+ "requested": "[10.16.1.129956, )",
+ "resolved": "10.16.1.129956",
+ "contentHash": "XjMarxz00Xc+GD8JGYut1swL0RIw2iwfBhltEITsxsqC/MDLjK+8dk58fPYkS+YPwtdqzkU4VUuSqX3qrN2HYA=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ },
+ "NetEvolve.Defaults.Analyzer": {
+ "type": "Transitive",
+ "resolved": "1.4.81",
+ "contentHash": "SdgwEaqTdjpylQnCzTW3qWHlCJo8l/k5pVi1/wtu8zNq2RCmjKjdEwdzbqnuNZgq88O1kKk03eoC0QrBnLzf+w=="
+ }
+ },
+ "net9.0": {
+ "CliWrap": {
+ "type": "Direct",
+ "requested": "[3.10.0, )",
+ "resolved": "3.10.0",
+ "contentHash": "Igph39WNImUFqQrpTeBDPafcCnM1u/8IooZHqMRF/5JdV5H78p+AbZkeYY1Nkz1WlbI/Gt2Hq/3rYh55jxRF9Q=="
+ },
+ "CSharpier.MsBuild": {
+ "type": "Direct",
+ "requested": "[1.2.1, )",
+ "resolved": "1.2.1",
+ "contentHash": "HolJfE0CR81eBFbYluoPxj3Kj6eQAeosVQ8QThw2NlTer1/2o8D6IxFhmRvZR8MkpgqAuvbO7WL90oudTYLGOw=="
+ },
+ "Microsoft.CodeAnalysis.BannedApiAnalyzers": {
+ "type": "Direct",
+ "requested": "[3.3.4, )",
+ "resolved": "3.3.4",
+ "contentHash": "0k2Jwpc8eq0hjOtX6TxRkHm9clkJ2PAQ3heEHgqIJZcsfdFosC/iyz18nsgTVDDWpID80rC7aiYK7ripx+Qndg=="
+ },
+ "Microsoft.CodeAnalysis.NetAnalyzers": {
+ "type": "Direct",
+ "requested": "[10.0.100, )",
+ "resolved": "10.0.100",
+ "contentHash": "uj9VuyvqylnNueJfU7u2PkI/hEMpZl8Wg9BXyI0eatNEldU5jDYPdwsM8aDL18+1oLovju25MiqOPaGRBnG72A=="
+ },
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.VisualStudio.Threading.Analyzers": {
+ "type": "Direct",
+ "requested": "[17.14.15, )",
+ "resolved": "17.14.15",
+ "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw=="
+ },
+ "NetEvolve.Arguments": {
+ "type": "Direct",
+ "requested": "[2.0.17, )",
+ "resolved": "2.0.17",
+ "contentHash": "YjyDqJqlaVQZOzNrsTmENusTi+IOSPvS0qtwi5YiToHqn4OrddAohSF1taokEFbsBElxdxptNAJyiaDMhZteMg=="
+ },
+ "NetEvolve.Defaults": {
+ "type": "Direct",
+ "requested": "[1.4.81, )",
+ "resolved": "1.4.81",
+ "contentHash": "1P/7oZ6k188KaGLaMYVgT4BE/fGNr3wsMFWLyOU7BZE6PvrRovMU57brX/KU6h9sTZHC1r6mWLAljqtxTyR6/g==",
+ "dependencies": {
+ "NetEvolve.Defaults.Analyzer": "1.4.81"
+ }
+ },
+ "SonarAnalyzer.CSharp": {
+ "type": "Direct",
+ "requested": "[10.16.1.129956, )",
+ "resolved": "10.16.1.129956",
+ "contentHash": "XjMarxz00Xc+GD8JGYut1swL0RIw2iwfBhltEITsxsqC/MDLjK+8dk58fPYkS+YPwtdqzkU4VUuSqX3qrN2HYA=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ },
+ "NetEvolve.Defaults.Analyzer": {
+ "type": "Transitive",
+ "resolved": "1.4.81",
+ "contentHash": "SdgwEaqTdjpylQnCzTW3qWHlCJo8l/k5pVi1/wtu8zNq2RCmjKjdEwdzbqnuNZgq88O1kKk03eoC0QrBnLzf+w=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/GlobalJsonBuilderTests.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/GlobalJsonBuilderTests.cs
new file mode 100644
index 0000000..27442ef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/GlobalJsonBuilderTests.cs
@@ -0,0 +1,26 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration.Builders;
+
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models;
+
+[ClassDataSource]
+public class GlobalJsonBuilderTests(TemporaryDirectory directory)
+{
+ [Test]
+ [MatrixDataSource]
+ public async Task CreateAsync_Theory_Expected(
+ [Matrix(Constants.RuntimeSdkDefault, "10.0.100")] string runtimeVersion,
+ bool allowPrerelease,
+ RollForward rollForward
+ )
+ {
+ var subdirectory = directory.CreateDirectory($"{nameof(CreateAsync_Theory_Expected)}");
+ await using var builder = new GlobalJsonBuilder(subdirectory, runtimeVersion);
+ await builder.SetAllowPrerelease(allowPrerelease).SetRollForward(rollForward).CreateAsync();
+ _ = await VerifyFile(builder.FullPath)
+ .UseParameters(allowPrerelease, rollForward, runtimeVersion)
+ .HashParameters();
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/ProjectBuilderTests.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/ProjectBuilderTests.cs
new file mode 100644
index 0000000..c741d13
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Builders/ProjectBuilderTests.cs
@@ -0,0 +1,97 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration.Builders;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models;
+
+[ClassDataSource]
+public class ProjectBuilderTests(TemporaryDirectory directory)
+{
+ [Test]
+ [MatrixDataSource]
+ public async ValueTask CreateAsync_TargetFrameworkTheory_Expected(
+ [Matrix(null, "Microsoft.NET.Sdk", "Microsoft.NET.Sdk.Web")] string? sdk,
+ NullableOptions nullable,
+ [MatrixInstanceMethod(nameof(GetTargetFrameworkValues))] TargetFramework targetFramework
+ )
+ {
+ var subdirectory = directory.CreateDirectory($"{nameof(CreateAsync_TargetFrameworkTheory_Expected)}");
+ await using var builder = new ProjectBuilder(subdirectory, Constants.CSharpProjectFileName);
+
+ await builder.WithNullable(nullable).WithTargetFramework(targetFramework).SetProjectSdk(sdk).CreateAsync();
+
+ _ = await VerifyFile(builder.FullPath, extension: "xml")
+ .UseParameters(nullable, targetFramework, sdk)
+ .HashParameters();
+ }
+
+ [Test]
+ [MatrixDataSource]
+ public async ValueTask CreateAsync_TargetFrameworksTheory_Expected(
+ [Matrix(null, "Microsoft.NET.Sdk", "Microsoft.NET.Sdk.Web")] string? sdk,
+ NullableOptions nullable,
+ [MatrixInstanceMethod(nameof(GetTargetFrameworkValues))] TargetFramework targetFramework
+ )
+ {
+ var subdirectory = directory.CreateDirectory(
+ $"{nameof(CreateAsync_TargetFrameworksTheory_Expected)}{nullable}"
+ );
+ await using var builder = new ProjectBuilder(subdirectory, Constants.CSharpProjectFileName);
+
+ await builder
+ .WithNullable(nullable)
+ .WithTargetFrameworks(TargetFramework.NetStandard2_0, targetFramework)
+ .SetProjectSdk(sdk)
+ .CreateAsync();
+
+ _ = await VerifyFile(builder.FullPath, extension: "xml")
+ .UseParameters(nullable, targetFramework, sdk)
+ .HashParameters();
+ }
+
+ [SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Required by TUnit.")]
+ public static IEnumerable GetTargetFrameworkValues() =>
+ [TargetFramework.NetStandard2_0, TargetFramework.Net10Windows, TargetFramework.NetFramework4_8_1];
+
+ [Test]
+ [MatrixDataSource]
+ public async ValueTask AddPackageReference_Newtonsoft_Expected(
+ [Matrix("13.0.1", null)] string? version,
+ [Matrix("13.0.1", null)] string? versionOverride,
+ bool generatePathProperty,
+ [Matrix("NJson", "")] string? aliases,
+ [Matrix(ReferenceAssets.All, null)] ReferenceAssets? includeAssets,
+ [Matrix(ReferenceAssets.None, ReferenceAssets.Runtime)] ReferenceAssets? excludeAssets,
+ [Matrix(ReferenceAssets.Build | ReferenceAssets.ContentFiles, null)] ReferenceAssets? privateAssets
+ )
+ {
+ var subdirectory = directory.CreateDirectory($"{nameof(AddPackageReference_Newtonsoft_Expected)}");
+ await using var builder = new ProjectBuilder(subdirectory, Constants.CSharpProjectFileName);
+ await builder
+ .AddPackageReference(
+ "Newtonsoft.Json",
+ version,
+ versionOverride,
+ generatePathProperty,
+ aliases,
+ includeAssets,
+ excludeAssets,
+ privateAssets
+ )
+ .CreateAsync();
+
+ _ = await VerifyFile(builder.FullPath, extension: "xml")
+ .UseParameters(
+ version,
+ versionOverride,
+ generatePathProperty,
+ aliases,
+ includeAssets,
+ excludeAssets,
+ privateAssets
+ )
+ .HashParameters();
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/CSharpProjectTests.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/CSharpProjectTests.cs
new file mode 100644
index 0000000..1f82a12
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/CSharpProjectTests.cs
@@ -0,0 +1,82 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration;
+
+using System;
+using System.Threading.Tasks;
+using NetEvolve.Extensions.TUnit.Logging;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+
+[ClassDataSource]
+public class CSharpProjectTests(TemporaryDirectory directory)
+{
+ [Test]
+ [MethodDataSource(nameof(AddCSharpFileData))]
+ public async Task BuildAsync_CSharp_Theory(bool expectedErrors, bool expectedWarnings, string content)
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var projectDirectory = directory.CreateDirectory($"{nameof(BuildAsync_CSharp_Theory)}{Guid.NewGuid()}");
+ var nugetDirectory = directory.CreateDirectory($"{nameof(BuildAsync_CSharp_Theory)}{Guid.NewGuid()}");
+
+ await using var nugetFactory = new TestPackageBuilder(nugetDirectory);
+ await using var factory = ProjectFactory.Create(
+ nugetFactory,
+ projectDirectory,
+ logger.ConvertTo()
+ );
+
+ var result = await factory
+ .AddCSharpProject(builder =>
+ {
+ builder.WithDefaults().AddCSharpFile("main.cs", content);
+ })
+ .AddGlobalJson(configure: projectBuilder => projectBuilder.WithDefaults())
+ .BuildAsync();
+
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(result.HasErrors()).IsEqualTo(expectedErrors);
+ _ = await Assert.That(result.HasWarnings()).IsEqualTo(expectedWarnings);
+ }
+ }
+
+ [Test]
+ [MethodDataSource(nameof(AddCSharpFileData))]
+ public async Task BuildAsync_CSharp_VerifyDirectory(bool expectedErrors, bool expectedWarnings, string content)
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var projectDirectory = directory.CreateDirectory(
+ $"{nameof(BuildAsync_CSharp_VerifyDirectory)}{Guid.NewGuid()}"
+ );
+ var nugetDirectory = directory.CreateDirectory($"{nameof(BuildAsync_CSharp_VerifyDirectory)}{Guid.NewGuid()}");
+
+ await using var nugetFactory = new TestPackageBuilder(nugetDirectory);
+ await using var factory = ProjectFactory.Create(
+ nugetFactory,
+ projectDirectory,
+ logger.ConvertTo()
+ );
+
+ _ = await factory
+ .AddCSharpProject(builder =>
+ {
+ builder.WithDefaults().AddCSharpFile("main.cs", content);
+ })
+ .AddGlobalJson(configure: projectBuilder => projectBuilder.WithDefaults())
+ .BuildAsync();
+
+ _ = await VerifyDirectory(projectDirectory.FullPath, include: ProjectHelpers.DirectoryFilter)
+ .UseParameters(expectedErrors, expectedWarnings, content)
+ .HashParameters();
+ }
+
+ public static IEnumerable<(bool, bool, string)> AddCSharpFileData =>
+ [
+ (false, false, "class Program { static void Main() { System.Console.WriteLine(\"Hello, World!\"); } }"),
+ (true, false, "class Program { static void Main() { WriteLine(\"Hello, World!\"); }"),
+ (
+ false,
+ true,
+ "class Program { static async void Main() { System.Console.WriteLine(\"Hello, World!\"); } }"
+ ),
+ ];
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/NetEvolve.ProjectBuilders.TUnit.Tests.Integration.csproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/NetEvolve.ProjectBuilders.TUnit.Tests.Integration.csproj
new file mode 100644
index 0000000..6a28270
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/NetEvolve.ProjectBuilders.TUnit.Tests.Integration.csproj
@@ -0,0 +1,27 @@
+
+
+ Exe
+ $(TestTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Predefined.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Predefined.cs
new file mode 100644
index 0000000..c013753
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/Predefined.cs
@@ -0,0 +1,23 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration;
+
+using System.IO;
+using System.Runtime.CompilerServices;
+using VerifyTests;
+
+internal static class Predefined
+{
+ [ModuleInitializer]
+ public static void Init()
+ {
+ Verifier.DerivePathInfo(
+ (sourceFile, projectDirectory, method, type) =>
+ {
+ var snapshots = Path.Combine(projectDirectory, "_snapshots");
+ _ = Directory.CreateDirectory(snapshots);
+ return new(snapshots, type.Name, method.Name);
+ }
+ );
+
+ VerifierSettings.AutoVerify(includeBuildServer: false, throwException: true);
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectFactoryTests.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectFactoryTests.cs
new file mode 100644
index 0000000..25a6a7b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectFactoryTests.cs
@@ -0,0 +1,53 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration;
+
+using System.Threading.Tasks;
+using NetEvolve.Extensions.TUnit.Logging;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models;
+
+[ClassDataSource]
+public class ProjectFactoryTests(TemporaryDirectory directory)
+{
+ [Test]
+ public async Task BuildAsync_CSharpProject_Expected()
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var subdirectory = directory.CreateDirectory(nameof(BuildAsync_CSharpProject_Expected));
+ await using var factory = ProjectFactory.Create(
+ directory: subdirectory,
+ logger: logger.ConvertTo()
+ );
+
+ var result = await factory
+ .AddCSharpProject(projectBuilder => projectBuilder.WithTargetFramework(TargetFramework.Net8))
+ .AddGlobalJson(
+ Constants.RuntimeSdkDefault,
+ jsonBuilder => jsonBuilder.SetRollForward(RollForward.LatestMinor)
+ )
+ .BuildAsync();
+
+ _ = await Assert.That(result.HasNoErrorsOrWarnings()).IsTrue();
+ }
+
+ [Test]
+ public async Task BuildAsync_VBProject_Expected()
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var subdirectory = directory.CreateDirectory(nameof(BuildAsync_VBProject_Expected));
+ await using var factory = ProjectFactory.Create(
+ directory: subdirectory,
+ logger: logger.ConvertTo()
+ );
+
+ var result = await factory
+ .AddVBProject(projectBuilder => projectBuilder.WithTargetFramework(TargetFramework.Net8))
+ .AddGlobalJson(
+ Constants.RuntimeSdkDefault,
+ jsonBuilder => jsonBuilder.SetRollForward(RollForward.LatestMinor)
+ )
+ .BuildAsync();
+
+ _ = await Assert.That(result.HasNoErrorsOrWarnings()).IsTrue();
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectHelpers.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectHelpers.cs
new file mode 100644
index 0000000..811ba0f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/ProjectHelpers.cs
@@ -0,0 +1,32 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration;
+
+using System;
+
+internal static class ProjectHelpers
+{
+ public static bool DirectoryFilter(string path)
+ {
+ // Path contains `obj/` or `bin/` folders are ignored
+ if (
+ path.Contains(
+ $"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}",
+ StringComparison.OrdinalIgnoreCase
+ )
+ || path.Contains(
+ $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}",
+ StringComparison.OrdinalIgnoreCase
+ )
+ )
+ {
+ return false;
+ }
+
+ // Path ends with `.sarif` files are ignored
+ if (path.EndsWith(".sarif", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/VBProjectTests.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/VBProjectTests.cs
new file mode 100644
index 0000000..0512bb5
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/VBProjectTests.cs
@@ -0,0 +1,106 @@
+namespace NetEvolve.ProjectBuilders.TUnit.Tests.Integration;
+
+using System;
+using System.Threading.Tasks;
+using NetEvolve.Extensions.TUnit.Logging;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+
+[ClassDataSource]
+public class VBProjectTests(TemporaryDirectory directory)
+{
+ [Test]
+ [MethodDataSource(nameof(AddVBFileData))]
+ public async Task BuildAsync_VB_Theory(bool expectedErrors, bool expectedWarnings, string content)
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var projectDirectory = directory.CreateDirectory($"{nameof(BuildAsync_VB_Theory)}{Guid.NewGuid()}");
+ var nugetDirectory = directory.CreateDirectory($"{nameof(BuildAsync_VB_Theory)}{Guid.NewGuid()}");
+
+ await using var nugetFactory = new TestPackageBuilder(nugetDirectory);
+ await using var factory = ProjectFactory.Create(
+ nugetFactory,
+ projectDirectory,
+ logger.ConvertTo()
+ );
+
+ var result = await factory
+ .AddVBProject(builder =>
+ {
+ builder.WithDefaults().AddVBFile("main.vb", content);
+ })
+ .AddGlobalJson(configure: projectBuilder => projectBuilder.WithDefaults())
+ .BuildAsync();
+
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(result.HasErrors()).IsEqualTo(expectedErrors);
+ _ = await Assert.That(result.HasWarnings()).IsEqualTo(expectedWarnings);
+ }
+ }
+
+ [Test]
+ [MethodDataSource(nameof(AddVBFileData))]
+ public async Task BuildAsync_VB_VerifyDirectory(bool expectedErrors, bool expectedWarnings, string content)
+ {
+ var logger = TestContext.Current!.GetDefaultLogger();
+ var projectDirectory = directory.CreateDirectory($"{nameof(BuildAsync_VB_Theory)}{Guid.NewGuid()}");
+ var nugetDirectory = directory.CreateDirectory($"{nameof(BuildAsync_VB_Theory)}{Guid.NewGuid()}");
+
+ await using var nugetFactory = new TestPackageBuilder(nugetDirectory);
+ await using var factory = ProjectFactory.Create(
+ nugetFactory,
+ projectDirectory,
+ logger.ConvertTo()
+ );
+
+ _ = await factory
+ .AddVBProject(builder =>
+ {
+ builder.WithDefaults().AddVBFile("main.vb", content);
+ })
+ .AddGlobalJson(configure: projectBuilder => projectBuilder.WithDefaults())
+ .BuildAsync();
+
+ _ = await VerifyDirectory(projectDirectory.FullPath, include: ProjectHelpers.DirectoryFilter)
+ .UseParameters(expectedErrors, expectedWarnings, content)
+ .HashParameters();
+ }
+
+ public static IEnumerable<(bool, bool, string)> AddVBFileData =>
+ [
+ (
+ false,
+ false,
+ """
+ Module Program
+ Sub Main()
+ System.Console.WriteLine("Hello, World!")
+ End Sub
+ End Module
+ """
+ ),
+ (
+ true,
+ false,
+ """
+ Module Program
+ Sub Main()
+ WriteLine(""Hello, World!"")
+ End Sub
+ End Module
+ """
+ ),
+ (
+ false,
+ true,
+ """
+ Module Program
+ Async Sub Main()
+ System.Console.WriteLine("Hello, World!")
+ End Sub
+ End Module
+ """
+ ),
+ ];
+}
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_002576b009b69084.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_002576b009b69084.verified.xml
new file mode 100644
index 0000000..e8ee7fd
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_002576b009b69084.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_014c88aa1eb0fa59.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_014c88aa1eb0fa59.verified.xml
new file mode 100644
index 0000000..3ab1213
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_014c88aa1eb0fa59.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0157c632cd6f3878.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0157c632cd6f3878.verified.xml
new file mode 100644
index 0000000..8a90427
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0157c632cd6f3878.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_01781dd25150fdfa.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_01781dd25150fdfa.verified.xml
new file mode 100644
index 0000000..69f2b7d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_01781dd25150fdfa.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_04f6e0921c8a1a39.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_04f6e0921c8a1a39.verified.xml
new file mode 100644
index 0000000..3f24003
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_04f6e0921c8a1a39.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_05f6b20131874c63.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_05f6b20131874c63.verified.xml
new file mode 100644
index 0000000..ca46d3c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_05f6b20131874c63.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_06cb3fda7ba88edf.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_06cb3fda7ba88edf.verified.xml
new file mode 100644
index 0000000..a544967
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_06cb3fda7ba88edf.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0dc9993dbce50e2a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0dc9993dbce50e2a.verified.xml
new file mode 100644
index 0000000..50d0eef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0dc9993dbce50e2a.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0ec66c7ff8f3fd88.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0ec66c7ff8f3fd88.verified.xml
new file mode 100644
index 0000000..448556b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0ec66c7ff8f3fd88.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0f77c42c24f69d61.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0f77c42c24f69d61.verified.xml
new file mode 100644
index 0000000..c693b61
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_0f77c42c24f69d61.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_10044da6698faaec.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_10044da6698faaec.verified.xml
new file mode 100644
index 0000000..93d2268
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_10044da6698faaec.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_148f8409ababd45d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_148f8409ababd45d.verified.xml
new file mode 100644
index 0000000..e2c0034
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_148f8409ababd45d.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1a62563615cffdfa.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1a62563615cffdfa.verified.xml
new file mode 100644
index 0000000..13b4b55
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1a62563615cffdfa.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1ae659289f7de4b6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1ae659289f7de4b6.verified.xml
new file mode 100644
index 0000000..93d2268
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1ae659289f7de4b6.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bbb5107ee3ccebd.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bbb5107ee3ccebd.verified.xml
new file mode 100644
index 0000000..3989c2a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bbb5107ee3ccebd.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bc6f8254dafd0b3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bc6f8254dafd0b3.verified.xml
new file mode 100644
index 0000000..e0e0630
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bc6f8254dafd0b3.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bedd9430f8f06f3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bedd9430f8f06f3.verified.xml
new file mode 100644
index 0000000..279b39b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_1bedd9430f8f06f3.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_20252e5e1a81019d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_20252e5e1a81019d.verified.xml
new file mode 100644
index 0000000..9893e53
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_20252e5e1a81019d.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_2047f6d7bd38000f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_2047f6d7bd38000f.verified.xml
new file mode 100644
index 0000000..e5aa94c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_2047f6d7bd38000f.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_235a2ab415a98681.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_235a2ab415a98681.verified.xml
new file mode 100644
index 0000000..50d0eef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_235a2ab415a98681.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27907c1071a0cdcf.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27907c1071a0cdcf.verified.xml
new file mode 100644
index 0000000..72593b1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27907c1071a0cdcf.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27e4822e4c5f91be.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27e4822e4c5f91be.verified.xml
new file mode 100644
index 0000000..098e832
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27e4822e4c5f91be.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27f2305435e36a11.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27f2305435e36a11.verified.xml
new file mode 100644
index 0000000..683e1ee
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_27f2305435e36a11.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_28316a8eb252d7fd.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_28316a8eb252d7fd.verified.xml
new file mode 100644
index 0000000..3ab1213
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_28316a8eb252d7fd.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_295d67a72f4d6e81.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_295d67a72f4d6e81.verified.xml
new file mode 100644
index 0000000..da2da16
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_295d67a72f4d6e81.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_29625f5cc5ed8c80.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_29625f5cc5ed8c80.verified.xml
new file mode 100644
index 0000000..a5bdc5c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_29625f5cc5ed8c80.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_309d76eecdaa2b5a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_309d76eecdaa2b5a.verified.xml
new file mode 100644
index 0000000..a5215f5
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_309d76eecdaa2b5a.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_31e49db9ec57e02c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_31e49db9ec57e02c.verified.xml
new file mode 100644
index 0000000..e2c0034
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_31e49db9ec57e02c.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_353b10b3ec725703.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_353b10b3ec725703.verified.xml
new file mode 100644
index 0000000..2db7132
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_353b10b3ec725703.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3ad713e2a28b150f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3ad713e2a28b150f.verified.xml
new file mode 100644
index 0000000..3578039
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3ad713e2a28b150f.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3d555cae51f96fee.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3d555cae51f96fee.verified.xml
new file mode 100644
index 0000000..e5aa94c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_3d555cae51f96fee.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4097f55783c42ebc.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4097f55783c42ebc.verified.xml
new file mode 100644
index 0000000..448556b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4097f55783c42ebc.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_409add5e539970a6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_409add5e539970a6.verified.xml
new file mode 100644
index 0000000..424a860
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_409add5e539970a6.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_41c164fb550de493.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_41c164fb550de493.verified.xml
new file mode 100644
index 0000000..19643b0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_41c164fb550de493.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4477483d7c3449f2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4477483d7c3449f2.verified.xml
new file mode 100644
index 0000000..3f24003
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4477483d7c3449f2.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4982b6947191a479.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4982b6947191a479.verified.xml
new file mode 100644
index 0000000..19643b0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4982b6947191a479.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4a25a05a4a07b91c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4a25a05a4a07b91c.verified.xml
new file mode 100644
index 0000000..dad570a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4a25a05a4a07b91c.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4af30c419b62c7ec.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4af30c419b62c7ec.verified.xml
new file mode 100644
index 0000000..dad570a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4af30c419b62c7ec.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4b38e5ea87ae960f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4b38e5ea87ae960f.verified.xml
new file mode 100644
index 0000000..e8ee7fd
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4b38e5ea87ae960f.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4e911658dffabfd0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4e911658dffabfd0.verified.xml
new file mode 100644
index 0000000..816611e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_4e911658dffabfd0.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_52f04dfca817a8e7.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_52f04dfca817a8e7.verified.xml
new file mode 100644
index 0000000..50d0eef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_52f04dfca817a8e7.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_551512310fc5ed30.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_551512310fc5ed30.verified.xml
new file mode 100644
index 0000000..a544967
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_551512310fc5ed30.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_56e7e31730678e66.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_56e7e31730678e66.verified.xml
new file mode 100644
index 0000000..da2da16
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_56e7e31730678e66.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_580cf9f37b633a49.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_580cf9f37b633a49.verified.xml
new file mode 100644
index 0000000..69f2b7d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_580cf9f37b633a49.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5894e61598effa69.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5894e61598effa69.verified.xml
new file mode 100644
index 0000000..f6de690
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5894e61598effa69.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_59e302674fc09194.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_59e302674fc09194.verified.xml
new file mode 100644
index 0000000..e8ee7fd
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_59e302674fc09194.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5da0ae6ea52d225d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5da0ae6ea52d225d.verified.xml
new file mode 100644
index 0000000..d51d5df
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5da0ae6ea52d225d.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5dbe9b53b68e0d40.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5dbe9b53b68e0d40.verified.xml
new file mode 100644
index 0000000..f6de690
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5dbe9b53b68e0d40.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5ed34826fed7437e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5ed34826fed7437e.verified.xml
new file mode 100644
index 0000000..55c1d5f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_5ed34826fed7437e.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_604ef611963ee6df.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_604ef611963ee6df.verified.xml
new file mode 100644
index 0000000..098e832
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_604ef611963ee6df.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_64730a3314bba34e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_64730a3314bba34e.verified.xml
new file mode 100644
index 0000000..8083793
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_64730a3314bba34e.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_67a105338e6d13da.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_67a105338e6d13da.verified.xml
new file mode 100644
index 0000000..d51d5df
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_67a105338e6d13da.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6815fb81918c6716.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6815fb81918c6716.verified.xml
new file mode 100644
index 0000000..9df7f76
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6815fb81918c6716.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_69d1d05ca8234708.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_69d1d05ca8234708.verified.xml
new file mode 100644
index 0000000..bc98d5d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_69d1d05ca8234708.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6fb26878dd44f98d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6fb26878dd44f98d.verified.xml
new file mode 100644
index 0000000..1b5f65d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_6fb26878dd44f98d.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_721234dc01054059.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_721234dc01054059.verified.xml
new file mode 100644
index 0000000..e8ee7fd
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_721234dc01054059.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_728b41b2da145d08.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_728b41b2da145d08.verified.xml
new file mode 100644
index 0000000..c693b61
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_728b41b2da145d08.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_74ed91b3a2f05aee.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_74ed91b3a2f05aee.verified.xml
new file mode 100644
index 0000000..448556b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_74ed91b3a2f05aee.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_773b040a7c1121a3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_773b040a7c1121a3.verified.xml
new file mode 100644
index 0000000..70bb23a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_773b040a7c1121a3.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_793a7f4e4b1d27c3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_793a7f4e4b1d27c3.verified.xml
new file mode 100644
index 0000000..8a90427
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_793a7f4e4b1d27c3.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_79d445af5f45c5d7.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_79d445af5f45c5d7.verified.xml
new file mode 100644
index 0000000..3ab1213
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_79d445af5f45c5d7.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7c6029fa650c1a04.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7c6029fa650c1a04.verified.xml
new file mode 100644
index 0000000..ca46d3c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7c6029fa650c1a04.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7d0ba9ca01aa10ac.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7d0ba9ca01aa10ac.verified.xml
new file mode 100644
index 0000000..1b5f65d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_7d0ba9ca01aa10ac.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_81bdaf5908c5e286.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_81bdaf5908c5e286.verified.xml
new file mode 100644
index 0000000..31ab6df
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_81bdaf5908c5e286.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_847707a8d629d400.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_847707a8d629d400.verified.xml
new file mode 100644
index 0000000..5da367c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_847707a8d629d400.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_860bcae73f5a5212.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_860bcae73f5a5212.verified.xml
new file mode 100644
index 0000000..c5c52a7
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_860bcae73f5a5212.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_868e89228ad8a321.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_868e89228ad8a321.verified.xml
new file mode 100644
index 0000000..131aaa8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_868e89228ad8a321.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_88843c8ebda07ce1.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_88843c8ebda07ce1.verified.xml
new file mode 100644
index 0000000..da2da16
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_88843c8ebda07ce1.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8f8e8d1722716363.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8f8e8d1722716363.verified.xml
new file mode 100644
index 0000000..13b4b55
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8f8e8d1722716363.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8fb099899cc8500f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8fb099899cc8500f.verified.xml
new file mode 100644
index 0000000..72593b1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_8fb099899cc8500f.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_91d03f4d03311e33.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_91d03f4d03311e33.verified.xml
new file mode 100644
index 0000000..094655f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_91d03f4d03311e33.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_95fb52281322a35f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_95fb52281322a35f.verified.xml
new file mode 100644
index 0000000..9893e53
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_95fb52281322a35f.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9665b3cd2fc43e0c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9665b3cd2fc43e0c.verified.xml
new file mode 100644
index 0000000..e5aa94c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9665b3cd2fc43e0c.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9822994d7c495041.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9822994d7c495041.verified.xml
new file mode 100644
index 0000000..819d64e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9822994d7c495041.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9a7e351d5167113b.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9a7e351d5167113b.verified.xml
new file mode 100644
index 0000000..31ab6df
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9a7e351d5167113b.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9af96e678e60a26c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9af96e678e60a26c.verified.xml
new file mode 100644
index 0000000..3578039
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9af96e678e60a26c.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9bae22bea543ace3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9bae22bea543ace3.verified.xml
new file mode 100644
index 0000000..8083793
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9bae22bea543ace3.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9c1d74dc6c5c3401.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9c1d74dc6c5c3401.verified.xml
new file mode 100644
index 0000000..279b39b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9c1d74dc6c5c3401.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f27a509ce48af41.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f27a509ce48af41.verified.xml
new file mode 100644
index 0000000..816611e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f27a509ce48af41.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f9fc9cf70769933.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f9fc9cf70769933.verified.xml
new file mode 100644
index 0000000..e5aa94c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_9f9fc9cf70769933.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a32ccb328169316d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a32ccb328169316d.verified.xml
new file mode 100644
index 0000000..ca46d3c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a32ccb328169316d.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a513774af2831f66.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a513774af2831f66.verified.xml
new file mode 100644
index 0000000..e2c0034
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a513774af2831f66.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a8a69de65d665526.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a8a69de65d665526.verified.xml
new file mode 100644
index 0000000..20c3378
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_a8a69de65d665526.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aa651ea6c3e645ff.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aa651ea6c3e645ff.verified.xml
new file mode 100644
index 0000000..094655f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aa651ea6c3e645ff.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ae09fd766cfa3fd4.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ae09fd766cfa3fd4.verified.xml
new file mode 100644
index 0000000..c5c52a7
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ae09fd766cfa3fd4.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aed2e9c5749b1564.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aed2e9c5749b1564.verified.xml
new file mode 100644
index 0000000..4af5455
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_aed2e9c5749b1564.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b0b3a0c389632cab.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b0b3a0c389632cab.verified.xml
new file mode 100644
index 0000000..f6de690
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b0b3a0c389632cab.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1207f67c738cf28.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1207f67c738cf28.verified.xml
new file mode 100644
index 0000000..e0e0630
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1207f67c738cf28.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b13f5a218aaed0bd.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b13f5a218aaed0bd.verified.xml
new file mode 100644
index 0000000..683e1ee
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b13f5a218aaed0bd.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b15c552f0d5c0281.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b15c552f0d5c0281.verified.xml
new file mode 100644
index 0000000..806408c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b15c552f0d5c0281.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1bdefe6e9d0acd7.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1bdefe6e9d0acd7.verified.xml
new file mode 100644
index 0000000..094655f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b1bdefe6e9d0acd7.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b2b9a91b77fd25d2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b2b9a91b77fd25d2.verified.xml
new file mode 100644
index 0000000..a5bdc5c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b2b9a91b77fd25d2.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b3a492a5dc76de8c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b3a492a5dc76de8c.verified.xml
new file mode 100644
index 0000000..20c3378
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b3a492a5dc76de8c.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b47b3d7a613e5a06.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b47b3d7a613e5a06.verified.xml
new file mode 100644
index 0000000..ca46d3c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_b47b3d7a613e5a06.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bc2fa3f40e004f8b.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bc2fa3f40e004f8b.verified.xml
new file mode 100644
index 0000000..72593b1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bc2fa3f40e004f8b.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_be7fcac195ecb3f7.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_be7fcac195ecb3f7.verified.xml
new file mode 100644
index 0000000..a5215f5
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_be7fcac195ecb3f7.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bf61838e358de815.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bf61838e358de815.verified.xml
new file mode 100644
index 0000000..4af5455
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bf61838e358de815.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bfd5db912f05a94a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bfd5db912f05a94a.verified.xml
new file mode 100644
index 0000000..bc98d5d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_bfd5db912f05a94a.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c36b1289e04fa2ce.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c36b1289e04fa2ce.verified.xml
new file mode 100644
index 0000000..098e832
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c36b1289e04fa2ce.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c3d9dd8f2cb0315a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c3d9dd8f2cb0315a.verified.xml
new file mode 100644
index 0000000..55eafc0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c3d9dd8f2cb0315a.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c53456238483f046.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c53456238483f046.verified.xml
new file mode 100644
index 0000000..da2da16
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c53456238483f046.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7a2c1faa32df3f2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7a2c1faa32df3f2.verified.xml
new file mode 100644
index 0000000..094655f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7a2c1faa32df3f2.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7c0ce2f63effb43.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7c0ce2f63effb43.verified.xml
new file mode 100644
index 0000000..806408c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_c7c0ce2f63effb43.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cae2b5135b008a52.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cae2b5135b008a52.verified.xml
new file mode 100644
index 0000000..3989c2a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cae2b5135b008a52.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cfb02bb2552925d7.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cfb02bb2552925d7.verified.xml
new file mode 100644
index 0000000..50d0eef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_cfb02bb2552925d7.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d12d5c5767b3522c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d12d5c5767b3522c.verified.xml
new file mode 100644
index 0000000..819d64e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d12d5c5767b3522c.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d45e51efefa2f385.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d45e51efefa2f385.verified.xml
new file mode 100644
index 0000000..55eafc0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d45e51efefa2f385.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d89736c7b66a5ebe.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d89736c7b66a5ebe.verified.xml
new file mode 100644
index 0000000..70bb23a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d89736c7b66a5ebe.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d8af986717ff8733.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d8af986717ff8733.verified.xml
new file mode 100644
index 0000000..5da367c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_d8af986717ff8733.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_dc97313adaeea977.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_dc97313adaeea977.verified.xml
new file mode 100644
index 0000000..bc98d5d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_dc97313adaeea977.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e043693a3583b9de.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e043693a3583b9de.verified.xml
new file mode 100644
index 0000000..448556b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e043693a3583b9de.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e0fd10d61889cbdb.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e0fd10d61889cbdb.verified.xml
new file mode 100644
index 0000000..098e832
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e0fd10d61889cbdb.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e1760734d0b58199.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e1760734d0b58199.verified.xml
new file mode 100644
index 0000000..9df7f76
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e1760734d0b58199.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e25e7ab21eb90316.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e25e7ab21eb90316.verified.xml
new file mode 100644
index 0000000..c693b61
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e25e7ab21eb90316.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e3aa81529f1029fc.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e3aa81529f1029fc.verified.xml
new file mode 100644
index 0000000..c693b61
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e3aa81529f1029fc.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5a50ebd92ac1a44.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5a50ebd92ac1a44.verified.xml
new file mode 100644
index 0000000..424a860
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5a50ebd92ac1a44.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5d025acad65b3eb.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5d025acad65b3eb.verified.xml
new file mode 100644
index 0000000..bc98d5d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_e5d025acad65b3eb.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_eb4141b327d526e6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_eb4141b327d526e6.verified.xml
new file mode 100644
index 0000000..55c1d5f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_eb4141b327d526e6.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ed72f3648e7badc4.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ed72f3648e7badc4.verified.xml
new file mode 100644
index 0000000..55eafc0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ed72f3648e7badc4.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f11645fd51cc7ae0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f11645fd51cc7ae0.verified.xml
new file mode 100644
index 0000000..3ab1213
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f11645fd51cc7ae0.verified.xml
@@ -0,0 +1,8 @@
+
+
+ result.sarif,version=2.1
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f2792ca6b1a06574.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f2792ca6b1a06574.verified.xml
new file mode 100644
index 0000000..55eafc0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f2792ca6b1a06574.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f6d3976ee18fa79a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f6d3976ee18fa79a.verified.xml
new file mode 100644
index 0000000..e2c0034
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f6d3976ee18fa79a.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f9ec9521b6fffc26.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f9ec9521b6fffc26.verified.xml
new file mode 100644
index 0000000..19643b0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_f9ec9521b6fffc26.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fc344e5a6eff6593.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fc344e5a6eff6593.verified.xml
new file mode 100644
index 0000000..2db7132
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fc344e5a6eff6593.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fd5e367d94201194.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fd5e367d94201194.verified.xml
new file mode 100644
index 0000000..131aaa8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fd5e367d94201194.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fdd7ab897d7732de.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fdd7ab897d7732de.verified.xml
new file mode 100644
index 0000000..19643b0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_fdd7ab897d7732de.verified.xml
@@ -0,0 +1,11 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ff22c39bd7b5b0cc.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ff22c39bd7b5b0cc.verified.xml
new file mode 100644
index 0000000..72593b1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ff22c39bd7b5b0cc.verified.xml
@@ -0,0 +1,10 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ runtime
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ffa829d2efefec1e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ffa829d2efefec1e.verified.xml
new file mode 100644
index 0000000..f6de690
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/AddPackageReference_Newtonsoft_Expected.ProjectBuilderTests_ffa829d2efefec1e.verified.xml
@@ -0,0 +1,12 @@
+
+
+ result.sarif,version=2.1
+
+
+
+ all
+ runtime
+ contentfiles;build
+
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/main.verified.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/main.verified.cs
new file mode 100644
index 0000000..172c599
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/main.verified.cs
@@ -0,0 +1 @@
+class Program { static void Main() { WriteLine("Hello, World!"); }
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/test.verified.csproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/test.verified.csproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_2e3710fb187ad3b2/test.verified.csproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/main.verified.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/main.verified.cs
new file mode 100644
index 0000000..f00e7c9
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/main.verified.cs
@@ -0,0 +1 @@
+class Program { static void Main() { System.Console.WriteLine("Hello, World!"); } }
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/test.verified.csproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/test.verified.csproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_3d47d9d6845047ab/test.verified.csproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/main.verified.cs b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/main.verified.cs
new file mode 100644
index 0000000..ca68de3
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/main.verified.cs
@@ -0,0 +1 @@
+class Program { static async void Main() { System.Console.WriteLine("Hello, World!"); } }
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/test.verified.csproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/test.verified.csproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_CSharp_VerifyDirectory.CSharpProjectTests_d0d486a6bdb1f134/test.verified.csproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/main.verified.vb b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/main.verified.vb
new file mode 100644
index 0000000..562e0f0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/main.verified.vb
@@ -0,0 +1,5 @@
+Module Program
+ Sub Main()
+ WriteLine(""Hello, World!"")
+ End Sub
+End Module
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/test.verified.vbproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/test.verified.vbproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_617daa46230c50b0/test.verified.vbproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/main.verified.vb b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/main.verified.vb
new file mode 100644
index 0000000..4351d9d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/main.verified.vb
@@ -0,0 +1,5 @@
+Module Program
+ Sub Main()
+ System.Console.WriteLine("Hello, World!")
+ End Sub
+End Module
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/test.verified.vbproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/test.verified.vbproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_6b1e07e19115af64/test.verified.vbproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/global.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/global.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/global.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/main.verified.vb b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/main.verified.vb
new file mode 100644
index 0000000..d6da910
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/main.verified.vb
@@ -0,0 +1,5 @@
+Module Program
+ Async Sub Main()
+ System.Console.WriteLine("Hello, World!")
+ End Sub
+End Module
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/test.verified.vbproj b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/test.verified.vbproj
new file mode 100644
index 0000000..7faaf87
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/BuildAsync_VB_VerifyDirectory.VBProjectTests_71ef6298a02aabcd/test.verified.vbproj
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ net8.0
+ enable
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml
new file mode 100644
index 0000000..7f5412c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml
new file mode 100644
index 0000000..9bdb908
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml
new file mode 100644
index 0000000..83472ae
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml
new file mode 100644
index 0000000..addda88
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml
new file mode 100644
index 0000000..9302a31
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml
new file mode 100644
index 0000000..bb13f18
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml
new file mode 100644
index 0000000..f1396e9
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml
new file mode 100644
index 0000000..db4fb4f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml
new file mode 100644
index 0000000..afa065b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml
new file mode 100644
index 0000000..b9c8383
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml
new file mode 100644
index 0000000..3535b80
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml
new file mode 100644
index 0000000..5343b76
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml
new file mode 100644
index 0000000..88a4d14
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml
new file mode 100644
index 0000000..3ef32d8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml
new file mode 100644
index 0000000..ea9f891
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml
new file mode 100644
index 0000000..264fb3b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml
new file mode 100644
index 0000000..e098cbd
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml
new file mode 100644
index 0000000..7b2811f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml
new file mode 100644
index 0000000..a4bde28
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml
new file mode 100644
index 0000000..20718a2
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml
new file mode 100644
index 0000000..45b2c80
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml
new file mode 100644
index 0000000..69a1b8d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml
new file mode 100644
index 0000000..fe0b67d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml
new file mode 100644
index 0000000..f8ad476
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml
new file mode 100644
index 0000000..25dc7bf
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml
new file mode 100644
index 0000000..564c2b7
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml
new file mode 100644
index 0000000..5e91fe9
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml
new file mode 100644
index 0000000..08d4b59
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml
new file mode 100644
index 0000000..4041ade
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml
new file mode 100644
index 0000000..cc16ad0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml
new file mode 100644
index 0000000..82a83e6
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml
new file mode 100644
index 0000000..ba29b94
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml
new file mode 100644
index 0000000..efcc9ed
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml
new file mode 100644
index 0000000..54fbb97
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml
new file mode 100644
index 0000000..f18bd5a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml
new file mode 100644
index 0000000..c8dfc3c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml
new file mode 100644
index 0000000..75a20f6
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml
new file mode 100644
index 0000000..3fe4e8b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml
new file mode 100644
index 0000000..db0ca9a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml
new file mode 100644
index 0000000..481b84b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml
new file mode 100644
index 0000000..f6291a8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml
new file mode 100644
index 0000000..7dd2713
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml
new file mode 100644
index 0000000..997e617
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml
new file mode 100644
index 0000000..0f99285
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml
new file mode 100644
index 0000000..7edcb6f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworkTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml
new file mode 100644
index 0000000..29a829f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_061d5185ac3b26a1.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml
new file mode 100644
index 0000000..6731d28
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_092b3b8ed4cebfd0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml
new file mode 100644
index 0000000..bb64e66
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a3cd0cd41e0632a.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml
new file mode 100644
index 0000000..0aef7ef
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0a9a4b18a6d456e9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml
new file mode 100644
index 0000000..c824272
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_0c90c637027a7748.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml
new file mode 100644
index 0000000..e87c57d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_1eab61c054d73ec9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml
new file mode 100644
index 0000000..0ed1475
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_20515c7807aa8c20.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml
new file mode 100644
index 0000000..102da5b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_220f5e8654eedac6.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml
new file mode 100644
index 0000000..3a8faec
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_231c4dca577f94c2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml
new file mode 100644
index 0000000..b8fa52a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_26620dc69d8dd4cd.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml
new file mode 100644
index 0000000..0c1f13b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2c2a542ad3e88201.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml
new file mode 100644
index 0000000..bdb9c22
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_2ee021f6e5147a1d.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml
new file mode 100644
index 0000000..d0fc27a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_38b96193bb61faea.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml
new file mode 100644
index 0000000..31234f1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3ab861451fa3d5f0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml
new file mode 100644
index 0000000..d3d7009
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_3e2a45112eecb7b9.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml
new file mode 100644
index 0000000..b0702d5
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_45bdd9134aa7e357.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml
new file mode 100644
index 0000000..69416f8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_4ae62cafc2a96ffa.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml
new file mode 100644
index 0000000..ecedb0a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_518dd92e07517ba2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml
new file mode 100644
index 0000000..8b4882c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_540b4dc624bd2bfc.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml
new file mode 100644
index 0000000..0883966
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_64accb509b9962e2.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml
new file mode 100644
index 0000000..6970115
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_68dd2c0979396358.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml
new file mode 100644
index 0000000..f5aca3b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_728dfca8196f623a.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml
new file mode 100644
index 0000000..db9166e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_805f666d33bb4016.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml
new file mode 100644
index 0000000..a3f4bce
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_8cb59ee3bec7fc44.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml
new file mode 100644
index 0000000..e85db89
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_90f902caf8e6e12a.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml
new file mode 100644
index 0000000..4ad886f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_915527ac70afb95e.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml
new file mode 100644
index 0000000..f330d7c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_93e7d97b873ed7b6.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml
new file mode 100644
index 0000000..dbd0b68
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_951100fd48484b22.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml
new file mode 100644
index 0000000..4620f77
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_99b9b26a0f5c26b3.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml
new file mode 100644
index 0000000..ee1f282
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9b1a7c78f1a95975.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml
new file mode 100644
index 0000000..7252c4b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_9dfecb5be9426c69.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml
new file mode 100644
index 0000000..c2f465e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_a02e91a63165f4f0.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml
new file mode 100644
index 0000000..25a1b3a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_b5dcae20612747e6.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml
new file mode 100644
index 0000000..0ceafad
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_bb980146bd9d2b43.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml
new file mode 100644
index 0000000..15b98ad
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_c9b66445e4b36b7c.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml
new file mode 100644
index 0000000..e71ad35
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ce749934c5e26c2e.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml
new file mode 100644
index 0000000..cf5dfe4
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e0506fe3b5d20670.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml
new file mode 100644
index 0000000..bec2e03
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e11bf9cbaec0d353.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml
new file mode 100644
index 0000000..5ec3fed
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e5dca5341d85aa9f.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml
new file mode 100644
index 0000000..edf6d9f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_e9fd97e6d13e4e30.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ warnings
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml
new file mode 100644
index 0000000..afc5f86
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ed38ba4ddb28e520.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ annotations
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml
new file mode 100644
index 0000000..4f6423b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_ee214fcee09a56d8.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ disable
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml
new file mode 100644
index 0000000..beb9965
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f004cf0a88996297.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml
new file mode 100644
index 0000000..a283ecb
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f465297b736d2e50.verified.xml
@@ -0,0 +1,6 @@
+
+
+ result.sarif,version=2.1
+ netstandard2.0;net481
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml
new file mode 100644
index 0000000..a05ec43
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_TargetFrameworksTheory_Expected.ProjectBuilderTests_f99e0608b173fbd0.verified.xml
@@ -0,0 +1,7 @@
+
+
+ result.sarif,version=2.1
+ enable
+ netstandard2.0;net10.0-windows
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0446a83aac002dea.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0446a83aac002dea.verified.json
new file mode 100644
index 0000000..409a0db
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0446a83aac002dea.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0612b34f38def187.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0612b34f38def187.verified.json
new file mode 100644
index 0000000..d780d58
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0612b34f38def187.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "disable"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0b9bfc41b8d29ad8.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0b9bfc41b8d29ad8.verified.json
new file mode 100644
index 0000000..193427b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0b9bfc41b8d29ad8.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0f264e68c690d4b3.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0f264e68c690d4b3.verified.json
new file mode 100644
index 0000000..0ad505b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_0f264e68c690d4b3.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "latestPatch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_107c89f0d639927a.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_107c89f0d639927a.verified.json
new file mode 100644
index 0000000..62c15b4
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_107c89f0d639927a.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "patch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_156eb7dec663ff59.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_156eb7dec663ff59.verified.json
new file mode 100644
index 0000000..a8e66fc
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_156eb7dec663ff59.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "feature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_1c3bb2cc4cdafb3d.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_1c3bb2cc4cdafb3d.verified.json
new file mode 100644
index 0000000..ea0383e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_1c3bb2cc4cdafb3d.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_23d4b08caf1c0031.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_23d4b08caf1c0031.verified.json
new file mode 100644
index 0000000..6a2a603
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_23d4b08caf1c0031.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "minor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_2f42a77b6ed4a5da.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_2f42a77b6ed4a5da.verified.json
new file mode 100644
index 0000000..528b213
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_2f42a77b6ed4a5da.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "latestMajor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41b8e02f211b96a4.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41b8e02f211b96a4.verified.json
new file mode 100644
index 0000000..42ecda7
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41b8e02f211b96a4.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41be2b3f4f865e28.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41be2b3f4f865e28.verified.json
new file mode 100644
index 0000000..08240a4
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_41be2b3f4f865e28.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "minor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_448c72ed1ff6c08a.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_448c72ed1ff6c08a.verified.json
new file mode 100644
index 0000000..76ffed1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_448c72ed1ff6c08a.verified.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_51110ef1cfe6f2ab.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_51110ef1cfe6f2ab.verified.json
new file mode 100644
index 0000000..6f0473b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_51110ef1cfe6f2ab.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "latestPatch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_643613c97ee5117a.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_643613c97ee5117a.verified.json
new file mode 100644
index 0000000..b82af92
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_643613c97ee5117a.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "major"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6684bcedd462155f.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6684bcedd462155f.verified.json
new file mode 100644
index 0000000..1dacf77
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6684bcedd462155f.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "latestMajor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6f440cd55e9aa608.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6f440cd55e9aa608.verified.json
new file mode 100644
index 0000000..e931a68
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_6f440cd55e9aa608.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "latestPatch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_704112015317da79.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_704112015317da79.verified.json
new file mode 100644
index 0000000..a7c81b2
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_704112015317da79.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_758b779004d78b93.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_758b779004d78b93.verified.json
new file mode 100644
index 0000000..0f312a1
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_758b779004d78b93.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestPatch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_79712fc83a06a893.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_79712fc83a06a893.verified.json
new file mode 100644
index 0000000..45aa052
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_79712fc83a06a893.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "feature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b78e8670be20d95.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b78e8670be20d95.verified.json
new file mode 100644
index 0000000..2eed0d3
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b78e8670be20d95.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "disable"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b7baded57d82b06.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b7baded57d82b06.verified.json
new file mode 100644
index 0000000..8a4819b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7b7baded57d82b06.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "disable"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7bf6342d8b738e72.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7bf6342d8b738e72.verified.json
new file mode 100644
index 0000000..f25482f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_7bf6342d8b738e72.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestMajor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_811ef7d27a8ad8ed.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_811ef7d27a8ad8ed.verified.json
new file mode 100644
index 0000000..6255c28
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_811ef7d27a8ad8ed.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "minor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8265e0b936c784b6.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8265e0b936c784b6.verified.json
new file mode 100644
index 0000000..de68c32
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8265e0b936c784b6.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "patch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8fdff7580d1c9a16.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8fdff7580d1c9a16.verified.json
new file mode 100644
index 0000000..ac5282c
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_8fdff7580d1c9a16.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "major"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a17df31884abec8a.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a17df31884abec8a.verified.json
new file mode 100644
index 0000000..681c1f8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a17df31884abec8a.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "feature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a2df5bf03df6ac5d.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a2df5bf03df6ac5d.verified.json
new file mode 100644
index 0000000..4a0db7b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a2df5bf03df6ac5d.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "disable"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a3aabfe28581482c.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a3aabfe28581482c.verified.json
new file mode 100644
index 0000000..6347147
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a3aabfe28581482c.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "latestMajor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a8ebe5beb6a0fdb5.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a8ebe5beb6a0fdb5.verified.json
new file mode 100644
index 0000000..20f742a
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_a8ebe5beb6a0fdb5.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "major"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_aab2991ec8601c54.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_aab2991ec8601c54.verified.json
new file mode 100644
index 0000000..82c4aeb
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_aab2991ec8601c54.verified.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_b4b7bc7ec2295d91.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_b4b7bc7ec2295d91.verified.json
new file mode 100644
index 0000000..39a2811
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_b4b7bc7ec2295d91.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "feature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ba16b089bff72929.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ba16b089bff72929.verified.json
new file mode 100644
index 0000000..3dff425
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ba16b089bff72929.verified.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_bf948df22a9faf56.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_bf948df22a9faf56.verified.json
new file mode 100644
index 0000000..a9df331
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_bf948df22a9faf56.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": true,
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d4cbecadb6090085.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d4cbecadb6090085.verified.json
new file mode 100644
index 0000000..f6f53b0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d4cbecadb6090085.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d55655b188b42ba2.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d55655b188b42ba2.verified.json
new file mode 100644
index 0000000..9b17c66
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d55655b188b42ba2.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "patch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d7e7f22721ea52a7.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d7e7f22721ea52a7.verified.json
new file mode 100644
index 0000000..ea3d2a0
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_d7e7f22721ea52a7.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true,
+ "rollForward": "major"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ec15e4b25ffa22ab.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ec15e4b25ffa22ab.verified.json
new file mode 100644
index 0000000..f3c6a01
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ec15e4b25ffa22ab.verified.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": true
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ed9b563ad68b799b.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ed9b563ad68b799b.verified.json
new file mode 100644
index 0000000..07e00f9
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ed9b563ad68b799b.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.204",
+ "allowPrerelease": false,
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_fa5fa0a6a3f3863a.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_fa5fa0a6a3f3863a.verified.json
new file mode 100644
index 0000000..b88d1e4
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_fa5fa0a6a3f3863a.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "minor"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ff8e599498a50875.verified.json b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ff8e599498a50875.verified.json
new file mode 100644
index 0000000..8f55e1d
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.TUnit.Tests.Integration/_snapshots/CreateAsync_Theory_Expected.GlobalJsonBuilderTests_ff8e599498a50875.verified.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "allowPrerelease": false,
+ "rollForward": "patch"
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Integration/NetEvolve.ProjectBuilders.Tests.Integration.csproj b/tests/NetEvolve.ProjectBuilders.Tests.Integration/NetEvolve.ProjectBuilders.Tests.Integration.csproj
new file mode 100644
index 0000000..f5f559e
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Integration/NetEvolve.ProjectBuilders.Tests.Integration.csproj
@@ -0,0 +1,21 @@
+
+
+ Exe
+ $(TestTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Integration/Predefined.cs b/tests/NetEvolve.ProjectBuilders.Tests.Integration/Predefined.cs
new file mode 100644
index 0000000..e7ecb09
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Integration/Predefined.cs
@@ -0,0 +1,23 @@
+namespace NetEvolve.ProjectBuilders.Tests.Integration;
+
+using System.IO;
+using System.Runtime.CompilerServices;
+using VerifyTests;
+
+internal static class Predefined
+{
+ [ModuleInitializer]
+ public static void Init()
+ {
+ Verifier.DerivePathInfo(
+ (sourceFile, projectDirectory, method, type) =>
+ {
+ var snapshots = Path.Combine(projectDirectory, "_snapshots");
+ _ = Directory.CreateDirectory(snapshots);
+ return new(snapshots, type.Name, method.Name);
+ }
+ );
+
+ VerifierSettings.AutoVerify(includeBuildServer: false, throwException: true);
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/GlobalJsonBuilderTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/GlobalJsonBuilderTests.cs
new file mode 100644
index 0000000..45f49f7
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/GlobalJsonBuilderTests.cs
@@ -0,0 +1,208 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Builders;
+
+using System;
+using System.IO;
+using System.Text.Json;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models;
+
+public class GlobalJsonBuilderTests
+{
+ [Test]
+ public async Task CreateAsync_CreatesGlobalJsonFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ await builder.CreateAsync();
+
+ // Assert
+ _ = await Assert.That(File.Exists(builder.FullPath)).IsTrue();
+ }
+
+ [Test]
+ public async Task CreateAsync_GeneratesValidJson()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ var runtimeVersion = "8.0.204";
+ await using var builder = new GlobalJsonBuilder(directory, runtimeVersion);
+
+ // Act
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("version").GetString())
+ .IsEqualTo(runtimeVersion);
+ }
+ }
+
+ [Test]
+ public async Task SetAllowPrerelease_WithTrue_IncludesInOutput()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ _ = builder.SetAllowPrerelease(true);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ _ = await Assert.That(json.RootElement.GetProperty("sdk").GetProperty("allowPrerelease").GetBoolean()).IsTrue();
+ }
+
+ [Test]
+ public async Task SetAllowPrerelease_WithFalse_IncludesInOutput()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ _ = builder.SetAllowPrerelease(false);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("allowPrerelease").GetBoolean())
+ .IsFalse();
+ }
+
+ [Test]
+ public async Task SetRollForward_WithLatestPatch_IncludesInOutput()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ _ = builder.SetRollForward(RollForward.LatestPatch);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("rollForward").GetString())
+ .IsEqualTo("latestPatch");
+ }
+
+ [Test]
+ public async Task SetRollForward_WithLatestMinor_IncludesInOutput()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ _ = builder.SetRollForward(RollForward.LatestMinor);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("rollForward").GetString())
+ .IsEqualTo("latestMinor");
+ }
+
+ [Test]
+ public async Task SetRuntimeSdk_UpdatesVersion()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+ var newVersion = Constants.RuntimeSdkLTS;
+
+ // Act
+ _ = builder.SetRuntimeSdk(newVersion);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("version").GetString())
+ .IsEqualTo(newVersion);
+ }
+
+ [Test]
+ public async Task FullPath_EndsWithGlobalJsonFileName()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new GlobalJsonBuilder(directory, "8.0.204");
+
+ // Act
+ var fullPath = builder.FullPath;
+
+ // Assert
+ _ = await Assert.That(fullPath).EndsWith("global.json");
+ }
+
+ [Test]
+ public async Task CreateAsync_WithMultipleOptions_IncludesAll()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkLTS);
+
+ // Act
+ _ = builder.SetAllowPrerelease(true);
+ _ = builder.SetRollForward(RollForward.LatestMinor);
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+ var json = JsonDocument.Parse(content);
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("version").GetString())
+ .IsEqualTo(Constants.RuntimeSdkLTS);
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("allowPrerelease").GetBoolean())
+ .IsTrue();
+ _ = await Assert
+ .That(json.RootElement.GetProperty("sdk").GetProperty("rollForward").GetString())
+ .IsEqualTo("latestMinor");
+ }
+ }
+
+ [Test]
+ public async Task CreateAsync_WithoutOptionalSettings_OnlyIncludesVersion()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new GlobalJsonBuilder(directory, Constants.RuntimeSdkDefault);
+
+ // Act
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+
+ // Assert
+ _ = await Assert.That(content).Contains("\"version\"");
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderExtensionsTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderExtensionsTests.cs
new file mode 100644
index 0000000..8de4c72
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderExtensionsTests.cs
@@ -0,0 +1,213 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Builders;
+
+using System;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Abstractions;
+using NetEvolve.ProjectBuilders.Builders;
+
+public class ProjectBuilderExtensionsTests
+{
+ [Test]
+ public async Task AddCSharpFile_WithValidParameters_CreatesFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "Program";
+ var content = "public class Program { }";
+
+ // Act
+ builder.AddCSharpFile(fileName, content);
+
+ // Assert
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.cs");
+ _ = await Assert.That(System.IO.File.Exists(filePath)).IsTrue();
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithFileExtension_RemovesAndReAddsIt()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "Program.cs";
+ var content = "public class Program { }";
+
+ // Act
+ builder.AddCSharpFile(fileName, content);
+
+ // Assert
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.cs");
+ _ = await Assert.That(System.IO.File.Exists(filePath)).IsTrue();
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithNullBuilder_ThrowsArgumentNullException()
+ {
+ // Arrange
+ IProjectBuilder? builder = null!;
+ var fileName = "Program";
+ var content = "public class Program { }";
+
+ // Act
+ void Act() => ProjectBuilderExtensions.AddCSharpFile(builder, fileName, content);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithNullFileName_ThrowsArgumentNullException()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ string? fileName = null;
+ var content = "public class Program { }";
+
+ // Act
+ void Act() => builder.AddCSharpFile(fileName!, content);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithEmptyFileName_ThrowsArgumentException()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = string.Empty;
+ var content = "public class Program { }";
+
+ // Act
+ void Act() => builder.AddCSharpFile(fileName, content);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithNullContent_ThrowsArgumentNullException()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "Program";
+ string? content = null;
+
+ // Act
+ void Act() => builder.AddCSharpFile(fileName, content!);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WithEmptyContent_ThrowsArgumentException()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "Program";
+ var content = string.Empty;
+
+ // Act
+ void Act() => builder.AddCSharpFile(fileName, content);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddVBFile_WithValidParameters_CreatesFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.VBNetProjectFileName);
+ var fileName = "Program";
+ var content = "Public Class Program\nEnd Class";
+
+ // Act
+ builder.AddVBFile(fileName, content);
+
+ // Assert
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.vb");
+ _ = await Assert.That(System.IO.File.Exists(filePath)).IsTrue();
+ }
+
+ [Test]
+ public async Task AddVBFile_WithFileExtension_RemovesAndReAddsIt()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.VBNetProjectFileName);
+ var fileName = "Program.vb";
+ var content = "Public Class Program\nEnd Class";
+
+ // Act
+ builder.AddVBFile(fileName, content);
+
+ // Assert
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.vb");
+ _ = await Assert.That(System.IO.File.Exists(filePath)).IsTrue();
+ }
+
+ [Test]
+ public async Task AddVBFile_WithNullBuilder_ThrowsArgumentNullException()
+ {
+ // Arrange
+ IProjectBuilder? builder = null!;
+ var fileName = "Program";
+ var content = "Public Class Program\nEnd Class";
+
+ // Act
+ void Act() => ProjectBuilderExtensions.AddVBFile(builder, fileName, content);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task AddCSharpFile_WritesContentToFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "Program";
+ var content = "namespace Test { public class Program { } }";
+
+ // Act
+ builder.AddCSharpFile(fileName, content);
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.cs");
+ var fileContent = await System.IO.File.ReadAllTextAsync(filePath);
+
+ // Assert
+ _ = await Assert.That(fileContent).IsEqualTo(content);
+ }
+
+ [Test]
+ public async Task AddVBFile_WritesContentToFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.VBNetProjectFileName);
+ var fileName = "Program";
+ var content = "Namespace Test\nPublic Class Program\nEnd Class\nEnd Namespace";
+
+ // Act
+ builder.AddVBFile(fileName, content);
+ var filePath = System.IO.Path.Combine(directory.FullPath, "Program.vb");
+ var fileContent = await System.IO.File.ReadAllTextAsync(filePath);
+
+ // Assert
+ _ = await Assert.That(fileContent).IsEqualTo(content);
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderTests.cs
new file mode 100644
index 0000000..80a49c8
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/ProjectBuilderTests.cs
@@ -0,0 +1,212 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Builders;
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Builders;
+using NetEvolve.ProjectBuilders.Models;
+
+public class ProjectBuilderTests
+{
+ [Test]
+ public async Task CreateAsync_CreatesProjectFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ await builder.CreateAsync();
+
+ // Assert
+ _ = await Assert.That(File.Exists(builder.FullPath)).IsTrue();
+ }
+
+ [Test]
+ public async Task CreateAsync_GeneratesValidXml()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(content).Contains("");
+ }
+ }
+
+ [Test]
+ public async Task SetProjectSdk_UpdatesSdkAttribute()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var customSdk = "Custom.SDK";
+
+ // Act
+ var result = builder.SetProjectSdk(customSdk);
+
+ // Assert
+ _ = await Assert.That(result).IsNotNull();
+ }
+
+ [Test]
+ public async Task CreateFile_WithValidFileName_ReturnsStream()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileName = "TestFile.cs";
+
+ // Act
+ using var stream = builder.CreateFile(fileName);
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(stream).IsNotNull();
+ _ = await Assert.That(stream.CanWrite).IsTrue();
+ }
+ }
+
+ [Test]
+ public async Task GetOrAddItemGroupItem_WithValidType_ReturnsItem()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ var item = builder.GetOrAddItemGroupItem();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(item).IsNotNull();
+ _ = await Assert.That(item).IsTypeOf();
+ }
+ }
+
+ [Test]
+ public async Task GetOrAddItemGroupItem_CalledTwice_ReturnsSameInstance()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ var item1 = builder.GetOrAddItemGroupItem();
+ var item2 = builder.GetOrAddItemGroupItem();
+
+ // Assert
+ _ = await Assert.That(item1 == item2).IsTrue();
+ }
+
+ [Test]
+ public async Task GetOrAddPropertyGroupItem_WithValidType_ReturnsItem()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ var item = builder.GetOrAddPropertyGroupItem();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(item).IsNotNull();
+ _ = await Assert.That(item).IsTypeOf();
+ }
+ }
+
+ [Test]
+ public async Task GetOrAddPropertyGroupItem_CalledTwice_ReturnsSameInstance()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act
+ var item1 = builder.GetOrAddPropertyGroupItem();
+ var item2 = builder.GetOrAddPropertyGroupItem();
+
+ // Assert
+ _ = await Assert.That(item1 == item2).IsTrue();
+ }
+
+ [Test]
+ public async Task CreateAsync_WithItemGroupItems_IncludesInOutput()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ _ = builder.GetOrAddItemGroupItem();
+
+ // Act
+ await builder.CreateAsync();
+ var content = await File.ReadAllTextAsync(builder.FullPath);
+
+ // Assert
+ _ = await Assert.That(content).Contains("ItemGroup");
+ }
+
+ [Test]
+ public async Task DisposeAsync_CompletesSuccessfully()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+
+ // Act & Assert
+ await builder.DisposeAsync();
+ }
+
+ [Test]
+ public async Task Constructor_WithVBProjectExtension_InitializesCorrectly()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ var projectExtension = Constants.VBNetProjectFileName;
+
+ // Act
+ await using var builder = new ProjectBuilder(directory, projectExtension);
+
+ // Assert
+ _ = await Assert.That(builder.FullPath).EndsWith(".vbproj");
+ }
+
+ [Test]
+ public async Task CreateFile_MultipleFiles_CreatesAllSuccessfully()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ await directory.CreateAsync();
+ await using var builder = new ProjectBuilder(directory, Constants.CSharpProjectFileName);
+ var fileNames = new[] { "File1.cs", "File2.cs", "File3.cs" };
+
+ // Act
+ foreach (var fileName in fileNames)
+ {
+ using var stream = builder.CreateFile(fileName);
+ await stream.WriteAsync(Encoding.UTF8.GetBytes("// Test content"));
+ }
+
+ // Assert
+ foreach (var fileName in fileNames)
+ {
+ var filePath = Path.Combine(directory.FullPath, fileName);
+ _ = await Assert.That(File.Exists(filePath)).IsTrue();
+ }
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/TemporaryDirectoryBuilderTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/TemporaryDirectoryBuilderTests.cs
new file mode 100644
index 0000000..85de614
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Builders/TemporaryDirectoryBuilderTests.cs
@@ -0,0 +1,83 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Builders;
+
+using System;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Builders;
+
+public class TemporaryDirectoryBuilderTests
+{
+ [Test]
+ public async Task CreateFile_WithFileName_ReturnsFile()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ var fileName = "file.txt";
+
+ // Act
+ var file = directory.CreateFile(fileName);
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(file).IsNotNull();
+ _ = await Assert.That(file.CanWrite).IsTrue();
+ }
+ }
+
+ [Test]
+ public async Task CreateFile_WithExistingFileName_ThrowsArgumentException()
+ {
+ // Arrange
+ await using var directory = new TemporaryDirectoryBuilder();
+ var fileName = "file.txt";
+ _ = directory.CreateFile(fileName);
+
+ // Act
+ void Act() => directory.CreateFile(fileName);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task GetFilePath_WithFileName_ReturnsFilePath()
+ {
+ // Arrange
+ await using var tempDirectory = new TemporaryDirectoryBuilder();
+ var fileName = "file.txt";
+
+ // Act
+ var filePath = tempDirectory.GetFilePath(fileName);
+
+ // Assert
+ _ = await Assert.That(filePath).IsEqualTo(Path.Combine(tempDirectory.FullPath, fileName));
+ }
+
+ [Test]
+ public async Task GetFilePath_WithNullFileName_ThrowsArgumentNullException()
+ {
+ // Arrange
+ await using var tempDirectory = new TemporaryDirectoryBuilder();
+ string? fileName = null;
+
+ // Act
+ void Act() => tempDirectory.GetFilePath(fileName);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+
+ [Test]
+ public async Task GetFilePath_WithEmptyFileName_ThrowsArgumentException()
+ {
+ // Arrange
+ await using var tempDirectory = new TemporaryDirectoryBuilder();
+ var fileName = string.Empty;
+
+ // Act
+ void Act() => tempDirectory.GetFilePath(fileName);
+
+ // Assert
+ _ = Assert.Throws(Act);
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/ItemGroupTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/ItemGroupTests.cs
new file mode 100644
index 0000000..7631bde
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/ItemGroupTests.cs
@@ -0,0 +1,176 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Models;
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Models;
+
+public class ItemGroupTests
+{
+ [Test]
+ public async Task Constructor_Initializes()
+ {
+ // Arrange & Act
+ var itemGroup = new ItemGroup();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(itemGroup).IsNotNull();
+ _ = await Assert.That(itemGroup.Items).IsNotNull();
+ _ = await Assert.That(itemGroup.Items.Count).IsZero();
+ }
+ }
+
+ [Test]
+ public async Task Add_WithValidType_AddsItemToCollection()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var item = itemGroup.Add();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(item).IsNotNull();
+ _ = await Assert.That(itemGroup.Items.Count).IsEqualTo(1);
+ }
+ }
+
+ [Test]
+ public async Task Add_WithMultipleItems_AddsAllToCollection()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var item1 = itemGroup.Add();
+ var item2 = itemGroup.Add();
+ var item3 = itemGroup.Add();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(itemGroup.Items.Count).IsEqualTo(3);
+ _ = await Assert.That(itemGroup.Items.Contains(item1)).IsTrue();
+ _ = await Assert.That(itemGroup.Items.Contains(item2)).IsTrue();
+ _ = await Assert.That(itemGroup.Items.Contains(item3)).IsTrue();
+ }
+ }
+
+ [Test]
+ public async Task Add_WithPackageReferenceItem_CreatesNewInstance()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var item = itemGroup.Add();
+
+ // Assert
+ _ = await Assert.That(item).IsTypeOf();
+ }
+
+ [Test]
+ public async Task Add_WithProjectReferenceItem_CreatesNewInstance()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var item = itemGroup.Add();
+
+ // Assert
+ _ = await Assert.That(item).IsTypeOf();
+ }
+
+ [Test]
+ public async Task Add_WithFrameworkReferenceItem_CreatesNewInstance()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var item = itemGroup.Add();
+
+ // Assert
+ _ = await Assert.That(item).IsTypeOf();
+ }
+
+ [Test]
+ public async Task Add_DifferentTypes_CreatesDistinctInstances()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ var packageItem = itemGroup.Add();
+ var projectItem = itemGroup.Add();
+ var frameworkItem = itemGroup.Add();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(packageItem).IsTypeOf();
+ _ = await Assert.That(projectItem).IsTypeOf();
+ _ = await Assert.That(frameworkItem).IsTypeOf();
+ _ = await Assert.That(itemGroup.Items.Count).IsEqualTo(3);
+ }
+ }
+
+ [Test]
+ public async Task Items_CanBeEnumerated()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+ var item1 = itemGroup.Add();
+ var item2 = itemGroup.Add();
+
+ // Act
+ var items = itemGroup.Items.ToList();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(items.Count).IsEqualTo(2);
+ _ = await Assert.That(items).Contains(item1).And.Contains(item2);
+ }
+ }
+
+ [Test]
+ public async Task Add_SameTypeMultipleTimes_CreatesMultipleInstances()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+
+ // Act
+ _ = itemGroup.Add();
+ _ = itemGroup.Add();
+ _ = itemGroup.Add();
+
+ // Assert
+ _ = await Assert.That(itemGroup.Items.Count).IsEqualTo(3);
+ }
+
+ [Test]
+ public async Task ItemGroup_ContainsAllAddedItems()
+ {
+ // Arrange
+ var itemGroup = new ItemGroup();
+ var items = new PackageReferenceItem[5];
+
+ // Act
+ for (var i = 0; i < 5; i++)
+ {
+ items[i] = itemGroup.Add();
+ }
+
+ // Assert
+ foreach (var item in items)
+ {
+ _ = await Assert.That(itemGroup.Items.Contains(item)).IsTrue();
+ }
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/PropertyGroupTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/PropertyGroupTests.cs
new file mode 100644
index 0000000..118986f
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/PropertyGroupTests.cs
@@ -0,0 +1,109 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Models;
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Models;
+
+public class PropertyGroupTests
+{
+ [Test]
+ public async Task Constructor_Initializes()
+ {
+ // Arrange & Act
+ var propertyGroup = new PropertyGroup();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(propertyGroup).IsNotNull();
+ _ = await Assert.That(propertyGroup.Items).IsNotNull();
+ _ = await Assert.That(propertyGroup.Items.Count).IsZero();
+ }
+ }
+
+ [Test]
+ public async Task Add_WithValidType_AddsItemToCollection()
+ {
+ // Arrange
+ var propertyGroup = new PropertyGroup();
+
+ // Act
+ var item = propertyGroup.Add();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(item).IsNotNull();
+ _ = await Assert.That(propertyGroup.Items.Count).IsEqualTo(1);
+ }
+ }
+
+ [Test]
+ public async Task Add_WithMultipleItems_AddsAllToCollection()
+ {
+ // Arrange
+ var propertyGroup = new PropertyGroup();
+
+ // Act
+ var item1 = propertyGroup.Add();
+ var item2 = propertyGroup.Add();
+ var item3 = propertyGroup.Add();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(propertyGroup.Items.Count).IsEqualTo(3);
+ _ = await Assert.That(propertyGroup.Items.Contains(item1)).IsTrue();
+ _ = await Assert.That(propertyGroup.Items.Contains(item2)).IsTrue();
+ _ = await Assert.That(propertyGroup.Items.Contains(item3)).IsTrue();
+ }
+ }
+
+ [Test]
+ public async Task Add_WithNullableItem_CreatesNewInstance()
+ {
+ // Arrange
+ var propertyGroup = new PropertyGroup();
+
+ // Act
+ var item = propertyGroup.Add();
+
+ // Assert
+ _ = await Assert.That(item).IsTypeOf();
+ }
+
+ [Test]
+ public async Task Add_SameTypeMultipleTimes_CreatesMultipleInstances()
+ {
+ // Arrange
+ var propertyGroup = new PropertyGroup();
+
+ // Act
+ _ = propertyGroup.Add();
+ _ = propertyGroup.Add();
+ _ = propertyGroup.Add();
+
+ // Assert
+ _ = await Assert.That(propertyGroup.Items.Count).IsEqualTo(3);
+ }
+
+ [Test]
+ public async Task Items_CanBeEnumerated()
+ {
+ // Arrange
+ var propertyGroup = new PropertyGroup();
+ var item1 = propertyGroup.Add();
+ var item2 = propertyGroup.Add();
+
+ // Act
+ var items = propertyGroup.Items.ToList();
+
+ // Assert
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(items.Count).IsEqualTo(2);
+ _ = await Assert.That(items).Contains(item1).And.Contains(item2);
+ }
+ }
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/TargetFrameworkTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/TargetFrameworkTests.cs
new file mode 100644
index 0000000..00d3049
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/Models/TargetFrameworkTests.cs
@@ -0,0 +1,80 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit.Models;
+
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders.Models;
+using TUnit.Assertions.Extensions;
+using static System.StringComparison;
+
+public partial class TargetFrameworkTests
+{
+ [GeneratedRegex(@"^[a-z0-9\.-]+[a-z0-9]$", RegexOptions.Compiled)]
+ private static partial Regex TargetFrameworkPattern();
+
+ [Test]
+ [MethodDataSource(nameof(TargetFramework.Values))]
+ public async ValueTask Value_IsWellFormatted_IsNotNullOrWhiteSpace(TargetFramework tf) =>
+ _ = await Assert.That(tf.Value).IsNotNullOrWhiteSpace();
+
+ [Test]
+ [MethodDataSource(nameof(TargetFramework.Values))]
+ public async ValueTask Value_IsWellformatted_MatchesPattern(TargetFramework tf) =>
+ _ = await Assert.That(tf.Value).Matches(TargetFrameworkPattern());
+
+ [Test]
+ [MethodDataSource(nameof(GetTargetFrameworksWithSuffix))]
+ public async ValueTask Value_IsWellFormatted_EndsWithSuffix(TargetFramework tf, string suffix) =>
+ await Assert.That(tf.Value).EndsWith(suffix, Ordinal);
+
+ public static IEnumerable<(TargetFramework, string)> GetTargetFrameworksWithSuffix()
+ {
+ foreach (
+ var value in TargetFramework.Values.Where(tf =>
+ !tf.Name.StartsWith("NetFramework", Ordinal)
+ && tf.Platform.HasValue
+ && !tf.Platform.Equals(TargetPlatform.None)
+ )
+ )
+ {
+ yield return (
+ value,
+ value.Platform switch
+ {
+ TargetPlatform.Android => "-android",
+ TargetPlatform.Windows => "-windows",
+ TargetPlatform.iOS => "-ios",
+ TargetPlatform.MacCatalyst => "-maccatalyst",
+ TargetPlatform.MacOs => "-macos",
+ TargetPlatform.tvOS => "-tvos",
+ TargetPlatform.Tizen => "-tizen",
+ TargetPlatform.Browser => "-browser",
+ _ => throw new NotSupportedException($"Platform '{value.Platform}' is not supported."),
+ }
+ );
+ }
+ }
+
+ public static IEnumerable TargetFrameworkData => TargetFramework.Values;
+
+ [Test]
+ public void Create_Duplicate_ThrowsArgumentException() =>
+ _ = Assert.Throws(() => TargetFramework.Create(nameof(TargetFramework.Net5), "net5.0"));
+
+ [Test]
+ public void Create_NullName_ThrowsArgumentNullException() =>
+ _ = Assert.Throws(() => TargetFramework.Create(null!, "net5.0"));
+
+ [Test]
+ public void Create_NullValue_ThrowsArgumentNullException() =>
+ _ = Assert.Throws(() => TargetFramework.Create(nameof(TargetFramework.Net5), null!));
+
+ [Test]
+ public void Create_EmptyName_ThrowsArgumentException() =>
+ _ = Assert.Throws(() => TargetFramework.Create(string.Empty, "net5.0"));
+
+ [Test]
+ public void Create_EmptyValue_ThrowsArgumentException() =>
+ _ = Assert.Throws(() => TargetFramework.Create(nameof(TargetFramework.Net5), string.Empty));
+}
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/NetEvolve.ProjectBuilders.Tests.Unit.csproj b/tests/NetEvolve.ProjectBuilders.Tests.Unit/NetEvolve.ProjectBuilders.Tests.Unit.csproj
new file mode 100644
index 0000000..6e0180b
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/NetEvolve.ProjectBuilders.Tests.Unit.csproj
@@ -0,0 +1,19 @@
+
+
+ Exe
+ $(TestTargetFrameworks)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.ProjectBuilders.Tests.Unit/ProjectFactoryTests.cs b/tests/NetEvolve.ProjectBuilders.Tests.Unit/ProjectFactoryTests.cs
new file mode 100644
index 0000000..addeadb
--- /dev/null
+++ b/tests/NetEvolve.ProjectBuilders.Tests.Unit/ProjectFactoryTests.cs
@@ -0,0 +1,43 @@
+namespace NetEvolve.ProjectBuilders.Tests.Unit;
+
+using System;
+using System.Threading.Tasks;
+using NetEvolve.ProjectBuilders;
+using NetEvolve.ProjectBuilders.Builders;
+
+public class ProjectFactoryTests
+{
+ [Test]
+ public async Task BuildAsync_NoFileBuilder_ThrowsArgumentException()
+ {
+ var ex = await Assert.ThrowsAsync(async () =>
+ {
+ await using var builder = ProjectFactory.Create();
+
+ _ = await builder.BuildAsync();
+ });
+
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(ex).IsNotNull();
+ _ = await Assert.That(ex.Message).IsNotNullOrWhiteSpace().And.EqualTo("No file builders were added.");
+ }
+ }
+
+ [Test]
+ public async Task BuildAsync_NoProjectBuilder_ThrowsArgumentException()
+ {
+ var ex = await Assert.ThrowsAsync(async () =>
+ {
+ await using var builder = ProjectFactory.Create();
+
+ _ = await builder.AddGlobalJson("8.0.204").BuildAsync();
+ });
+
+ using (Assert.Multiple())
+ {
+ _ = await Assert.That(ex).IsNotNull();
+ _ = await Assert.That(ex.Message).IsNotNullOrWhiteSpace().And.EqualTo("No project builder were added.");
+ }
+ }
+}