feat: drawing_fill_title_block — основная надпись чертежа (API7)
Веха 2D-ЧЕРТЁЖ, инкремент 2 (оформление). DrawingService.FillTitleBlockAsync: LayoutSheets.ItemByNumber[1].Stamp.Text[id].Str = text → Update(). Enum StampField → номер графы ГОСТ (designation=2, name=1, material=3). Заполнение нескольких граф за вызов; перезапись (Str замещает, Clear не нужен — подтверждено спайком). Новый инструмент drawing_fill_title_block; ReadStampCellAsync для проверки. Ревью Codex спека учтено: Update() результат проверяется; null-checks (LayoutSheets/sheet/Stamp); RequireActiveDrawing выделен (сохраняет cast-проверку); ColumnId switch с дефолтным throw; счётчик = непустые поля; name=графа 1 однозначно. Валидация — чистый StampFields (ColumnId + Collect). Тесты: +7 unit (StampFields), +4 integration (DrawingStampTests: заполнение+reread 3 граф, перезапись, пустой ввод, не-чертёж). Итого 123 unit + 65 integration = 188. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
using Kompas.Mcp.Core.Documents;
|
||||
using Kompas.Mcp.Core.Drawings;
|
||||
using Kompas.Mcp.Core.Modeling;
|
||||
|
||||
namespace Kompas.Mcp.Tests.Integration;
|
||||
|
||||
/// <summary>Интеграция: заполнение основной надписи чертежа (API7 IStamp.Text).</summary>
|
||||
[Trait("Category", "Integration")]
|
||||
[Collection(KompasCollection.Name)]
|
||||
public sealed class DrawingStampTests : IntegrationTestBase
|
||||
{
|
||||
private readonly DocumentService _docs;
|
||||
private readonly DrawingService _drawing;
|
||||
private readonly PartModeler _modeler;
|
||||
|
||||
public DrawingStampTests(KompasFixture fx) : base(fx)
|
||||
{
|
||||
_docs = new DocumentService(fx.Session, fx.Dispatcher);
|
||||
_drawing = new DrawingService(fx.Session, fx.Dispatcher);
|
||||
_modeler = new PartModeler(fx.Session, fx.Dispatcher);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fills_and_reads_back_title_block_cells()
|
||||
{
|
||||
await _docs.CreateAsync(KompasDocumentType.Drawing);
|
||||
try
|
||||
{
|
||||
var filled = await _drawing.FillTitleBlockAsync(
|
||||
designation: "ДЕТАЛЬ.001", name: "Кронштейн", material: "Сталь 45");
|
||||
Assert.Equal(3, filled);
|
||||
|
||||
// Явный reread каждой графы (графа 2/1/3).
|
||||
Assert.Equal("ДЕТАЛЬ.001", await _drawing.ReadStampCellAsync(2));
|
||||
Assert.Equal("Кронштейн", await _drawing.ReadStampCellAsync(1));
|
||||
Assert.Equal("Сталь 45", await _drawing.ReadStampCellAsync(3));
|
||||
}
|
||||
finally { await _docs.CloseAsync(save: false); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Overwrites_existing_cell_text()
|
||||
{
|
||||
await _docs.CreateAsync(KompasDocumentType.Drawing);
|
||||
try
|
||||
{
|
||||
await _drawing.FillTitleBlockAsync(designation: "СТАРОЕ.000");
|
||||
await _drawing.FillTitleBlockAsync(designation: "НОВОЕ.111");
|
||||
|
||||
// Перезапись, не дописывание.
|
||||
Assert.Equal("НОВОЕ.111", await _drawing.ReadStampCellAsync(2));
|
||||
}
|
||||
finally { await _docs.CloseAsync(save: false); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Empty_input_throws()
|
||||
{
|
||||
await _docs.CreateAsync(KompasDocumentType.Drawing);
|
||||
try
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentException>(
|
||||
() => _drawing.FillTitleBlockAsync(null, " ", null));
|
||||
}
|
||||
finally { await _docs.CloseAsync(save: false); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Rejects_non_drawing_document()
|
||||
{
|
||||
await _docs.CreateAsync(KompasDocumentType.Part);
|
||||
try
|
||||
{
|
||||
// Деталь — не чертёж: FillTitleBlock должен бросить.
|
||||
var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
|
||||
await _modeler.AddRectangleAsync(s, 0, 0, 10, 10);
|
||||
await _modeler.CloseSketchAsync(s);
|
||||
await _modeler.ExtrudeAsync(s, depth: 5);
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => _drawing.FillTitleBlockAsync(designation: "X"));
|
||||
}
|
||||
finally { await _docs.CloseAsync(save: false); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Kompas.Mcp.Core.Drawings;
|
||||
|
||||
namespace Kompas.Mcp.Tests;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class StampFieldsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(StampField.Designation, 2)]
|
||||
[InlineData(StampField.Name, 1)]
|
||||
[InlineData(StampField.Material, 3)]
|
||||
public void ColumnId_maps_known_fields(StampField field, int expected)
|
||||
=> Assert.Equal(expected, StampFields.ColumnId(field));
|
||||
|
||||
[Fact]
|
||||
public void ColumnId_throws_on_unknown()
|
||||
=> Assert.Throws<ArgumentOutOfRangeException>(() => StampFields.ColumnId((StampField)999));
|
||||
|
||||
[Fact]
|
||||
public void Collect_skips_null_empty_and_whitespace()
|
||||
=> Assert.Empty(StampFields.Collect(null, "", " "));
|
||||
|
||||
[Fact]
|
||||
public void Collect_trims_and_maps_provided_fields()
|
||||
{
|
||||
var result = StampFields.Collect(" ДЕТАЛЬ.001 ", null, "Сталь 45");
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, t => t.ColumnId == 2 && t.Text == "ДЕТАЛЬ.001"); // designation
|
||||
Assert.Contains(result, t => t.ColumnId == 3 && t.Text == "Сталь 45"); // material
|
||||
Assert.DoesNotContain(result, t => t.ColumnId == 1); // name не задан
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Collect_includes_name_as_column_1()
|
||||
{
|
||||
var result = StampFields.Collect(null, "Кронштейн", null);
|
||||
Assert.Single(result);
|
||||
Assert.Equal((1, "Кронштейн"), result[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user