using SheetMe.Core.Catalog;
namespace SheetMe.Core.Tests;
///
/// SQL 정리 테스트.
///
/// 가장 중요한 불변식은 뜻이 바뀌지 않는 것이다. 특히 치환 변수는 대소문자가 맞아야
/// 런타임이 찾으므로, 정리하면서 건드리면 그 서식은 조용히 값을 못 받는다.
///
[TestClass]
public sealed class SqlFormatterTests
{
[TestMethod]
public void Format_BreaksBeforeMajorClauses()
{
var formatted = SqlFormatter.Format("select a from t where b=1 and c=2");
var lines = formatted.Split('\n');
StringAssert.StartsWith(lines[0], "SELECT");
Assert.IsTrue(lines.Any(l => l.StartsWith("FROM", StringComparison.Ordinal)));
Assert.IsTrue(lines.Any(l => l.StartsWith("WHERE", StringComparison.Ordinal)));
Assert.IsTrue(lines.Any(l => l.StartsWith("AND", StringComparison.Ordinal)));
}
[TestMethod]
public void Format_UppercasesKeywordsAndFunctions()
{
var formatted = SqlFormatter.Format("select nvl(a,0) from dual");
StringAssert.Contains(formatted, "SELECT");
StringAssert.Contains(formatted, "NVL");
StringAssert.Contains(formatted, "DUAL");
}
/// 식별자는 건드리지 않는다 — 대소문자를 가리는 곳에서 깨진다
[TestMethod]
public void Format_LeavesIdentifiersAlone()
{
var formatted = SqlFormatter.Format("select ChtNum, PatNam from P_PatMst");
StringAssert.Contains(formatted, "ChtNum");
StringAssert.Contains(formatted, "PatNam");
StringAssert.Contains(formatted, "P_PatMst");
}
///
/// 치환 변수는 원문 그대로여야 한다. 대문자로 바꾸면 런타임이 클래스 이름을 못 찾아
/// 그 칸이 조용히 빈다 — 이 포매터가 저지를 수 있는 가장 나쁜 일이다.
///
[TestMethod]
public void Format_NeverTouchesSubstitutionVariables()
{
const string token = "<>";
var formatted = SqlFormatter.Format($"select * from t where a = '{token}'");
StringAssert.Contains(formatted, token);
}
/// 《컨트롤명》도 마찬가지다
[TestMethod]
public void Format_NeverTouchesControlSubstitution()
{
var formatted = SqlFormatter.Format("select * from t where a = 《TextBox1》");
StringAssert.Contains(formatted, "《TextBox1》");
}
/// 문자열 안은 손대지 않는다 — 예약어와 같은 낱말이 들어 있어도
[TestMethod]
public void Format_LeavesStringLiteralsAlone()
{
var formatted = SqlFormatter.Format("select 'from where select' from t");
StringAssert.Contains(formatted, "'from where select'");
}
[TestMethod]
public void Format_IndentsByParenthesisDepth()
{
var formatted = SqlFormatter.Format("select * from (select a from t)");
Assert.IsTrue(formatted.Split('\n').Any(l => l.StartsWith(" ", StringComparison.Ordinal)),
formatted);
}
[TestMethod]
public void Format_LeavesNoTrailingWhitespace()
{
var formatted = SqlFormatter.Format("select a , b from t where c = 1");
foreach (var line in formatted.Split('\n'))
{
Assert.AreEqual(line.TrimEnd(), line, $"줄 끝 공백이 남았습니다: '{line}'");
}
}
[DataTestMethod]
[DataRow("")]
[DataRow(" ")]
public void Format_ReturnsEmptyInputUnchanged(string input)
=> Assert.AreEqual(input, SqlFormatter.Format(input));
/// 정리해도 다시 정리하면 같아야 한다 — 누를 때마다 모양이 흔들리면 못 쓴다
[TestMethod]
public void Format_IsStableWhenAppliedTwice()
{
var once = SqlFormatter.Format("select a,b from t where c=1 and d=2");
var twice = SqlFormatter.Format(once);
Assert.AreEqual(once, twice);
}
}