Files
kompas3d-mcp/tests/Kompas.Mcp.Tests/Integration/ConversionTests.cs
T
mikhail 28d2ae3868 feat(inspection): структурное «зрение» модели — осмотр без снимка
Новый слой «модель как данные» (приоритетный над model_snapshot):
- describe_model — структурный «паспорт» детали одним вызовом (габарит,
  МЦХ, тела, сводка топологии, дерево построения с параметрами, переменные)
- list_features / list_bodies / list_variables
- describe_face / describe_edge (drill-down по индексу)
- measure (расстояние/угол между гранями/рёбрами/вершинами)
- model_snapshot понижен до fallback для визуально-пространственных вопросов

Реализация: ModelInspectionService (COM) + чистый InspectionText (рендер,
группировка, детект «импорт без истории») + record-модели; InspectionTools.
Дерево читается через ksPart.GetFeature()->SubFeatureCollection; точный тип
и параметры операций берутся из GetObject()->GetDefinition() (ksFeature.type
отдаёт лишь coarse o3d_entity).

Снимок дерева также включает слои conversion (STEP), editing (move_face/solid)
и validation, развивавшиеся параллельно. Полный прогон: 61 тест зелёный,
43 MCP-инструмента. Документация (README, ARCHITECTURE, OPEN_QUESTIONS,
CLAUDE.md, presentation.html) синхронизирована.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 18:44:38 +03:00

108 lines
3.8 KiB
C#

using Kompas.Mcp.Core.Conversion;
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>Интеграция: импорт/экспорт STEP и обход компонентов сборки.</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class ConversionTests
{
private readonly DocumentService _docs;
private readonly PartModeler _modeler;
private readonly ConversionService _conv;
private readonly QueryService _query;
public ConversionTests(KompasFixture fx)
{
_docs = new DocumentService(fx.Session, fx.Dispatcher);
_modeler = new PartModeler(fx.Session, fx.Dispatcher);
_conv = new ConversionService(fx.Session, fx.Dispatcher);
_query = new QueryService(fx.Session, fx.Dispatcher);
}
private async Task BuildBoxAsync(double w, double d, double h)
{
var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.AddRectangleAsync(s, 0, 0, w, d);
await _modeler.CloseSketchAsync(s);
await _modeler.ExtrudeAsync(s, depth: h);
await _modeler.RebuildAsync();
}
[Fact]
public async Task Exports_active_part_to_step_file()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
await BuildBoxAsync(30, 20, 10);
var path = TestPaths.NewFile(".step");
await _conv.ExportStepAsync(path, StepFormat.Ap214);
Assert.True(File.Exists(path), "STEP-файл не создан.");
Assert.True(new FileInfo(path).Length > 0, "STEP-файл пуст.");
}
finally
{
await _docs.CloseAsync(save: false);
}
}
[Fact]
public async Task Imports_step_back_with_geometry()
{
// arrange: построить брусок и экспортировать в STEP
await _docs.CreateAsync(KompasDocumentType.Part);
string path = TestPaths.NewFile(".step");
try
{
await BuildBoxAsync(40, 30, 10);
await _conv.ExportStepAsync(path, StepFormat.Auto);
}
finally
{
await _docs.CloseAsync(save: false);
}
// act: импортировать обратно как деталь
await _conv.ImportStepAsync(path, KompasDocumentType.Part);
try
{
// assert: геометрия пришла — ненулевой объём (40·30·10 = 12000 мм³)
var info = await _query.GetPartInfoAsync();
Assert.InRange(info.Volume, 12000 * 0.95, 12000 * 1.05);
}
finally
{
await _docs.CloseAsync(save: false);
}
}
[Fact]
public async Task Lists_components_of_imported_assembly()
{
// Реальная сборка кейса (gitignored); если её нет локально — тест пропускается.
var caseStep = Path.Combine(TestPaths.RepoRoot(),
"usecases", "0002-voron-pug-strain-relief-2mm", "source", "G2E_PUG.step");
if (!File.Exists(caseStep)) return; // gitignored кейс отсутствует локально — пропускаем
await _conv.ImportStepAsync(caseStep, KompasDocumentType.Assembly);
try
{
var comps = await _query.ListComponentsAsync();
Assert.True(comps.Count >= 2, $"Ожидалось ≥2 компонента, получено {comps.Count}.");
Assert.All(comps, c => Assert.False(string.IsNullOrWhiteSpace(c.Name)));
Assert.Contains(comps, c => c.Name.Contains("spacer", StringComparison.OrdinalIgnoreCase));
}
finally
{
await _docs.CloseAsync(save: false);
}
}
}