using SheetMe.Core.Catalog; namespace SheetMe.Core.Tests; /// 인스펙터 속성 스키마(ControlRegistry) 불변식 테스트. [TestClass] public sealed class ControlRegistryTests { /// /// Choice 편집기의 Default 는 반드시 자기 Choices 안에 있어야 한다. /// 어긋나면 ComboBox 가 값을 null 로 코어스해 되쓰면서 속성을 삭제한다. /// [TestMethod] public void ChoiceDefaults_AreWithinTheirOwnChoices() { foreach (var descriptor in ControlRegistry.All) { foreach (var def in descriptor.Properties.Where(p => p.Editor == PropEditorKind.Choice && p.Default is not null)) { Assert.IsNotNull(def.Choices, $"{descriptor.Type}.{def.Key}: Default 가 있는데 Choices 가 없습니다."); CollectionAssert.Contains(def.Choices!, def.Default, $"{descriptor.Type}.{def.Key}: Default('{def.Default}')가 Choices 에 없습니다."); } } } /// Choice 가 아닌 편집기에는 선택지 개념이 없다 — Choices 를 달아두면 죽은 설정이 된다. [TestMethod] public void NonChoiceEditors_HaveNoChoices() { foreach (var descriptor in ControlRegistry.All) { foreach (var def in descriptor.Properties.Where(p => p.Editor != PropEditorKind.Choice)) { Assert.IsNull(def.Choices, $"{descriptor.Type}.{def.Key}: {def.Editor} 편집기에 Choices 가 지정돼 있습니다."); } } } /// Toggle 기본값은 "True"/"False" 만 — IsOn 이 문자열 정확 비교라 다른 표기는 조용히 꺼짐이 된다. [TestMethod] public void ToggleDefaults_AreCanonicalBooleanText() { foreach (var descriptor in ControlRegistry.All) { foreach (var def in descriptor.Properties.Where(p => p.Editor == PropEditorKind.Toggle && p.Default is not null)) { Assert.IsTrue(def.Default is "True" or "False", $"{descriptor.Type}.{def.Key}: Toggle Default 는 \"True\"/\"False\" 여야 합니다(현재 '{def.Default}')."); } } } /// /// 운영 실사용 값이 Choices 에 전부 들어 있어야 한다(2026-08-11 활성 디자인 1,305건 census 근거). /// 목록에서 빠진 값을 가진 컨트롤은 인스펙터에서 선택하는 것만으로 속성이 삭제된다. /// [TestMethod] [DataRow("Label", "TextAlign", "TopLeft,TopCenter,MiddleLeft,MiddleCenter,MiddleRight,BottomLeft,BottomCenter,BottomRight")] [DataRow("TextBox", "TextAlign", "Center,Right")] [DataRow("TextBox", "BorderStyle", "None,FixedSingle")] [DataRow("Panel", "BorderStyle", "None,FixedSingle")] [DataRow("PictureBox", "SizeMode", "StretchImage,Zoom,AutoSize")] [DataRow("DateTimePicker", "Format", "Custom,Time,Short")] [DataRow("TextBox", "IsRequiredValue", "No,Yes")] public void Choices_CoverProductionValues(string type, string key, string csvValues) { var def = ControlRegistry.Find(type)?.Properties.FirstOrDefault(p => p.Key == key); Assert.IsNotNull(def, $"{type}.{key} 정의를 찾을 수 없습니다."); foreach (var value in csvValues.Split(',')) { CollectionAssert.Contains(def!.Choices!, value, $"{type}.{key}: 운영에서 쓰이는 값 '{value}'가 Choices 에 없습니다."); } } }