| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- using Domain.Entities.Stocks.ValueObject;
- using Infrastructure.StockData;
- namespace Application.Tests;
- [TestClass]
- public sealed class KrxWarrantParserTests
- {
- [TestMethod]
- public void ParseDaily_SubscriptionWarrant_MapsFields_FromSampleJson()
- {
- // KRX OpenAPI(sw_bydd_trd) 실검증 샘플 — ISU_CD 8자리 영숫자, EXER_PRC/EXST_* 행사정보, TARSTK_* 대상주식, FLUC_RT 소수 %
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20250102","MKT_NM":"KOSDAQ","ISU_CD":"1099621D","ISU_NM":"AP헬스케어 6WR","TDD_CLSPRC":"99","CMPPREVDD_PRC":"0","FLUC_RT":"0.00","TDD_OPNPRC":"100","TDD_HGPRC":"100","TDD_LWPRC":"98","ACC_TRDVOL":"4,037","ACC_TRDVAL":"397,282","MKTCAP":"1,685,106,027","LIST_SHRS":"17,021,273","EXER_PRC":"809","EXST_STRT_DD":"20230825","EXST_END_DD":"20260625","TARSTK_ISU_SRT_CD":"109960","TARSTK_ISU_NM":"AP헬스케어","TARSTK_ISU_PRSNT_PRC":"510"},
- {"BAS_DD":"20250102","MKT_NM":"KOSPI","ISU_CD":"0036221D","ISU_NM":"KG모빌리티 122WR","TDD_CLSPRC":"655","CMPPREVDD_PRC":"18","FLUC_RT":"2.83","TDD_OPNPRC":"728","TDD_HGPRC":"728","TDD_LWPRC":"650","ACC_TRDVOL":"15,563","ACC_TRDVAL":"10,411,492","MKTCAP":"11,719,775,485","LIST_SHRS":"17,892,787","EXER_PRC":"6,729","EXST_STRT_DD":"20240105","EXST_END_DD":"20281105","TARSTK_ISU_SRT_CD":"003620","TARSTK_ISU_NM":"KG모빌리티","TARSTK_ISU_PRSNT_PRC":"3,710"}
- ]}
- """;
- var rows = KrxWarrantParser.ParseDaily(json, WarrantType.SubscriptionWarrant);
- Assert.AreEqual(2, rows.Count);
- var w = rows[0];
- Assert.AreEqual(WarrantType.SubscriptionWarrant, w.WarrantType, "유형은 호출 인자로 결정");
- Assert.AreEqual("1099621D", w.Code, "8자리 영숫자 코드는 그대로 유지");
- Assert.AreEqual("AP헬스케어 6WR", w.Name);
- Assert.AreEqual(StockMarket.KOSDAQ, w.Market, "MKT_NM → Market");
- Assert.AreEqual(new DateOnly(2025, 1, 2), w.TradeDate);
- Assert.AreEqual(99m, w.Close);
- Assert.AreEqual(100m, w.Open);
- Assert.AreEqual(98m, w.Low);
- Assert.AreEqual(0m, w.ChangeAmount);
- Assert.AreEqual(0.00m, w.ChangeRate, "FLUC_RT 소수 % 그대로");
- Assert.AreEqual(4037L, w.Volume, "거래량 콤마 제거");
- Assert.AreEqual(397282L, w.TradeValue, "거래대금 콤마 제거");
- Assert.AreEqual(1685106027L, w.MarketCap);
- Assert.AreEqual(17021273L, w.ListedShares);
- Assert.AreEqual("109960", w.TargetStockCode, "TARSTK_ISU_SRT_CD → 대상주식 코드");
- Assert.AreEqual("AP헬스케어", w.TargetStockName);
- Assert.AreEqual(510m, w.TargetStockPrice, "TARSTK_ISU_PRSNT_PRC → 대상주식 현재가");
- Assert.AreEqual(809m, w.ExercisePrice, "EXER_PRC → 행사가");
- Assert.AreEqual(new DateOnly(2023, 8, 25), w.ExerciseStartDate, "EXST_STRT_DD → 행사 시작일");
- Assert.AreEqual(new DateOnly(2026, 6, 25), w.ExerciseEndDate, "EXST_END_DD → 행사 종료일");
- Assert.IsNull(w.IssuePrice, "증권은 발행가 없음");
- Assert.IsNull(w.DelistDate, "증권은 상장폐지일 없음");
- Assert.AreEqual(StockMarket.KOSPI, rows[1].Market, "두 번째 행 MKT_NM=KOSPI");
- Assert.AreEqual(6729m, rows[1].ExercisePrice, "행사가 콤마 제거");
- }
- [TestMethod]
- public void ParseDaily_SubscriptionRight_MapsIssuePriceAndDelistDate()
- {
- // KRX OpenAPI(sr_bydd_trd) 실검증 샘플 — ISU_PRC(발행가)/DELIST_DD(상장폐지일), 행사정보 없음. FLUC_RT 음수.
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20240628","MKT_NM":"KOSDAQ","ISU_CD":"1013601E","ISU_NM":"에코앤드림 14R","TDD_CLSPRC":"16,450","CMPPREVDD_PRC":"2","FLUC_RT":"-2.26","TDD_OPNPRC":"16,820","TDD_HGPRC":"16,920","TDD_LWPRC":"16,290","ACC_TRDVOL":"148,924","ACC_TRDVAL":"2,466,653,620","MKTCAP":"55,771,981,300","LIST_SHRS":"3,390,394","ISU_PRC":"30,150","DELIST_DD":"20240702","TARSTK_ISU_SRT_CD":"101360","TARSTK_ISU_NM":"에코앤드림","TARSTK_ISU_PRSNT_PRC":"52,900"}
- ]}
- """;
- var rows = KrxWarrantParser.ParseDaily(json, WarrantType.SubscriptionRight);
- Assert.AreEqual(1, rows.Count);
- var r = rows[0];
- Assert.AreEqual(WarrantType.SubscriptionRight, r.WarrantType);
- Assert.AreEqual("1013601E", r.Code);
- Assert.AreEqual("에코앤드림 14R", r.Name);
- Assert.AreEqual(StockMarket.KOSDAQ, r.Market);
- Assert.AreEqual(16450m, r.Close, "종가 콤마 제거");
- Assert.AreEqual(-2.26m, r.ChangeRate, "FLUC_RT 음수 소수 %");
- Assert.AreEqual(148924L, r.Volume);
- Assert.AreEqual(2466653620L, r.TradeValue);
- Assert.AreEqual(30150m, r.IssuePrice, "ISU_PRC → 발행가");
- Assert.AreEqual(new DateOnly(2024, 7, 2), r.DelistDate, "DELIST_DD → 상장폐지일");
- Assert.AreEqual("101360", r.TargetStockCode);
- Assert.AreEqual(52900m, r.TargetStockPrice, "대상주식 현재가 콤마 제거");
- Assert.IsNull(r.ExercisePrice, "증서는 행사가 없음");
- Assert.IsNull(r.ExerciseStartDate, "증서는 행사기간 없음");
- Assert.IsNull(r.ExerciseEndDate);
- }
- [TestMethod]
- public void ParseDaily_MissingOptionalValues_AreNull()
- {
- // 대상주식/행사가 결측치("-" 또는 "") → null, 코드 "-" 은 행 skip
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20250102","MKT_NM":"KOSPI","ISU_CD":"9999991D","ISU_NM":"테스트 1WR","TDD_CLSPRC":"100","CMPPREVDD_PRC":"0","FLUC_RT":"0.00","TDD_OPNPRC":"100","TDD_HGPRC":"100","TDD_LWPRC":"100","ACC_TRDVOL":"0","ACC_TRDVAL":"0","MKTCAP":"-","LIST_SHRS":"-","EXER_PRC":"-","EXST_STRT_DD":"","EXST_END_DD":"","TARSTK_ISU_SRT_CD":"-","TARSTK_ISU_NM":"-","TARSTK_ISU_PRSNT_PRC":"-"}
- ]}
- """;
- var rows = KrxWarrantParser.ParseDaily(json, WarrantType.SubscriptionWarrant);
- Assert.AreEqual(1, rows.Count);
- var w = rows[0];
- Assert.IsNull(w.MarketCap, "\"-\" 시가총액은 null");
- Assert.IsNull(w.ListedShares, "\"-\" 상장증권수는 null");
- Assert.IsNull(w.ExercisePrice, "\"-\" 행사가는 null");
- Assert.IsNull(w.ExerciseStartDate, "빈 행사 시작일은 null");
- Assert.IsNull(w.ExerciseEndDate);
- Assert.IsNull(w.TargetStockCode, "\"-\" 대상주식 코드는 null");
- Assert.IsNull(w.TargetStockName);
- Assert.IsNull(w.TargetStockPrice);
- }
- [TestMethod]
- public void ParseDaily_EmptyOrMissingBlock_ReturnsEmpty()
- {
- // 증서(sr)는 대부분 영업일에 0건이 정상 — 빈 배열 안전 처리
- Assert.AreEqual(0, KrxWarrantParser.ParseDaily("""{"OutBlock_1":[]}""", WarrantType.SubscriptionRight).Count);
- // 인증 실패 등 OutBlock_1 노드 자체가 없는 응답도 안전하게 0건
- Assert.AreEqual(0, KrxWarrantParser.ParseDaily("""{"respMsg":"Unauthorized API Call","respCode":"401"}""", WarrantType.SubscriptionWarrant).Count);
- // 존재하지 않는 경로의 404 바디도 0건
- Assert.AreEqual(0, KrxWarrantParser.ParseDaily("""{"respMsg":"API referenced by the path does not exist.","respCode":"404"}""", WarrantType.SubscriptionWarrant).Count);
- }
- }
|