FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

test: expand out-of-host coverage and run pixi/pip without env gates · trgiangv/RevitDevTool@a73abdb · GitHub

test: expand out-of-host coverage and run pixi/pip without env gates · trgiangv/RevitDevTool@a73abdb · GitHub
Skip to content

Navigation Menu

Repository navigation

Commit a73abdb

Browse files
committed
test: expand out-of-host coverage and run pixi/pip without env gates
Add Execution, Logging, Telemetry, Hosting, and related facts. PixiInstaller downloads pixi when needed; Skip only if that download fails. Serialize pythonnet-touching facts with PythonRuntimeCollection.
1 parent c36d82d commit a73abdb

102 files changed

Lines changed: 9409 additions & 20 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using DevTools.AssemblyIsolation;
2+
3+
namespace DevTools.AssemblyIsolation.Tests;
4+
5+
public sealed class SharedSidecarsTests
6+
{
7+
[Theory]
8+
[InlineData("MahApps.Metro", true)]
9+
[InlineData("controlzex", true)]
10+
[InlineData("Microsoft.Xaml.Behaviors", true)]
11+
[InlineData("DevTools.UI", false)]
12+
[InlineData(null, false)]
13+
public void Contains_recognizes_known_sidecar_simple_names(string? name, bool expected)
14+
{
15+
Assert.Equal(expected, SharedSidecars.Contains(name));
16+
}
17+
18+
[Fact]
19+
public void ShareFromDirectory_requires_directory()
20+
{
21+
var plan = AssemblyIsolationPlan.Create("entry.dll");
22+
Assert.Throws<ArgumentException>(() => SharedSidecars.ShareFromDirectory(plan, " "));
23+
}
24+
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
using DevTools.Execution.External.Mcp.Connections;
2+
using DevTools.Execution.Models;
3+
using DevTools.Execution.Providers.FSharp;
4+
using DevTools.Execution.Services;
5+
using DevTools.Hosting;
6+
using Microsoft.Extensions.Logging.Abstractions;
7+
8+
namespace DevTools.Execution.Tests;
9+
10+
[Collection(nameof(NugetRestoreCollection))]
11+
public sealed class AdditionalCoverageTests
12+
{
13+
[Fact]
14+
public async Task PackageVersionChecker_AttachLatestVersions_EmptyList_ReturnsEmpty()
15+
{
16+
var checker = new PackageVersionChecker(
17+
new NugetManager(NullLogger<NugetManager>.Instance),
18+
NullLogger<PackageVersionChecker>.Instance);
19+
20+
var result = await checker.AttachLatestVersionsAsync([], TestContext.Current.CancellationToken);
21+
22+
Assert.Empty(result);
23+
}
24+
25+
[Fact]
26+
public async Task PackageVersionChecker_AttachLatestVersions_NuGetPackage_FetchesLatest()
27+
{
28+
var checker = new PackageVersionChecker(
29+
new NugetManager(NullLogger<NugetManager>.Instance),
30+
NullLogger<PackageVersionChecker>.Instance);
31+
var packages = new List<Package> { new(Marketplace.NuGet, "Newtonsoft.Json", "13.0.1", "13.0.1") };
32+
33+
var result = await checker.AttachLatestVersionsAsync(packages, TestContext.Current.CancellationToken);
34+
35+
Assert.Single(result);
36+
Assert.False(string.IsNullOrWhiteSpace(result[0].LatestVersion));
37+
}
38+
39+
[Fact]
40+
public void McpConnectState_RecordsToolCallsAndExecutionScope()
41+
{
42+
var state = new McpConnectState(NullLogger<McpConnectState>.Instance);
43+
state.RecordCall("id-1", "echo");
44+
state.RecordCall("id-1", "echo");
45+
46+
Assert.Equal(2, state.TotalToolCalls);
47+
Assert.Single(state.ToolCalls);
48+
Assert.Equal(2, state.ToolCalls[0].Count);
49+
50+
using var scope = state.BeginExecution("echo");
51+
scope.MarkRunning();
52+
scope.Dispose();
53+
Assert.False(state.IsExecuting);
54+
}
55+
56+
[Fact]
57+
public void McpExecutionTracker_ForwardsToConnectState()
58+
{
59+
var state = new McpConnectState(NullLogger<McpConnectState>.Instance);
60+
var tracker = new McpExecutionTracker(state);
61+
62+
tracker.RecordCall("tool-id", "sample");
63+
using var scope = tracker.BeginExecution("sample");
64+
tracker.MarkRunning(scope);
65+
scope.Dispose();
66+
67+
Assert.Equal(1, state.TotalToolCalls);
68+
}
69+
70+
[Fact]
71+
public async Task NugetManager_ResolvePackageDlls_ReturnsDllPaths()
72+
{
73+
var manager = new NugetManager(NullLogger<NugetManager>.Instance);
74+
75+
var dlls = await manager.ResolvePackageDllsAsync("Newtonsoft.Json", "13.0.3", TestContext.Current.CancellationToken);
76+
77+
Assert.NotEmpty(dlls);
78+
Assert.All(dlls, path => Assert.EndsWith(".dll", path, StringComparison.OrdinalIgnoreCase));
79+
}
80+
81+
[Fact]
82+
public async Task NetworkService_GetBytesAsync_DownloadsFromLocalServer()
83+
{
84+
var port = GetFreeTcpPort();
85+
using var listener = new System.Net.HttpListener();
86+
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
87+
listener.Start();
88+
var url = $"http://127.0.0.1:{port}/bytes";
89+
var payload = new byte[] { 1, 2, 3 };
90+
91+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
92+
_ = Task.Run(async () =>
93+
{
94+
while (listener.IsListening && !cts.Token.IsCancellationRequested)
95+
{
96+
var context = await listener.GetContextAsync().WaitAsync(cts.Token);
97+
context.Response.ContentLength64 = payload.Length;
98+
await context.Response.OutputStream.WriteAsync(payload, cts.Token);
99+
context.Response.Close();
100+
}
101+
}, cts.Token);
102+
103+
try
104+
{
105+
var bytes = await NetworkService.GetBytesAsync(url, TestContext.Current.CancellationToken);
106+
Assert.Equal(payload, bytes);
107+
}
108+
finally
109+
{
110+
listener.Stop();
111+
listener.Close();
112+
cts.Cancel();
113+
}
114+
}
115+
116+
[Fact]
117+
public async Task NetworkService_GetJsonDocumentAsync_ParsesLocalPayload()
118+
{
119+
var port = GetFreeTcpPort();
120+
using var listener = new System.Net.HttpListener();
121+
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
122+
listener.Start();
123+
var url = $"http://127.0.0.1:{port}/json";
124+
const string payload = """{"info":{"version":"9.9.9"}}""";
125+
126+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
127+
_ = Task.Run(async () =>
128+
{
129+
while (listener.IsListening && !cts.Token.IsCancellationRequested)
130+
{
131+
var context = await listener.GetContextAsync().WaitAsync(cts.Token);
132+
var bytes = System.Text.Encoding.UTF8.GetBytes(payload);
133+
context.Response.ContentLength64 = bytes.Length;
134+
await context.Response.OutputStream.WriteAsync(bytes, cts.Token);
135+
context.Response.Close();
136+
}
137+
}, cts.Token);
138+
139+
try
140+
{
141+
using var doc = await NetworkService.GetJsonDocumentAsync(url, TestContext.Current.CancellationToken);
142+
Assert.NotNull(doc);
143+
Assert.Equal("9.9.9", doc!.RootElement.GetProperty("info").GetProperty("version").GetString());
144+
}
145+
finally
146+
{
147+
listener.Stop();
148+
listener.Close();
149+
cts.Cancel();
150+
}
151+
}
152+
153+
[Fact]
154+
public void NetworkService_Configure_UpdatesUserAgent()
155+
{
156+
NetworkService.Configure(HostApp.Revit);
157+
NetworkService.Configure(HostApp.AutoCad);
158+
}
159+
160+
[Fact]
161+
public async Task NetworkService_GetStringAsync_DownloadsFromLocalServer()
162+
{
163+
var port = GetFreeTcpPort();
164+
using var listener = new System.Net.HttpListener();
165+
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
166+
listener.Start();
167+
var url = $"http://127.0.0.1:{port}/text";
168+
const string payload = "hello-network";
169+
170+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
171+
_ = Task.Run(async () =>
172+
{
173+
while (listener.IsListening && !cts.Token.IsCancellationRequested)
174+
{
175+
var context = await listener.GetContextAsync().WaitAsync(cts.Token);
176+
var bytes = System.Text.Encoding.UTF8.GetBytes(payload);
177+
context.Response.ContentLength64 = bytes.Length;
178+
await context.Response.OutputStream.WriteAsync(bytes, cts.Token);
179+
context.Response.Close();
180+
}
181+
}, cts.Token);
182+
183+
try
184+
{
185+
var text = await NetworkService.GetStringAsync(url, TestContext.Current.CancellationToken);
186+
Assert.Equal(payload, text);
187+
}
188+
finally
189+
{
190+
listener.Stop();
191+
listener.Close();
192+
cts.Cancel();
193+
}
194+
}
195+
196+
[Fact]
197+
public async Task NetworkService_GetJsonDocumentAsync_ReturnsNull_OnNotFound()
198+
{
199+
var port = GetFreeTcpPort();
200+
using var listener = new System.Net.HttpListener();
201+
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
202+
listener.Start();
203+
var url = $"http://127.0.0.1:{port}/missing";
204+
205+
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
206+
_ = Task.Run(async () =>
207+
{
208+
while (listener.IsListening && !cts.Token.IsCancellationRequested)
209+
{
210+
var context = await listener.GetContextAsync().WaitAsync(cts.Token);
211+
context.Response.StatusCode = 404;
212+
context.Response.Close();
213+
}
214+
}, cts.Token);
215+
216+
try
217+
{
218+
using var doc = await NetworkService.GetJsonDocumentAsync(url, TestContext.Current.CancellationToken);
219+
Assert.Null(doc);
220+
}
221+
finally
222+
{
223+
listener.Stop();
224+
listener.Close();
225+
cts.Cancel();
226+
}
227+
}
228+
229+
private static int GetFreeTcpPort()
230+
{
231+
var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
232+
listener.Start();
233+
var port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
234+
listener.Stop();
235+
return port;
236+
}
237+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using DevTools.Execution.Abstractions;
2+
using DevTools.Execution.Tests.AssemblyIsolation;
3+
using DevTools.Execution.Interfaces;
4+
using DevTools.Execution.Models;
5+
using DevTools.Execution.Providers.Dotnet;
6+
using Microsoft.Extensions.Logging.Abstractions;
7+
using Moq;
8+
9+
namespace DevTools.Execution.Tests;
10+
11+
public sealed class AssemblyExecutionProviderTests
12+
{
13+
[Fact]
14+
public async Task DiscoverAsync_BuildsNamespaceTreeForCommands()
15+
{
16+
using var graph = DynamicCommandGraph.Create("assembly-provider");
17+
var discovery = new Mock<ICommandDiscovery>();
18+
discovery
19+
.Setup(d => d.ParseCommands(graph.EntryPath))
20+
.Returns([
21+
new CommandItem(graph.EntryPath, "Fixture.Entry") { Name = "Entry" },
22+
]);
23+
24+
var provider = new AssemblyExecutionProvider(
25+
discovery.Object,
26+
ExecutionTestHelpers.InlineHostContext(),
27+
Mock.Of<ICommandRunner>(),
28+
NullLogger<AssemblyExecutionProvider>.Instance);
29+
30+
var nodes = await provider.DiscoverAsync(graph.EntryPath, TestContext.Current.CancellationToken);
31+
var root = Assert.IsType<ExecutionNodeRoot>(Assert.Single(nodes));
32+
var namespaceNode = Assert.IsType<ExecutionNodeIntermediate>(Assert.Single(root.Children));
33+
var command = Assert.IsType<ExecutionNode>(Assert.Single(namespaceNode.Children));
34+
35+
Assert.Equal(ExecutionMode.Dotnet, command.ExecutionMode);
36+
Assert.Equal("Entry", command.Name);
37+
}
38+
39+
[Fact]
40+
public async Task DiscoverAsync_InvalidPath_ReturnsEmpty()
41+
{
42+
var provider = new AssemblyExecutionProvider(
43+
Mock.Of<ICommandDiscovery>(),
44+
ExecutionTestHelpers.InlineHostContext(),
45+
Mock.Of<ICommandRunner>(),
46+
NullLogger<AssemblyExecutionProvider>.Instance);
47+
48+
var nodes = await provider.DiscoverAsync("missing.dll", TestContext.Current.CancellationToken);
49+
50+
Assert.Empty(nodes);
51+
}
52+
53+
[Fact]
54+
public void CanHandle_AcceptsDllFilesOnly()
55+
{
56+
var provider = new AssemblyExecutionProvider(
57+
Mock.Of<ICommandDiscovery>(),
58+
ExecutionTestHelpers.InlineHostContext(),
59+
Mock.Of<ICommandRunner>(),
60+
NullLogger<AssemblyExecutionProvider>.Instance);
61+
62+
using var graph = DynamicCommandGraph.Create("assembly-handle");
63+
Assert.True(provider.CanHandle(graph.EntryPath));
64+
Assert.False(provider.CanHandle(graph.Directory));
65+
}
66+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using DevTools.Execution.Abstractions;
2+
using DevTools.Execution.Interfaces;
3+
using DevTools.Execution.Models;
4+
using DevTools.Execution.Providers.Dotnet;
5+
using Moq;
6+
7+
namespace DevTools.Execution.Tests;
8+
9+
public sealed class AssemblyExecutionStrategyTests
10+
{
11+
[Fact]
12+
public async Task ExecuteAsync_RunsCommandThroughHostContext()
13+
{
14+
var command = new CommandItem("sample.dll", "Sample.Command") { Name = "Command" };
15+
var runner = new Mock<ICommandRunner>();
16+
runner
17+
.Setup(r => r.RunCommand(command))
18+
.Returns(ExecutionResult.Succeeded("ran", 3));
19+
var progress = new List<string>();
20+
var strategy = new AssemblyExecutionStrategy(
21+
command,
22+
ExecutionTestHelpers.InlineHostContext(),
23+
runner.Object);
24+
var result = await strategy.ExecuteAsync(new Progress<string>(message =>
25+
{
26+
lock (progress)
27+
progress.Add(message);
28+
}), TestContext.Current.CancellationToken);
29+
30+
Assert.True(result.Success);
31+
runner.Verify(r => r.RunCommand(command), Times.Once);
32+
}
33+
34+
[Fact]
35+
public async Task ExecuteAsync_Cancelled_ReturnsCancelledResult()
36+
{
37+
var command = new CommandItem("sample.dll", "Sample.Command");
38+
var host = new Mock<IHostContextExecutor>();
39+
using var cts = new CancellationTokenSource();
40+
cts.Cancel();
41+
host
42+
.Setup(h => h.ExecuteAsync(It.IsAny<Func<ExecutionResult>>(), It.IsAny<CancellationToken>()))
43+
.ThrowsAsync(new OperationCanceledException());
44+
45+
var strategy = new AssemblyExecutionStrategy(command, host.Object, Mock.Of<ICommandRunner>());
46+
var result = await strategy.ExecuteAsync(cancellationToken: cts.Token);
47+
48+
Assert.True(result.IsCancelled);
49+
}
50+
}

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.

Back | FazBrowse Home | New Git URL