| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- using System.Text.RegularExpressions;
- using System.Xml;
- using Infrastructure.StockData;
- namespace Application.Tests;
- [TestClass]
- public sealed class SeibroXmlTests
- {
- [TestMethod]
- public void Parse_All37Fixtures_SmokeTest_RowsMatchActualDataElements()
- {
- // 샘플 37종 전수 스모크 — 전부 예외 없이 파싱되고, rows 수는 파일에 실제 존재하는 <data> 수와 일치해야 한다
- // (vector@result 는 원문 행수라 truncate 된 샘플에선 rows 보다 클 수 있음 → ResultCount 는 음수 아님만 확인)
- var files = SeibroFixtures.AllXmlFiles();
- Assert.AreEqual(37, files.Length, "SEIBro fixture 는 37종 전부 복사되어야 한다");
- foreach (var file in files)
- {
- var xml = File.ReadAllText(file);
- var envelope = SeibroXml.Parse(xml);
- // 파서와 독립적인 검증용 카운트 — <data ...> 시작 태그 수 (셀프클로징 없음, 래퍼/필드 element 는 data 로 시작하지 않음)
- var actualDataCount = Regex.Matches(xml, @"<data[\s>]", RegexOptions.IgnoreCase).Count;
- Assert.AreEqual(actualDataCount, envelope.Rows.Count, $"{Path.GetFileName(file)}: rows 수는 실제 data element 수와 일치");
- Assert.IsTrue(envelope.ResultCount >= 0, $"{Path.GetFileName(file)}: result 행수 속성 파싱");
- Assert.IsTrue(envelope.ResultCount >= envelope.Rows.Count, $"{Path.GetFileName(file)}: result 는 원문 행수 (truncate 샘플은 rows 이상)");
- }
- }
- [TestMethod]
- public void Parse_UppercaseResultWrapper_GetAssetInfo_MapsFields()
- {
- // 파생결합 getAssetInfo 는 래퍼가 대문자 <RESULT> — 대소문자 무시 파싱 검증 (docs/SEIBro/readme.md 규칙 4)
- var envelope = SeibroXml.Parse(SeibroFixtures.Read("getAssetInfo.xml"));
- Assert.AreEqual(3, envelope.ResultCount);
- var row = envelope.Rows[0];
- Assert.AreEqual("KR6539335879", SeibroXml.GetOrNull(row, "ISIN"));
- Assert.AreEqual("1", SeibroXml.GetOrNull(row, "ASSET_SEQ"));
- Assert.AreEqual("Hang Seng China Enterprises Index", SeibroXml.GetOrNull(row, "STND_BASSET_NM"));
- Assert.AreEqual("6090.15", SeibroXml.GetOrNull(row, "XRC_STOP_LOLMT_PRICE"));
- }
- [TestMethod]
- public void Parse_LowercaseResultWrapper_GetShotnByMart_MapsFields()
- {
- // 주식 getShotnByMart 는 래퍼가 소문자 <result> — 필드값 = value 속성
- var envelope = SeibroXml.Parse(SeibroFixtures.Read("getShotnByMart.xml"));
- Assert.AreEqual(126, envelope.ResultCount, "vector@result = 원문 행수");
- var row = envelope.Rows[0];
- Assert.AreEqual("000800", SeibroXml.GetOrNull(row, "SHOTN_ISIN"));
- Assert.AreEqual("경남기업", SeibroXml.GetOrNull(row, "KOR_SECN_NM"));
- Assert.AreEqual("80", SeibroXml.GetOrNull(row, "ISSUCO_CUSTNO"));
- }
- [TestMethod]
- public void Parse_EmptyResult_ZeroRows()
- {
- // result="0" + data 없음 = 정상 빈 결과 (getXrcStkStatInfo 샘플이 실제 이 형태)
- var envelope = SeibroXml.Parse(SeibroFixtures.Read("getXrcStkStatInfo.xml"));
- Assert.AreEqual(0, envelope.ResultCount);
- Assert.AreEqual(0, envelope.Rows.Count);
- }
- [TestMethod]
- public void Parse_EmptyValueAttribute_TreatedAsNull()
- {
- // value="" 는 null 취급 — 행 딕셔너리에서 키 자체가 빠진다 (element 생략과 동일 의미)
- const string xml = """
- <vector result="1">
- <data vectorkey="0" type="Document">
- <result>
- <ISIN value="KR7005930003"/>
- <EMPTY_FIELD value=""/>
- </result>
- </data>
- </vector>
- """;
- var envelope = SeibroXml.Parse(xml);
- Assert.AreEqual(1, envelope.Rows.Count);
- Assert.AreEqual("KR7005930003", SeibroXml.GetOrNull(envelope.Rows[0], "ISIN"));
- Assert.IsNull(SeibroXml.GetOrNull(envelope.Rows[0], "EMPTY_FIELD"), "value=\"\" → null");
- Assert.IsNull(SeibroXml.GetOrNull(envelope.Rows[0], "OMITTED_FIELD"), "element 생략 → null");
- }
- [TestMethod]
- public void Parse_FieldLookup_IsCaseInsensitive()
- {
- const string xml = """
- <vector result="1">
- <data vectorkey="0" type="Document">
- <RESULT>
- <ISSUCO_CUSTNO value="593"/>
- </RESULT>
- </data>
- </vector>
- """;
- var envelope = SeibroXml.Parse(xml);
- Assert.AreEqual("593", SeibroXml.GetOrNull(envelope.Rows[0], "issuco_custno"), "필드명 조회는 대소문자 무시");
- }
- [TestMethod]
- public void Parse_NonXmlInput_Throws()
- {
- // 비XML 응답(에러 페이지 등)은 명시적 예외 — silent 빈 결과 금지
- Assert.ThrowsExactly<XmlException>(() => SeibroXml.Parse("Unauthorized Key"));
- }
- [TestMethod]
- public void Parse_NonVectorRoot_Throws()
- {
- Assert.ThrowsExactly<FormatException>(() => SeibroXml.Parse("<error message=\"invalid key\"/>"));
- }
- [TestMethod]
- public void Parse_MissingResultAttribute_Throws()
- {
- Assert.ThrowsExactly<FormatException>(() => SeibroXml.Parse("<vector><data vectorkey=\"0\"><result/></data></vector>"));
- }
- }
|