feat(drawing): формат и ориентация листа (drawing_set_sheet_format)

Задать формат (A0–A5/user) и ориентацию (книжная/альбомная) листа чертежа через
API7 ILayoutSheet.Format (ISheetFormat). Стандартный формат — размеры авто; user —
явные width/height (landscape игнорируется, ориентация из соотношения сторон).

- DrawingService.SetSheetFormatAsync + RequireLayoutSheet
- PaperFormat (enum + Parse/ToKompas/FromKompas), SheetFormatResult
- DrawingValidation.ValidateFormatDimensions (user: >0; стандартный: размеры запрещены)
- 19 unit + 7 интеграционных тестов (всего 304 зелёных), сборка Release чистая

Спайк подтвердил: дефолт A4 portrait; стандартный формат пересчитывает W/H авто
(A3 landscape→420×297); user применяет width/height. Ревью спека pi/glm-5.1 + pi/kimi-k2.6
учтено (FromKompas для дружелюбного имени, запрет размеров у стандартного, sheetNumber>0,
landscape игнорируется для user).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 23:19:37 +03:00
parent adc9da37fa
commit 56ed2cb0cf
9 changed files with 470 additions and 0 deletions
@@ -0,0 +1,111 @@
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Drawings;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>Интеграция: формат и ориентация листа чертежа (API7 ILayoutSheet.Format / ISheetFormat).</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class DrawingSheetFormatTests : IntegrationTestBase
{
private readonly DocumentService _docs;
private readonly DrawingService _drawing;
public DrawingSheetFormatTests(KompasFixture fx) : base(fx)
{
_docs = new DocumentService(fx.Session, fx.Dispatcher);
_drawing = new DrawingService(fx.Session, fx.Dispatcher);
}
[Fact]
public async Task A3_landscape()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
var r = await _drawing.SetSheetFormatAsync(PaperFormat.A3, landscape: true, width: 0, height: 0);
Assert.Equal("A3", r.Format);
Assert.InRange(r.Width, 419.5, 420.5);
Assert.InRange(r.Height, 296.5, 297.5);
Assert.True(r.Landscape);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task A4_portrait()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
var r = await _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0);
Assert.Equal("A4", r.Format);
Assert.InRange(r.Width, 209.5, 210.5);
Assert.InRange(r.Height, 296.5, 297.5);
Assert.False(r.Landscape);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task User_format_with_dimensions()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
var r = await _drawing.SetSheetFormatAsync(PaperFormat.User, landscape: false, width: 500, height: 300);
Assert.Equal("User", r.Format);
Assert.InRange(r.Width, 499.5, 500.5);
Assert.InRange(r.Height, 299.5, 300.5);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task User_without_dimensions_throws()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() =>
_drawing.SetSheetFormatAsync(PaperFormat.User, landscape: false, width: 0, height: 0));
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Standard_with_dimensions_throws()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
await Assert.ThrowsAsync<ArgumentException>(() =>
_drawing.SetSheetFormatAsync(PaperFormat.A3, landscape: false, width: 400, height: 0));
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Nonexistent_sheet_throws()
{
await _docs.CreateAsync(KompasDocumentType.Drawing);
try
{
await Assert.ThrowsAsync<InvalidOperationException>(() =>
_drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0, sheetNumber: 99));
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Active_document_not_drawing_throws()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
await Assert.ThrowsAsync<InvalidOperationException>(() =>
_drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0));
}
finally { await _docs.CloseAsync(save: false); }
}
}