using SheetMe.Core.Catalog;
namespace SheetMe.Core.Tests;
///
/// 자동완성 문맥 판단 테스트.
///
/// 문맥을 잘못 잡으면 목록이 엉뚱한 것을 보여 주고, 그러면 안 쓰느니만 못하다.
/// 특히 << 직후는 이 편집기에만 있는 문법이라 여기서 놓치면 손으로 외워 쳐야 한다.
///
[TestClass]
public sealed class SqlCompletionTests
{
/// 커서를 | 로 표시한 텍스트를 받아 분석한다 — 테스트가 읽히게
private static SqlCompletionQuery? At(string marked)
{
var caret = marked.IndexOf('|');
return SqlCompletion.Analyze(marked.Remove(caret, 1), caret);
}
[TestMethod]
public void Analyze_AfterOpenAngle_SuggestsVariables()
{
var query = At("WHERE a = <이미 닫힌 변수 뒤에서는 변수 문맥이 아니다
[TestMethod]
public void Analyze_AfterClosedVariable_IsNotVariableContext()
{
var query = At("WHERE a = <> AND na|");
Assert.IsNotNull(query);
Assert.AreNotEqual(SqlCompletionContext.Variable, query.Context);
}
[DataTestMethod]
[DataRow("SELECT * FROM P_|")]
[DataRow("SELECT * FROM t JOIN P_|")]
public void Analyze_AfterFromOrJoin_SuggestsTables(string marked)
{
var query = At(marked);
Assert.IsNotNull(query);
Assert.AreEqual(SqlCompletionContext.TableName, query.Context);
Assert.AreEqual("P_", query.Prefix);
}
/// FROM 바로 뒤(아직 한 글자도 안 침)에서도 테이블을 제안해야 한다
[TestMethod]
public void Analyze_ImmediatelyAfterFrom_SuggestsTablesWithEmptyPrefix()
{
var query = At("SELECT * FROM |");
Assert.IsNotNull(query);
Assert.AreEqual(SqlCompletionContext.TableName, query.Context);
Assert.AreEqual(string.Empty, query.Prefix);
}
[TestMethod]
public void Analyze_AfterDot_SuggestsColumnsOfQualifier()
{
var query = At("SELECT p.Cht| FROM P_PatMst p");
Assert.IsNotNull(query);
Assert.AreEqual(SqlCompletionContext.ColumnOf, query.Context);
Assert.AreEqual("p", query.Qualifier);
Assert.AreEqual("Cht", query.Prefix);
}
/// 아무것도 안 친 일반 위치에서는 목록을 띄우지 않는다 — 방해가 된다
[TestMethod]
public void Analyze_EmptyPrefixInGeneralPosition_ReturnsNull()
=> Assert.IsNull(At("SELECT a, |"));
[TestMethod]
public void Analyze_TypingWord_SuggestsGeneral()
{
var query = At("SEL|");
Assert.IsNotNull(query);
Assert.AreEqual(SqlCompletionContext.General, query.Context);
Assert.AreEqual("SEL", query.Prefix);
Assert.AreEqual(0, query.ReplaceStart);
}
/// 별칭을 실제 테이블로 풀어야 컬럼을 찾을 수 있다
[DataTestMethod]
[DataRow("SELECT p.x FROM P_PatMst p", "p", "P_PatMst")]
[DataRow("SELECT p.x FROM P_PatMst AS p", "p", "P_PatMst")]
[DataRow("SELECT c.x FROM P_PatMst p JOIN P_ComInf c ON p.a=c.a", "c", "P_ComInf")]
public void ResolveTable_FindsAliasTarget(string sql, string qualifier, string expected)
=> Assert.AreEqual(expected, SqlCompletion.ResolveTable(sql, qualifier));
/// 별칭이 없으면 한정자 자체가 테이블 이름이다
[TestMethod]
public void ResolveTable_FallsBackToQualifier()
=> Assert.AreEqual("P_PatMst", SqlCompletion.ResolveTable("SELECT * FROM P_PatMst", "P_PatMst"));
///
/// 별칭 자리에 키워드가 오면 별칭이 아니다 — FROM P_PatMst WHERE ... 에서
/// WHERE 를 별칭으로 잡으면 엉뚱한 테이블을 가리킨다.
///
[TestMethod]
public void ResolveTable_IgnoresKeywordAsAlias()
=> Assert.AreEqual("WHERE", SqlCompletion.ResolveTable("SELECT * FROM P_PatMst WHERE a=1", "WHERE"));
[TestMethod]
public void Filter_PutsPrefixMatchesFirst()
{
var items = new[]
{
new SqlCompletionItem("PrintBackColor", SqlCompletionKind.Column),
new SqlCompletionItem("PrintOutPut", SqlCompletionKind.Column),
new SqlCompletionItem("XPrint", SqlCompletionKind.Column),
};
var filtered = SqlCompletion.Filter(items, "Print");
Assert.AreEqual(3, filtered.Count, "부분 일치도 포함해야 한다");
Assert.AreEqual("PrintOutPut", filtered[0].Text, "접두 일치 중 짧은 것이 먼저");
Assert.AreEqual("XPrint", filtered[^1].Text, "부분 일치는 뒤로");
}
///
/// 별칭 없이 컬럼을 칠 때도 후보가 나와야 한다 — 별칭을 안 쓰는 쪽이 오히려 흔하다.
/// 이걸 못 잡으면 WHERE 절에서 아무것도 안 뜬다.
///
[TestMethod]
public void ReferencedTables_FindsTablesWithoutAlias()
{
var tables = SqlCompletion.ReferencedTables("select * FROM P_COMINF where comcht");
CollectionAssert.AreEqual(new[] { "P_COMINF" }, tables.ToArray());
}
[TestMethod]
public void ReferencedTables_FindsJoinedTablesOnce()
{
var tables = SqlCompletion.ReferencedTables(
"SELECT * FROM P_PatMst p JOIN P_ComInf c ON p.a=c.a JOIN P_ComInf d ON p.b=d.b");
CollectionAssert.AreEqual(new[] { "P_PatMst", "P_ComInf" }, tables.ToArray(),
"같은 테이블이 두 번 조인돼도 후보는 한 번만");
}
/// FROM 뒤에 키워드가 오면 테이블로 보지 않는다
[TestMethod]
public void ReferencedTables_IgnoresKeywordAfterFrom()
=> Assert.AreEqual(0, SqlCompletion.ReferencedTables("SELECT * FROM SELECT").Count);
[TestMethod]
public void BuiltIns_CoverKeywordsAndFunctions()
{
var items = SqlCompletion.BuiltIns();
Assert.IsTrue(items.Any(i => i.Text == "SELECT" && i.Kind == SqlCompletionKind.Keyword));
Assert.IsTrue(items.Any(i => i.Text == "NVL" && i.Kind == SqlCompletionKind.Function));
}
}