MaskedTextBox 를 레거시와 동일하게 프롬프트 문자로 표시
4단계 육안 대조에서 발견한 차이. 마스크 패턴을 그대로 그려서 값이 이미 입력된 것처럼 보였다.
레거시 ___년 __월 __일 (프롬프트 문자)
SheetMe 0000년 90월 90일 (마스크 패턴 원문)
저장 데이터와는 무관한 표시 문제지만, 운영 실사용이 MaskedTextBox 475개 / Mask 보유 460개라
자주 눈에 띈다.
LegacyMask.ToPromptDisplay 신설(Core, 순수 함수) — 입력 자리 지시자는 프롬프트 문자로,
리터럴은 그대로, 이스케이프(\)는 다음 문자를 리터럴로, 대소문자 변환자(< > |)는 표시하지 않는다.
활성 디자인 전수 census 로 지원 범위를 정했다: 등장 지시자는 0(2,675) 9(687) #(12) 와
이스케이프 \(2) 뿐이고 문자류(L ? & C A a)와 변환자는 쓰이지 않는다. PromptChar 속성을 가진
컨트롤은 0개라 전부 기본값 '_' 이지만, 속성이 있으면 반영하도록 구현했다.
구분자 . , : / $ 는 WinForms 가 문화권 구분자로 치환하지만 원문 그대로 둔다 —
운영 마스크는 보이는 대로 쓰이고 레거시 화면도 그렇게 나온다.
MaskDisplay 는 표시 전용 파생 속성이라 PropBag 에 아무것도 쓰지 않는다(왕복 무손실 유지).
인스펙터 편집용 Mask 원문 속성은 그대로 둔다.
검증: 테스트 98/98(마스크 28건 추가 — 운영 실사용 마스크 10종, 이스케이프, 문자류 지시자,
변환자, PromptChar 지정, 끝 백슬래시, 표시 길이 보존). S481 재렌더로 레거시와 동일 표시 확인.
edit-smoke 실패 0, 왕복 1,271건 diff 0/예외 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d1e488625e
commit
a749e18e7b
@@ -0,0 +1,95 @@
|
||||
using SheetMe.Core.Serialization;
|
||||
|
||||
namespace SheetMe.Core.Tests;
|
||||
|
||||
/// <summary>WinForms MaskedTextBox 마스크 → 표시 문자열 변환 테스트.</summary>
|
||||
[TestClass]
|
||||
public sealed class LegacyMaskTests
|
||||
{
|
||||
/// <summary>운영 실사용 마스크 상위 항목 — 2026-08-11 활성 디자인 전수 census 근거</summary>
|
||||
[TestMethod]
|
||||
[DataRow("0000년 90월 90일", "____년 __월 __일")] // 198건 — 최다
|
||||
[DataRow("0000-00-00", "____-__-__")] // 51건
|
||||
[DataRow("90:90", "__:__")] // 36건
|
||||
[DataRow("90시90분", "__시__분")] // 22건
|
||||
[DataRow("0000.00.00.", "____.__.__.")] // 21건
|
||||
[DataRow("90월 90일", "__월 __일")] // 15건 — 연속 공백 보존
|
||||
[DataRow("000-9000-0000", "___-____-____")] // 6건
|
||||
[DataRow("( 90 : 00 )", "( __ : __ )")]
|
||||
[DataRow("####/##/## ##:##", "____/__/__ __:__")] // # 지시자
|
||||
[DataRow("0000년 90월 90일 90시 90분", "____년 __월 __일 __시 __분")]
|
||||
public void ToPromptDisplay_ProductionMasks(string mask, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, LegacyMask.ToPromptDisplay(mask));
|
||||
}
|
||||
|
||||
/// <summary>이스케이프 — 백슬래시 다음 문자는 리터럴(운영에 '2\000년' 형태가 존재)</summary>
|
||||
[TestMethod]
|
||||
[DataRow(@"2\000년", "20__년")]
|
||||
[DataRow(@"2\000년 90월 90일", "20__년 __월 __일")]
|
||||
[DataRow(@"\9\0", "90")]
|
||||
public void ToPromptDisplay_EscapedLiterals(string mask, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, LegacyMask.ToPromptDisplay(mask));
|
||||
}
|
||||
|
||||
/// <summary>문자·영숫자 지시자도 한 자리를 소비한다(운영 미사용이나 규약상 지원)</summary>
|
||||
[TestMethod]
|
||||
[DataRow("LLL", "___")]
|
||||
[DataRow("???", "___")]
|
||||
[DataRow("AAA", "___")]
|
||||
[DataRow("aaa", "___")]
|
||||
[DataRow("&&&", "___")]
|
||||
[DataRow("CCC", "___")]
|
||||
public void ToPromptDisplay_CharacterDirectives(string mask, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, LegacyMask.ToPromptDisplay(mask));
|
||||
}
|
||||
|
||||
/// <summary>대소문자 변환자는 자리를 차지하지 않고 표시에도 나오지 않는다</summary>
|
||||
[TestMethod]
|
||||
[DataRow(">LLL", "___")]
|
||||
[DataRow("<aaa", "___")]
|
||||
[DataRow(">LL|LL", "____")]
|
||||
public void ToPromptDisplay_CaseModifiersAreInvisible(string mask, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, LegacyMask.ToPromptDisplay(mask));
|
||||
}
|
||||
|
||||
/// <summary>PromptChar 지정 — 운영엔 0건이지만 속성이 있으면 반영해야 한다</summary>
|
||||
[TestMethod]
|
||||
public void ToPromptDisplay_HonorsPromptChar()
|
||||
{
|
||||
Assert.AreEqual("0000년 00월 00일", LegacyMask.ToPromptDisplay("0000년 90월 90일", '0'));
|
||||
Assert.AreEqual("####-##-##", LegacyMask.ToPromptDisplay("0000-00-00", '#'));
|
||||
Assert.AreEqual(" - - ", LegacyMask.ToPromptDisplay("0000-00-00", ' '));
|
||||
}
|
||||
|
||||
/// <summary>빈 마스크·null 안전</summary>
|
||||
[TestMethod]
|
||||
public void ToPromptDisplay_EmptyInputs()
|
||||
{
|
||||
Assert.AreEqual(string.Empty, LegacyMask.ToPromptDisplay(null));
|
||||
Assert.AreEqual(string.Empty, LegacyMask.ToPromptDisplay(string.Empty));
|
||||
}
|
||||
|
||||
/// <summary>끝에 홀로 남은 백슬래시는 리터럴로 — 인덱스 초과로 죽지 않아야 한다</summary>
|
||||
[TestMethod]
|
||||
public void ToPromptDisplay_TrailingBackslashIsLiteral()
|
||||
{
|
||||
Assert.AreEqual(@"__\", LegacyMask.ToPromptDisplay(@"00\"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 표시 길이는 마스크의 시각 길이와 같아야 한다(변환자·이스케이프 제외).
|
||||
/// 길이가 달라지면 캔버스에서 필드 폭이 어긋나 보인다.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[DataRow("0000년 90월 90일")]
|
||||
[DataRow("0000.00.00.")]
|
||||
[DataRow("( 90 : 00 )")]
|
||||
public void ToPromptDisplay_PreservesVisibleLength(string mask)
|
||||
{
|
||||
Assert.AreEqual(mask.Length, LegacyMask.ToPromptDisplay(mask).Length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user