test: consolidate 25 integration crates into one it binary

Each top-level tests/*.rs was its own crate → its own binary, each
statically linking the bundled engine + every dep. 26 of them, so an
edit to the lib relinked all 26. Moved the 25 standalone files into
tests/it/ under one tests/it/main.rs (the pattern typing_surface
already uses); cargo auto-detects it as the `it` target. End state: 2
integration-test binaries instead of 26.

Result: target/debug/deps 1.5 GB → 629 MB (-58%). Build time barely
moved (clean 22.9s→22.4s, lib-edit relink 13.3s→12.4s) — wall-clock is
dominated by compiling, not linking, so this is a disk win, not a speed
win (see docs/plans/20260602-test-consolidation.md). Tests unchanged at
2151/0/1; clippy clean; no fixups needed. typing_surface_matrix stays
its own already-consolidated binary.

Tradeoff: the 25 files now share one crate (a compile error fails the
whole `it` binary; module-scoped namespaces, no clashes) — negligible
for a solo project.
This commit is contained in:
claude@clouddev1
2026-06-02 22:13:03 +00:00
parent 42f95533ac
commit 9efae59c3c
27 changed files with 122 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
//! Sub-phase 4c integration tests for advanced-mode SQL
//! `DROP TABLE [IF EXISTS]` (ADR-0035 §4).
//!
//! `SqlDropTable` executes through the same `do_drop_table` machinery
//! as the simple `drop table` (cascade / inbound-relationship refusal /
//! metadata cleanup); the only new behaviour is `IF EXISTS` as a
//! no-op-with-note (`DropOutcome::Skipped`). These drive the worker
//! directly; parsing (text → `Command::SqlDropTable`) is covered by the
//! `sql_drop_table_tests` in `src/dsl/grammar/ddl.rs`.
use rdbms_playground::db::{Database, DropOutcome};
use rdbms_playground::dsl::{ColumnSpec, SqlForeignKey, Type, Value};
use rdbms_playground::persistence::Persistence;
use rdbms_playground::project;
fn rt() -> tokio::runtime::Runtime {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("tokio rt")
}
fn open(undo: bool) -> (project::Project, Database, tempfile::TempDir) {
let dir = tempfile::tempdir().expect("create tempdir");
let project =
project::open_or_create(None, Some(dir.path())).expect("open or create project");
let persistence = Persistence::new(project.path().to_path_buf());
let db = Database::open_with_persistence_and_undo(project.db_path(), persistence, undo)
.expect("open db with persistence");
(project, db, dir)
}
/// Create a simple `T (id int primary key, body text)`.
fn make_t(db: &Database, r: &tokio::runtime::Runtime) {
r.block_on(db.sql_create_table(
"T".to_string(),
vec![ColumnSpec::new("id", Type::Int), ColumnSpec::new("body", Type::Text)],
vec!["id".to_string()],
vec![],
vec![],
vec![],
false,
Some("create table T (id int primary key, body text)".to_string()),
))
.expect("create T");
}
#[test]
fn drop_table_removes_an_existing_table() {
let (_p, db, _d) = open(false);
let r = rt();
make_t(&db, &r);
let out = r
.block_on(db.sql_drop_table("T".to_string(), false, Some("drop table T".to_string())))
.expect("drop");
assert!(matches!(out, DropOutcome::Dropped));
assert!(!r.block_on(db.list_tables()).unwrap().contains(&"T".to_string()));
}
#[test]
fn if_exists_on_an_absent_table_is_a_noop_and_journalled() {
let (p, db, _d) = open(false);
let r = rt();
let line = "drop table if exists Ghost";
let out = r
.block_on(db.sql_drop_table("Ghost".to_string(), true, Some(line.to_string())))
.expect("IF EXISTS on an absent table succeeds as a no-op");
assert!(matches!(out, DropOutcome::Skipped));
// The no-op is still journalled (ADR-0034), like the create-skip.
let log = std::fs::read_to_string(p.path().join("history.log")).expect("read history.log");
assert!(log.contains(line), "the skipped drop should be journalled; log:\n{log}");
}
#[test]
fn plain_drop_of_an_absent_table_errors() {
let (_p, db, _d) = open(false);
let r = rt();
let res = r.block_on(db.sql_drop_table("Ghost".to_string(), false, Some("drop table Ghost".to_string())));
assert!(res.is_err(), "plain DROP TABLE on an absent table errors (no IF EXISTS)");
}
#[test]
fn dropping_a_referenced_parent_is_refused() {
// Parity with `do_drop_table`: a table with inbound relationships
// can't be dropped (ADR-0013), via the SQL path too.
let (_p, db, _d) = open(false);
let r = rt();
r.block_on(db.sql_create_table(
"parent".to_string(),
vec![ColumnSpec::new("id", Type::Serial), ColumnSpec::new("label", Type::Text)],
vec!["id".to_string()],
vec![],
vec![],
vec![],
false,
Some("create table parent (id serial primary key, label text)".to_string()),
))
.expect("create parent");
r.block_on(db.sql_create_table(
"child".to_string(),
vec![ColumnSpec::new("id", Type::Serial), ColumnSpec::new("pid", Type::Int)],
vec!["id".to_string()],
vec![],
vec![],
vec![SqlForeignKey {
name: None,
child_column: "pid".to_string(),
parent_table: "parent".to_string(),
parent_column: Some("id".to_string()),
on_delete: rdbms_playground::dsl::ReferentialAction::NoAction,
on_update: rdbms_playground::dsl::ReferentialAction::NoAction,
}],
false,
Some("create table child (id serial primary key, pid int references parent(id))".to_string()),
))
.expect("create child with FK");
// The parent is referenced — refused (even with IF EXISTS, since the
// table *does* exist; the refusal is about the relationship).
assert!(
r.block_on(db.sql_drop_table("parent".to_string(), false, Some("drop table parent".to_string())))
.is_err(),
"a referenced parent can't be dropped"
);
// Dropping the child first succeeds, then the parent.
r.block_on(db.sql_drop_table("child".to_string(), false, Some("drop table child".to_string())))
.expect("drop child");
r.block_on(db.sql_drop_table("parent".to_string(), false, Some("drop table parent".to_string())))
.expect("now the parent drops");
}
#[test]
fn drop_table_is_one_undo_step_and_restores_data() {
let (_p, db, _d) = open(true); // undo enabled
let r = rt();
make_t(&db, &r);
r.block_on(db.insert(
"T".to_string(),
Some(vec!["id".to_string(), "body".to_string()]),
vec![Value::Number("1".to_string()), Value::Text("hi".to_string())],
Some("insert".to_string()),
))
.expect("row");
r.block_on(db.sql_drop_table("T".to_string(), false, Some("drop table T".to_string())))
.expect("drop");
assert!(!r.block_on(db.list_tables()).unwrap().contains(&"T".to_string()));
// One undo brings the table — and its row — back.
assert!(r.block_on(db.undo()).expect("undo").is_some(), "the drop was one undo step");
assert!(r.block_on(db.list_tables()).unwrap().contains(&"T".to_string()));
let data = r
.block_on(db.query_data("T".to_string(), None, None, None))
.expect("query");
assert_eq!(data.rows.len(), 1, "the dropped row was restored by undo");
}