Forge
csharp4405de34
1#nullable enable
2
3using Xunit;
4
5namespace CascadeIDE.ArchitectureAnalyzers.Tests;
6
7/// <summary>
8/// Соглашения слоя Application / ComputingUnits в репозитории (без полной компиляции CascadeIDE).
9/// </summary>
10public sealed class LayerRoleConsistencyConventionTests
11{
12 private static string CascadeIdeRoot =>
13 Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", ".."));
14
15 [Fact]
16 public void Application_OrchestratorFiles_HaveApplicationOrchestratorAttribute()
17 {
18 var violations = new List<string>();
19 foreach (var file in EnumerateApplicationCs("*Orchestrator.cs"))
20 {
21 var text = File.ReadAllText(file);
22 if (!text.Contains("class ", StringComparison.Ordinal))
23 continue;
24 if (text.Contains("class ", StringComparison.Ordinal)
25 && text.Contains("Orchestrator", StringComparison.Ordinal)
26 && !text.Contains("[ApplicationOrchestrator", StringComparison.Ordinal))
27 {
28 violations.Add(Relative(file));
29 }
30 }
31
32 Assert.Empty(violations);
33 }
34
35 [Fact]
36 public void Application_PresentationProjectionFiles_HaveRoleMarker()
37 {
38 var violations = new List<string>();
39 foreach (var file in EnumerateApplicationCs("*PresentationProjection.cs"))
40 {
41 var text = File.ReadAllText(file);
42 if (!text.Contains("[PresentationProjection", StringComparison.Ordinal)
43 && !text.Contains("[ComputingUnit", StringComparison.Ordinal))
44 {
45 violations.Add(Relative(file));
46 }
47 }
48
49 Assert.Empty(violations);
50 }
51
52 [Fact]
53 public void Application_ShortProjectionFiles_HaveRoleMarker()
54 {
55 var violations = new List<string>();
56 foreach (var file in EnumerateApplicationCs("*Projection.cs"))
57 {
58 if (file.EndsWith("PresentationProjection.cs", StringComparison.OrdinalIgnoreCase))
59 continue;
60
61 var text = File.ReadAllText(file);
62 if (!text.Contains("[PresentationProjection", StringComparison.Ordinal)
63 && !text.Contains("[ComputingUnit", StringComparison.Ordinal))
64 {
65 violations.Add(Relative(file));
66 }
67 }
68
69 Assert.Empty(violations);
70 }
71
72 [Fact]
73 public void ComputingUnits_ImplementingCcu_HaveComputingUnitAttribute()
74 {
75 var violations = new List<string>();
76 var cuDir = Path.Combine(CascadeIdeRoot, "Cockpit", "ComputingUnits");
77 foreach (var file in Directory.EnumerateFiles(cuDir, "*.cs", SearchOption.AllDirectories))
78 {
79 var text = File.ReadAllText(file);
80 if (!text.Contains(": ICockpitComputeUnit", StringComparison.Ordinal))
81 continue;
82 if (text.Contains(": ICockpitComputeUnitPayload", StringComparison.Ordinal))
83 continue;
84 if (!text.Contains("[ComputingUnit", StringComparison.Ordinal))
85 violations.Add(Relative(file));
86 }
87
88 Assert.Empty(violations);
89 }
90
91 [Fact]
92 public void Application_NoComputingUnitOnOrchestratorName()
93 {
94 var violations = new List<string>();
95 foreach (var file in EnumerateApplicationCs("*Orchestrator.cs"))
96 {
97 var text = File.ReadAllText(file);
98 if (text.Contains("[ComputingUnit", StringComparison.Ordinal)
99 && text.Contains("Orchestrator", StringComparison.Ordinal))
100 {
101 violations.Add(Relative(file));
102 }
103 }
104
105 Assert.Empty(violations);
106 }
107
108 private static IEnumerable<string> EnumerateApplicationCs(string fileNamePattern)
109 {
110 var features = Path.Combine(CascadeIdeRoot, "Features");
111 if (!Directory.Exists(features))
112 yield break;
113
114 foreach (var file in Directory.EnumerateFiles(features, fileNamePattern, SearchOption.AllDirectories))
115 {
116 var normalized = file.Replace('\\', '/');
117 if (normalized.Contains("/Application/", StringComparison.OrdinalIgnoreCase))
118 yield return file;
119 }
120 }
121
122 private static string Relative(string absolutePath) =>
123 Path.GetRelativePath(CascadeIdeRoot, absolutePath);
124}
125
View only · write via MCP/CIDE