test: cover CheckConstraintTest and run
This commit is contained in:
1 parent
415047ac02
commit
f58df29ed4
1 file changed
+111
@@ -0,0 +1,111 @@
|
||||
package kestrel
|
||||
|
||||
import kestrel.catalog.Catalog
|
||||
import kestrel.engine.Executor
|
||||
import kestrel.engine.InsertResult
|
||||
import kestrel.engine.SelectResult
|
||||
import kestrel.engine.StatementResult
|
||||
import kestrel.engine.UpdateResult
|
||||
import kestrel.sql.lexer.Lexer
|
||||
import kestrel.sql.parser.Parser
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CheckConstraintTest {
|
||||
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
|
||||
|
||||
@Test
|
||||
fun columnLevelCheckAcceptsSatisfyingRows() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age > 0))")
|
||||
assertEquals(InsertResult(1), exec("INSERT INTO t VALUES (1, 30)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun columnLevelCheckRejectsViolatingRows() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age > 0))")
|
||||
val error = assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (1, -5)") }
|
||||
assertTrue(error.message!!.contains("CHECK"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkPassesWhenExpressionIsUnknownBecauseOfNull() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age > 0))")
|
||||
// three-valued logic: NULL > 0 is UNKNOWN, not FALSE, so the row is accepted
|
||||
assertEquals(InsertResult(1), exec("INSERT INTO t VALUES (1, NULL)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tableLevelCheckCanSpanMultipleColumns() {
|
||||
run("CREATE TABLE ranges (id INTEGER PRIMARY KEY, low INTEGER, high INTEGER, CHECK (low <= high))")
|
||||
assertEquals(InsertResult(1), exec("INSERT INTO ranges VALUES (1, 1, 10)"))
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO ranges VALUES (2, 10, 1)") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun multipleCheckConstraintsAllMustBeSatisfied() {
|
||||
run(
|
||||
"CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age >= 0), " +
|
||||
"score INTEGER CHECK (score BETWEEN 0 AND 100))"
|
||||
)
|
||||
assertEquals(InsertResult(1), exec("INSERT INTO t VALUES (1, 30, 90)"))
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (2, 30, 150)") }
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (3, -1, 90)") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkIsEnforcedOnUpdateToo() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age > 0))")
|
||||
run("INSERT INTO t VALUES (1, 30)")
|
||||
assertFailsWith<KestrelException> { run("UPDATE t SET age = -1 WHERE id = 1") }
|
||||
assertEquals(UpdateResult(1), exec("UPDATE t SET age = 40 WHERE id = 1"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkRejectsAggregateFunctions() {
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, amount INTEGER CHECK (SUM(amount) > 0))")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkRejectsSubqueries() {
|
||||
run("CREATE TABLE other (id INTEGER PRIMARY KEY)")
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY CHECK (id IN (SELECT id FROM other)))")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkRejectsUnknownColumn() {
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, CHECK (nope > 0))")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkCanReferenceStringAndCallExpressions() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT CHECK (LENGTH(name) > 0))")
|
||||
assertEquals(InsertResult(1), exec("INSERT INTO t VALUES (1, 'ada')"))
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (2, '')") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkConstraintSurvivesRollback() {
|
||||
run("CREATE TABLE t (id INTEGER PRIMARY KEY, age INTEGER CHECK (age > 0))")
|
||||
run("BEGIN")
|
||||
run("INSERT INTO t VALUES (1, 30)")
|
||||
run("ROLLBACK")
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (1, -5)") }
|
||||
assertEquals(0, select("SELECT * FROM t").rows.size)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user