| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- using Application.Helpers;
- using Domain.Entities.Stocks.ValueObject;
- namespace Application.Tests;
- /// <summary>
- /// 종목마스터 상폐 sweep 시장별 가드 검증 — 한 시장만 빈/부분 응답일 때 그 시장 전체가 대량 상폐되지 않도록
- /// (0건 또는 활성 대비 80% 미만이면 해당 시장 상폐 보류) 하는 StockMasterDelist 순수 로직.
- /// </summary>
- [TestClass]
- public sealed class StockMasterDelistTests
- {
- [TestMethod]
- public void GetDelistableMarkets_NormalSnapshot_AllMarketsDelistable()
- {
- // 기대 행위: 세 시장 모두 정상 스냅샷이면 전부 상폐 sweep 허용 (기존 상폐 동작 유지).
- var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 950, [StockMarket.KOSDAQ] = 1700, [StockMarket.KONEX] = 120 };
- var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 953, [StockMarket.KOSDAQ] = 1705, [StockMarket.KONEX] = 121 };
- var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
- Assert.AreEqual(3, result.Count, "정상 스냅샷은 세 시장 모두 상폐 허용");
- }
- [TestMethod]
- public void GetDelistableMarkets_OneMarketEmptySnapshot_ThatMarketExcluded()
- {
- // 기대 행위: 한 시장(KOSDAQ)만 빈 응답이면 그 시장은 상폐 보류 — KOSDAQ ~1,700종목 대량 상폐 방지 (감사 결함 2 재현 시나리오).
- var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 950, [StockMarket.KOSDAQ] = 0, [StockMarket.KONEX] = 120 };
- var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 953, [StockMarket.KOSDAQ] = 1705, [StockMarket.KONEX] = 121 };
- var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
- Assert.AreEqual(2, result.Count);
- Assert.IsFalse(result.Contains(StockMarket.KOSDAQ), "빈 스냅샷 시장은 상폐 sweep 에서 제외");
- Assert.IsTrue(result.Contains(StockMarket.KOSPI), "정상 시장은 상폐 동작 유지");
- Assert.IsTrue(result.Contains(StockMarket.KONEX), "정상 시장은 상폐 동작 유지");
- }
- [TestMethod]
- public void GetDelistableMarkets_PartialSnapshotBelow80Percent_Excluded()
- {
- // 기대 행위: 스냅샷이 활성 종목수의 80% 미만이면 부분 응답으로 간주해 상폐 보류.
- var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 700, [StockMarket.KOSDAQ] = 1700 };
- var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 1000, [StockMarket.KOSDAQ] = 1705 };
- var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
- Assert.IsFalse(result.Contains(StockMarket.KOSPI), "활성 1000 대비 스냅샷 700(70%) → 보류");
- Assert.IsTrue(result.Contains(StockMarket.KOSDAQ), "정상 비율 시장은 허용");
- }
- [TestMethod]
- public void CanDelist_BoundaryAndBootstrap()
- {
- Assert.IsTrue(StockMasterDelist.CanDelist(800, 1000), "정확히 80% 는 허용 (경계 포함)");
- Assert.IsFalse(StockMasterDelist.CanDelist(799, 1000), "80% 미만은 보류");
- Assert.IsTrue(StockMasterDelist.CanDelist(500, 0), "활성 0(최초 적재)은 비교 기준이 없어 허용");
- Assert.IsFalse(StockMasterDelist.CanDelist(0, 0), "빈 스냅샷은 항상 보류");
- }
- }
|