StockMasterDelistTests.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. using Application.Helpers;
  2. using Domain.Entities.Stocks.ValueObject;
  3. namespace Application.Tests;
  4. /// <summary>
  5. /// 종목마스터 상폐 sweep 시장별 가드 검증 — 한 시장만 빈/부분 응답일 때 그 시장 전체가 대량 상폐되지 않도록
  6. /// (0건 또는 활성 대비 80% 미만이면 해당 시장 상폐 보류) 하는 StockMasterDelist 순수 로직.
  7. /// </summary>
  8. [TestClass]
  9. public sealed class StockMasterDelistTests
  10. {
  11. [TestMethod]
  12. public void GetDelistableMarkets_NormalSnapshot_AllMarketsDelistable()
  13. {
  14. // 기대 행위: 세 시장 모두 정상 스냅샷이면 전부 상폐 sweep 허용 (기존 상폐 동작 유지).
  15. var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 950, [StockMarket.KOSDAQ] = 1700, [StockMarket.KONEX] = 120 };
  16. var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 953, [StockMarket.KOSDAQ] = 1705, [StockMarket.KONEX] = 121 };
  17. var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
  18. Assert.AreEqual(3, result.Count, "정상 스냅샷은 세 시장 모두 상폐 허용");
  19. }
  20. [TestMethod]
  21. public void GetDelistableMarkets_OneMarketEmptySnapshot_ThatMarketExcluded()
  22. {
  23. // 기대 행위: 한 시장(KOSDAQ)만 빈 응답이면 그 시장은 상폐 보류 — KOSDAQ ~1,700종목 대량 상폐 방지 (감사 결함 2 재현 시나리오).
  24. var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 950, [StockMarket.KOSDAQ] = 0, [StockMarket.KONEX] = 120 };
  25. var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 953, [StockMarket.KOSDAQ] = 1705, [StockMarket.KONEX] = 121 };
  26. var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
  27. Assert.AreEqual(2, result.Count);
  28. Assert.IsFalse(result.Contains(StockMarket.KOSDAQ), "빈 스냅샷 시장은 상폐 sweep 에서 제외");
  29. Assert.IsTrue(result.Contains(StockMarket.KOSPI), "정상 시장은 상폐 동작 유지");
  30. Assert.IsTrue(result.Contains(StockMarket.KONEX), "정상 시장은 상폐 동작 유지");
  31. }
  32. [TestMethod]
  33. public void GetDelistableMarkets_PartialSnapshotBelow80Percent_Excluded()
  34. {
  35. // 기대 행위: 스냅샷이 활성 종목수의 80% 미만이면 부분 응답으로 간주해 상폐 보류.
  36. var snapshot = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 700, [StockMarket.KOSDAQ] = 1700 };
  37. var active = new Dictionary<StockMarket, int> { [StockMarket.KOSPI] = 1000, [StockMarket.KOSDAQ] = 1705 };
  38. var result = StockMasterDelist.GetDelistableMarkets(snapshot, active);
  39. Assert.IsFalse(result.Contains(StockMarket.KOSPI), "활성 1000 대비 스냅샷 700(70%) → 보류");
  40. Assert.IsTrue(result.Contains(StockMarket.KOSDAQ), "정상 비율 시장은 허용");
  41. }
  42. [TestMethod]
  43. public void CanDelist_BoundaryAndBootstrap()
  44. {
  45. Assert.IsTrue(StockMasterDelist.CanDelist(800, 1000), "정확히 80% 는 허용 (경계 포함)");
  46. Assert.IsFalse(StockMasterDelist.CanDelist(799, 1000), "80% 미만은 보류");
  47. Assert.IsTrue(StockMasterDelist.CanDelist(500, 0), "활성 0(최초 적재)은 비교 기준이 없어 허용");
  48. Assert.IsFalse(StockMasterDelist.CanDelist(0, 0), "빈 스냅샷은 항상 보류");
  49. }
  50. }