PAT_나이(bzDataInterface.vb:373 Case Else — 통합 대표행의 AgeMonth 파생 컬럼과 같은 식을 SQL 로: UDF_GETAGE_FROMRESNUM(복호화, 적용일시), dtCommonLib.vb:3725 확인. CGCH 분기·암호화 N 갈래 미이식), PAT_나이_세(:417 — 산정코드 24* 는 UDF_GETAGE(PatBthDay), 그 밖은 AgeCheck), PAT_성별_나이(:359 — "성별/나이". HIMCHAN_BP·BSYD 분기 미이식), PAT_나이_개월수(:430 — 월 경계 -1, 기존 MonthsSince 재사용), 개월·일 4종(:436-508 — 30일 나눗셈, 새 DaysSince 로 분해). AgeCheck(clsCommonLib.vb:665-974)를 ResidentNumber.AgeOf 로 이식 — 세기 접두 규칙(1·2→19, 3·4→20, 5·6→출생2자리<20 이면 20xx 아니면 19xx+월일 0101 강제, 7·8→서버 연도 2자리 비교, 그 외→18xx. REDCROSS· BSYD·BSGH 특례 미이식), 만나이(생일 당일 차감 없음 — 2024-09-25 이후 전 병원 규칙), 1세 이하는 고정 365일. 테스트 5건 — 기대값 하나가 틀려 있었다(출생 2자리 "20"은 <20 이 아니라 1920년으로 강제 — 구현이 맞고 판정을 고침). 개월·일 4종의 기준일은 레거시가 PC 시계(Now)라 서버 오늘로 바꿈(의도적 이탈 — 단말마다 값이 갈리면 안 된다). PAT_주민번호_Blind/SexTyp_Blind/SexTyp_BlindStar(:105-186 Case Else — 앞6 " - " 뒤 XXXXXXX / 성별1+XXXXXX / 성별1+******. SYBS 의 J-계열 서식 전체 노출 분기 미이식). 대조군 교체: PAT_나이가 이식되면서 ⑬·edit-smoke 의 "안 옮긴 태그" 대조군이 깨졌다(의도된 동작) — ETC_수술실간호사로 교체. ㊱ 신설: 나이 UDF 2종이 실값을 돌려준다(접두 없이 동작 확인). - dotnet test 342/342 (AgeOf 5건 추가) · --edit-smoke 실패 0 - --db-patient ①~㊱ 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
209 lines
9.8 KiB
C#
209 lines
9.8 KiB
C#
using SheetMe.Core.Catalog;
|
|
|
|
namespace SheetMe.Core.Tests;
|
|
|
|
/// <summary>
|
|
/// 주민번호 보정 고정.
|
|
///
|
|
/// 이 값이 틀리면 종이에 <b>다른 사람의 번호</b>가 찍힌다. 그리고 그건 그럴듯해 보여서
|
|
/// 아무도 의심하지 않는다 — 빈칸으로 나오는 고장보다 위험하다.
|
|
/// </summary>
|
|
[TestClass]
|
|
public sealed class ResidentNumberTests
|
|
{
|
|
#region Methods
|
|
[TestMethod]
|
|
public void 기관기호_병원은_앞_여섯자리를_생년월일로_바꾼다()
|
|
{
|
|
// 레거시 예시: 9750012203265 (앞자리가 날짜가 아니라 보장기관기호)
|
|
// 1998-03-04 생 → 앞 6자리가 980304 로 갈린다. 뒤 7자리는 그대로.
|
|
Assert.AreEqual("9803042203265",
|
|
ResidentNumber.Normalize("9750012203265", "19980304", string.Empty, "SRCH"));
|
|
Assert.AreEqual("9803042203265",
|
|
ResidentNumber.Normalize("9750012203265", "19980304", string.Empty, "JINJU"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 앞자리가_유효한_날짜여도_바꾼다()
|
|
{
|
|
// 원본의 If Not DateValidCheck(Substring(1,6)) 는 <b>항상 참</b>이다 —
|
|
// DateValidCheck 는 길이가 8·12·14·17 이 아니면 무조건 False 이고 6자리를 넘긴다.
|
|
// 즉 조건이 아무것도 걸러 내지 않는다. "고쳐서" 진짜 날짜 검사를 넣으면
|
|
// 여기서 레거시와 다른 번호가 나온다. 그 사실을 이 판정으로 못 박는다.
|
|
Assert.AreEqual("8801011234567",
|
|
ResidentNumber.Normalize("9001011234567", "19880101", string.Empty, "SRCH"),
|
|
"앞자리 900101 은 유효한 날짜지만 레거시는 그래도 갈아 끼운다");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 다른_병원은_기관기호_보정을_하지_않는다()
|
|
{
|
|
Assert.AreEqual("9750012203265",
|
|
ResidentNumber.Normalize("9750012203265", "19980304", string.Empty, "HANKOOK"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 생년월일이_없으면_기관기호_보정을_건너뛴다()
|
|
{
|
|
// 원본도 PatBthDay 가 비면 갈아 끼우지 않는다 — 바꿀 재료가 없다
|
|
Assert.AreEqual("9750012203265",
|
|
ResidentNumber.Normalize("9750012203265", string.Empty, string.Empty, "SRCH"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 외국인은_일곱번째_자리를_세기로_바꾼다()
|
|
{
|
|
// 0 → 19xx 면 6, 그 밖이면 8
|
|
Assert.AreEqual("8801016234567",
|
|
ResidentNumber.Normalize("8801010234567", "19880101", "USA", "HANKOOK"));
|
|
Assert.AreEqual("0501018234567",
|
|
ResidentNumber.Normalize("0501010234567", "20050101", "USA", "HANKOOK"));
|
|
|
|
// 9 → 19xx 면 5, 그 밖이면 7
|
|
Assert.AreEqual("8801015234567",
|
|
ResidentNumber.Normalize("8801019234567", "19880101", "USA", "HANKOOK"));
|
|
Assert.AreEqual("0501017234567",
|
|
ResidentNumber.Normalize("0501019234567", "20050101", "USA", "HANKOOK"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 국적코드가_없으면_외국인_보정을_하지_않는다()
|
|
{
|
|
// 이 조건이 빠지면 내국인의 7번째 자리까지 바꿔 버린다
|
|
Assert.AreEqual("8801010234567",
|
|
ResidentNumber.Normalize("8801010234567", "19880101", string.Empty, "HANKOOK"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 일곱번째_자리가_0_9_가_아니면_손대지_않는다()
|
|
{
|
|
foreach (var digit in new[] { '1', '2', '3', '4', '5', '6', '7', '8' })
|
|
{
|
|
var input = "880101" + digit + "234567";
|
|
Assert.AreEqual(input,
|
|
ResidentNumber.Normalize(input, "19880101", "USA", "HANKOOK"),
|
|
$"7번째 자리 {digit} 는 보정 대상이 아니다");
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 두_보정이_함께_걸린다()
|
|
{
|
|
// SRCH 에서 앞자리를 갈고, 그 결과의 7번째 자리가 0 이면 외국인 보정까지 이어진다.
|
|
// 순서가 뒤바뀌면 다른 값이 나온다 — 기관기호 보정이 7번째 자리를 새로 정하기 때문이다.
|
|
Assert.AreEqual("9803046203265",
|
|
ResidentNumber.Normalize("9750010203265", "19980304", "USA", "SRCH"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 열세자리가_안_되면_그대로_돌려준다()
|
|
{
|
|
// 원본은 Substring 에서 예외가 나고 Try 가 삼킨다 — 손대지 않는 것이 같은 결과다
|
|
Assert.AreEqual("880101", ResidentNumber.Normalize("880101", "19880101", "USA", "SRCH"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.Normalize(string.Empty, "19880101", "USA", "SRCH"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.Normalize(null, null, null, null));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 성별은_일곱번째_자리_홀짝이다()
|
|
{
|
|
Assert.AreEqual("M", ResidentNumber.SexOf("8801011234567"));
|
|
Assert.AreEqual("F", ResidentNumber.SexOf("8801012234567"));
|
|
Assert.AreEqual("M", ResidentNumber.SexOf("0501013234567"));
|
|
Assert.AreEqual("F", ResidentNumber.SexOf("0501014234567"));
|
|
// 외국인 자리(5~8)도 같은 규칙이다
|
|
Assert.AreEqual("M", ResidentNumber.SexOf("8801015234567"));
|
|
Assert.AreEqual("F", ResidentNumber.SexOf("8801016234567"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 성별을_만들_수_없으면_빈_값이다()
|
|
{
|
|
// 원본은 CLong 에서 예외가 나고 삼켜져 값이 빈다 — 추측해서 채우지 않는다
|
|
Assert.AreEqual(string.Empty, ResidentNumber.SexOf("880101"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.SexOf("880101X234567"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.SexOf(null));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 한글_성별은_남녀로_바꾼다()
|
|
{
|
|
Assert.AreEqual("남", ResidentNumber.SexKoreanOf("8801011234567"));
|
|
Assert.AreEqual("여", ResidentNumber.SexKoreanOf("8801012234567"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.SexKoreanOf("880101"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 개월수는_월_경계만_센다()
|
|
{
|
|
// VB DateDiff(Month, ...) 는 날짜를 보지 않는다 — 연차×12 + 월차, 거기서 1을 뺀다.
|
|
// 일수로 환산하면 레거시와 다른 수가 나온다.
|
|
// 2025-01 → 2025-12 는 월 경계 11, 거기서 1을 뺀 10 이다(기대값을 처음에 11로 잘못 적었다)
|
|
Assert.AreEqual("10", ResidentNumber.MonthsSince("20250101", "20251201"));
|
|
// 같은 달이면 -1 이 된다(레거시 그대로 — 음수도 그대로 찍힌다)
|
|
Assert.AreEqual("-1", ResidentNumber.MonthsSince("20260101", "20260101"));
|
|
// 날짜는 보지 않는다: 1일생과 말일생이 같은 값
|
|
Assert.AreEqual(ResidentNumber.MonthsSince("20250101", "20260101"),
|
|
ResidentNumber.MonthsSince("20250131", "20260101"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.MonthsSince("2025", "20260101"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 개월_일은_달력이_아니라_30일로_나눈다()
|
|
{
|
|
// 레거시가 days \ 30 · days Mod 30 이다. 달력으로 고치면 값이 달라진다.
|
|
Assert.AreEqual("0개월 10일", ResidentNumber.MonthsDaysSince("20260101", "20260111"));
|
|
Assert.AreEqual("1개월 1일", ResidentNumber.MonthsDaysSince("20260101", "20260201"));
|
|
Assert.AreEqual("12개월 5일", ResidentNumber.MonthsDaysSince("20250101", "20260101"));
|
|
Assert.AreEqual(string.Empty, ResidentNumber.MonthsDaysSince("2026", "20260101"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 하이픈은_양쪽_공백을_지킨다()
|
|
{
|
|
// 레거시가 " - " 다. 공백을 빼면 서식에서 폭이 달라진다
|
|
Assert.AreEqual("880101 - 1234567", ResidentNumber.WithDash("8801011234567"));
|
|
Assert.AreEqual("880101", ResidentNumber.WithDash("880101"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 만나이는_세기_접두를_7번째_자리로_정한다()
|
|
{
|
|
// 1·2 → 19xx, 3·4 → 20xx (AgeCheck, clsCommonLib.vb:686-700)
|
|
Assert.AreEqual(38L, ResidentNumber.AgeOf("8801011234567", "20260820", "20260820"));
|
|
Assert.AreEqual(6L, ResidentNumber.AgeOf("2001013234567", "20260820", "20260820"));
|
|
// 7·8 — 서버 오늘의 연도 2자리(26)보다 크면 19xx: 88 > 26 → 1988년생
|
|
Assert.AreEqual(38L, ResidentNumber.AgeOf("8801017234567", "20260820", "20260820"));
|
|
// 그 외(9) → 18xx
|
|
Assert.AreEqual(138L, ResidentNumber.AgeOf("8801019234567", "20260820", "20260820"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 만나이는_생일_전이면_하나_줄고_당일은_줄지_않는다()
|
|
{
|
|
Assert.AreEqual(37L, ResidentNumber.AgeOf("8812311234567", "20260820", "20260820"));
|
|
Assert.AreEqual(38L, ResidentNumber.AgeOf("8808201234567", "20260820", "20260820"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 한_살_이하는_고정_365일로_가른다()
|
|
{
|
|
// 총 일수차 < 365 → 0세, 이상 → 1세 (윤년 무시 — 레거시 고정 365)
|
|
Assert.AreEqual(0L, ResidentNumber.AgeOf("2510013234567", "20260820", "20260820"));
|
|
Assert.AreEqual(1L, ResidentNumber.AgeOf("2501013234567", "20260820", "20260820"));
|
|
Assert.AreEqual(0L, ResidentNumber.AgeOf("", "20260820", "20260820"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 외국인_5_6은_출생_2자리로_갈린다()
|
|
{
|
|
// 출생 2자리 < 20 → 20xx 그대로, >= 20 → 19xx + 월일 0101 강제.
|
|
// 경계 주의: "20" 은 < 20 이 아니라서 2020년생이 아니라 1920-01-01 로 강제된다(레거시 그대로)
|
|
Assert.AreEqual(20L, ResidentNumber.AgeOf("0601015234567", "20260820", "20260820"));
|
|
Assert.AreEqual(106L, ResidentNumber.AgeOf("2001015234567", "20260820", "20260820"));
|
|
// 88 >= 20 → 1988-01-01 로 강제 → 만 38세
|
|
Assert.AreEqual(38L, ResidentNumber.AgeOf("8812315234567", "20260820", "20260820"));
|
|
}
|
|
#endregion
|
|
}
|