Files
kompas3d-mcp/tests/Kompas.Mcp.Tests/Integration/DocumentTests.cs
T
mikhail 4f4dd082d9 Документы и диагностика: имя детали, честное сохранение, причина ошибки
set_part_info задаёт наименование и обозначение детали: без него в дереве
стоит безликая «Деталь», и она же уходит в штамп чертежа и в спецификацию.
describe_model показывает наименование в шапке, а безымянную деталь помечает
явно. Имя файла этого не заменяет — это разные свойства.

document_save рапортовал «Сохранено», ничего не записав: SaveAs возвращает
void и молча отказывает, если файл с этим именем уже открыт в КОМПАС другим
документом. Теперь путь и наличие файла проверяются после записи, а Save
сверяет флаг Changed. Освободить занятое имя нечем не было — document_close
получил режим all.

Текст исключения доходил до клиента только у McpException, всё остальное
подменялось на «An error occurred invoking». То есть подсказки в наших
сообщениях агент не видел вовсе. Фильтр CallTool в Program.cs возвращает
IsError с реальной причиной (ToolErrorText разворачивает AggregateException
и склеивает вложенные причины). Там же — регистрация PrimitiveService.
2026-07-31 14:51:12 +03:00

83 lines
3.2 KiB
C#

using Kompas.Mcp.Core.Documents;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>Интеграция: жизненный цикл документов.</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class DocumentTests : IntegrationTestBase
{
private readonly DocumentService _docs;
public DocumentTests(KompasFixture fx) : base(fx)
=> _docs = new DocumentService(fx.Session, fx.Dispatcher);
[Fact]
public async Task Create_part_saveas_close_roundtrip()
{
var created = await _docs.CreateAsync(KompasDocumentType.Part);
Assert.Equal(KompasDocumentType.Part, created.Type);
var path = TestPaths.NewFile(".m3d");
await _docs.SaveAsAsync(path);
var active = await _docs.GetActiveAsync();
Assert.NotNull(active);
Assert.Equal(path, active!.PathName, ignoreCase: true);
var closed = await _docs.CloseAsync(save: false);
Assert.True(closed);
Assert.True(File.Exists(path));
}
[Fact]
public async Task SaveAs_over_a_name_held_by_another_open_document_fails_loudly()
{
// КОМПАС не перезаписывает файл, открытый другим документом, и НИЧЕГО об этом не сообщает:
// SaveAs возвращает void. Без проверки по факту агент получает ложное «Сохранено».
var path = TestPaths.NewFile(".m3d");
await _docs.CreateAsync(KompasDocumentType.Part);
await _docs.SaveAsAsync(path); // первый документ занял имя и остался открытым
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => _docs.SaveAsAsync(path));
Assert.Contains(path, ex.Message, StringComparison.OrdinalIgnoreCase);
}
finally
{
await _docs.CloseAsync(save: false);
await _docs.CloseAsync(save: false);
}
}
[Fact]
public async Task Part_name_and_marking_survive_the_write()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var written = await _docs.SetPartIdentityAsync("Значок декоративный", "ОМЕ.741124.001");
Assert.Equal("Значок декоративный", written.Name);
Assert.Equal("ОМЕ.741124.001", written.Marking);
// Незаданный параметр не затирает уже записанное.
var partial = await _docs.SetPartIdentityAsync(name: null, marking: "ОМЕ.741124.002");
Assert.Equal("Значок декоративный", partial.Name);
Assert.Equal("ОМЕ.741124.002", partial.Marking);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Create_fragment_reports_type()
{
await _docs.CreateAsync(KompasDocumentType.Fragment);
var active = await _docs.GetActiveAsync();
Assert.NotNull(active);
Assert.Equal(KompasDocumentType.Fragment, active!.Type);
await _docs.CloseAsync(save: false);
}
}