Forge
csharp3407750f
1using System.Net;
2using System.Net.Http.Json;
3using System.Text.Json;
4
5namespace AgentForge.Tests;
6
7public sealed class ForgeCommandTests(ForgeWebApplicationFactory factory) : IClassFixture<ForgeWebApplicationFactory>
8{
9 private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };
10
11 [Fact]
12 public async Task Capabilities_includes_forge_commands()
13 {
14 var response = await factory.CreateClient().GetAsync("/api/v1/capabilities");
15 response.EnsureSuccessStatusCode();
16
17 var caps = await response.Content.ReadFromJsonAsync<JsonElement>(JsonOptions);
18 var commands = caps.GetProperty("commands").EnumerateArray().ToList();
19 Assert.NotEmpty(commands);
20
21 var ids = commands.Select(c => c.GetProperty("commandId").GetString()).ToHashSet(StringComparer.Ordinal);
22 Assert.Contains("forge.issue.open", ids);
23 Assert.Contains("forge.issue.create", ids);
24 Assert.Contains("forge.merge_request.open", ids);
25 Assert.Contains("forge.repo.open", ids);
26 }
27
28 [Fact]
29 public async Task Capabilities_surface_filter_limits_commands()
30 {
31 var response = await factory.CreateClient().GetAsync("/api/v1/capabilities?surface=mr-comment");
32 response.EnsureSuccessStatusCode();
33
34 var caps = await response.Content.ReadFromJsonAsync<JsonElement>(JsonOptions);
35 var commands = caps.GetProperty("commands").EnumerateArray().ToList();
36 Assert.All(commands, c =>
37 {
38 var surfaces = c.GetProperty("surfaces").EnumerateArray().Select(e => e.GetString()).ToList();
39 Assert.Contains("mr-comment", surfaces);
40 });
41 }
42
43 [Fact]
44 public async Task Execute_issue_open_redirects_to_view()
45 {
46 var client = factory.CreateClient(new() { AllowAutoRedirect = false });
47 var payload = new
48 {
49 path = "/issue open",
50 args = "42",
51 context = new Dictionary<string, string> { ["repo"] = "demo" },
52 };
53
54 var response = await client.PostAsJsonAsync("/api/v1/commands/execute", payload);
55 Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
56 Assert.Equal("/view/repos/demo/issues/42", response.Headers.Location?.OriginalString);
57 }
58
59 [Fact]
60 public async Task Execute_repo_open_redirects_to_view()
61 {
62 var client = factory.CreateClient(new() { AllowAutoRedirect = false });
63 var payload = new
64 {
65 path = "/repo open",
66 context = new Dictionary<string, string> { ["repo"] = "demo" },
67 };
68
69 var response = await client.PostAsJsonAsync("/api/v1/commands/execute", payload);
70 Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
71 Assert.Equal("/view/repos/demo", response.Headers.Location?.OriginalString);
72 }
73
74 [Fact]
75 public async Task Execute_unknown_path_returns_bad_request()
76 {
77 var response = await factory.CreateClient().PostAsJsonAsync(
78 "/api/v1/commands/execute",
79 new { path = "/not-a-command" });
80
81 Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
82 }
83}
84
View only · write via MCP/CIDE