use super::*;
#[test]
fn test_no_config_path_opens_with_core_defaults() {
let dir = tempfile::tempdir().expect("test: temp dir");
let db = open_database_with_config(dir.path(), None).expect("test: open without config");
assert_eq!(
db.config().limits.max_collections,
velesdb_core::config::LimitsConfig::default().max_collections
);
}
#[test]
fn test_no_config_path_reads_the_default_file_when_present() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let default_file = toml_dir.path().join("velesdb.toml");
std::fs::write(&default_file, "[limits]\nmax_collections = 3\n").expect("test: write config");
let db = open_database_with_default_file(dir.path(), None, &default_file)
.expect("test: open with default file");
assert_eq!(db.config().limits.max_collections, 3);
}
#[test]
fn test_explicit_config_path_wins_over_the_default_file() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let default_file = toml_dir.path().join("velesdb.toml");
let explicit = toml_dir.path().join("explicit.toml");
std::fs::write(&default_file, "[limits]\nmax_collections = 3\n").expect("test: write config");
std::fs::write(&explicit, "[limits]\nmax_collections = 5\n").expect("test: write config");
let db = open_database_with_default_file(dir.path(), Some(&explicit), &default_file)
.expect("test: open with explicit config");
assert_eq!(db.config().limits.max_collections, 5);
}
#[test]
fn test_invalid_default_file_is_an_error_naming_the_key_and_its_implicit_origin() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let default_file = toml_dir.path().join("velesdb.toml");
std::fs::write(&default_file, "[limits]\nmax_collections = 0\n").expect("test: write config");
let err = match open_database_with_default_file(dir.path(), None, &default_file) {
Err(e) => e,
Ok(_) => panic!("test: an invalid default file must fail, not fall back to defaults"),
};
let msg = err.to_string();
assert!(
msg.contains("limits.max_collections"),
"unexpected error: {msg}"
);
assert!(
msg.contains("working directory") && msg.contains("--config <file>"),
"an implicit file must say where it came from and how to override it: {msg}"
);
}
#[test]
fn test_invalid_explicit_config_does_not_claim_an_implicit_origin() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let default_file = toml_dir.path().join("velesdb.toml");
let explicit = toml_dir.path().join("explicit.toml");
std::fs::write(&default_file, "[limits]\nmax_collections = 3\n").expect("test: write config");
std::fs::write(&explicit, "[limits]\nmax_collections = 0\n").expect("test: write config");
let err = match open_database_with_default_file(dir.path(), Some(&explicit), &default_file) {
Err(e) => e,
Ok(_) => panic!("test: an invalid explicit config must fail fast"),
};
let msg = err.to_string();
assert!(
msg.contains("limits.max_collections"),
"unexpected error: {msg}"
);
assert!(
!msg.contains("working directory"),
"an explicit path was named by the caller, no origin hint: {msg}"
);
}
#[test]
fn test_server_style_default_file_is_tolerated_and_its_limit_enforced() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let default_file = toml_dir.path().join("velesdb.toml");
std::fs::write(
&default_file,
"[server]\nhost = \"0.0.0.0\"\nport = 443\n\n[auth]\napi_keys = [\"k\"]\n\n[limits]\nmax_collections = 1\n",
)
.expect("test: write config");
let db = open_database_with_default_file(dir.path(), None, &default_file)
.expect("test: a server-style default file must not block the open");
assert_eq!(db.config().limits.max_collections, 1);
db.create_vector_collection("first", 4, velesdb_core::DistanceMetric::Cosine)
.expect("test: first collection is within the cap");
let err = db
.create_vector_collection("second", 4, velesdb_core::DistanceMetric::Cosine)
.expect_err("test: the configured cap must be enforced");
assert!(
err.to_string().contains("max_collections"),
"unexpected error: {err}"
);
}
#[test]
fn test_custom_toml_limit_is_actually_enforced_not_just_parsed() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let config_path = toml_dir.path().join("velesdb.toml");
std::fs::write(&config_path, "[limits]\nmax_collections = 1\n").expect("test: write config");
let db = open_database_with_config(dir.path(), Some(&config_path))
.expect("test: open with custom config");
assert_eq!(db.config().limits.max_collections, 1);
db.create_vector_collection_with_options(
"first",
4,
velesdb_core::DistanceMetric::Cosine,
velesdb_core::StorageMode::Full,
)
.expect("test: first collection under the limit should succeed");
let err = db
.create_vector_collection_with_options(
"second",
4,
velesdb_core::DistanceMetric::Cosine,
velesdb_core::StorageMode::Full,
)
.expect_err("test: second collection should be refused by the configured limit");
assert!(
err.to_string().contains("max_collections"),
"unexpected error: {err}"
);
}
#[test]
fn test_shell_owned_server_section_does_not_block_cli_open() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let config_path = toml_dir.path().join("velesdb.toml");
std::fs::write(
&config_path,
"[server]\nport = 443\n\n[limits]\nmax_collections = 5\n",
)
.expect("test: write config");
let db = open_database_with_config(dir.path(), Some(&config_path))
.expect("a shell-owned [server] port=443 must not block CLI database open");
assert_eq!(db.config().limits.max_collections, 5);
}
#[test]
fn test_explicit_missing_config_path_fails_fast_no_silent_default() {
let dir = tempfile::tempdir().expect("test: temp dir");
let missing = std::path::Path::new("/nonexistent/velesdb-issue-1549.toml");
let err = match open_database_with_config(dir.path(), Some(missing)) {
Err(e) => e,
Ok(_) => panic!("test: missing explicit config path must error, not fall back"),
};
assert!(
err.to_string().contains("config file not found"),
"unexpected error: {err}"
);
}
#[test]
fn test_invalid_config_value_surfaces_typed_config_error_fail_fast() {
let dir = tempfile::tempdir().expect("test: temp dir");
let toml_dir = tempfile::tempdir().expect("test: config dir");
let config_path = toml_dir.path().join("velesdb.toml");
std::fs::write(&config_path, "[limits]\nmax_collections = 0\n").expect("test: write config");
let err = match open_database_with_config(dir.path(), Some(&config_path)) {
Err(e) => e,
Ok(_) => panic!("test: invalid value must fail fast, not silently default"),
};
assert!(
err.to_string().contains("limits.max_collections"),
"unexpected error: {err}"
);
}
#[test]
fn test_point_payload_to_row_with_payload() {
let payload = Some(serde_json::json!({
"title": "Hello",
"score": 0.95
}));
let row = point_payload_to_row(42, &payload);
assert_eq!(row.get("id"), Some(&serde_json::json!(42)));
assert_eq!(row.get("title"), Some(&serde_json::json!("Hello")));
assert_eq!(row.get("score"), Some(&serde_json::json!(0.95)));
assert_eq!(row.len(), 3);
}
#[test]
fn test_point_payload_to_row_without_payload() {
let row = point_payload_to_row(7, &None);
assert_eq!(row.get("id"), Some(&serde_json::json!(7)));
assert_eq!(row.len(), 1);
}
#[test]
fn test_point_payload_to_browse_row_truncates() {
let long_string = "a".repeat(80);
let payload = Some(serde_json::json!({
"content": long_string,
"short": "ok"
}));
let row = point_payload_to_browse_row(1, &payload);
assert_eq!(row.get("id"), Some(&serde_json::json!(1)));
assert_eq!(row.get("short"), Some(&serde_json::json!("ok")));
let content = row.get("content").unwrap().as_str().unwrap();
assert_eq!(content.len(), 50);
assert!(content.ends_with("..."));
}
#[test]
fn test_truncate_display_value_short_string() {
let val = serde_json::json!("short text");
let result = truncate_display_value(&val);
assert_eq!(result, serde_json::json!("short text"));
}
#[test]
fn test_truncate_display_value_long_string() {
let long = "x".repeat(100);
let result = truncate_display_value(&serde_json::json!(long));
let s = result.as_str().unwrap();
assert_eq!(s.len(), 50);
assert!(s.ends_with("..."));
assert!(s.starts_with("xxxxxxx"));
}