Files
kompas3d-mcp/tests/Kompas.Mcp.Tests/Integration/FeatureDeleteTests.cs
T
mikhail e127cebb49 Итерация 1: удаление операции, выравнивание надписи, отбор рёбер
По протоколу регресс-прогона (46 вызовов против 90 в прошлом):

feature_delete — ksDocument3D.DeleteObject + RebuildDocument, зависимые уходят каскадом.
Неудачная проба больше не требует пересобирать документ (у субагента таких кругов было три).

align/vAlign у примитива text: сервер строит, замеряет и сдвигает надпись сам. Ловушка,
стоившая двух заходов: ksMoveObj и ksDeleteObj по ссылке от ksConvertTextToCurve возвращают
успех и не делают ничего — двигать надо по ссылке ТЕКСТА, а габарит после сдвига считать
арифметикой (по текстовой ссылке рамка идёт по ячейке). Поймано тестом, который сверяет
заявленный габарит с выдавленной геометрией.

list_edges: отбор по типу и координатному окну + концы рёбер в списке. Так адресуется
нижний контур под фаску, который иначе не выбрать: индексов не отфильтровать, точек не угадать.

Навык: wf меряет пропорцию крупно (1.0→1.25 = +29 %), но квантован ступенями — точную ширину
набирают height; прирост каймы указан НА СТОРОНУ и зависит от начертания, а не от шрифта;
добавлено предупреждение, что primitive(subtract) режет наехавшие буквы.
2026-07-31 17:11:53 +03:00

119 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>
/// Интеграция: удаление операции/эскиза. Без него любая неудачная проба (не тот кегль надписи,
/// не та глубина) оставалась в дереве навсегда, и единственным выходом было закрыть документ
/// без сохранения и построить всё заново.
/// </summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class FeatureDeleteTests : IntegrationTestBase
{
private readonly DocumentService _docs;
private readonly PartModeler _modeler;
private readonly ModelInspectionService _inspection;
private readonly QueryService _query;
public FeatureDeleteTests(KompasFixture fx) : base(fx)
{
_docs = new DocumentService(fx.Session, fx.Dispatcher);
_modeler = new PartModeler(fx.Session, fx.Dispatcher);
_inspection = new ModelInspectionService(fx.Session, fx.Dispatcher);
_query = new QueryService(fx.Session, fx.Dispatcher);
}
private async Task<IReadOnlyList<string>> TreeNamesAsync()
=> (await _inspection.DescribeModelAsync(InspectionText.ModelSections.Tree))
.Features.Select(f => f.Name).ToList();
[Fact]
public async Task Deleted_extrusion_leaves_the_tree_and_gives_the_material_back()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var plate = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Контур плиты");
await _modeler.AddRectangleAsync(plate, 0, 0, 20, 10);
await _modeler.CloseSketchAsync(plate);
await _modeler.ExtrudeAsync(plate, depth: 3, name: "Плита");
var probe = await _modeler.OpenSketchOnOffsetPlaneAsync(BasePlane.XOY, offset: 3, name: "Проба кегля");
await _modeler.AddRectangleAsync(probe, 2, 2, 8, 8);
await _modeler.CloseSketchAsync(probe);
var probeId = await _modeler.ExtrudeAsync(probe, depth: 5, name: "Неудачная проба");
await _modeler.RebuildAsync();
var withProbe = (await _query.GetPartInfoAsync()).Volume;
var deleted = await _modeler.DeleteAsync(probeId);
await _modeler.RebuildAsync();
Assert.Contains("Неудачная проба", deleted, StringComparison.Ordinal);
var names = await TreeNamesAsync();
Assert.DoesNotContain("Неудачная проба", names);
Assert.Contains("Плита", names);
// 20×10×3 = 600: проба ушла вместе со своим материалом (6×6×5 = 180).
var after = (await _query.GetPartInfoAsync()).Volume;
Assert.InRange(after, 594, 606);
Assert.True(withProbe > after, "проба не добавляла материала — тест ничего не проверяет");
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Deleting_a_sketch_takes_its_operation_with_it()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var s = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Контур пробы");
await _modeler.AddRectangleAsync(s, 0, 0, 20, 10);
await _modeler.CloseSketchAsync(s);
await _modeler.ExtrudeAsync(s, depth: 3, name: "Тело пробы");
await _modeler.RebuildAsync();
await _modeler.DeleteAsync(s); // КОМПАС удаляет зависимые каскадом
await _modeler.RebuildAsync();
var names = await TreeNamesAsync();
Assert.DoesNotContain("Контур пробы", names);
Assert.DoesNotContain("Тело пробы", names);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Unknown_id_says_what_can_be_deleted()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var ex = await Assert.ThrowsAsync<KeyNotFoundException>(() => _modeler.DeleteAsync(4242));
Assert.Contains("4242", ex.Message, StringComparison.Ordinal);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Open_sketch_is_closed_before_deletion()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
// Эскиз остался в режиме редактирования — удаление обязано с этим справиться само.
var s = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Открытая проба");
await _modeler.AddRectangleAsync(s, 0, 0, 10, 10);
await _modeler.DeleteAsync(s);
await _modeler.RebuildAsync();
Assert.DoesNotContain("Открытая проба", await TreeNamesAsync());
}
finally { await _docs.CloseAsync(save: false); }
}
}