Forge
csharpdeeb25a2
1using System.Threading.Channels;
2using CascadeIDE.Features.Workspace.Application;
3using CascadeIDE.Services;
4using Xunit;
5
6namespace CascadeIDE.Tests;
7
8public sealed class BlankSolutionCreatorTests
9{
10 private sealed class CapturingDotnetRunner : IDotnetCommandRunner
11 {
12 public List<(IReadOnlyList<string> Args, string WorkingDir)> Calls { get; } = [];
13
14 public Task<(bool Success, int ExitCode, string Output)> RunAsync(
15 IReadOnlyList<string> args,
16 string workingDirectory,
17 CancellationToken cancellationToken = default)
18 {
19 Calls.Add((args, workingDirectory));
20 return Task.FromResult((true, 0, ""));
21 }
22
23 public Task<(bool Success, int ExitCode)> RunWithChunkWriterAsync(
24 IReadOnlyList<string> args,
25 string workingDirectory,
26 ChannelWriter<string> chunkWriter,
27 CancellationToken cancellationToken = default) =>
28 throw new NotSupportedException();
29 }
30
31 /// <summary>Имитирует <c>dotnet new sln</c>: создаёт <c>{name}.sln</c> в каталоге <c>-o</c>.</summary>
32 private sealed class DotnetNewSlnSimRunner : IDotnetCommandRunner
33 {
34 public List<(IReadOnlyList<string> Args, string WorkingDir)> Calls { get; } = [];
35
36 public Task<(bool Success, int ExitCode, string Output)> RunAsync(
37 IReadOnlyList<string> args,
38 string workingDirectory,
39 CancellationToken cancellationToken = default)
40 {
41 Calls.Add((args, workingDirectory));
42 // new sln -n NAME -o OUT
43 var name = args.Count > 3 ? args[3] : "";
44 var outDir = args.Count > 5 ? args[5] : "";
45 Directory.CreateDirectory(outDir);
46 var slnPath = Path.Combine(outDir, name + ".sln");
47 File.WriteAllText(slnPath, "Microsoft Visual Studio Solution File, Format Version 12.00\r\n");
48 return Task.FromResult((true, 0, ""));
49 }
50
51 public Task<(bool Success, int ExitCode)> RunWithChunkWriterAsync(
52 IReadOnlyList<string> args,
53 string workingDirectory,
54 ChannelWriter<string> chunkWriter,
55 CancellationToken cancellationToken = default) =>
56 throw new NotSupportedException();
57 }
58
59 [Fact]
60 public async Task TryCreateAsync_Rejects_ExistingFile()
61 {
62 var tmp = Path.Combine(Path.GetTempPath(), "cide-blank-sln-test-" + Guid.NewGuid().ToString("n"));
63 Directory.CreateDirectory(tmp);
64 var sln = Path.Combine(tmp, "Already.sln");
65 await File.WriteAllTextAsync(sln, "", CancellationToken.None);
66
67 try
68 {
69 var r = await BlankSolutionCreator.TryCreateAsync(sln, new CapturingDotnetRunner(), CancellationToken.None);
70 Assert.False(r.Ok);
71 Assert.Contains("уже существует", r.ErrorMessage ?? "", StringComparison.Ordinal);
72 }
73 finally
74 {
75 try
76 {
77 File.Delete(sln);
78 Directory.Delete(tmp, recursive: true);
79 }
80 catch
81 {
82 // ignore
83 }
84 }
85 }
86
87 [Fact]
88 public async Task TryCreateAsync_Invokes_DotnetNewSln_WithNameAndOutputDir()
89 {
90 var tmp = Path.Combine(Path.GetTempPath(), "cide-blank-sln-new-" + Guid.NewGuid().ToString("n"));
91 var sln = Path.Combine(tmp, "MyApp.sln");
92 var runner = new DotnetNewSlnSimRunner();
93
94 try
95 {
96 var r = await BlankSolutionCreator.TryCreateAsync(sln, runner, CancellationToken.None);
97 Assert.True(r.Ok, r.ErrorMessage);
98 Assert.Equal(sln, r.SolutionPath, StringComparer.OrdinalIgnoreCase);
99 Assert.True(File.Exists(sln));
100
101 var call = Assert.Single(runner.Calls);
102 Assert.Equal(tmp, call.WorkingDir, StringComparer.OrdinalIgnoreCase);
103 Assert.Equal(["new", "sln", "-n", "MyApp", "-o", tmp], call.Args);
104 }
105 finally
106 {
107 try
108 {
109 if (File.Exists(sln))
110 File.Delete(sln);
111 if (Directory.Exists(tmp))
112 Directory.Delete(tmp, recursive: true);
113 }
114 catch
115 {
116 // ignore
117 }
118 }
119 }
120}
121
View only · write via MCP/CIDE