Files
git.stella-ops.org/tests/architecture/StellaOps.Architecture.Tests/NamingConventionRulesTests.cs
master 491e883653 Add tests for SBOM generation determinism across multiple formats
- Created `StellaOps.TestKit.Tests` project for unit tests related to determinism.
- Implemented `DeterminismManifestTests` to validate deterministic output for canonical bytes and strings, file read/write operations, and error handling for invalid schema versions.
- Added `SbomDeterminismTests` to ensure identical inputs produce consistent SBOMs across SPDX 3.0.1 and CycloneDX 1.6/1.7 formats, including parallel execution tests.
- Updated project references in `StellaOps.Integration.Determinism` to include the new determinism testing library.
2025-12-24 00:36:14 +02:00

159 lines
5.8 KiB
C#

using System.Reflection;
using NetArchTest.Rules;
using Xunit;
using FluentAssertions;
namespace StellaOps.Architecture.Tests;
/// <summary>
/// Architecture tests for naming convention rules.
/// Enforces consistent naming across the codebase.
/// </summary>
[Trait("Category", "Architecture")]
public sealed class NamingConventionRulesTests
{
/// <summary>
/// Test projects must end with .Tests.
/// </summary>
[Fact]
public void TestProjects_MustEndWith_Tests()
{
var testAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.StartsWith("StellaOps") == true)
.Where(a => ContainsTestTypes(a));
foreach (var assembly in testAssemblies)
{
var name = assembly.GetName().Name;
// If it has test types, it should end with .Tests
if (!name!.EndsWith(".Tests"))
{
// Check if it's in a known test location pattern
var isValidTestAssembly = name.Contains("Test") ||
name.EndsWith(".Tests") ||
name.Contains("Testing");
isValidTestAssembly.Should().BeTrue(
$"Assembly {name} contains tests but doesn't follow naming convention (.Tests suffix)");
}
}
}
/// <summary>
/// Plugin assemblies must follow naming pattern.
/// </summary>
[Fact]
public void Plugins_MustFollow_NamingPattern()
{
var pluginAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.Contains("Plugin") == true &&
a.GetName().Name?.StartsWith("StellaOps") == true);
foreach (var assembly in pluginAssemblies)
{
var name = assembly.GetName().Name!;
// Valid patterns: StellaOps.<Module>.Plugin.* or StellaOps.<Module>.Plugins.*
var isValidPluginName =
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Plugin\.\w+$") ||
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Plugins\.\w+$") ||
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Plugin$");
isValidPluginName.Should().BeTrue(
$"Plugin assembly {name} doesn't follow naming pattern StellaOps.<Module>.Plugin[s].*");
}
}
/// <summary>
/// Connector assemblies must follow naming pattern.
/// </summary>
[Fact]
public void Connectors_MustFollow_NamingPattern()
{
var connectorAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.Contains("Connector") == true &&
a.GetName().Name?.StartsWith("StellaOps") == true);
foreach (var assembly in connectorAssemblies)
{
var name = assembly.GetName().Name!;
// Valid patterns: StellaOps.<Module>.Connector.* or StellaOps.<Module>.Connector
var isValidConnectorName =
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Connector\.\w+$") ||
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Connector$") ||
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Connector\.Common$");
isValidConnectorName.Should().BeTrue(
$"Connector assembly {name} doesn't follow naming pattern StellaOps.<Module>.Connector[.*]");
}
}
/// <summary>
/// Storage assemblies must follow naming pattern.
/// </summary>
[Fact]
public void Storage_MustFollow_NamingPattern()
{
var storageAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.Contains("Storage") == true &&
a.GetName().Name?.StartsWith("StellaOps") == true);
foreach (var assembly in storageAssemblies)
{
var name = assembly.GetName().Name!;
// Valid patterns: StellaOps.<Module>.Storage or StellaOps.<Module>.Storage.<Provider>
var isValidStorageName =
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Storage$") ||
System.Text.RegularExpressions.Regex.IsMatch(name, @"^StellaOps\.\w+\.Storage\.\w+$");
isValidStorageName.Should().BeTrue(
$"Storage assembly {name} doesn't follow naming pattern StellaOps.<Module>.Storage[.<Provider>]");
}
}
/// <summary>
/// Interface types should start with 'I'.
/// </summary>
[Fact]
public void Interfaces_MustStartWith_I()
{
var stellaOpsAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.StartsWith("StellaOps") == true &&
!a.GetName().Name?.Contains("Test") == true);
if (!stellaOpsAssemblies.Any())
{
return;
}
var result = Types.InAssemblies(stellaOpsAssemblies)
.That()
.AreInterfaces()
.Should()
.HaveNameStartingWith("I")
.GetResult();
result.IsSuccessful.Should().BeTrue(
$"Interface types must start with 'I'. " +
$"Violations: {string.Join(", ", result.FailingTypeNames ?? Enumerable.Empty<string>())}");
}
private static bool ContainsTestTypes(Assembly assembly)
{
try
{
return assembly.GetTypes()
.Any(t => t.GetMethods()
.Any(m => m.GetCustomAttributes(typeof(FactAttribute), false).Any() ||
m.GetCustomAttributes(typeof(TheoryAttribute), false).Any()));
}
catch
{
return false;
}
}
}