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); } } }