Forge
csharpdeeb25a2
1using CascadeIDE.Features.Chat;
2using CascadeIDE.Services;
3using Xunit;
4
5namespace CascadeIDE.Tests;
6
7public sealed class ChatSlashParametricTests
8{
9 [Theory]
10 [InlineData("5", 5, 5)]
11 [InlineData("5 10", 5, 10)]
12 [InlineData("5:10", 5, 10)]
13 [InlineData("5;10", 5, 10)]
14 public void TryParseLineRangeTail_AcceptsCommonForms(string tail, int start, int end)
15 {
16 Assert.True(ChatSlashParametricArgsBuilder.TryParseLineRangeTail(tail, out var s, out var e, out _));
17 Assert.Equal(start, s);
18 Assert.Equal(end, e);
19 }
20
21 [Fact]
22 public void Catalog_lists_all_parametric_commands()
23 {
24 Assert.True(IntentMelodyCatalog.TryGetParametricRootByCommandId(IdeCommands.Select, out var select));
25 Assert.Equal("els", select.Slug);
26 Assert.True(IntentMelodyCatalog.TryGetParametricRootByCommandId(IdeCommands.ApplyEdit, out var edit));
27 Assert.Equal("eld", edit.Slug);
28 Assert.True(IntentMelodyCatalog.TryGetParametricRootByCommandId(IdeCommands.ShowWebAiPortalPage, out var portal));
29 Assert.Equal("wai", portal.Slug);
30 }
31
32 [Fact]
33 public void ResolveInput_EditorLineSelect_WithRange()
34 {
35 Assert.True(SlashLineResolver.TryResolveSlashLine("/editor line select 5 10", out var line));
36 Assert.Equal("/editor line select", line.CanonicalPath);
37 Assert.Equal("5 10", line.ArgTail);
38 }
39
40 [Fact]
41 public void Catalog_ResolvesEditorLineSelect()
42 {
43 ChatSlashCatalogTestSupport.AssertResolves("/editor line select 5", "/editor line select", "5");
44 Assert.True(
45 ChatSlashCommandCatalog.TryResolveInput("/editor line select 5", out var d, out _));
46 Assert.Equal(IdeCommands.Select, d.CommandId);
47 }
48
49 [Fact]
50 public void Catalog_ResolvesPortalOpen()
51 {
52 ChatSlashCatalogTestSupport.AssertResolves(
53 "/portal open https://example.com",
54 "/portal open",
55 "https://example.com");
56 Assert.True(
57 ChatSlashCommandCatalog.TryResolveInput("/portal open https://example.com", out var d, out _));
58 Assert.Equal(IdeCommands.ShowWebAiPortalPage, d.CommandId);
59 }
60
61 [Fact]
62 public async Task TryRun_EditorLineSelect_BuildsLineArgs()
63 {
64 const string file = @"C:\proj\a.cs";
65 const string text = "one\ntwo\nthree\n";
66 string? capturedId = null;
67 IReadOnlyDictionary<string, System.Text.Json.JsonElement>? capturedArgs = null;
68
69 var runner = new ChatSlashCommandRunner(
70 (id, args, _) =>
71 {
72 capturedId = id;
73 capturedArgs = args;
74 return Task.FromResult("");
75 },
76 () => new ChatSlashEditorContext(file, text));
77
78 var result = await runner.TryRunAsync("/editor line select 2 2");
79 Assert.True(result.Success);
80 Assert.Equal(IdeCommands.Select, capturedId);
81 Assert.NotNull(capturedArgs);
82 Assert.Equal(file, capturedArgs!["file_path"].GetString());
83 Assert.Equal(2, capturedArgs["start_line"].GetInt32());
84 Assert.Equal(2, capturedArgs["end_line"].GetInt32());
85 }
86
87 [Fact]
88 public async Task TryRun_PortalOpen_WithUrl()
89 {
90 string? capturedId = null;
91 IReadOnlyDictionary<string, System.Text.Json.JsonElement>? capturedArgs = null;
92
93 var runner = new ChatSlashCommandRunner(
94 (id, args, _) =>
95 {
96 capturedId = id;
97 capturedArgs = args;
98 return Task.FromResult("");
99 },
100 () => new ChatSlashEditorContext(null, null));
101
102 var result = await runner.TryRunAsync("/portal open example.com");
103 Assert.True(result.Success);
104 Assert.Equal(IdeCommands.ShowWebAiPortalPage, capturedId);
105 Assert.NotNull(capturedArgs);
106 Assert.Equal("example.com", capturedArgs!["url"].GetString());
107 }
108
109 [Fact]
110 public async Task TryRun_GitCommit_StripsOptionalQuotes()
111 {
112 string? message = null;
113 var runner = new ChatSlashCommandRunner(
114 (id, args, _) =>
115 {
116 Assert.Equal(IdeCommands.GitCommit, id);
117 message = args!["message"].GetString();
118 return Task.FromResult("");
119 },
120 () => new ChatSlashEditorContext(null, null));
121
122 var result = await runner.TryRunAsync("/git commit \"feat: test\"");
123 Assert.True(result.Success);
124 Assert.Equal("feat: test", message);
125 }
126
127 [Fact]
128 public async Task TryRun_PortalOpen_WithoutUrl_AllowsNullArgs()
129 {
130 IReadOnlyDictionary<string, System.Text.Json.JsonElement>? capturedArgs = new Dictionary<string, System.Text.Json.JsonElement>();
131
132 var runner = new ChatSlashCommandRunner(
133 (_, args, _) =>
134 {
135 capturedArgs = args;
136 return Task.FromResult("");
137 },
138 () => new ChatSlashEditorContext(null, null));
139
140 var result = await runner.TryRunAsync("/portal open");
141 Assert.True(result.Success);
142 Assert.Null(capturedArgs);
143 }
144}
145
View only · write via MCP/CIDE