crates/mimir-schema/tests/schema_and_moniker.rs
//! mimir-schema unit tests: schemas, vocabularies, and BYTE-IDENTITY of the moved
//! moniker formatter against the pre-move `nornir::coderoom` code.
use mimir_schema::moniker::{self, Suffix};
use mimir_schema::*;
/// VERBATIM copy of the pre-move formatter in `nornir/src/coderoom.rs`
/// (origin/main c18e6d1, lines 516–556) — the ORACLE. The moved code must
/// produce the same bytes for every (kind, name, scope) it ever saw.
mod oracle {
pub fn scip_descriptor(kind: &str, name: &str) -> Option<String> {
let n = escape_scip_name(name);
Some(match kind {
"mod" => format!("{n}/"),
"struct" | "enum" | "trait" | "type" => format!("{n}#"),
"fn" | "method" => format!("{n}()."),
"const" | "static" => format!("{n}."),
"macro" => format!("{n}!"),
_ => return None,
})
}
pub fn escape_scip_name(name: &str) -> String {
if name
.chars()
.all(|c| c == '_' || c == '+' || c == '-' || c == '$' || c.is_ascii_alphanumeric())
{
name.to_string()
} else {
format!("`{}`", name.replace('`', "``"))
}
}
pub fn scip_moniker(krate: &str, version: &str, kind: &str, scope: &str, name: &str) -> Option<String> {
let desc = scip_descriptor(kind, name)?;
Some(format!("rust-analyzer cargo {krate} {version} {}{desc}", scope))
}
}
/// What `coderoom::scip_moniker` now does (scope + one descriptor via mimir-schema).
fn moved(krate: &str, version: &str, kind: &str, scope: &str, name: &str) -> Option<String> {
let desc = moniker::descriptor_for_kind(kind, name)?;
Some(moniker::moniker(krate, version, &format!("{scope}{desc}")))
}
const KINDS: &[&str] = &[
"fn", "method", "struct", "enum", "trait", "type", "const", "static", "macro", "mod", "impl",
"union", "", "variant",
];
const NAMES: &[&str] = &[
"foo", "Foo", "r#type", "with space", "back`tick", "dash-ok", "plus+ok", "$dollar", "ünï",
"", "0", "a::b", "`", "``x``", "_", "Self",
];
const SCOPES: &[&str] = &["", "m/", "m/B#", "a/b/c/", "`weird name`/T#", "Trait#"];
#[test]
fn moved_formatter_is_byte_identical_to_coderoom() {
let mut checked = 0;
for k in KINDS {
for n in NAMES {
for s in SCOPES {
for (krate, ver) in [("a", "1.0.0"), ("serde_json", "1.0.145"), ("x", "?")] {
assert_eq!(
moved(krate, ver, k, s, n),
oracle::scip_moniker(krate, ver, k, s, n),
"kind={k:?} name={n:?} scope={s:?}"
);
checked += 1;
}
}
}
for n in NAMES {
assert_eq!(moniker::escape_name(n), oracle::escape_scip_name(n));
}
}
assert_eq!(checked, KINDS.len() * NAMES.len() * SCOPES.len() * 3);
}
#[test]
fn coderoom_fixture_monikers_unchanged() {
// The literal strings coderoom's own tests pin (coderoom.rs tests, c18e6d1).
assert_eq!(
moved("a", "1.0.0", "fn", "", "foo").unwrap(),
"rust-analyzer cargo a 1.0.0 foo()."
);
assert_eq!(
moved("a", "1.0.0", "method", "m/B#", "go").unwrap(),
"rust-analyzer cargo a 1.0.0 m/B#go()."
);
// coderoom's inherent-impl scope is now rust-analyzer's `impl#[B]`
assert_eq!(
moved("a", "1.0.0", "method", &format!("m/{}", moniker::impl_descriptor("B", None)), "go").unwrap(),
"rust-analyzer cargo a 1.0.0 m/impl#[B]go()."
);
assert_eq!(moved("a", "1.0.0", "mod", "", "m").unwrap(), "rust-analyzer cargo a 1.0.0 m/");
}
#[test]
fn every_suffix_renders_the_scip_grammar() {
let cases = [
(Suffix::Namespace, "m/"),
(Suffix::Type, "m#"),
(Suffix::Term, "m."),
(Suffix::Method, "m()."),
(Suffix::TypeParameter, "[m]"),
(Suffix::Parameter, "(m)"),
(Suffix::Meta, "m:"),
(Suffix::Macro, "m!"),
];
for (s, want) in cases {
assert_eq!(moniker::descriptor(s, "m"), want);
}
assert_eq!(moniker::descriptor(Suffix::TypeParameter, "Vec<T>"), "[`Vec<T>`]");
}
#[test]
fn parse_round_trips() {
let m = moniker::moniker("skade", "0.3.1", "store/Table#open().");
assert_eq!(m, "rust-analyzer cargo skade 0.3.1 store/Table#open().");
assert_eq!(moniker::parse(&m), Some(("skade", "0.3.1", "store/Table#open().")));
assert_eq!(
moniker::parse(&moniker::crate_moniker("a", "?")),
Some(("a", "?", "crate/"))
);
assert_eq!(moniker::parse("scip-java maven x 1 a#"), None);
}
#[test]
fn vocabularies_round_trip() {
for k in EdgeKind::ALL {
assert_eq!(EdgeKind::parse(k.as_str()), Some(*k));
}
assert_eq!(EdgeKind::ALL.len(), 18);
assert_eq!(EdgeKind::CfgSucc.as_str(), "CFG_SUCC");
assert_eq!(EdgeKind::InstanceOf.as_str(), "INSTANCE_OF");
for l in Level::ALL {
assert_eq!(Level::parse(l.as_str()), Some(*l));
}
for o in Origin::ALL {
assert_eq!(Origin::parse(o.as_str()), Some(*o));
}
for p in Provenance::ALL {
assert_eq!(Provenance::parse(p.as_str()), Some(*p));
}
assert_eq!(Provenance::SourceOnly.as_str(), "source_only");
}
#[test]
fn schemas_have_the_plan_columns() {
let n = nodes_schema();
for c in [
"id", "kind", "level", "parent", "repo", "crate", "version", "file", "start_line",
"end_line", "cfg", "origin", "provenance", "valid_from_sha", "valid_to_sha",
] {
assert!(n.field_with_name(c).is_ok(), "code_nodes lacks {c}");
}
let e = edges_schema();
for c in ["from", "to", "kind", "count", "provenance", "valid_from_sha", "valid_to_sha"] {
assert!(e.field_with_name(c).is_ok(), "code_edges lacks {c}");
}
// Positions are not edge identity: no file / line on an edge.
assert!(e.field_with_name("line").is_err() && e.field_with_name("file").is_err());
let s = spans_schema();
for c in ["target", "key", "file", "start_line", "end_line"] {
assert!(s.field_with_name(c).is_ok(), "code_spans lacks {c}");
}
assert_eq!(n.metadata().get(META_TABLE).map(String::as_str), Some("code_nodes"));
assert_eq!(e.metadata().get(META_TABLE).map(String::as_str), Some("code_edges"));
}
#[test]
fn batches_build() {
let node = NodeRow {
id: moniker::crate_moniker("a", "0.1.0"),
kind: kind::CRATE.into(),
level: Level::Crate,
name: "a".into(),
parent: None,
repo: Some("fixture".into()),
krate: "a".into(),
version: "0.1.0".into(),
file: Some("a/src/lib.rs".into()),
start_line: Some(1),
end_line: Some(9),
cfg: None,
origin: Origin::Local,
provenance: Provenance::SourceOnly,
valid_from_sha: Some("deadbeef".into()),
valid_to_sha: None,
ty: None,
is_test: false,
defined_here: true,
visibility: Some(visibility::PUB.into()),
effective_visibility: Some(EffectiveVisibility::Direct),
doc: Some("fixture crate a".into()),
has_doc: Some(true),
ignored: None,
doc_hidden: None,
link_name: None,
};
let b = nodes_batch(&[node.clone(), node]).unwrap();
assert_eq!(b.num_rows(), 2);
assert_eq!(b.schema(), nodes_schema());
let e = edges_batch(&[EdgeRow {
from: "x".into(),
to: "y".into(),
kind: EdgeKind::Calls,
count: 2,
provenance: Provenance::SourceOnly,
valid_from_sha: None,
valid_to_sha: None,
negated: None,
partial: None,
access: None,
}])
.unwrap();
assert_eq!(e.num_rows(), 1);
assert_eq!(e.schema(), edges_schema());
let sp = spans_batch(&[SpanRow {
target: SPAN_EDGE,
key: edge_key("x", "y", EdgeKind::Calls),
file: "a/src/lib.rs".into(),
start_line: 3,
end_line: 3,
}])
.unwrap();
assert_eq!(sp.schema(), spans_schema());
assert!(!edge_key("x", "y", EdgeKind::Calls).contains('\u{1f}'), "edge keys must not use the log's key separator");
}
/// BYTE-IDENTITY with rust-analyzer: symbols copied verbatim from
/// `rust-analyzer scip` (rust-analyzer 1.101.0-nightly 2822155 2026-10-04) run
/// over crates/mimir-driver/tests/fixture, rebuilt here through the formatter.
#[test]
fn formatter_reproduces_rust_analyzer_scip_symbols() {
let a = |d: &str| moniker::moniker("a", "0.1.0", d);
let b = |d: &str| moniker::moniker("b", "0.2.0", d);
let core = |d: &str| moniker::moniker("core", &moniker::lang_version("core"), d);
let alloc = |d: &str| moniker::moniker("alloc", &moniker::lang_version("alloc"), d);
let cases: Vec<(String, &str)> = vec![
(a(moniker::CRATE_ROOT_DESCRIPTOR), "rust-analyzer cargo a 0.1.0 crate/"),
(a(&format!("{}{}", moniker::impl_descriptor("Point", None), moniker::descriptor(Suffix::Method, "new"))),
"rust-analyzer cargo a 0.1.0 impl#[Point]new()."),
(b(&format!("{}{}", moniker::impl_descriptor("Dog", Some("Greet")), moniker::descriptor(Suffix::Method, "greet"))),
"rust-analyzer cargo b 0.2.0 impl#[Dog][Greet]greet()."),
(a(&format!("{}{}", moniker::descriptor(Suffix::Type, "Point"), moniker::descriptor(Suffix::Term, "x"))),
"rust-analyzer cargo a 0.1.0 Point#x."),
(a(&format!("{}{}", moniker::descriptor(Suffix::Type, "Greet"), moniker::descriptor(Suffix::Method, "greet"))),
"rust-analyzer cargo a 0.1.0 Greet#greet()."),
(a(&moniker::descriptor(Suffix::Macro, "twice")), "rust-analyzer cargo a 0.1.0 twice!"),
(a(&format!("{}{}", moniker::descriptor(Suffix::Namespace, "tests"), moniker::descriptor(Suffix::Method, "adds"))),
"rust-analyzer cargo a 0.1.0 tests/adds()."),
(core(&format!("ops/arith/{}{}", moniker::impl_descriptor("i32", Some("Add<Self>")), moniker::descriptor(Suffix::Method, "add"))),
"rust-analyzer cargo core https://github.com/rust-lang/rust/library/core ops/arith/impl#[i32][`Add<Self>`]add()."),
(core(&format!("convert/{}{}", moniker::impl_descriptor("T", Some("Into<U>")), moniker::descriptor(Suffix::Method, "into"))),
"rust-analyzer cargo core https://github.com/rust-lang/rust/library/core convert/impl#[T][`Into<U>`]into()."),
(core(&format!("fmt/macros/{}", moniker::descriptor(Suffix::Meta, "Debug"))),
"rust-analyzer cargo core https://github.com/rust-lang/rust/library/core fmt/macros/Debug:"),
(alloc(&format!("string/{}{}", moniker::impl_descriptor("String", None), moniker::descriptor(Suffix::Method, "len"))),
"rust-analyzer cargo alloc https://github.com/rust-lang/rust/library/alloc string/impl#[String]len()."),
];
for (ours, ra) in cases {
assert_eq!(ours, ra);
}
}
/// The binary layer's table: linker facts keyed on the node moniker.
#[test]
fn symbols_table_and_mono_instance_ids() {
let s = symbols_schema();
for c in ["id", "symbol", "demangled", "role", "crate", "version", "binary", "section", "addr", "size", "provenance"] {
assert!(s.field_with_name(c).is_ok(), "code_symbols lacks {c}");
}
assert_eq!(s.field_with_name("addr").unwrap().data_type(), &arrow_schema::DataType::UInt64);
assert_eq!(s.metadata().get(META_TABLE).map(String::as_str), Some("code_symbols"));
let row = SymbolRow {
id: moniker::moniker("a", "0.1.0", "add()."),
symbol: "_RNvCs1234_1a3add".into(),
demangled: Some("a::add".into()),
role: role::ITEM.into(),
krate: "a".into(),
version: "0.1.0".into(),
binary: Some("bctl".into()),
section: Some(".text".into()),
addr: Some(0x1000),
size: Some(42),
provenance: Provenance::Both,
valid_from_sha: None,
valid_to_sha: None,
};
let driver_row = SymbolRow { binary: None, section: None, addr: None, size: None, provenance: Provenance::SourceOnly, ..row.clone() };
let b = symbols_batch(&[row, driver_row]).unwrap();
assert_eq!(b.num_rows(), 2);
assert_eq!(b.schema(), symbols_schema());
// a mono instance id: the generic item's moniker + a meta descriptor
let g = moniker::moniker("a", "0.1.0", "ident().");
let m = moniker::mono_instance(&g, "a::ident::<u32>");
assert_eq!(m, "rust-analyzer cargo a 0.1.0 ident().`a::ident::<u32>`:");
assert!(m.starts_with(&g));
assert_eq!(moniker::parse(&m), Some(("a", "0.1.0", "ident().`a::ident::<u32>`:")));
}
#[test]
fn provenance_is_derived_from_the_two_streams() {
use mimir_schema::{derive_provenance, BinaryFacts, Provenance};
let none = BinaryFacts::default();
let sym = BinaryFacts { has_symbol: true, ..none };
let inst = BinaryFacts { instances_linked: true, ..none };
let node = BinaryFacts { binary_node: true, ..none };
assert_eq!(derive_provenance(true, none), Some(Provenance::SourceOnly));
assert_eq!(derive_provenance(true, sym), Some(Provenance::Both));
assert_eq!(derive_provenance(true, inst), Some(Provenance::Both), "generic item with a linked instance");
assert_eq!(derive_provenance(true, node), Some(Provenance::Both));
assert_eq!(derive_provenance(false, node), Some(Provenance::BinaryOnly));
assert_eq!(derive_provenance(false, sym), Some(Provenance::BinaryOnly));
assert_eq!(derive_provenance(false, none), None);
}
// ---------------------------------------------------------------- schema 2
#[test]
fn schema_2_columns_are_additive_and_nullable() {
let n = nodes_schema();
// appended AFTER the schema-1 columns, in this order, all nullable
let names: Vec<&str> = n.fields().iter().map(|f| f.name().as_str()).collect();
let at = names.iter().position(|c| *c == "defined_here").unwrap();
assert_eq!(&names[at + 1..at + 5], ["visibility", "effective_visibility", "doc", "has_doc"]);
for c in ["visibility", "effective_visibility", "doc", "has_doc"] {
assert!(n.field_with_name(c).unwrap().is_nullable(), "{c} must be nullable (reference stubs know none of it)");
}
assert_eq!(n.field_with_name("has_doc").unwrap().data_type(), &arrow_schema::DataType::Boolean);
let e = edges_schema();
let enames: Vec<&str> = e.fields().iter().map(|f| f.name().as_str()).collect();
let at = enames.iter().position(|c| *c == "valid_to_sha").unwrap();
assert_eq!(&enames[at + 1..at + 3], ["negated", "partial"]);
assert!(e.field_with_name("negated").unwrap().is_nullable() && e.field_with_name("partial").unwrap().is_nullable());
}
// ---------------------------------------------------------------- schema 3
/// Schema 3 only ADDS, at the end, nullable: that is what lets `mimir-ingest`
/// evolve a schema-2 lake in place instead of refusing it.
#[test]
fn schema_3_columns_are_appended_and_nullable() {
let n = nodes_schema();
let names: Vec<&str> = n.fields().iter().map(|f| f.name().as_str()).collect();
assert_eq!(&names[names.len() - 4..names.len() - 1], ["has_doc", "ignored", "doc_hidden"]);
for c in ["ignored", "doc_hidden"] {
let f = n.field_with_name(c).unwrap();
assert!(f.is_nullable() && f.data_type() == &arrow_schema::DataType::Boolean, "{c}");
}
// three values each: yes, no, and "no such notion here" (null)
use arrow_array::cast::AsArray;
use arrow_array::Array;
let mut heavy = NodeRow::new("k slow().", kind::FN, Level::Item, "slow", "k", "0.1.0", Origin::Local);
heavy.is_test = true;
heavy.ignored = Some(true);
heavy.doc_hidden = Some(false);
let plain = NodeRow::new("k f().", kind::FN, Level::Item, "f", "k", "0.1.0", Origin::Local);
let b = nodes_batch(&[heavy, plain]).unwrap();
let (ignored, hidden) = (b.column_by_name("ignored").unwrap().as_boolean(), b.column_by_name("doc_hidden").unwrap().as_boolean());
assert!(ignored.value(0) && !hidden.value(0) && !hidden.is_null(0));
assert!(ignored.is_null(1) && hidden.is_null(1));
}
#[test]
fn schema_2_values_reach_the_batch() {
use arrow_array::cast::AsArray;
use arrow_array::Array;
let mut documented = NodeRow::new("k f().", kind::FN, Level::Item, "f", "k", "0.1.0", Origin::Local);
documented.visibility = Some(visibility::pub_in("a::b"));
documented.effective_visibility = Some(EffectiveVisibility::Reexported);
documented.doc = doc_summary(" Opens the store.\n\n Long text.");
documented.has_doc = Some(true);
let mut stub = NodeRow::new("dep g().", kind::FN, Level::Item, "g", "dep", "1.0.0", Origin::Library);
stub.defined_here = false;
let b = nodes_batch(&[documented, stub]).unwrap();
let col = |c: &str| b.column_by_name(c).unwrap().clone();
assert_eq!(col("visibility").as_string::<i32>().value(0), "pub(in crate::a::b)");
assert_eq!(col("effective_visibility").as_string::<i32>().value(0), "reexported");
assert_eq!(col("doc").as_string::<i32>().value(0), "Opens the store.");
assert!(col("has_doc").as_boolean().value(0));
// a reference stub knows none of it: NULL, not `false` / ""
for c in ["visibility", "effective_visibility", "doc", "has_doc"] {
assert!(col(c).is_null(1), "{c} of a reference stub must be null");
}
let mut gate = EdgeRow::new("k f().", moniker::feature("k", "0.1.0", "s3"), EdgeKind::GatedBy);
gate.negated = Some(true);
gate.partial = Some(false);
let e = edges_batch(&[gate, EdgeRow::new("a", "b", EdgeKind::Calls)]).unwrap();
let neg = e.column_by_name("negated").unwrap().as_boolean().clone();
assert!(neg.value(0) && neg.is_null(1), "negated is set on GATED_BY, null on every other kind");
let part = e.column_by_name("partial").unwrap().as_boolean().clone();
assert!(!part.is_null(0) && !part.value(0) && part.is_null(1), "partial likewise");
}
#[test]
fn schema_2_vocabularies_round_trip() {
for v in EffectiveVisibility::ALL {
assert_eq!(EffectiveVisibility::parse(v.as_str()), Some(*v));
}
assert_eq!(
EffectiveVisibility::ALL.iter().filter(|v| v.is_public_api()).map(|v| v.as_str()).collect::<Vec<_>>(),
["direct", "reexported"]
);
assert_eq!(EdgeKind::parse("ENABLES"), Some(EdgeKind::Enables));
assert_eq!(EdgeKind::parse("ENABLES_WEAK"), Some(EdgeKind::EnablesWeak));
assert_eq!(EdgeKind::GatedBy.as_str(), "GATED_BY");
// appended: the kinds that existed keep their position (mimir-room keys a
// bit mask on it), and the whole set still fits its u16
assert_eq!(EdgeKind::ALL.iter().position(|k| *k == EdgeKind::InstanceOf), Some(12));
assert_eq!(&EdgeKind::ALL[13..15], [EdgeKind::Enables, EdgeKind::EnablesWeak]);
// builder 2's BUILT_FROM (artifact → crate / feature / commit) is the 16th:
// the masks are full now
assert_eq!(EdgeKind::ALL[15], EdgeKind::BuiltFrom);
assert_eq!(EdgeKind::parse("BUILT_FROM"), Some(EdgeKind::BuiltFrom));
assert_eq!(moniker::parse(&moniker::artifact("ab12")), Some((moniker::ARTIFACT_PACKAGE, ".", "`artifact=ab12`:")));
assert_eq!(moniker::parse(&moniker::commit("edda", "284d87b2")), Some((moniker::COMMIT_PACKAGE, ".", "`commit=edda@284d87b2`:")));
// the system boundary's SYSCALLS is the 17th: past a u16 kind mask
// (mimir-room keys its masks on u32 since)
assert_eq!(EdgeKind::ALL[16], EdgeKind::Syscalls);
assert_eq!(EdgeKind::parse("SYSCALLS"), Some(EdgeKind::Syscalls));
assert!(EdgeKind::ALL.len() <= 32);
assert_eq!((visibility::PUB, visibility::PUB_CRATE, visibility::PRIVATE), ("pub", "pub(crate)", "private"));
assert_eq!((kind::FEATURE, kind::CFG_GATED_OUT), ("feature", "cfg_gated_out"));
}
#[test]
fn doc_summary_is_the_first_non_blank_line() {
assert_eq!(doc_summary(" libc `abs` — the extern \"C\" border."), Some("libc `abs` — the extern \"C\" border.".into()));
assert_eq!(doc_summary("\n\n second line is first\n third"), Some("second line is first".into()));
// a block comment's gutter
assert_eq!(doc_summary("*\n * Opens it.\n * More.\n "), Some("Opens it.".into()));
// markdown emphasis at the start of a line is not a gutter
assert_eq!(doc_summary(" *never* inlined"), Some("*never* inlined".into()));
assert_eq!(doc_summary(" \n\t\n"), None);
let long = "å".repeat(DOC_SUMMARY_MAX + 50);
let cut = doc_summary(&long).unwrap();
assert_eq!(cut.chars().count(), DOC_SUMMARY_MAX);
assert!(cut.ends_with('…'));
}
/// Two targets of one package never share an id: the lib has rust-analyzer's
/// ids, every other target is prefixed with its kind and crate name.
#[test]
fn targets_of_one_package_have_ids_of_their_own() {
assert_eq!(moniker::target_prefix("lib", "lgz"), "");
assert_eq!(moniker::target_prefix("proc-macro", "lgz_derive"), "");
assert_eq!(moniker::target_prefix("bin", "lgz"), "`bin=lgz`:");
assert_eq!(moniker::target_prefix("test", "deflate_scan"), "`test=deflate_scan`:");
assert_eq!(moniker::target_prefix("bench", "deflate_scan"), "`bench=deflate_scan`:");
// the default layout: `src/lib.rs` + `src/main.rs`, both crates called `lgz`
let id = |kind: &str, d: &str| moniker::moniker("lgz", "0.3.14", &format!("{}{d}", moniker::target_prefix(kind, "lgz")));
let all: Vec<String> = ["lib", "bin", "test", "bench", "example"].iter().flat_map(|k| [id(k, "crate/"), id(k, "main().")]).collect();
assert_eq!(all.iter().collect::<std::collections::BTreeSet<_>>().len(), all.len(), "{all:#?}");
assert_eq!(id("lib", "crate/"), moniker::crate_moniker("lgz", "0.3.14"), "the lib keeps rust-analyzer's id");
// parseable, and never an item's own descriptor (a macro named `bin`, a module named `test`)
assert_eq!(moniker::parse(&id("bin", "main().")), Some(("lgz", "0.3.14", "`bin=lgz`:main().")));
assert_ne!(id("bin", "crate/"), moniker::moniker("lgz", "0.3.14", "bin:lgz:crate/"));
assert_ne!(moniker::target_prefix("test", "x"), moniker::descriptor(Suffix::Meta, "test"));
}
#[test]
fn feature_and_gated_out_monikers() {
let f = moniker::feature("a", "0.1.0", "extra");
assert_eq!(f, "rust-analyzer cargo a 0.1.0 `feature=extra`:");
// never the id of an item: a module / derive macro named `feature` or
// `extra` formats differently
assert_ne!(f, moniker::moniker("a", "0.1.0", &moniker::descriptor(Suffix::Meta, "extra")));
assert_ne!(f, moniker::moniker("a", "0.1.0", "feature/extra:"));
assert_eq!(moniker::parse(&f), Some(("a", "0.1.0", "`feature=extra`:")));
// one node per crate@version
assert_ne!(f, moniker::feature("a", "0.0.9", "extra"));
assert_eq!(moniker::feature("tokio", "1.40.0", "rt-multi-thread"), "rust-analyzer cargo tokio 1.40.0 `feature=rt-multi-thread`:");
// the scope a node's children are named in
assert_eq!(moniker::child_scope("rust-analyzer cargo a 0.1.0 crate/"), "rust-analyzer cargo a 0.1.0 ");
assert_eq!(moniker::child_scope("rust-analyzer cargo b 0.2.0 `bin=bctl`:crate/"), "rust-analyzer cargo b 0.2.0 `bin=bctl`:");
assert_eq!(moniker::child_scope("rust-analyzer cargo a 0.1.0 store/"), "rust-analyzer cargo a 0.1.0 store/");
assert_eq!(moniker::child_scope("rust-analyzer cargo a 0.1.0 impl#[Point]"), "rust-analyzer cargo a 0.1.0 impl#[Point]");
let scope = moniker::child_scope("rust-analyzer cargo a 0.1.0 crate/");
let on = moniker::cfg_gated_out(scope, &moniker::descriptor(Suffix::Method, "f"), "cfg(feature = \"x\")");
let off = moniker::cfg_gated_out(scope, &moniker::descriptor(Suffix::Method, "f"), "cfg(not(feature = \"x\"))");
assert_eq!(on, "rust-analyzer cargo a 0.1.0 f().`cfg(feature = \"x\")`:");
// the usual on/off pair is two ids, and neither is the resolved item's id
assert_ne!(on, off);
assert_ne!(on, "rust-analyzer cargo a 0.1.0 f().");
assert!(on.starts_with("rust-analyzer cargo a 0.1.0 f()."));
assert_eq!(moniker::parse(&on).map(|p| (p.0, p.1)), Some(("a", "0.1.0")));
// a backtick in the predicate is escaped, the id stays one descriptor
let odd = moniker::cfg_gated_out(scope, "g().", "cfg(feature = \"a`b\")");
assert!(odd.ends_with("`cfg(feature = \"a``b\")`:"));
}
// ---------------------------------------------------------------- schema 4
/// Schema 4 ADDS one nullable column at the end of `code_edges` (`access`),
/// one at the end of `code_nodes` (`link_name`, its own test below) and two
/// values (node kind `table`, the table id): additions only, which is what
/// lets `mimir-ingest` evolve a schema-3 lake in place.
#[test]
fn schema_4_adds_access_at_the_end_of_edges() {
assert_eq!(SCHEMA_VERSION, "5"); // 5 changed identities (moniker::stable), no column
let e = edges_schema();
assert_eq!(e.metadata().get(META_SCHEMA).map(String::as_str), Some("5"));
let names: Vec<&str> = e.fields().iter().map(|f| f.name().as_str()).collect();
assert_eq!(names, ["from", "to", "kind", "count", "provenance", "valid_from_sha", "valid_to_sha", "negated", "partial", "access"]);
let f = e.field_with_name("access").unwrap();
assert!(f.is_nullable() && f.data_type() == &arrow_schema::DataType::Utf8);
// nodes gained only `link_name` (schema 4 too); spans did not move
let n = nodes_schema();
assert_eq!(n.fields().len(), 26);
assert_eq!(n.fields()[24].name(), "doc_hidden");
assert_eq!(n.fields().last().unwrap().name(), "link_name");
assert_eq!(spans_schema().fields().len(), 5);
// set on TOUCHES_TABLE, null on every other kind
use arrow_array::cast::AsArray;
use arrow_array::Array;
let mut touch = EdgeRow::new("k f().", moniker::table("bench_runs"), EdgeKind::TouchesTable);
touch.access = Some(Access::Both);
let b = edges_batch(&[touch, EdgeRow::new("a", "b", EdgeKind::Calls)]).unwrap();
let a = b.column_by_name("access").unwrap().as_string::<i32>().clone();
assert_eq!(a.value(0), "both");
assert!(a.is_null(1));
}
#[test]
fn access_is_a_union_of_two_bits() {
for a in Access::ALL {
assert_eq!(Access::parse(a.as_str()), Some(*a));
assert_eq!(Access::from_bits(a.bits()), Some(*a));
}
assert_eq!(Access::from_bits(Access::READ | Access::WRITE), Some(Access::Both));
assert_eq!(Access::from_bits(0), None);
assert!(Access::Read.reads() && !Access::Read.writes());
assert!(Access::Write.writes() && !Access::Write.reads());
assert!(Access::Both.reads() && Access::Both.writes());
}
/// The table id is the table's NAME and nothing else — no crate, no version,
/// no repo — so two crates of two repos that touch one table meet at one
/// node; and it can never be an item's id.
#[test]
fn a_table_id_is_its_name_only() {
let id = moniker::table("bench_runs");
assert_eq!(id, "rust-analyzer cargo @warehouse . `table=bench_runs`:");
assert_eq!(moniker::parse(&id), Some(("@warehouse", ".", "`table=bench_runs`:")));
assert_eq!(moniker::table_name(&id).as_deref(), Some("bench_runs"));
// the unresolved node: one id, a name no table can have
let u = moniker::table(TABLE_UNRESOLVED);
assert_eq!(moniker::table_name(&u).as_deref(), Some("<unresolved>"));
assert_ne!(u, id);
// a name with a backtick survives the round trip (SCIP escaping)
assert_eq!(moniker::table_name(&moniker::table("a`b")).as_deref(), Some("a`b"));
// not a table: an item, a feature, another package
assert_eq!(moniker::table_name("rust-analyzer cargo k 0.1.0 table()."), None);
assert_eq!(moniker::table_name(&moniker::feature("k", "0.1.0", "table")), None);
assert_eq!(moniker::table_name("rust-analyzer cargo k 0.1.0 `table=x`:"), None);
assert_eq!(kind::TABLE, "table");
}
/// Schema 4 appends ONE nullable column, `link_name`: the symbol a foreign
/// item is linked as. Appended and nullable is what lets `mimir-ingest` evolve
/// an older lake in place; null on everything that is not a foreign item.
#[test]
fn schema_4_appends_the_link_name_of_a_foreign_item() {
use arrow_array::cast::AsArray;
use arrow_array::Array;
assert_eq!(SCHEMA_VERSION, "5"); // 5 changed identities (moniker::stable), no column
let n = nodes_schema();
assert_eq!(n.metadata().get(META_SCHEMA).map(String::as_str), Some("5"));
let last = n.fields().last().unwrap();
assert_eq!((last.name().as_str(), last.is_nullable(), last.data_type()), ("link_name", true, &arrow_schema::DataType::Utf8));
let mut ffi = NodeRow::new("libc 0.2.1 write().", kind::FFI, Level::Item, "write", "libc", "0.2.1", Origin::Library);
ffi.link_name = Some("__write_nocancel".into());
let plain = NodeRow::new("k f().", kind::FN, Level::Item, "f", "k", "0.1.0", Origin::Local);
let b = nodes_batch(&[ffi, plain]).unwrap();
let col = b.column_by_name("link_name").unwrap().as_string::<i32>();
assert_eq!((col.value(0), col.is_null(1)), ("__write_nocancel", true));
}
#[test]
fn stable_strips_only_the_version() {
let m = moniker::moniker("skade", "0.3.1", "store/Table#open().");
assert_eq!(moniker::stable(&m), "rust-analyzer cargo skade * store/Table#open().");
// Already stable: unchanged, and idempotent.
assert_eq!(moniker::stable(&moniker::stable(&m)), moniker::stable(&m));
// Two versions of one item collapse to one stable id.
let a = moniker::moniker("arrow", "59.2.0", "array/RecordBatch#");
let b = moniker::moniker("arrow", "59.3.1", "array/RecordBatch#");
assert_eq!(moniker::stable(&a), moniker::stable(&b));
// Not a cargo moniker: returned byte for byte (tables, artifacts, commits).
for other in ["mimir table git_heat_facts", "scip-java maven x 1 a#", ""] {
assert_eq!(moniker::stable(other), other);
}
// A descriptor containing a space must not be cut at the wrong field.
let spaced = moniker::moniker("a", "1.0.0", "m/`fn x`#");
assert_eq!(moniker::stable(&spaced), "rust-analyzer cargo a * m/`fn x`#");
}
#[test]
fn boundary_ids_carry_no_version_and_parse() {
let read = moniker::syscall("x86_64", "read");
assert_eq!(read, "rust-analyzer cargo @syscall . x86_64/read().");
assert_eq!(moniker::parse(&read), Some((moniker::SYSCALL_PACKAGE, ".", "x86_64/read().")));
// the run-time-chosen call is one node, its name escaped
assert_eq!(moniker::syscall("x86_64", "<indirect>"), "rust-analyzer cargo @syscall . x86_64/`<indirect>`().");
assert_eq!(moniker::syscall_crate(), "rust-analyzer cargo @syscall . crate/");
assert_eq!(moniker::syscall_arch("x86_64"), "rust-analyzer cargo @syscall . x86_64/");
assert_eq!(moniker::syscall_map_crate("libc@0.2.177:lib", "gnu"), "rust-analyzer cargo @syscall . `map=libc@0.2.177:lib/gnu`:crate/");
// the map crate is a crate root: its children start empty
assert_eq!(moniker::child_scope(&moniker::syscall_map_crate("x@1:lib", "musl")), "rust-analyzer cargo @syscall . `map=x@1:lib/musl`:");
// kernel items: the release is the version field, so the stable id is release-free
let ts = moniker::kernel_item("7.0.0-34-generic", "struct", "task_struct", None);
assert_eq!(ts, "rust-analyzer cargo @kernel 7.0.0-34-generic struct/task_struct#");
assert_eq!(moniker::stable(&ts), "rust-analyzer cargo @kernel * struct/task_struct#");
assert_eq!(moniker::kernel_item("6.12", "func", "__x64_sys_read", None), "rust-analyzer cargo @kernel 6.12 func/__x64_sys_read().");
assert_eq!(moniker::kernel_item("6.12", "struct", "foo", Some(77)), "rust-analyzer cargo @kernel 6.12 struct/foo#`btf=77`:");
assert_eq!(moniker::kernel_crate("6.12"), "rust-analyzer cargo @kernel 6.12 crate/");
assert_eq!(moniker::kernel_ns("6.12", "typedef"), "rust-analyzer cargo @kernel 6.12 typedef/");
assert_eq!(kind::SYSCALL, "syscall");
}