using Kompas.Mcp.Core.Assemblies; namespace Kompas.Mcp.Tests; [Trait("Category", "Unit")] public sealed class AssemblyValidationTests { [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] public void NormalizeComponentPath_throws_on_empty(string? path) => Assert.Throws(() => AssemblyValidation.NormalizeComponentPath(path)); [Theory] [InlineData(@"C:\parts\bolt.step")] [InlineData(@"C:\parts\bolt.txt")] [InlineData(@"C:\parts\bolt")] public void NormalizeComponentPath_throws_on_wrong_extension(string path) => Assert.Throws(() => AssemblyValidation.NormalizeComponentPath(path)); [Theory] [InlineData(@"C:\parts\bolt.m3d", ".m3d")] [InlineData(@"C:\parts\frame.a3d", ".a3d")] [InlineData(@"C:\parts\bolt.M3D", ".m3d")] // регистр не важен [InlineData(" C:\\parts\\bolt.a3d ", ".a3d")] // пробелы обрезаются public void NormalizeComponentPath_accepts_m3d_and_a3d(string path, string expectedExt) { var result = AssemblyValidation.NormalizeComponentPath(path); Assert.True(Path.IsPathFullyQualified(result), "Должен вернуться абсолютный путь."); Assert.EndsWith(expectedExt, result, StringComparison.OrdinalIgnoreCase); } [Theory] [InlineData(double.NaN, 0, 0)] [InlineData(0, double.PositiveInfinity, 0)] [InlineData(0, 0, double.NegativeInfinity)] public void RequireFinitePosition_throws_on_non_finite(double x, double y, double z) => Assert.Throws(() => AssemblyValidation.RequireFinitePosition(x, y, z)); [Fact] public void RequireFinitePosition_accepts_finite() => Assert.Null(Record.Exception(() => AssemblyValidation.RequireFinitePosition(50, -10, 0))); // ── Сопряжения (Mates) ─────────────────────────────────────────────── [Theory] [InlineData("coincidence", MateType.Coincidence)] [InlineData("совпадение", MateType.Coincidence)] [InlineData("DISTANCE", MateType.Distance)] [InlineData(" расстояние ", MateType.Distance)] public void Mates_Parse_maps_known(string text, MateType expected) => Assert.Equal(expected, Mates.Parse(text)); [Theory] [InlineData("parallel")] // пока не поддержан [InlineData("сопряжение")] [InlineData("")] public void Mates_Parse_throws_on_unknown(string text) => Assert.Throws(() => Mates.Parse(text)); // Корректность ToConstraintType проверяется интеграционно (coincidence даёт прилегание, // distance — зазор), а не unit-ассертом: КОМПАС-enum встроен (EmbedInteropTypes) и не виден // тестовому проекту через границу сборки. [Theory] [InlineData(MateType.Distance, true)] [InlineData(MateType.Coincidence, false)] public void Mates_RequiresValue(MateType type, bool expected) => Assert.Equal(expected, Mates.RequiresValue(type)); [Fact] public void RequireMateValue_ignores_value_when_not_required() => Assert.Null(Record.Exception(() => AssemblyValidation.RequireMateValue(false, double.NaN))); [Theory] [InlineData(double.NaN)] [InlineData(double.PositiveInfinity)] [InlineData(-1)] [InlineData(0)] // нулевой зазор вырождается в coincidence → ошибка public void RequireMateValue_throws_on_bad_required_value(double value) => Assert.Throws(() => AssemblyValidation.RequireMateValue(true, value)); [Fact] public void RequireMateValue_accepts_positive_required_value() => Assert.Null(Record.Exception(() => AssemblyValidation.RequireMateValue(true, 30))); }