Forge
csharpdeeb25a2
1using CascadeIDE.Features.Chat;
2
3using Xunit;
4
5
6
7namespace CascadeIDE.Tests;
8
9
10
11public sealed class ChatSlashAutocompleteTests
12
13{
14
15 [Fact]
16
17 public void GetSuggestions_EmptySlash_ReturnsRootNamespacesOnly()
18
19 {
20
21 var suggestions = ChatSlashAutocomplete.GetSuggestions("/");
22
23 Assert.NotEmpty(suggestions);
24
25 Assert.All(suggestions, s => Assert.EndsWith(" ", s.InsertText));
26
27 Assert.Contains(suggestions, s => s.InsertText.Equals("/intercom ", StringComparison.Ordinal));
28
29 Assert.Contains(suggestions, s => s.InsertText.Equals("/build ", StringComparison.Ordinal));
30
31 Assert.Contains(suggestions, s => s.ListTitle == "intercom");
32
33 Assert.Contains(suggestions, s => s.ListTitle == "build");
34
35 Assert.All(suggestions, s => Assert.DoesNotContain(' ', s.ListTitle));
36
37 Assert.All(suggestions, s => Assert.DoesNotContain(' ', s.SlashPath.TrimStart('/')));
38
39 }
40
41
42
43 [Fact]
44
45 public void GetSuggestions_JustSlash_CaretAfterSlash_ReturnsDomainSegmentsOnly()
46
47 {
48
49 var suggestions = ChatSlashAutocomplete.GetSuggestions("/", caretIndex: 1);
50
51 Assert.NotEmpty(suggestions);
52
53 Assert.All(suggestions, s => Assert.DoesNotContain(' ', s.ListTitle));
54
55 Assert.Contains(suggestions, s => s.ListTitle == "intercom");
56
57 }
58
59
60
61 [Fact]
62
63 public void GetSuggestions_NotSlash_ReturnsEmpty()
64
65 {
66
67 Assert.Empty(ChatSlashAutocomplete.GetSuggestions("hello"));
68
69 }
70
71
72
73 [Fact]
74
75 public void GetSuggestions_SlashOnSecondLine_WithCaret_ReturnsRootNamespaces()
76
77 {
78
79 var text = "привет\n/";
80
81 var suggestions = ChatSlashAutocomplete.GetSuggestions(text, caretIndex: text.Length);
82
83 Assert.NotEmpty(suggestions);
84
85 Assert.Contains(suggestions, s => s.InsertText.Equals("/intercom ", StringComparison.Ordinal));
86
87 }
88
89
90
91 [Fact]
92
93 public void GetSuggestions_SlashAfterTextOnSameLine_ReturnsEmpty()
94
95 {
96
97 Assert.Empty(ChatSlashAutocomplete.GetSuggestions("hello /help", caretIndex: 11));
98
99 }
100
101
102
103 [Fact]
104
105 public void GetSuggestions_PrefixBuild_FiltersNamespaceCommands()
106
107 {
108
109 var suggestions = ChatSlashAutocomplete.GetSuggestions("/b");
110
111 Assert.Contains(suggestions, s => s.InsertText == "/build ");
112
113 Assert.DoesNotContain(suggestions, s => s.InsertText.StartsWith("/build run", StringComparison.Ordinal));
114
115 Assert.DoesNotContain(suggestions, s => s.SlashPath == "/overview");
116
117 }
118
119
120
121 [Fact]
122
123 public void GetSuggestions_BuildNamespace_ListsActions()
124
125 {
126
127 var suggestions = ChatSlashAutocomplete.GetSuggestions("/build ");
128
129 Assert.Equal(3, suggestions.Count);
130
131 Assert.Contains(suggestions, s => s.InsertText == "/build run");
132
133 Assert.Contains(suggestions, s => s.InsertText == "/build ui");
134
135 Assert.Contains(suggestions, s => s.InsertText == "/build structured");
136
137 }
138
139
140
141 [Fact]
142
143 public void GetSuggestions_BuildActionPrefix_FiltersRun()
144
145 {
146
147 var suggestions = ChatSlashAutocomplete.GetSuggestions("/build r");
148
149 Assert.Single(suggestions);
150
151 Assert.Equal("/build run", suggestions[0].InsertText);
152
153 }
154
155
156
157 [Fact]
158
159 public void GetSuggestions_IntercomPrefix_CompletesDomainOnly()
160
161 {
162
163 var suggestions = ChatSlashAutocomplete.GetSuggestions("/i");
164
165 Assert.Contains(suggestions, s => s.InsertText == "/intercom ");
166
167 Assert.DoesNotContain(suggestions, s => s.InsertText.Contains("topic rename", StringComparison.Ordinal));
168
169 }
170
171
172
173 [Fact]
174
175 public void GetSuggestions_IntercomDomain_ListsServerObject()
176
177 {
178
179 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom ");
180
181 Assert.Contains(suggestions, s => s.ListTitle == "server");
182
183 Assert.Equal("/intercom server ", suggestions.First(s => s.ListTitle == "server").InsertText);
184
185 }
186
187
188
189 [Fact]
190
191 public void GetSuggestions_IntercomServerSpace_ListsStartStatusStop()
192
193 {
194
195 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom server ");
196
197 Assert.Contains(suggestions, s => s.ListTitle == "start" && s.InsertText == "/intercom server start ");
198
199 Assert.Contains(suggestions, s => s.ListTitle == "status");
200
201 Assert.Contains(suggestions, s => s.ListTitle == "stop");
202
203 }
204
205 [Fact]
206 public void GetSuggestions_IntercomServerStartComplete_ReturnsEmpty()
207 {
208 Assert.Empty(ChatSlashAutocomplete.GetSuggestions("/intercom server start"));
209 }
210
211 [Fact]
212 public void GetSuggestions_IntercomServerStartWithTrailingSpace_ReturnsEmpty()
213 {
214 Assert.Empty(ChatSlashAutocomplete.GetSuggestions("/intercom server start "));
215 }
216
217 [Fact]
218 public void GetSuggestions_IntercomServerStartWithBaseUrl_ReturnsEmpty()
219 {
220 Assert.Empty(ChatSlashAutocomplete.GetSuggestions("/intercom server start http://127.0.0.1:5080"));
221 }
222
223 [Fact]
224 public void GetSuggestions_IntercomServerStaPartial_StillListsMatches()
225 {
226 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom server sta");
227 Assert.Contains(suggestions, s => s.ListTitle == "start");
228 Assert.Contains(suggestions, s => s.ListTitle == "status");
229 }
230
231 [Fact]
232 public void IsRunnableSlashLineAtCaret_IntercomServerStart_ReturnsTrue()
233 {
234 const string line = "/intercom server start";
235 Assert.True(ChatSlashAutocomplete.IsRunnableSlashLineAtCaret(line, line.Length));
236 }
237
238 [Fact]
239 public void IsRunnableSlashLineAtCaret_FileOpenWithoutPath_ReturnsFalse()
240 {
241 const string line = "/file open";
242 Assert.False(ChatSlashAutocomplete.IsRunnableSlashLineAtCaret(line, line.Length));
243 }
244
245
246
247 [Fact]
248
249 public void GetSuggestions_IntercomDomain_ListsObjects()
250
251 {
252
253 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom ");
254
255 Assert.Contains(suggestions, s => s.InsertText == "/intercom topic ");
256
257 Assert.Contains(suggestions, s => s.InsertText == "/intercom message ");
258
259 Assert.DoesNotContain(suggestions, s => s.InsertText == "/intercom topic rename ");
260
261 Assert.Contains(suggestions, s => s.ListTitle == "topic");
262
263 Assert.Contains(suggestions, s => s.ListTitle == "message");
264
265 Assert.All(suggestions, s => Assert.DoesNotContain('/', s.ListTitle));
266
267 }
268
269
270
271 [Fact]
272
273 public void GetSuggestions_IntercomWithoutTrailingSpace_ListsObjectSegmentsOnly()
274
275 {
276
277 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom");
278
279 Assert.NotEmpty(suggestions);
280
281 Assert.Contains(suggestions, s => s.ListTitle == "topic");
282
283 Assert.DoesNotContain(suggestions, s => s.ListTitle == "selection");
284
285 Assert.All(suggestions, s => Assert.DoesNotContain('/', s.ListTitle));
286
287 }
288
289
290
291 [Fact]
292 public void CatalogListsIntercomTopicRename()
293 {
294 Assert.Contains(
295 ChatSlashCommandCatalog.AllSuggestions(),
296 s => s.SlashPath == "/intercom topic rename");
297 }
298
299 [Fact]
300 public void GetSuggestions_IntercomTopicSpace_IncludesRenamePath()
301 {
302 var paths = ChatSlashAutocomplete.GetSuggestions("/intercom topic ")
303 .Select(s => s.SlashPath)
304 .ToList();
305 Assert.Contains("/intercom topic rename", paths);
306 }
307
308 [Fact]
309 public void GetSuggestions_IntercomTopicObject_ListsActions()
310 {
311 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom topic ");
312 Assert.Contains(suggestions, s => s.SlashPath == "/intercom topic rename");
313 Assert.Contains(suggestions, s => s.InsertText == "/intercom topic rename ");
314 Assert.Contains(suggestions, s => s.InsertText == "/intercom topic create ");
315 Assert.Contains(suggestions, s => s.InsertText == "/intercom topic open");
316 Assert.DoesNotContain(suggestions, s => s.InsertText == "/intercom message select ");
317 Assert.Contains(suggestions, s => s.ListTitle == "rename");
318 Assert.Contains(suggestions, s => s.ListTitle == "create");
319 Assert.All(suggestions, s => Assert.DoesNotContain('/', s.ListTitle));
320 }
321
322 [Fact]
323
324 public void GetSuggestions_IntercomTopicRenamePrefix_CompletesActionWithArgSpace()
325
326 {
327
328 var suggestions = ChatSlashAutocomplete.GetSuggestions("/intercom topic r");
329
330 Assert.Single(suggestions);
331
332 Assert.Equal("/intercom topic rename ", suggestions[0].InsertText);
333
334 }
335
336
337
338 [Fact]
339 public void GetHierarchyContext_RootSlash_ShowsDomainStep()
340 {
341 var ctx = ChatSlashAutocomplete.GetHierarchyContext("/");
342 Assert.NotNull(ctx);
343 Assert.Equal("/", ctx.PathPrefix);
344 Assert.Equal("домен", ctx.NextStepLabel);
345 Assert.Contains("домен", ctx.Breadcrumb, StringComparison.Ordinal);
346 }
347
348 [Fact]
349 public void GetHierarchyContext_IntercomDomain_ShowsObjectStep()
350 {
351 var ctx = ChatSlashAutocomplete.GetHierarchyContext("/intercom ");
352 Assert.NotNull(ctx);
353 Assert.Equal("/intercom", ctx.PathPrefix);
354 Assert.Equal("объект", ctx.NextStepLabel);
355 Assert.Contains("intercom", ctx.Breadcrumb, StringComparison.Ordinal);
356 }
357
358 [Fact]
359 public void GetHierarchyContext_IntercomTopic_ShowsIntentStep()
360 {
361 var ctx = ChatSlashAutocomplete.GetHierarchyContext("/intercom topic ");
362 Assert.NotNull(ctx);
363 Assert.Equal("/intercom topic", ctx.PathPrefix);
364 Assert.Equal("действие", ctx.NextStepLabel);
365 }
366
367 [Fact]
368
369 public void TryReplaceSlashLineAtCaret_PreservesTextBeforeSlashLine()
370
371 {
372
373 var text = "привет\n/intercom top";
374
375 var ok = ChatSlashAutocomplete.TryReplaceSlashLineAtCaret(
376
377 text,
378
379 caretIndex: text.Length,
380
381 "/intercom topic ",
382
383 out var newText,
384
385 out var newCaret);
386
387
388
389 Assert.True(ok);
390
391 Assert.Equal("привет\n/intercom topic ", newText);
392
393 Assert.Equal(newText.Length, newCaret);
394
395 }
396
397}
398
399
View only · write via MCP/CIDE