-
-
Notifications
You must be signed in to change notification settings - Fork 359
Expand file tree
/
Copy pathCompletionEngineTests.swift
More file actions
203 lines (178 loc) · 7.36 KB
/
Copy pathCompletionEngineTests.swift
File metadata and controls
203 lines (178 loc) · 7.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//
// CompletionEngineTests.swift
// TableProTests
//
// Created by TablePro Tests on 2026-02-17.
//
import Foundation
import TableProPluginKit
import Testing
@testable import TablePro
@Suite("Completion Engine", .serialized)
struct CompletionEngineTests {
private let schemaProvider: SQLSchemaProvider
private let engine: CompletionEngine
init() {
schemaProvider = SQLSchemaProvider()
engine = CompletionEngine(schemaProvider: schemaProvider, databaseType: .mysql)
}
@Test("Empty text returns nil")
func testEmptyText() async {
let result = await engine.getCompletions(text: "", cursorPosition: 0)
#expect(result != nil)
}
@Test("Cursor inside string returns nil")
func testCursorInsideString() async {
let text = "SELECT * FROM users WHERE name = 'John'"
let cursorInString = 38
let result = await engine.getCompletions(text: text, cursorPosition: cursorInString)
#expect(result == nil)
}
@Test("Cursor inside comment returns nil")
func testCursorInsideComment() async {
let text = "SELECT * FROM users -- this is a comment"
let cursorInComment = 30
let result = await engine.getCompletions(text: text, cursorPosition: cursorInComment)
#expect(result == nil)
}
@Test("SELECT keyword returns completions")
func testSelectKeyword() async {
let text = "SELECT"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
#expect(!result.items.isEmpty)
}
}
@Test("Cursor at start of empty query returns completions")
func testStartOfEmptyQuery() async {
let text = " "
let result = await engine.getCompletions(text: text, cursorPosition: 0)
#expect(result != nil)
if let result = result {
#expect(!result.items.isEmpty)
let hasStatementKeywords = result.items.contains { item in
["SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "ALTER", "DROP"].contains(item.label)
}
#expect(hasStatementKeywords)
}
}
@Test("Completion items have valid replacement range")
func testValidReplacementRange() async {
let text = "SEL"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
#expect(result.replacementRange.location >= 0)
#expect(result.replacementRange.length >= 0)
}
}
@Test("Replacement range does not exceed text length")
func testReplacementRangeInBounds() async {
let text = "SELECT * FROM users WHERE"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
let maxRange = result.replacementRange.location + result.replacementRange.length
#expect(maxRange <= (text as NSString).length)
}
}
@Test("Result is nil when no items match")
func testNoMatchingItems() async {
let text = "SELECT * FROM users WHERE xyz123abc"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result == nil)
}
@Test("Prefix filtering works for SEL")
func testPrefixFiltering() async {
let text = "SEL"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
let hasSelect = result.items.contains { $0.label == "SELECT" }
#expect(hasSelect)
}
}
@Test("Short text completion works")
func testShortText() async {
let text = "S"
let result = await engine.getCompletions(text: text, cursorPosition: 1)
#expect(result != nil)
if let result = result {
#expect(!result.items.isEmpty)
}
}
@Test("Simple FROM clause returns items")
func testFromClause() async {
let text = "SELECT * FROM "
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
#expect(!result.items.isEmpty)
}
}
@Test("WHERE clause returns items")
func testWhereClause() async {
let text = "SELECT * FROM users WHERE "
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
#expect(!result.items.isEmpty)
}
}
@Test("Result is nil when prefix matches no items")
func testSQLContext() async {
let text = "SELECT * FROM users"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
// "users" prefix in FROM clause with no schema tables loaded yields no matching items
#expect(result == nil)
}
@Test("Completions are limited to maxSuggestions for the clause type")
func testCompletionsLimited() async {
let text = "SEL"
let result = await engine.getCompletions(text: text, cursorPosition: text.count)
#expect(result != nil)
if let result = result {
#expect(result.items.count <= 40)
}
}
@Test("Test with various cursor positions")
func testVariousCursorPositions() async {
let text = "SELECT * FROM users WHERE id = 1"
let positions = [0, 6, 9, 14, 20, 26, text.count]
for position in positions {
let result = await engine.getCompletions(text: text, cursorPosition: position)
if result != nil {
#expect(result!.replacementRange.location >= 0)
}
}
}
@Test("Derived-table alias suggests the subquery's output columns")
func testDerivedTableAliasCompletion() async {
let driver = MockDatabaseDriver()
driver.tablesToReturn = [TestFixtures.makeTableInfo(name: "happiness_scores")]
await schemaProvider.loadSchema(using: driver, connection: TestFixtures.makeConnection())
let prefix = "SELECT ahs."
let text = prefix + " FROM happiness_scores hs "
+ "LEFT JOIN (SELECT country, AVG(score) AS avg_score FROM happiness_scores GROUP BY country) ahs "
+ "ON hs.country = ahs.country"
let result = await engine.getCompletions(text: text, cursorPosition: (prefix as NSString).length)
#expect(result != nil)
let labels = result?.items.map(\.label) ?? []
#expect(labels.contains("country"))
#expect(labels.contains("avg_score"))
}
@Test("CTE alias suggests the CTE's output columns")
func testCteAliasCompletion() async {
let driver = MockDatabaseDriver()
driver.tablesToReturn = [TestFixtures.makeTableInfo(name: "sales")]
await schemaProvider.loadSchema(using: driver, connection: TestFixtures.makeConnection())
let prefix = "WITH totals AS (SELECT region, SUM(amount) AS total FROM sales GROUP BY region) SELECT t."
let text = prefix + " FROM totals t"
let result = await engine.getCompletions(text: text, cursorPosition: (prefix as NSString).length)
#expect(result != nil)
let labels = result?.items.map(\.label) ?? []
#expect(labels.contains("region"))
#expect(labels.contains("total"))
}
}