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.
61 lines
2.4 KiB
C#
61 lines
2.4 KiB
C#
using Kompas.Mcp.Core.Startup;
|
|
|
|
namespace Kompas.Mcp.Tests;
|
|
|
|
/// <summary>
|
|
/// Текст ошибки инструмента. SDK показывает клиенту сообщение только у McpException, поэтому
|
|
/// причину собирает фильтр — и она обязана называть инструмент и суть, а не тип исключения.
|
|
/// </summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class ToolErrorTextTests
|
|
{
|
|
[Fact]
|
|
public void Message_names_the_tool_and_the_reason()
|
|
{
|
|
var text = ToolErrorText.Describe("extrude", new InvalidOperationException("Эскиз id=7 уже закрыт."));
|
|
|
|
Assert.Contains("extrude", text, StringComparison.Ordinal);
|
|
Assert.Contains("Эскиз id=7 уже закрыт.", text, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Inner_exception_is_appended_as_the_underlying_cause()
|
|
{
|
|
var inner = new InvalidOperationException("ksTextEx вернул 0.");
|
|
var outer = new InvalidOperationException("Примитив [0] (text) не построен.", inner);
|
|
|
|
var text = ToolErrorText.Describe("sketch_add", outer);
|
|
|
|
Assert.Contains("Примитив [0] (text) не построен.", text, StringComparison.Ordinal);
|
|
Assert.Contains("ksTextEx вернул 0.", text, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Single_wrapped_aggregate_is_unwrapped_to_the_real_cause()
|
|
{
|
|
var aggregate = new AggregateException(new KeyNotFoundException("Эскиз с id=42 не найден."));
|
|
|
|
var text = ToolErrorText.Describe("extrude", aggregate);
|
|
|
|
Assert.Contains("Эскиз с id=42 не найден.", text, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("One or more errors", text, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Empty_message_falls_back_to_the_exception_type()
|
|
{
|
|
var text = ToolErrorText.Describe("hole", new TimeoutException(""));
|
|
|
|
Assert.Contains("TimeoutException", text, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Missing_tool_name_still_yields_a_readable_message()
|
|
{
|
|
var text = ToolErrorText.Describe(null, new ArgumentException("Радиус должен быть > 0."));
|
|
|
|
Assert.Contains("Радиус должен быть > 0.", text, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("«»", text, StringComparison.Ordinal);
|
|
}
|
|
}
|