pgLab/tests/pglabtests/tst_SqlContext.cpp

271 lines
7.8 KiB
C++

#include <gtest/gtest.h>
#include "SqlContext.h"
#include "PrintTo_Qt.h"
using namespace testing;
namespace {
// '|' in the text marks the cursor
SqlContext analyze(QString text)
{
int pos = text.indexOf('|');
text.remove(pos, 1);
return analyzeSqlContext(text, pos);
}
QStringList names(const SqlContext &ctx)
{
QStringList l;
for (auto &r : ctx.relations)
l << (r.schema.isEmpty() ? r.name : r.schema + "." + r.name) + (r.alias.isEmpty() ? "" : "/" + r.alias);
return l;
}
} // namespace
TEST(SqlContext, emptyDocument)
{
auto ctx = analyzeSqlContext("", 0);
EXPECT_EQ(ctx.kind, CompletionKind::None);
}
TEST(SqlContext, selectListColumnWithFromAfterCursor)
{
auto ctx = analyze("SELECT | FROM t");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.clause, SqlClause::Select);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
EXPECT_TRUE(ctx.prefix.isEmpty());
}
TEST(SqlContext, prefixIsReplaceRange)
{
auto ctx = analyze("SELECT na| FROM t");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.prefix, "na");
EXPECT_EQ(ctx.prefixStart, 7);
EXPECT_EQ(ctx.prefixLen, 2);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
}
TEST(SqlContext, relationAfterFrom)
{
auto ctx = analyze("SELECT * FROM us|");
EXPECT_EQ(ctx.kind, CompletionKind::Relation);
EXPECT_EQ(ctx.prefix, "us");
EXPECT_TRUE(ctx.relations.empty());
}
TEST(SqlContext, relationAfterSchemaDot)
{
auto ctx = analyze("SELECT * FROM sch.|");
EXPECT_EQ(ctx.kind, CompletionKind::Relation);
EXPECT_EQ(ctx.qualifier, "sch");
EXPECT_TRUE(ctx.relations.empty());
}
TEST(SqlContext, noRelationAfterAlias)
{
auto ctx = analyze("SELECT * FROM t a|");
EXPECT_EQ(ctx.kind, CompletionKind::None);
}
TEST(SqlContext, relationAfterComma)
{
auto ctx = analyze("SELECT * FROM t, |");
EXPECT_EQ(ctx.kind, CompletionKind::Relation);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
}
TEST(SqlContext, aliasQualifier)
{
auto ctx = analyze("SELECT a.| FROM public.tbl AS a JOIN other o ON o.id = a.id");
EXPECT_EQ(ctx.kind, CompletionKind::QualifiedColumn);
EXPECT_EQ(ctx.qualifier, "a");
EXPECT_EQ(names(ctx), QStringList({ "public.tbl/a", "other/o" }));
}
TEST(SqlContext, schemaQualifiedTableQualifier)
{
auto ctx = analyze("SELECT s.t.c| FROM s.t");
EXPECT_EQ(ctx.kind, CompletionKind::QualifiedColumn);
EXPECT_EQ(ctx.qualifierSchema, "s");
EXPECT_EQ(ctx.qualifier, "t");
EXPECT_EQ(ctx.prefix, "c");
}
TEST(SqlContext, onClause)
{
auto ctx = analyze("SELECT * FROM a x JOIN b y ON x.id = |");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.clause, SqlClause::On);
EXPECT_EQ(names(ctx), QStringList({ "a/x", "b/y" }));
}
TEST(SqlContext, relationAfterJoin)
{
auto ctx = analyze("SELECT * FROM a x LEFT JOIN |");
EXPECT_EQ(ctx.kind, CompletionKind::JoinTarget);
EXPECT_EQ(ctx.clause, SqlClause::Join);
EXPECT_EQ(names(ctx), QStringList({ "a/x" }));
EXPECT_EQ(analyze("SELECT * FROM a x JOIN b|").kind, CompletionKind::JoinTarget);
EXPECT_EQ(analyze("SELECT * FROM a x JOIN sch.|").kind, CompletionKind::Relation);
EXPECT_EQ(analyze("SELECT * FROM a x JOIN b y |").kind, CompletionKind::None);
}
TEST(SqlContext, whereGroupOrderHaving)
{
EXPECT_EQ(analyze("SELECT * FROM t WHERE |").clause, SqlClause::Where);
EXPECT_EQ(analyze("SELECT * FROM t GROUP BY |").clause, SqlClause::GroupBy);
EXPECT_EQ(analyze("SELECT * FROM t ORDER BY |").clause, SqlClause::OrderBy);
EXPECT_EQ(analyze("SELECT * FROM t GROUP BY a HAVING |").clause, SqlClause::Having);
}
TEST(SqlContext, quotedPrefix)
{
auto ctx = analyze("SELECT \"My| FROM t");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_TRUE(ctx.prefixWasQuoted);
EXPECT_EQ(ctx.prefix, "My");
EXPECT_EQ(ctx.prefixStart, 7);
EXPECT_EQ(ctx.prefixLen, 3);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
}
TEST(SqlContext, quotedRelationNamesKeepCase)
{
auto ctx = analyze("SELECT | FROM \"My Tab\" AS \"X\", Other O");
EXPECT_EQ(names(ctx), QStringList({ "My Tab/X", "other/o" }));
EXPECT_TRUE(ctx.relations[0].quoted);
}
TEST(SqlContext, multipleStatements)
{
auto ctx = analyze("SELECT * FROM a; SELECT | FROM b; SELECT 1 FROM c");
EXPECT_EQ(names(ctx), QStringList({ "b" }));
}
TEST(SqlContext, subQueryHasOwnScopeAndSeesParent)
{
auto ctx = analyze("SELECT * FROM a WHERE a.id IN (SELECT | FROM b)");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(names(ctx), QStringList({ "b", "a" }));
}
TEST(SqlContext, derivedTableDoesNotSeeParent)
{
auto ctx = analyze("SELECT * FROM a, (SELECT | FROM b) d");
EXPECT_EQ(names(ctx), QStringList({ "b" }));
auto ctx2 = analyze("SELECT | FROM a, (SELECT 1 FROM b) d");
EXPECT_EQ(names(ctx2), QStringList({ "a", "d/d" }));
EXPECT_TRUE(ctx2.relations[1].derived);
}
TEST(SqlContext, functionCallParenInheritsClause)
{
auto ctx = analyze("SELECT count(|) FROM t");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
}
TEST(SqlContext, cte)
{
auto ctx = analyze("WITH x (a) AS (SELECT 1), y AS MATERIALIZED (SELECT 2) SELECT | FROM x JOIN t ON true");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(names(ctx), QStringList({ "x", "t", "x", "y" }));
EXPECT_TRUE(ctx.relations[2].derived);
}
TEST(SqlContext, unionSegments)
{
auto ctx = analyze("SELECT * FROM a UNION SELECT | FROM b");
EXPECT_EQ(names(ctx), QStringList({ "b" }));
}
TEST(SqlContext, noCompletionInCommentOrString)
{
EXPECT_EQ(analyze("SELECT * FROM t -- co|").kind, CompletionKind::None);
EXPECT_EQ(analyze("SELECT * FROM t /* co| */").kind, CompletionKind::None);
EXPECT_EQ(analyze("SELECT 'ab|c' FROM t").kind, CompletionKind::None);
}
TEST(SqlContext, incompleteSql)
{
auto ctx = analyze("SELECT a.id, b.| FROM a, b WHERE");
EXPECT_EQ(ctx.kind, CompletionKind::QualifiedColumn);
EXPECT_EQ(ctx.qualifier, "b");
EXPECT_EQ(names(ctx), QStringList({ "a", "b" }));
}
TEST(SqlContext, updateSetAndWhere)
{
auto ctx = analyze("UPDATE sch.t AS x SET |");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.clause, SqlClause::Set);
EXPECT_EQ(names(ctx), QStringList({ "sch.t/x" }));
auto ctx2 = analyze("UPDATE t SET a = 1, b = 2 WHERE |");
EXPECT_EQ(ctx2.clause, SqlClause::Where);
EXPECT_EQ(names(ctx2), QStringList({ "t" }));
}
TEST(SqlContext, updateRelation)
{
auto ctx = analyze("UPDATE |");
EXPECT_EQ(ctx.kind, CompletionKind::Relation);
}
TEST(SqlContext, updateFrom)
{
auto ctx = analyze("UPDATE t SET a = u.| FROM u WHERE t.id = u.id");
EXPECT_EQ(ctx.kind, CompletionKind::QualifiedColumn);
EXPECT_EQ(names(ctx), QStringList({ "t", "u" }));
}
TEST(SqlContext, deleteFrom)
{
auto ctx = analyze("DELETE FROM |");
EXPECT_EQ(ctx.kind, CompletionKind::Relation);
auto ctx2 = analyze("DELETE FROM t WHERE |");
EXPECT_EQ(ctx2.kind, CompletionKind::Column);
EXPECT_EQ(names(ctx2), QStringList({ "t" }));
}
TEST(SqlContext, insertIntoRelation)
{
EXPECT_EQ(analyze("INSERT INTO |").kind, CompletionKind::Relation);
EXPECT_EQ(analyze("INSERT INTO sch.t|").kind, CompletionKind::Relation);
}
TEST(SqlContext, insertColumnList)
{
auto ctx = analyze("INSERT INTO s.t (|");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.clause, SqlClause::InsertInto);
EXPECT_EQ(names(ctx), QStringList({ "s.t" }));
auto ctx2 = analyze("INSERT INTO t (a, b|) VALUES (1, 2)");
EXPECT_EQ(ctx2.kind, CompletionKind::Column);
EXPECT_EQ(ctx2.prefix, "b");
EXPECT_EQ(names(ctx2), QStringList({ "t" }));
}
TEST(SqlContext, insertValuesAndSelect)
{
auto ctx = analyze("INSERT INTO t (a) VALUES (|)");
EXPECT_EQ(ctx.clause, SqlClause::Values);
auto ctx2 = analyze("INSERT INTO t (a) SELECT | FROM u");
EXPECT_EQ(ctx2.kind, CompletionKind::Column);
EXPECT_EQ(names(ctx2), QStringList({ "u" }));
}
TEST(SqlContext, returning)
{
auto ctx = analyze("INSERT INTO t (a) VALUES (1) RETURNING |");
EXPECT_EQ(ctx.kind, CompletionKind::Column);
EXPECT_EQ(ctx.clause, SqlClause::Returning);
EXPECT_EQ(names(ctx), QStringList({ "t" }));
EXPECT_EQ(analyze("DELETE FROM t RETURNING |").clause, SqlClause::Returning);
}