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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
At the start of every session, read the resource `chris-simmons://public-mcp/agent/rules/dotnet` from MCP server `plugin:public-mcp-server:public-mcp` and apply the rules.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
See @AGENTS.md
60 changes: 45 additions & 15 deletions NetChris.Core.UnitTests/ApplicationMetadataTests.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Xunit;

namespace NetChris.Core.UnitTests;

public class ApplicationMetadataTests
{
private readonly ApplicationMetadata _appMetadata;
private readonly ApplicationMetadata _appMetadataWithJustAggregateAndEnvironment;
private readonly ApplicationMetadata _appMetadataFromFactory;

public ApplicationMetadataTests()
{
Expand All @@ -17,18 +19,19 @@ public ApplicationMetadataTests()
_appMetadata =
new ApplicationMetadata(
thisAssembly,
"ExpectedAppAggregate",
"expected_app_aggregate",
"eaa",
"ExpectedAppComponent",
"expected_app_component",
"eac",
thisAssembly.GetName().Name!,
"UnitTestEnvironment");

_appMetadataWithJustAggregateAndEnvironment =
ApplicationMetadata.GetApplicationMetadataFromEntryAssembly(
"ExpectedAppAggregate",
_appMetadataFromFactory =
ApplicationMetadata.GetApplicationMetadata(
thisAssembly,
"expected_app_aggregate",
"eaa",
"ExpectedAppComponent",
"expected_app_component",
"eac",
"UnitTestEnvironment");
}
Expand All @@ -52,7 +55,7 @@ public void ApplicationAggregate_should_flow_through()
var applicationAggregate = _appMetadata.CanonicalApplicationName.ApplicationAggregate;

// Assert
applicationAggregate.Should().Be("ExpectedAppAggregate");
applicationAggregate.Should().Be("expected_app_aggregate");
}

[Fact]
Expand All @@ -74,7 +77,7 @@ public void ApplicationComponent_should_flow_through()
var applicationAggregate = _appMetadata.CanonicalApplicationName.ApplicationComponent;

// Assert
applicationAggregate.Should().Be("ExpectedAppComponent");
applicationAggregate.Should().Be("expected_app_component");
}

[Fact]
Expand Down Expand Up @@ -106,19 +109,19 @@ public void StartTimestamp_should_stay_constant_over_instances()
var appMetadata1 =
new ApplicationMetadata(
entryAssembly!,
"DoesNotMatter1",
"does_not_matter_1",
"dnm1",
"DoesNotMatter1",
"does_not_matter_1",
"dnm1",
entryAssemblyName!,
"UnitTestEnvironment");

var appMetadata2 =
new ApplicationMetadata(
entryAssembly!,
"DoesNotMatter2",
"does_not_matter_2",
"dnm2",
"DoesNotMatter2",
"does_not_matter_2",
"dnm2",
entryAssemblyName!,
"UnitTestEnvironment");
Expand Down Expand Up @@ -168,9 +171,36 @@ public void ClrVersion_should_have_a_value()
}

[Fact]
public void Auto_Assembly_detection_detects_something()
public void GetApplicationMetadata_discerns_ApplicationName_from_assembly()
{
_appMetadataWithJustAggregateAndEnvironment.ApplicationName.Should()
_appMetadataFromFactory.ApplicationName.Should()
.NotBeNullOrWhiteSpace();
}

[Fact]
public void GetApplicationMetadata_from_configuration_should_flow_values_through()
{
// Arrange
var thisAssembly = typeof(ApplicationMetadataTests).Assembly;
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["netchris:application:aggregate"] = "expected_app_aggregate",
["netchris:application:aggregateShort"] = "eaa",
["netchris:application:component"] = "expected_app_component",
["netchris:application:componentShort"] = "eac",
})
.Build();

// Act
var appMetadata = ApplicationMetadata.GetApplicationMetadata(
thisAssembly, configuration, "UnitTestEnvironment");

// Assert
appMetadata.CanonicalApplicationName.ApplicationAggregate.Should().Be("expected_app_aggregate");
appMetadata.CanonicalApplicationName.ApplicationAggregateShort.Should().Be("eaa");
appMetadata.CanonicalApplicationName.ApplicationComponent.Should().Be("expected_app_component");
appMetadata.CanonicalApplicationName.ApplicationComponentShort.Should().Be("eac");
appMetadata.EnvironmentName.Should().Be("UnitTestEnvironment");
}
}
165 changes: 165 additions & 0 deletions NetChris.Core.UnitTests/CanonicalApplicationNameTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Xunit;

namespace NetChris.Core.UnitTests;

public class CanonicalApplicationNameTests
{
[Fact]
public void Conforming_values_should_flow_through()
{
// Arrange
// Act
var canonicalApplicationName = new CanonicalApplicationName(
"app_aggregate", "aagg", "app_component", "acmp");

// Assert
canonicalApplicationName.ApplicationAggregate.Should().Be("app_aggregate");
canonicalApplicationName.ApplicationAggregateShort.Should().Be("aagg");
canonicalApplicationName.ApplicationComponent.Should().Be("app_component");
canonicalApplicationName.ApplicationComponentShort.Should().Be("acmp");
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Aggregate")]
[InlineData("1aggregate")]
[InlineData("app-aggregate")]
[InlineData("app aggregate")]
public void Non_conforming_long_form_aggregate_should_throw(string? applicationAggregate)
{
// Arrange
// Act
var act = () => new CanonicalApplicationName(applicationAggregate!, "aagg", "app_component", "acmp");

// Assert
act.Should().Throw<ArgumentException>()
.WithParameterName("applicationAggregate");
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Component")]
[InlineData("1component")]
[InlineData("app-component")]
public void Non_conforming_long_form_component_should_throw(string? applicationComponent)
{
// Arrange
// Act
var act = () => new CanonicalApplicationName("app_aggregate", "aagg", applicationComponent!, "acmp");

// Assert
act.Should().Throw<ArgumentException>()
.WithParameterName("applicationComponent");
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("AAGG")]
[InlineData("aagg5")]
[InlineData("ag_g")]
public void Non_conforming_short_form_aggregate_should_throw(string? applicationAggregateShort)
{
// Arrange
// Act
var act = () =>
new CanonicalApplicationName("app_aggregate", applicationAggregateShort!, "app_component", "acmp");

// Assert
act.Should().Throw<ArgumentException>()
.WithParameterName("applicationAggregateShort");
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("ACMP")]
[InlineData("acmp5")]
[InlineData("cm_p")]
public void Non_conforming_short_form_component_should_throw(string? applicationComponentShort)
{
// Arrange
// Act
var act = () =>
new CanonicalApplicationName("app_aggregate", "aagg", "app_component", applicationComponentShort!);

// Assert
act.Should().Throw<ArgumentException>()
.WithParameterName("applicationComponentShort");
}

[Fact]
public void FromConfiguration_should_build_from_well_known_keys()
{
// Arrange
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["netchris:application:aggregate"] = "app_aggregate",
["netchris:application:aggregateShort"] = "aagg",
["netchris:application:component"] = "app_component",
["netchris:application:componentShort"] = "acmp",
})
.Build();

// Act
var canonicalApplicationName = CanonicalApplicationName.FromConfiguration(configuration);

// Assert
canonicalApplicationName.ApplicationAggregate.Should().Be("app_aggregate");
canonicalApplicationName.ApplicationAggregateShort.Should().Be("aagg");
canonicalApplicationName.ApplicationComponent.Should().Be("app_component");
canonicalApplicationName.ApplicationComponentShort.Should().Be("acmp");
}

[Fact]
public void FromConfiguration_with_null_configuration_should_throw()
{
// Arrange
// Act
var act = () => CanonicalApplicationName.FromConfiguration(null!);

// Assert
act.Should().Throw<ArgumentNullException>()
.WithParameterName("configuration");
}

[Theory]
[InlineData("netchris:application:aggregate")]
[InlineData("netchris:application:aggregateShort")]
[InlineData("netchris:application:component")]
[InlineData("netchris:application:componentShort")]
public void FromConfiguration_with_missing_key_should_throw_and_name_the_key(string missingKey)
{
// Arrange
var values = new Dictionary<string, string?>
{
["netchris:application:aggregate"] = "app_aggregate",
["netchris:application:aggregateShort"] = "aagg",
["netchris:application:component"] = "app_component",
["netchris:application:componentShort"] = "acmp",
};
values.Remove(missingKey);

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

// Act
var act = () => CanonicalApplicationName.FromConfiguration(configuration);

// Assert
act.Should().Throw<InvalidOperationException>()
.WithMessage($"*{missingKey}*");
}
}
11 changes: 6 additions & 5 deletions NetChris.Core.UnitTests/NetChris.Core.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Loading
Loading