Files
dbx/apps/desktop/src/lib/__tests__/sql/currentStatementFrame.spec.ts
T

96 lines
4.2 KiB
TypeScript
Vendored
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import { currentStatementFrameRangeTo, estimateInlineHintVisualColumns, isWideSqlChar, shouldRebuildCurrentStatementFrame, visualSqlColumns, visualSqlColumnsWithInlineHints } from "@/lib/sql/currentStatementFrame";
import type { SqlTextRange } from "@/lib/sql/sqlStatementRanges";
function frameDocument(sql: string) {
return {
length: sql.length,
sliceString: (from: number, to: number) => sql.slice(from, to),
};
}
describe("currentStatementFrameRangeTo", () => {
it("includes a directly adjacent trailing semicolon in frame width calculations", () => {
const sql = "SELECT 1;";
const range: SqlTextRange = { from: 0, to: "SELECT 1".length, sql: "SELECT 1" };
expect(currentStatementFrameRangeTo(frameDocument(sql), range)).toBe(sql.length);
});
it("includes a trailing semicolon on its own line", () => {
const sql = "SELECT 1\n;\n\nSELECT 2;";
const range: SqlTextRange = { from: 0, to: "SELECT 1".length, sql: "SELECT 1" };
expect(currentStatementFrameRangeTo(frameDocument(sql), range)).toBe(sql.indexOf(";") + 1);
});
it("does not extend the frame across a comment before a later semicolon", () => {
const sql = "SELECT 1\n-- comment\n;";
const range: SqlTextRange = { from: 0, to: "SELECT 1".length, sql: "SELECT 1" };
expect(currentStatementFrameRangeTo(frameDocument(sql), range)).toBe(range.to);
});
it("does not extend the frame across a blank line before a later semicolon", () => {
const sql = "SELECT 1\n\n;";
const range: SqlTextRange = { from: 0, to: "SELECT 1".length, sql: "SELECT 1" };
expect(currentStatementFrameRangeTo(frameDocument(sql), range)).toBe(range.to);
});
it("does not extend the frame when the next non-whitespace character is not a semicolon", () => {
const sql = "SELECT 1\n\nSELECT 2";
const range: SqlTextRange = { from: 0, to: "SELECT 1".length, sql: "SELECT 1" };
expect(currentStatementFrameRangeTo(frameDocument(sql), range)).toBe(range.to);
});
});
describe("shouldRebuildCurrentStatementFrame", () => {
it("reuses frame decorations for pure viewport updates", () => {
expect(shouldRebuildCurrentStatementFrame({ docChanged: false, selectionSet: false, configurationChanged: false })).toBe(false);
});
it("rebuilds after document, selection, or configuration updates", () => {
expect(shouldRebuildCurrentStatementFrame({ docChanged: true, selectionSet: false, configurationChanged: false })).toBe(true);
expect(shouldRebuildCurrentStatementFrame({ docChanged: false, selectionSet: true, configurationChanged: false })).toBe(true);
expect(shouldRebuildCurrentStatementFrame({ docChanged: false, selectionSet: false, configurationChanged: true })).toBe(true);
});
});
describe("visualSqlColumns", () => {
it("counts ASCII as one column, tabs as four, and CJK/fullwidth characters as two", () => {
expect(visualSqlColumns("A\t中B")).toBe(1 + 4 + 2 + 2);
});
it("recognizes common wide SQL text characters", () => {
expect(isWideSqlChar("中")).toBe(true);
expect(isWideSqlChar("A")).toBe(true);
expect(isWideSqlChar("A")).toBe(false);
});
});
describe("visualSqlColumnsWithInlineHints", () => {
it("adds estimated columns for insert-value hints on the line", () => {
const text = "VALUES (12, 'a')";
const lineFrom = 0;
const lineTo = text.length;
const withoutHints = visualSqlColumns(text);
const withHints = visualSqlColumnsWithInlineHints(text, lineFrom, lineTo, [
{ from: 8, column: "id" },
{ from: 12, column: "name" },
]);
expect(withHints).toBe(withoutHints + estimateInlineHintVisualColumns("id") + estimateInlineHintVisualColumns("name"));
});
it("ignores hints that belong to other lines", () => {
const text = "VALUES (1)";
expect(visualSqlColumnsWithInlineHints(text, 0, text.length, [{ from: 100, column: "id" }])).toBe(visualSqlColumns(text));
});
it("dedupes hints that share the same document offset", () => {
const text = "VALUES (1)";
const once = visualSqlColumnsWithInlineHints(text, 0, text.length, [{ from: 8, column: "id" }]);
const twice = visualSqlColumnsWithInlineHints(text, 0, text.length, [
{ from: 8, column: "id" },
{ from: 8, column: "id" },
]);
expect(twice).toBe(once);
});
});