using Kompas.Mcp.Core.Query; namespace Kompas.Mcp.Tests; /// Юнит-тесты чистого рендера/группировки структурного «паспорта». COM не требуется. [Trait("Category", "Unit")] public sealed class InspectionTextTests { // ── Детект пустой модели по габариту ────────────────────────────────── [Fact] public void IsEmptyGabarit_true_for_sentinel() => Assert.True(InspectionText.IsEmptyGabarit(double.MaxValue, double.MaxValue, double.MaxValue)); [Fact] public void IsEmptyGabarit_true_for_all_zero() => Assert.True(InspectionText.IsEmptyGabarit(0, 0, 0)); [Fact] public void IsEmptyGabarit_false_for_real_part() => Assert.False(InspectionText.IsEmptyGabarit(40, 20, 15)); // ── Группировка типов ──────────────────────────────────────────────── [Fact] public void GroupTypes_orders_by_count_desc() { var s = InspectionText.GroupTypes(new[] { "plane", "cylinder", "plane", "plane", "cylinder" }); Assert.Equal("3 plane, 2 cylinder", s); } [Fact] public void GroupTypes_empty_returns_dash() => Assert.Equal("—", InspectionText.GroupTypes(Array.Empty())); // ── Детект импорта без истории ─────────────────────────────────────── private static FeatureInfo Feat(int i, string name, string kind) => new() { Index = i, Name = name, Kind = kind }; [Fact] public void IsImported_true_for_bare_origin_and_body() { var fs = new[] { Feat(0, "Начало координат", "origin"), Feat(1, "Body1", "other") }; Assert.True(InspectionText.IsImported(fs, bodyCount: 1)); } [Fact] public void IsImported_false_when_tree_has_edit_history() { // Импорт, отредактированный move_face: origin + тело + 5 узлов-правок (>2) — это уже история. var fs = new[] { Feat(0, "Начало координат", "origin"), Feat(1, "Body1", "other"), Feat(2, "Смещенная плоскость:1", "other"), Feat(3, "Разрезать:1", "other"), Feat(4, "Переместить грани:1", "other"), Feat(5, "Булева операция:1", "other"), }; Assert.False(InspectionText.IsImported(fs, bodyCount: 1)); } [Fact] public void IsImported_false_for_native_part_with_operations() { var fs = new[] { Feat(0, "Начало координат", "origin"), Feat(1, "Эскиз:1", "sketch"), Feat(2, "Элемент выдавливания:1", "extrusion"), Feat(3, "Скругление:1", "fillet"), }; Assert.False(InspectionText.IsImported(fs, bodyCount: 1)); } [Fact] public void IsImported_false_without_body() => Assert.False(InspectionText.IsImported(new[] { Feat(0, "Начало координат", "origin") }, bodyCount: 0)); // ── Рендер: родная параметрическая деталь ──────────────────────────── [Fact] public void Render_native_part_shows_tree_with_params() { var d = new ModelDescription { Name = "demo", IsEmpty = false, Box = new BoundingBox { MinX = -20, MinY = -10, MinZ = 0, MaxX = 20, MaxY = 10, MaxZ = 15 }, Mass = new PartInfo { Volume = 11961, Mass = 0.094, Area = 3370, CenterX = 0, CenterY = 0, CenterZ = 7.5 }, Bodies = new[] { new BodyInfo { Index = 0, IsSolid = true, FaceCount = 7 } }, FaceTypes = new[] { "plane", "plane", "cylinder" }, EdgeTypes = new[] { "line", "line" }, Imported = false, Features = new[] { new FeatureInfo { Index = 0, Name = "Начало координат", Kind = "origin" }, new FeatureInfo { Index = 1, Name = "Эскиз:1", Kind = "sketch" }, new FeatureInfo { Index = 2, Name = "Элемент выдавливания:1", Kind = "extrusion", Detail = "глубина 15.00 мм" }, new FeatureInfo { Index = 3, Name = "Скругление:1", Kind = "fillet", Detail = "R3.00 мм" }, }, Variables = Array.Empty(), }; var text = InspectionText.Render(d); Assert.Contains("Документ: «demo»", text); Assert.Contains("Габарит (Д×Ш×В): 40.00 × 20.00 × 15.00 мм", text); Assert.Contains("Тела: 1", text); Assert.Contains("граней 3 (2 plane, 1 cylinder)", text); Assert.Contains("Дерево построения (4", text); Assert.Contains("«Элемент выдавливания:1» — глубина 15.00 мм", text); Assert.Contains("«Скругление:1» — R3.00 мм", text); Assert.Contains("Переменные: нет", text); } // ── Рендер: импортированная модель (флаг Imported) ─────────────────── [Fact] public void Render_imported_model_notes_no_history() { var d = new ModelDescription { Name = "top_spacer", IsEmpty = false, Box = new BoundingBox { MinX = 0, MinY = 0, MinZ = 0, MaxX = 18, MaxY = 8, MaxZ = 39 }, Mass = new PartInfo { Volume = 2463, Mass = 0.019, Area = 2053, CenterX = 0, CenterY = 0, CenterZ = 21 }, Bodies = new[] { new BodyInfo { Index = 0, IsSolid = true, FaceCount = 61 } }, FaceTypes = new[] { "plane", "cylinder" }, EdgeTypes = new[] { "line" }, Imported = true, Features = new[] { new FeatureInfo { Index = 0, Name = "Начало координат", Kind = "origin" }, new FeatureInfo { Index = 1, Name = "Body1", Kind = "body" }, }, Variables = Array.Empty(), }; var text = InspectionText.Render(d); Assert.Contains("импортирован", text.ToLowerInvariant()); Assert.DoesNotContain("Дерево построения (", text); // не показываем как параметрическое дерево } // ── Рендер: пустая модель ──────────────────────────────────────────── [Fact] public void Render_empty_model() { var d = new ModelDescription { Name = "empty", IsEmpty = true, Bodies = Array.Empty(), FaceTypes = Array.Empty(), EdgeTypes = Array.Empty(), Imported = false, Features = Array.Empty(), Variables = Array.Empty(), }; var text = InspectionText.Render(d); Assert.Contains("Модель пуста", text); } // ── Рендер переменных ──────────────────────────────────────────────── [Fact] public void Render_variables_listed_with_flags() { var d = new ModelDescription { Name = "p", IsEmpty = false, Box = new BoundingBox { MinX = 0, MinY = 0, MinZ = 0, MaxX = 1, MaxY = 1, MaxZ = 1 }, Mass = new PartInfo { Volume = 1, Mass = 1, Area = 6, CenterX = 0, CenterY = 0, CenterZ = 0 }, Bodies = new[] { new BodyInfo { Index = 0, IsSolid = true, FaceCount = 6 } }, FaceTypes = new[] { "plane" }, EdgeTypes = new[] { "line" }, Imported = false, Features = Array.Empty(), Variables = new[] { new VariableInfo { Name = "L", Expression = "80", Value = 80, External = true, Information = false }, new VariableInfo { Name = "v", Expression = "L/2", Value = 40, External = false, Information = true }, }, }; var text = InspectionText.Render(d); Assert.Contains("Переменные (2):", text); Assert.Contains("L = 80", text); Assert.Contains("[внешняя]", text); Assert.Contains("[инфо]", text); } }