test: cover ViewTest and run

This commit is contained in:
dualfroz committed 2026-09-10 19:42:20 +02:00
1 parent 4682431a80
commit 03072818c2
1 file changed
+157
+157
View File
@@ -0,0 +1,157 @@
package kestrel
import kestrel.catalog.Catalog
import kestrel.engine.CreateViewResult
import kestrel.engine.DropViewResult
import kestrel.engine.Executor
import kestrel.engine.SelectResult
import kestrel.engine.StatementResult
import kestrel.sql.lexer.Lexer
import kestrel.sql.parser.Parser
import kestrel.storage.Value
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
class ViewTest {
private val catalog = Catalog()
private val executor = Executor(catalog)
private fun run(sql: String): List<StatementResult> =
Parser(Lexer(sql).tokenize()).parseProgram().map { executor.execute(it) }
private fun exec(sql: String): StatementResult = run(sql).single()
private fun select(sql: String): SelectResult = exec(sql) as SelectResult
private fun int(value: Long) = Value.IntegerValue(value)
private fun text(value: String) = Value.TextValue(value)
private fun seedUsers() {
run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER, dept TEXT)")
run(
"INSERT INTO users VALUES " +
"(1, 'ada', 36, 'eng'), (2, 'linus', 54, 'eng'), (3, 'grace', 85, 'navy'), (4, 'alan', 41, NULL)"
)
}
@Test
fun createViewReturnsResultAndRegistersName() {
seedUsers()
val result = exec("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 40") as CreateViewResult
assertEquals("adults", result.viewName)
assertEquals(listOf("adults"), catalog.viewNames)
}
@Test
fun queryingAViewRunsItsDefiningQueryFresh() {
seedUsers()
run("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 40")
val first = select("SELECT name FROM adults ORDER BY id ASC")
assertEquals(listOf(text("linus"), text("grace"), text("alan")), first.rows.map { it.single() })
run("INSERT INTO users VALUES (5, 'margaret', 61, 'navy')")
val second = select("SELECT name FROM adults ORDER BY id ASC")
assertEquals(
listOf(text("linus"), text("grace"), text("alan"), text("margaret")),
second.rows.map { it.single() }
)
}
@Test
fun viewCanBeUsedAsAJoinTarget() {
seedUsers()
run("CREATE TABLE bonuses (dept TEXT, amount INTEGER)")
run("INSERT INTO bonuses VALUES ('eng', 1000), ('navy', 500)")
run("CREATE VIEW eng_staff AS SELECT id, name, dept FROM users WHERE dept = 'eng'")
val result = select(
"SELECT eng_staff.name, bonuses.amount FROM eng_staff " +
"JOIN bonuses ON eng_staff.dept = bonuses.dept ORDER BY eng_staff.id ASC"
)
assertEquals(
listOf(listOf(text("ada"), int(1000)), listOf(text("linus"), int(1000))),
result.rows
)
}
@Test
fun viewOverAggregateQueryWorks() {
seedUsers()
run("CREATE VIEW dept_counts AS SELECT dept, COUNT(*) AS n FROM users GROUP BY dept")
val result = select("SELECT dept, n FROM dept_counts WHERE n > 1 ORDER BY dept ASC")
assertEquals(listOf(listOf(text("eng"), int(2))), result.rows)
}
@Test
fun viewDefinitionCanReferenceAnotherView() {
seedUsers()
run("CREATE VIEW adults AS SELECT id, name, age FROM users WHERE age >= 40")
run("CREATE VIEW seniors AS SELECT id, name FROM adults WHERE age >= 60")
val result = select("SELECT name FROM seniors")
assertEquals(listOf(listOf(text("grace"))), result.rows)
}
@Test
fun creatingAViewValidatesColumnsEagerly() {
seedUsers()
assertFailsWith<KestrelException> { run("CREATE VIEW broken AS SELECT nope FROM users") }
assertTrue(catalog.viewNames.isEmpty())
}
@Test
fun creatingAViewOverAnUnknownTableFails() {
assertFailsWith<KestrelException> { run("CREATE VIEW v AS SELECT * FROM missing") }
}
@Test
fun duplicateViewNameFailsWithoutOrReplace() {
seedUsers()
run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
assertFailsWith<KestrelException> { run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 21") }
}
@Test
fun createOrReplaceViewSwapsTheDefinition() {
seedUsers()
run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
run("CREATE OR REPLACE VIEW adults AS SELECT id FROM users WHERE age >= 50")
val result = select("SELECT id FROM adults ORDER BY id ASC")
assertEquals(listOf(listOf(int(2)), listOf(int(3))), result.rows)
}
@Test
fun dropViewRemovesItAndItStopsBeingQueryable() {
seedUsers()
run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
val result = exec("DROP VIEW adults") as DropViewResult
assertEquals("adults", result.viewName)
assertFailsWith<KestrelException> { run("SELECT * FROM adults") }
}
@Test
fun droppingAnUnknownViewFails() {
assertFailsWith<KestrelException> { run("DROP VIEW nope") }
}
@Test
fun cannotCreateTableWithSameNameAsAnExistingView() {
seedUsers()
run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
assertFailsWith<KestrelException> { run("CREATE TABLE adults (id INTEGER)") }
}
@Test
fun cannotCreateViewWithSameNameAsAnExistingTable() {
seedUsers()
assertFailsWith<KestrelException> { run("CREATE VIEW users AS SELECT id FROM users") }
}
@Test
fun dropTableRefusesAViewNameAndDropViewRefusesATableName() {
seedUsers()
run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
assertFailsWith<KestrelException> { run("DROP TABLE adults") }
assertFailsWith<KestrelException> { run("DROP VIEW users") }
}