xiangning 52383d83f3 style: 目录统一 PascalCase 驼峰
- build-flow.host → BuildFlow.Host(子目录也驼峰:Configuration/Endpoints/Hubs/Services)
- build-flow.shared → BuildFlow.Shared
- build-flow.slnx → BuildFlow.slnx
- 同步所有 slnx/ProjectReference/run-dev.sh/架构测试 路径
- 删 macOS 大小写残留重复目录(旧 BuildFlow.Host/BuildFlow.Shared 空壳)
- build 0/0
2026-07-02 17:52:39 +08:00

97 lines
3.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

namespace BuildFlow.Architecture.Tests;
using System.Xml.Linq;
using Xunit;
/// <summary>
/// BuildFlow Host 架构约束测试。确保后台只有 BuildFlow Host 一个启动入口,
/// 业务模块(Domain/Application/Infrastructure 三层)不能退化为独立进程。
/// HTTP 层已统一并入 BuildFlow.Host,模块不再保留 Api 类库。
/// </summary>
public class HostArchitectureTests
{
[Fact]
public void BusinessModulesShouldNotContainStandaloneProgramEntryPoints()
{
var repoRoot = FindRepoRoot();
var moduleRoot = Path.Combine(repoRoot.FullName, "src", "modules");
var programFiles = Directory
.EnumerateFiles(moduleRoot, "Program.cs", SearchOption.AllDirectories)
.Where(path => !ContainsPathSegment(path, "bin") && !ContainsPathSegment(path, "obj"))
.Select(path => Path.GetRelativePath(repoRoot.FullName, path).Replace('\\', '/'))
.Order(StringComparer.Ordinal)
.ToArray();
Assert.True(
programFiles.Length == 0,
"业务模块不允许包含独立 Program.cs,后台应只由 src/BuildFlow.Host/Program.cs 统一启动。当前残留:" +
Environment.NewLine +
string.Join(Environment.NewLine, programFiles));
}
[Fact]
public void BusinessModulesShouldNotContainLaunchProfiles()
{
var repoRoot = FindRepoRoot();
var moduleRoot = Path.Combine(repoRoot.FullName, "src", "modules");
var launchProfiles = Directory
.EnumerateFiles(moduleRoot, "launchSettings.json", SearchOption.AllDirectories)
.Where(path => !ContainsPathSegment(path, "bin") && !ContainsPathSegment(path, "obj"))
.Select(path => Path.GetRelativePath(repoRoot.FullName, path).Replace('\\', '/'))
.Order(StringComparer.Ordinal)
.ToArray();
Assert.True(
launchProfiles.Length == 0,
"业务模块不允许保留独立启动配置 launchSettings.json。当前残留:" +
Environment.NewLine +
string.Join(Environment.NewLine, launchProfiles));
}
[Fact]
public void BusinessModulesShouldNotHaveStandaloneApiProjects()
{
var repoRoot = FindRepoRoot();
var moduleRoot = Path.Combine(repoRoot.FullName, "src", "modules");
var apiProjects = Directory
.EnumerateFiles(moduleRoot, "*.Api.csproj", SearchOption.AllDirectories)
.Concat(Directory.EnumerateFiles(moduleRoot, "*Api.csproj", SearchOption.AllDirectories))
.Where(path => !ContainsPathSegment(path, "bin") && !ContainsPathSegment(path, "obj"))
.Distinct(StringComparer.Ordinal)
.Select(path => Path.GetRelativePath(repoRoot.FullName, path).Replace('\\', '/'))
.Order(StringComparer.Ordinal)
.ToArray();
Assert.True(
apiProjects.Length == 0,
"业务模块不允许保留独立 Api 类库项目(HTTP 层已统一并入 BuildFlow.Host)。当前残留:" +
Environment.NewLine +
string.Join(Environment.NewLine, apiProjects));
}
private static DirectoryInfo FindRepoRoot()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current is not null)
{
if (File.Exists(Path.Combine(current.FullName, "BuildFlow.slnx")))
{
return current;
}
current = current.Parent;
}
throw new InvalidOperationException("无法定位 BuildFlow.slnx,架构测试无法确定仓库边界。");
}
private static bool ContainsPathSegment(string path, string segment)
{
return path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.Any(part => string.Equals(part, segment, StringComparison.Ordinal));
}
}