Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using DesignPatterns.Behavioral;
using PluginAssemblies.Sample.Contracts;

namespace PluginAssemblies.Sample.Providers.AlphaConflict;

[RegisterStrategy<ICardMotion>("alpha")]
public sealed class ConflictCard : ICardMotion
{
public string ProviderName => "alpha-conflict";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>PluginAssemblies.Sample.Providers.AlphaConflict</RootNamespace>
<DesignPatternsPluginProvider>true</DesignPatternsPluginProvider>
<Description>Duplicate alpha key provider for DP033 demo (plugin-assemblies sample).</Description>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Contracts\DesignPatterns.Samples.PluginAssemblies.Contracts.csproj" />
</ItemGroup>

</Project>
7 changes: 6 additions & 1 deletion DesignPatterns.Samples.PluginAssemblies/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ Maps to [PluginAssemblies.md](https://github.com/Skymly/DesignPatterns/blob/main
```
Contracts/ Shared interfaces (no provider code)
Providers.Alpha/ Card motion — key "alpha"
Providers.AlphaConflict/ Card motion — duplicate key "alpha" (DP033 demo only)
Providers.Beta/ Card motion — key "beta" (optional reference)
Providers.Gamma/ FC control + error — companion key "gamma"
Host/ Autofac host (references Alpha + Gamma, not Beta)
Scenarios.InvalidKey/ DP025 compile-time failure demo
Scenarios.DuplicateKey/ DP033 compile-time failure demo
```

Each provider assembly emits its own `{Contract}Registry` in the **contract namespace** (e.g. `PluginAssemblies.Sample.Contracts.CardMotionRegistry` inside `Providers.Alpha.dll`).
Expand All @@ -24,11 +26,14 @@ Each provider assembly emits its own `{Contract}Registry` in the **contract name
| **S1** | `dotnet run --project Host` | Starts; prints `Card=alpha`; `CardMotionRegistry.Keys` contains `alpha`, not `beta` |
| **S2** | `dotnet run --project Host -- s2` | Exit code 1; `App.config` key `CardMissing=beta` resolves via `RegistryConfiguration` but `beta` is not registered (Providers.Beta not referenced) |
| **S3** | `dotnet test` in sibling DesignPatterns repo (`UnknownRegistryKeyAnalyzerTests`) or IDE on `Scenarios.InvalidKey` | Diagnostic **DP025** for unknown literal key |
| **S4** | `dotnet test` in sibling DesignPatterns repo (`CrossAssemblyRegistryKeyAnalyzerTests`) or IDE on `Scenarios.DuplicateKey` | Diagnostic **DP033** when Alpha and AlphaConflict both register `alpha` |

`Host/App.config` selects `Card=alpha` and `FC=gamma` for S1. The host uses `DesignPatterns.Extensions.AppSettings.RegistryConfiguration` to map those keys to strategy registries (`CardMissing=beta` drives S2).

`Scenarios.InvalidKey/InvalidKeyUsage.cs` shows the invalid literal pattern; DP025 is enforced by the DesignPatterns analyzer (IDE or NuGet package). Local sibling `ProjectReference` builds may not surface Info-level diagnostics on the command line — CI runs the analyzer unit test instead.

`Scenarios.DuplicateKey` references **Providers.Alpha** and **Providers.AlphaConflict** (both register `ICardMotion` key `alpha`). DP033 is an **Error**; IDE or command-line builds with analyzers should fail. CI falls back to `CrossAssemblyRegistryKeyAnalyzerTests` when the demo project build does not surface DP033.

## Prerequisites

Sibling [DesignPatterns](https://github.com/Skymly/DesignPatterns) clone with `DesignPatterns.Extensions.Autofac` and `DesignPatterns.Extensions.AppSettings` (merged on `main`).
Expand All @@ -40,4 +45,4 @@ dotnet run --project DesignPatterns.Samples.PluginAssemblies/Host -c Release

## CI

`./build.ps1 --target Ci` builds the host, runs S1, asserts S2 failure output, and runs the sibling DesignPatterns **DP025** analyzer test for S3.
`./build.ps1 --target Ci` builds the host, runs S1, asserts S2 failure output, and runs sibling DesignPatterns analyzer tests for S3 (DP025) and S4 (DP033).
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>PluginAssemblies.Sample.Scenarios.DuplicateKey</RootNamespace>
<DesignPatternsPluginAnalyzerDemo>true</DesignPatternsPluginAnalyzerDemo>
<Description>Compile-time DP033 demo for the plugin-assemblies sample (see README; CI uses analyzer tests).</Description>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Contracts\DesignPatterns.Samples.PluginAssemblies.Contracts.csproj" />
<ProjectReference Include="..\Providers.Alpha\DesignPatterns.Samples.PluginAssemblies.Providers.Alpha.csproj" />
<ProjectReference Include="..\Providers.AlphaConflict\DesignPatterns.Samples.PluginAssemblies.Providers.AlphaConflict.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace PluginAssemblies.Sample.Scenarios.DuplicateKey;

/// <summary>
/// Illustrates DP033: the same strategy key for one contract in multiple referenced provider assemblies.
/// See sibling DesignPatterns repo <c>CrossAssemblyRegistryKeyAnalyzerTests</c>; CI runs that test for S4.
/// </summary>
public static class DuplicateKeyUsage
{
public static void HostReferencesConflictingProviders()
{
}
}
17 changes: 17 additions & 0 deletions build/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ static readonly (string RelativePath, bool RunAfterBuild)[] SampleProjects =
AbsolutePath PluginAssembliesInvalidKeyProject =>
Root / "DesignPatterns.Samples.PluginAssemblies/Scenarios.InvalidKey/DesignPatterns.Samples.PluginAssemblies.Scenarios.InvalidKey.csproj";

AbsolutePath PluginAssembliesDuplicateKeyProject =>
Root / "DesignPatterns.Samples.PluginAssemblies/Scenarios.DuplicateKey/DesignPatterns.Samples.PluginAssemblies.Scenarios.DuplicateKey.csproj";

AbsolutePath DesignPatternsAnalyzerTestsProject =>
Root / "../DesignPatterns/tests/DesignPatterns.Analyzers.Tests/DesignPatterns.Analyzers.Tests.csproj";

Expand Down Expand Up @@ -72,6 +75,7 @@ void RunPluginAssembliesScenarios()
{
Assert.FileExists(PluginAssembliesHostProject, $"Sample project not found: {PluginAssembliesHostProject}");
Assert.FileExists(PluginAssembliesInvalidKeyProject, $"Sample project not found: {PluginAssembliesInvalidKeyProject}");
Assert.FileExists(PluginAssembliesDuplicateKeyProject, $"Sample project not found: {PluginAssembliesDuplicateKeyProject}");

DotNetBuild(s => s
.SetProjectFile(PluginAssembliesHostProject)
Expand Down Expand Up @@ -110,6 +114,19 @@ void RunPluginAssembliesScenarios()
.SetProjectFile(DesignPatternsAnalyzerTestsProject)
.SetConfiguration(Configuration)
.SetFilter("FullyQualifiedName~UnknownRegistryKeyAnalyzerTests.ReportsDp025WhenStrategyRegistryKeyIsUnknown"));

var duplicateKeyBuild = StartDotNet(
$"build \"{PluginAssembliesDuplicateKeyProject}\" -c {Configuration}",
Root);
if (duplicateKeyBuild.ExitCode != 0 && duplicateKeyBuild.Output.Contains("DP033", StringComparison.Ordinal))
{
return;
}

DotNetTest(s => s
.SetProjectFile(DesignPatternsAnalyzerTestsProject)
.SetConfiguration(Configuration)
.SetFilter("FullyQualifiedName~CrossAssemblyRegistryKeyAnalyzerTests.ReportsDp033WhenSameStrategyKeyExistsInTwoReferencedAssemblies"));
}

static (int ExitCode, string Output) StartDotNet(string arguments, AbsolutePath workingDirectory)
Expand Down
Loading