use kevy_resp::ops_table::{KNOWN_GAPS, NotifyKind, OP_TABLE, surface};
use crate::verb_meta::VERB_META;
use kevy_rt::NotifyClass;
use crate::cmd::{is_growing_write_verb, is_write_verb, notify_class_for_verb};
use crate::cmd_block::wake_idx_for_verb;
#[test]
fn is_write_verb_matches_table() {
for o in OP_TABLE {
if o.surfaces & surface::SERVER == 0 {
continue; }
assert_eq!(
is_write_verb(o.name.as_bytes()),
o.write,
"{}: is_write_verb disagrees with OP_TABLE.write",
o.name
);
}
}
#[test]
fn is_growing_write_verb_matches_table() {
for o in OP_TABLE {
if o.surfaces & surface::SERVER == 0 {
continue;
}
assert_eq!(
is_growing_write_verb(o.name.as_bytes()),
o.growing,
"{}: is_growing_write_verb disagrees with OP_TABLE.growing",
o.name
);
}
}
#[test]
fn notify_class_matches_table() {
for o in OP_TABLE {
if o.surfaces & surface::SERVER == 0 {
continue;
}
let got = notify_class_for_verb(o.name.as_bytes());
let want = o.notify;
let matches = matches!(
(got, want),
(None, None)
| (Some(NotifyClass::String), Some(NotifyKind::String))
| (Some(NotifyClass::Hash), Some(NotifyKind::Hash))
| (Some(NotifyClass::List), Some(NotifyKind::List))
| (Some(NotifyClass::Set), Some(NotifyKind::Set))
| (Some(NotifyClass::Zset), Some(NotifyKind::Zset))
| (Some(NotifyClass::Stream), Some(NotifyKind::Stream))
| (Some(NotifyClass::Generic), Some(NotifyKind::Generic))
);
assert!(
matches,
"{}: notify_class_for_verb = {:?}, OP_TABLE.notify = {:?}",
o.name, got, want
);
}
}
#[test]
fn wake_set_matches_table() {
for o in OP_TABLE {
if o.surfaces & surface::SERVER == 0 {
continue;
}
assert_eq!(
wake_idx_for_verb(o.name.as_bytes()),
o.wake_idx,
"{}: wake_idx_for_verb disagrees with OP_TABLE.wake_idx",
o.name
);
}
}
fn server_sources() -> (String, usize) {
fn walk(dir: &std::path::Path, out: &mut String, files: &mut usize) {
let entries = std::fs::read_dir(dir).expect("the crate's src/ is readable");
for e in entries {
let path = e.expect("a directory entry").path();
if path.is_dir() {
walk(&path, out, files);
} else if path.extension().is_some_and(|x| x == "rs") {
let name = path.file_name().unwrap_or_default().to_string_lossy().to_string();
if name.starts_with("tests") || name.contains("_tests") {
continue;
}
let text = std::fs::read_to_string(&path).expect("a source file is readable");
out.push_str(&text);
*files += 1;
}
}
}
let (mut out, mut files) = (String::new(), 0);
walk(std::path::Path::new("src"), &mut out, &mut files);
(out, files)
}
#[test]
fn server_surface_has_dispatch_literals() {
let (sources, files) = server_sources();
let bytes = sources.len();
assert!(files > 20, "the source walk found {files} files — it is broken, not the server empty");
assert!(bytes > 200_000, "the source walk read {bytes} bytes — it is broken");
for o in OP_TABLE {
if o.surfaces & surface::SERVER == 0 {
continue;
}
let lit = format!("b\"{}\"", o.name);
assert!(
sources.contains(&lit),
"{}: OP_TABLE flags SERVER but no dispatch file contains {lit}",
o.name
);
}
for (name, flag, _) in KNOWN_GAPS {
if flag & surface::SERVER == 0 {
continue;
}
let lit = format!("b\"{name}\"");
assert!(
!sources.contains(&lit),
"{name}: ledgered as a SERVER gap but a dispatch literal exists — close the ledger entry"
);
}
}
const NON_KEYSPACE_GROUPS: &[&str] = &["connection", "tx", "pubsub", "script", "replication"];
const ADMIN_VERBS: &[&str] = &[
"BGREWRITEAOF",
"BGSAVE",
"CLIENT",
"CLUSTER",
"COMMAND",
"CONFIG",
"DEBUG",
"INFO",
"MEMORY",
"SAVE",
"SHUTDOWN",
"SLOWLOG",
];
#[test]
fn every_keyspace_verb_has_a_registry_row() {
use std::collections::BTreeSet;
let rows: BTreeSet<&str> = OP_TABLE.iter().map(|o| o.name).collect();
let groups: BTreeSet<&str> = NON_KEYSPACE_GROUPS.iter().copied().collect();
let admin: BTreeSet<&str> = ADMIN_VERBS.iter().copied().collect();
assert!(VERB_META.len() > 150, "VERB_META did not load");
let missing: Vec<&str> = VERB_META
.iter()
.filter(|m| !groups.contains(m.group) && !admin.contains(m.name) && !rows.contains(m.name))
.map(|m| m.name)
.collect();
assert!(
missing.is_empty(),
"{missing:?} are documented keyspace verbs with no OP_TABLE row — add the row, or \
name the verb in ADMIN_VERBS with its reason"
);
let healed_groups: Vec<&str> = NON_KEYSPACE_GROUPS
.iter()
.filter(|g| VERB_META.iter().any(|m| m.group == **g && rows.contains(m.name)))
.copied()
.collect();
assert!(
healed_groups.is_empty(),
"{healed_groups:?} are named as carrying no keyspace semantics but have rows now"
);
let healed_verbs: Vec<&str> =
ADMIN_VERBS.iter().filter(|v| rows.contains(*v)).copied().collect();
assert!(
healed_verbs.is_empty(),
"{healed_verbs:?} are named as administrative but have rows now — drop them from \
ADMIN_VERBS so the ledger stays exact"
);
}