using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
namespace Kompas.Mcp.Tests.Integration;
///
/// Интеграция: удаление операции/эскиза. Без него любая неудачная проба (не тот кегль надписи,
/// не та глубина) оставалась в дереве навсегда, и единственным выходом было закрыть документ
/// без сохранения и построить всё заново.
///
[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> 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(() => _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); }
}
}