using Infrastructure.StockData; namespace Application.Tests; [TestClass] public sealed class DartDisclosureParserTests { [TestMethod] public void Parse_Success_MapsAllFieldsAndMeta() { // OpenDART list.json 실검증 shape — status "000", 상장(stock_code 6자리) 항목 const string json = """ {"status":"000","message":"정상","page_no":1,"page_count":100,"total_count":1178,"total_page":12, "list":[ {"corp_code":"00126380","corp_name":"삼성전자","stock_code":"005930","corp_cls":"Y","report_nm":"주요사항보고서(자기주식취득결정)","rcept_no":"20250103000123","flr_nm":"삼성전자","rcept_dt":"20250103","rm":""} ]} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual("000", result.Status); Assert.AreEqual("정상", result.Message); Assert.AreEqual(1, result.PageNo); Assert.AreEqual(12, result.TotalPage); Assert.AreEqual(1178, result.TotalCount); Assert.AreEqual(1, result.Rows.Count); var d = result.Rows[0]; Assert.AreEqual("20250103000123", d.RceptNo, "접수번호 14자리"); Assert.AreEqual("00126380", d.CorpCode, "고유번호 8자리"); Assert.AreEqual("삼성전자", d.CorpName); Assert.AreEqual("005930", d.StockCode, "상장 종목코드 6자리"); Assert.AreEqual("Y", d.CorpCls, "유가증권시장"); Assert.AreEqual("주요사항보고서(자기주식취득결정)", d.ReportNm); Assert.AreEqual("삼성전자", d.FlrNm); Assert.AreEqual(new DateOnly(2025, 1, 3), d.RceptDt, "rcept_dt YYYYMMDD → DateOnly"); Assert.IsNull(d.Rm, "빈 rm 은 null"); } [TestMethod] public void Parse_EmptyStockCode_BecomesNull() { // 비상장(자산운용 등) — stock_code "" → null, corp_cls "E"(기타), rm "정"(정정) const string json = """ {"status":"000","message":"정상","page_no":1,"page_count":100,"total_count":1,"total_page":1, "list":[ {"corp_code":"00380942","corp_name":"카디안자산운용","stock_code":"","corp_cls":"E","report_nm":"[기재정정]일괄신고서(집합투자증권-신탁형)","rcept_no":"20250103000294","flr_nm":"카디안자산운용","rcept_dt":"20250103","rm":"정"} ]} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual(1, result.Rows.Count); var d = result.Rows[0]; Assert.IsNull(d.StockCode, "비상장 stock_code \"\" 는 null"); Assert.AreEqual("E", d.CorpCls); Assert.AreEqual("정", d.Rm, "비고(rm) 유지"); } [TestMethod] public void Parse_Status013_NoData_ReturnsEmptyRows() { // 013 = 조회된 데이터 없음 — list 노드 없이 status/message 만 const string json = """ {"status":"013","message":"조회된 데이터가 없습니다."} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual("013", result.Status); Assert.AreEqual(0, result.Rows.Count, "013 은 빈 목록"); } [TestMethod] public void Parse_KeyError_Status020_ReturnsEmptyRows() { // 020 = 등록되지 않은 키 등 오류 — status != "000" 이면 rows 비움 const string json = """ {"status":"020","message":"등록되지 않은 키입니다."} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual("020", result.Status); Assert.AreEqual(0, result.Rows.Count); } [TestMethod] public void Parse_MultipleRows_DateParsing() { // 여러 행 — 각기 다른 접수일 파싱 확인 const string json = """ {"status":"000","message":"정상","page_no":1,"page_count":100,"total_count":2,"total_page":1, "list":[ {"corp_code":"00111111","corp_name":"에이","stock_code":"111111","corp_cls":"K","report_nm":"분기보고서","rcept_no":"20250102000001","flr_nm":"에이","rcept_dt":"20250102","rm":""}, {"corp_code":"00222222","corp_name":"비","stock_code":"222222","corp_cls":"N","report_nm":"사업보고서","rcept_no":"20250103000002","flr_nm":"비","rcept_dt":"20250103","rm":"첨부추가"} ]} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual(2, result.Rows.Count); Assert.AreEqual(new DateOnly(2025, 1, 2), result.Rows[0].RceptDt); Assert.AreEqual("K", result.Rows[0].CorpCls, "코스닥"); Assert.AreEqual(new DateOnly(2025, 1, 3), result.Rows[1].RceptDt); Assert.AreEqual("N", result.Rows[1].CorpCls, "코넥스"); Assert.AreEqual("첨부추가", result.Rows[1].Rm); } [TestMethod] public void Parse_MissingRequiredField_RowSkipped() { // 필수(rcept_no/corp_code/report_nm/rcept_dt) 결측 행은 건너뜀 — 방어 const string json = """ {"status":"000","message":"정상","page_no":1,"page_count":100,"total_count":2,"total_page":1, "list":[ {"corp_code":"00333333","corp_name":"씨","stock_code":"333333","corp_cls":"Y","report_nm":"","rcept_no":"20250103000003","flr_nm":"씨","rcept_dt":"20250103","rm":""}, {"corp_code":"00444444","corp_name":"디","stock_code":"444444","corp_cls":"Y","report_nm":"정기보고서","rcept_no":"20250103000004","flr_nm":"디","rcept_dt":"20250103","rm":""} ]} """; var result = DartDisclosureParser.Parse(json); Assert.AreEqual(1, result.Rows.Count, "report_nm 빈 행은 skip"); Assert.AreEqual("20250103000004", result.Rows[0].RceptNo); } }