Forge
csharpdeeb25a2
1using CascadeIDE.Models;
2using CascadeIDE.Services;
3using Xunit;
4
5namespace CascadeIDE.Tests;
6
7public class SolutionParserNestingTests
8{
9 [Fact]
10 public void SdkGlob_Nests_PartialCs_UnderLongestExistingStem()
11 {
12 var dir = Path.Combine(Path.GetTempPath(), "cascade_sol_nest_" + Guid.NewGuid().ToString("N"));
13 Directory.CreateDirectory(Path.Combine(dir, "ViewModels"));
14 try
15 {
16 File.WriteAllText(Path.Combine(dir, "Nest.csproj"), """
17 <Project Sdk="Microsoft.NET.Sdk">
18 <PropertyGroup>
19 <TargetFramework>net10.0</TargetFramework>
20 <Nullable>enable</Nullable>
21 </PropertyGroup>
22 </Project>
23 """);
24
25 File.WriteAllText(Path.Combine(dir, "ViewModels", "Root.cs"), "// a");
26 File.WriteAllText(Path.Combine(dir, "ViewModels", "Root.Part.cs"), "// b");
27
28 var slnPath = Path.Combine(dir, "Nest.sln");
29 File.WriteAllText(slnPath, """
30 Microsoft Visual Studio Solution File, Format Version 12.00
31 # Visual Studio Version 17
32 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nest", "Nest.csproj", "{A1A1A1A1-A1A1-A1A1-A1A1-A1A1A1A1A1A1}"
33 EndProject
34 Global
35 GlobalSection(SolutionConfigurationPlatforms) = preSolution
36 Debug|Any CPU = Debug|Any CPU
37 EndGlobalSection
38 GlobalSection(ProjectConfigurationPlatforms) = postSolution
39 {A1A1A1A1-A1A1-A1A1-A1A1-A1A1A1A1A1A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 {A1A1A1A1-A1A1-A1A1-A1A1-A1A1A1A1A1A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 EndGlobalSection
42 EndGlobal
43 """);
44
45 var root = SolutionParser.Load(slnPath, out var err);
46 Assert.Null(err);
47 Assert.NotNull(root);
48
49 var proj = root!.Children.FirstOrDefault(c => c.Title.Equals("Nest.csproj", StringComparison.OrdinalIgnoreCase));
50 Assert.NotNull(proj);
51
52 var rootFile = FindFileByTitle(proj!, "Root.cs");
53 Assert.NotNull(rootFile);
54 Assert.Contains(rootFile!.Children, c => c.Title.Equals("Root.Part.cs", StringComparison.OrdinalIgnoreCase));
55 }
56 finally
57 {
58 try { Directory.Delete(dir, recursive: true); }
59 catch { /* best effort */ }
60 }
61 }
62
63 [Fact]
64 public void DependentUpon_InCsproj_OverridesHeuristic()
65 {
66 var dir = Path.Combine(Path.GetTempPath(), "cascade_sol_dep_" + Guid.NewGuid().ToString("N"));
67 Directory.CreateDirectory(Path.Combine(dir, "ViewModels"));
68 try
69 {
70 File.WriteAllText(Path.Combine(dir, "Dep.csproj"), """
71 <Project Sdk="Microsoft.NET.Sdk">
72 <PropertyGroup>
73 <TargetFramework>net10.0</TargetFramework>
74 <Nullable>enable</Nullable>
75 </PropertyGroup>
76 <ItemGroup>
77 <Compile Update="ViewModels\\Other.cs">
78 <DependentUpon>ViewModels\\Anchor.cs</DependentUpon>
79 </Compile>
80 </ItemGroup>
81 </Project>
82 """);
83
84 File.WriteAllText(Path.Combine(dir, "ViewModels", "Anchor.cs"), "// a");
85 File.WriteAllText(Path.Combine(dir, "ViewModels", "Other.cs"), "// b");
86
87 var slnPath = Path.Combine(dir, "Dep.sln");
88 File.WriteAllText(slnPath, """
89 Microsoft Visual Studio Solution File, Format Version 12.00
90 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dep", "Dep.csproj", "{B2B2B2B2-B2B2-B2B2-B2B2-B2B2B2B2B2B2}"
91 EndProject
92 Global
93 GlobalSection(SolutionConfigurationPlatforms) = preSolution
94 Debug|Any CPU = Debug|Any CPU
95 EndGlobalSection
96 GlobalSection(ProjectConfigurationPlatforms) = postSolution
97 {B2B2B2B2-B2B2-B2B2-B2B2-B2B2B2B2B2B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
98 {B2B2B2B2-B2B2-B2B2-B2B2-B2B2B2B2B2B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
99 EndGlobalSection
100 EndGlobal
101 """);
102
103 var root = SolutionParser.Load(slnPath, out var err);
104 Assert.Null(err);
105
106 var proj = root!.Children.FirstOrDefault(c => c.Title.Equals("Dep.csproj", StringComparison.OrdinalIgnoreCase));
107 Assert.NotNull(proj);
108
109 var anchor = FindFileByTitle(proj!, "Anchor.cs");
110 Assert.NotNull(anchor);
111 Assert.Contains(anchor!.Children, c => c.Title.Equals("Other.cs", StringComparison.OrdinalIgnoreCase));
112 }
113 finally
114 {
115 try { Directory.Delete(dir, recursive: true); }
116 catch { /* best effort */ }
117 }
118 }
119
120 private static SolutionItem? FindFileByTitle(SolutionItem node, string title)
121 {
122 foreach (var c in node.Children)
123 {
124 if (c.FullPath is not null && c.Title.Equals(title, StringComparison.OrdinalIgnoreCase))
125 return c;
126 var inner = FindFileByTitle(c, title);
127 if (inner is not null)
128 return inner;
129 }
130
131 return null;
132 }
133}
134
View only · write via MCP/CIDE