Files
kompas3d-mcp/tests/Kompas.Mcp.Tests/EdgeFilterTests.cs
T
mikhail e127cebb49 Итерация 1: удаление операции, выравнивание надписи, отбор рёбер
По протоколу регресс-прогона (46 вызовов против 90 в прошлом):

feature_delete — ksDocument3D.DeleteObject + RebuildDocument, зависимые уходят каскадом.
Неудачная проба больше не требует пересобирать документ (у субагента таких кругов было три).

align/vAlign у примитива text: сервер строит, замеряет и сдвигает надпись сам. Ловушка,
стоившая двух заходов: ksMoveObj и ksDeleteObj по ссылке от ksConvertTextToCurve возвращают
успех и не делают ничего — двигать надо по ссылке ТЕКСТА, а габарит после сдвига считать
арифметикой (по текстовой ссылке рамка идёт по ячейке). Поймано тестом, который сверяет
заявленный габарит с выдавленной геометрией.

list_edges: отбор по типу и координатному окну + концы рёбер в списке. Так адресуется
нижний контур под фаску, который иначе не выбрать: индексов не отфильтровать, точек не угадать.

Навык: wf меряет пропорцию крупно (1.0→1.25 = +29 %), но квантован ступенями — точную ширину
набирают height; прирост каймы указан НА СТОРОНУ и зависит от начертания, а не от шрифта;
добавлено предупреждение, что primitive(subtract) режет наехавшие буквы.
2026-07-31 17:11:53 +03:00

64 lines
2.4 KiB
C#

using Kompas.Mcp.Core.Query;
namespace Kompas.Mcp.Tests;
/// <summary>
/// Отбор рёбер. На теле с надписью их сотни: без окна нельзя адресовать «весь нижний контур»,
/// а полный список бесполезен по объёму ответа.
/// </summary>
[Trait("Category", "Unit")]
public sealed class EdgeFilterTests
{
private static EdgeInfo Edge(int index, string type,
(double, double, double)? start, (double, double, double)? end, double length = 10)
=> new() { Index = index, Type = type, Length = length, Start = start, End = end };
[Fact]
public void Empty_filter_takes_everything()
{
var filter = new EdgeFilter();
Assert.True(filter.IsEmpty);
Assert.True(filter.Matches(Edge(0, "line", (0, 0, 0), (10, 0, 0))));
Assert.True(filter.Matches(Edge(1, "nurbs", null, null)));
}
[Fact]
public void Window_keeps_only_edges_with_both_ends_inside()
{
var bottom = new EdgeFilter { MinZ = -0.01, MaxZ = 0.01 };
Assert.True(bottom.Matches(Edge(0, "line", (0, 0, 0), (10, 0, 0)))); // весь низ
Assert.False(bottom.Matches(Edge(1, "line", (0, 0, 0), (0, 0, 3)))); // вертикальное
Assert.False(bottom.Matches(Edge(2, "line", (0, 0, 3), (10, 0, 3)))); // весь верх
}
[Fact]
public void Edge_without_vertices_cannot_satisfy_a_window()
{
var filter = new EdgeFilter { MinZ = 0, MaxZ = 0 };
Assert.False(filter.Matches(Edge(0, "nurbs", null, null)));
}
[Fact]
public void Type_filter_is_case_insensitive_and_independent_of_the_window()
{
var lines = new EdgeFilter { Type = " LINE " };
Assert.False(lines.IsEmpty);
Assert.True(lines.Matches(Edge(0, "line", (0, 0, 0), (10, 0, 0))));
Assert.False(lines.Matches(Edge(1, "circle", (0, 0, 0), (0, 0, 0))));
Assert.True(lines.Matches(Edge(2, "line", null, null))); // без окна координаты не нужны
}
[Fact]
public void Window_and_type_are_combined()
{
var filter = new EdgeFilter { Type = "line", MinZ = -0.01, MaxZ = 0.01 };
Assert.True(filter.Matches(Edge(0, "line", (0, 0, 0), (10, 0, 0))));
Assert.False(filter.Matches(Edge(1, "arc", (0, 0, 0), (10, 0, 0))));
Assert.False(filter.Matches(Edge(2, "line", (0, 0, 0), (10, 0, 3))));
}
}