Implement engine-bridge PoC v1 (#9)
- Add Recordingtest.EngineBridge library (IEngineSnapshot, HmEgSnapshot skeleton, MetadataLoader, CandidateFinder, CatalogWriter). - Add Recordingtest.EngineBridge.Probe console exe that dumps hmeg-types.json and hmeg-candidates.json to docs/engine-catalog. - Add Recordingtest.EngineBridge.Tests (xUnit, 6 tests). - Add probe design doc with plugin-masquerade recommendation. - Static analysis only; SUT is never executed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
87
src/Recordingtest.EngineBridge.Probe/Program.cs
Normal file
87
src/Recordingtest.EngineBridge.Probe/Program.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Reflection;
|
||||
using Recordingtest.EngineBridge;
|
||||
|
||||
namespace Recordingtest.EngineBridge.Probe;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
private static readonly string[] DefaultAssemblyPatterns =
|
||||
{
|
||||
"HmEG.dll",
|
||||
"HmGeometry.dll",
|
||||
"HmGeometry.V2.dll",
|
||||
"HmTriangle.dll",
|
||||
"EditorCore.dll",
|
||||
"Editor*.dll",
|
||||
};
|
||||
|
||||
internal static int Main(string[] args)
|
||||
{
|
||||
string sutRoot = "EG-BIM Modeler";
|
||||
string outDir = Path.Combine("docs", "engine-catalog");
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
switch (args[i])
|
||||
{
|
||||
case "--sut" when i + 1 < args.Length:
|
||||
sutRoot = args[++i];
|
||||
break;
|
||||
case "--out" when i + 1 < args.Length:
|
||||
outDir = args[++i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Directory.Exists(sutRoot))
|
||||
{
|
||||
Console.Error.WriteLine($"SUT path not found: {sutRoot}");
|
||||
return 2;
|
||||
}
|
||||
|
||||
var assemblyNames = ResolveAssemblyNames(sutRoot);
|
||||
Console.WriteLine($"Loading {assemblyNames.Count} assemblies from {sutRoot}");
|
||||
|
||||
using var loader = new MetadataLoader(sutRoot);
|
||||
var types = loader.LoadTypes(assemblyNames).ToList();
|
||||
|
||||
var byAsm = types
|
||||
.GroupBy(t => t.Assembly.GetName().Name ?? "?")
|
||||
.OrderBy(g => g.Key, StringComparer.Ordinal);
|
||||
foreach (var g in byAsm)
|
||||
{
|
||||
Console.WriteLine($" {g.Key}: {g.Count()} types");
|
||||
}
|
||||
|
||||
var candidates = CandidateFinder.Find(types);
|
||||
var byCat = candidates
|
||||
.GroupBy(c => c.Category)
|
||||
.OrderBy(g => g.Key, StringComparer.Ordinal);
|
||||
Console.WriteLine("Candidate categories:");
|
||||
foreach (var g in byCat)
|
||||
{
|
||||
Console.WriteLine($" {g.Key}: {g.Count()}");
|
||||
}
|
||||
|
||||
var typesPath = Path.Combine(outDir, "hmeg-types.json").Replace('\\', '/');
|
||||
var candPath = Path.Combine(outDir, "hmeg-candidates.json").Replace('\\', '/');
|
||||
CatalogWriter.WriteTypes(typesPath, types);
|
||||
CatalogWriter.WriteCandidates(candPath, candidates);
|
||||
Console.WriteLine($"Wrote {typesPath}");
|
||||
Console.WriteLine($"Wrote {candPath}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static List<string> ResolveAssemblyNames(string sutRoot)
|
||||
{
|
||||
var set = new SortedSet<string>(StringComparer.Ordinal);
|
||||
foreach (var pat in DefaultAssemblyPatterns)
|
||||
{
|
||||
foreach (var f in Directory.EnumerateFiles(sutRoot, pat, SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
set.Add(Path.GetFileName(f));
|
||||
}
|
||||
}
|
||||
return set.ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>Recordingtest.EngineBridge.Probe</AssemblyName>
|
||||
<RootNamespace>Recordingtest.EngineBridge.Probe</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Recordingtest.EngineBridge\Recordingtest.EngineBridge.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user