crates/mimir-room/tests/room/shop.rs
//! A second hand-built log with everything a READER needs to see: real
//! monikers, names and parents, spans and edge sites, site counts, tests of
//! a harness unit, a `cfg` gate, linked symbols with sizes, and two kinds of
//! repeated key. Written through mimir-ingest's own consumer.
//!
//! repo `shop`, crate shop@0.1.0 — units `lib` and `lib+test`, one artifact:
//!
//! ```text
//! shop src/lib.rs
//! ├─ checkout() 10–20 CALLS total ×1 · charge ×3 (lines 14 15 18) USES_TYPE Cart
//! ├─ cart/ src/cart.rs
//! │ ├─ Cart { items } 3–6
//! │ ├─ impl Cart 8–30 FOR_TYPE Cart
//! │ │ ├─ add(item) 9–14
//! │ │ └─ total() 16–22 CALLS cart::open
//! │ ├─ open() 40–44
//! │ ├─ helper() 46–47 the dump repeats this key (two payloads)
//! │ └─ tests/ adds_up() 50–58 #[test] CALLS add ×2 · total TESTS add · total
//! └─ pay/ src/pay.rs
//! ├─ charge() 5–20 cfg(feature = "stripe") CALLS stripe send · audit ×2
//! ├─ audit() 22–30 CALLS libc_write (lib and lib+test describe it differently)
//! ├─ open() 32–36
//! ├─ charges_once() 40–46 #[test] CALLS charge TESTS charge
//! └─ libc_write() 48 ffi
//! stripe@2.0.0 Client#send() reference stub (its module is not in the room)
//! linked: checkout 120 B · charge 300 B + its closure 40 B · import `write`
//! seq 2: charge moves two lines down (spans only)
//! ```
//!
//! repo `web`, crate web@0.2.0, seq 1: `render()` CALLS shop checkout (stub).
use std::collections::BTreeSet;
use std::path::Path;
use mimir_ingest::{BinaryDump, CommitDump, Consumer, CrateDump, Dumper, EventLog};
use mimir_schema::{EdgeKind, EdgeRow, EffectiveVisibility, Level, NodeRow, Origin, Provenance, SPAN_EDGE, SPAN_NODE, SpanRow, SymbolRow, edge_key, moniker, role, visibility};
use skade::arrow_array::RecordBatch;
use super::common::{open_log, repo_spec, scratch};
pub const SHOP: &str = "shop";
pub const WEB: &str = "web";
pub const LIB: &str = "shop@0.1.0:lib";
pub const TEST: &str = "shop@0.1.0:lib+test";
pub const ARTIFACT: &str = "shop@x86_64-fixture:dev";
/// A shop moniker from its descriptors.
pub fn m(d: &str) -> String {
moniker::moniker("shop", "0.1.0", d)
}
pub fn send() -> String {
moniker::moniker("stripe", "2.0.0", "Client#send().")
}
pub fn stripe() -> String {
moniker::crate_moniker("stripe", "2.0.0")
}
pub fn render() -> String {
moniker::moniker("web", "0.2.0", "render().")
}
pub fn web() -> String {
moniker::crate_moniker("web", "0.2.0")
}
pub const CRATE: &str = "crate/";
pub const CHECKOUT: &str = "checkout().";
pub const CART: &str = "cart/";
pub const CART_T: &str = "cart/Cart#";
pub const ITEMS: &str = "cart/Cart#items.";
pub const IMPL: &str = "cart/impl#[Cart]";
pub const ADD: &str = "cart/impl#[Cart]add().";
pub const ADD_ITEM: &str = "cart/impl#[Cart]add().(item)";
pub const TOTAL: &str = "cart/impl#[Cart]total().";
pub const CART_OPEN: &str = "cart/open().";
pub const HELPER: &str = "cart/helper().";
pub const TESTS_MOD: &str = "cart/tests/";
pub const ADDS_UP: &str = "cart/tests/adds_up().";
pub const PAY: &str = "pay/";
pub const CHARGE: &str = "pay/charge().";
pub const AUDIT: &str = "pay/audit().";
pub const PAY_OPEN: &str = "pay/open().";
pub const CHARGES: &str = "pay/charges_once().";
pub const WRITE: &str = "pay/libc_write().";
struct N(NodeRow);
fn n(id: String, kind: &str, level: Level, name: &str, parent: Option<String>) -> N {
let (krate, version) = moniker::parse(&id).map(|(p, v, _)| (p.to_string(), v.to_string())).unwrap_or(("extern".into(), "0".into()));
let mut row = NodeRow::new(id, kind, level, name, krate, version, Origin::Local);
row.parent = parent;
N(row)
}
impl N {
fn ty(mut self, t: &str) -> Self {
self.0.ty = Some(t.into());
self
}
fn cfg(mut self, c: &str) -> Self {
self.0.cfg = Some(c.into());
self
}
/// A `#[test]` fn (not `#[ignore]`d).
fn test(mut self) -> Self {
self.0.is_test = true;
self.0.ignored = Some(false);
self
}
/// `#[ignore]` on a test.
fn ignored(mut self) -> Self {
self.0.ignored = Some(true);
self
}
/// As a lake evolved from mimir-schema 2 holds a row it has not consumed
/// again: the schema-3 columns have no value.
fn before_schema_3(mut self) -> Self {
self.0.ignored = None;
self.0.doc_hidden = None;
self
}
fn stub(mut self) -> Self {
self.0.defined_here = false;
self.0.origin = Origin::Library;
self
}
/// Nominal + effective visibility, and whether it is documented.
fn vis(mut self, nominal: &str, effective: EffectiveVisibility, doc: Option<&str>) -> Self {
self.0.visibility = Some(nominal.into());
self.0.effective_visibility = Some(effective);
self.0.has_doc = Some(doc.is_some());
self.0.doc = doc.map(str::to_string);
self.0.doc_hidden = Some(false);
self
}
}
fn item(d: &str, kind: &str, name: &str, parent: &str) -> N {
n(m(d), kind, Level::Item, name, Some(m(parent)))
}
fn e(from: &str, to: &str, kind: EdgeKind, count: u32) -> EdgeRow {
let mut row = EdgeRow::new(from, to, kind);
row.count = count;
row
}
fn span(id: &str, file: &str, start: u32, end: u32) -> SpanRow {
SpanRow { target: SPAN_NODE, key: id.into(), file: file.into(), start_line: start, end_line: end }
}
fn site(from: &str, to: &str, kind: EdgeKind, file: &str, line: u32) -> SpanRow {
SpanRow { target: SPAN_EDGE, key: edge_key(from, to, kind), file: file.into(), start_line: line, end_line: line }
}
/// The rows of one unit before they are batches (so a test can edit them).
type Rows = (Vec<N>, Vec<EdgeRow>, Vec<SpanRow>);
fn unit(owner: &str, nodes: Vec<N>, edges: Vec<EdgeRow>, spans: Vec<SpanRow>) -> CrateDump {
let rows: Vec<NodeRow> = nodes.into_iter().map(|n| n.0).collect();
CrateDump {
krate: owner.into(),
universe: false,
nodes: vec![mimir_schema::nodes_batch(&rows).unwrap()],
edges: vec![mimir_schema::edges_batch(&edges).unwrap()],
spans: vec![mimir_schema::spans_batch(&spans).unwrap()],
}
}
/// The lib unit; `moved` = charge sits two lines further down (seq 2).
fn lib(moved: bool) -> CrateDump {
let (nodes, edges, spans) = lib_rows(moved);
unit(LIB, nodes, edges, spans)
}
fn lib_rows(moved: bool) -> Rows {
use EdgeKind::*;
use EffectiveVisibility::*;
let down = if moved { 2 } else { 0 };
let helper_again = item(HELPER, "fn", "helper", CART).ty("fn() -> u8");
let nodes = vec![
n(m(CRATE), "crate", Level::Crate, "shop", None),
item(CHECKOUT, "fn", "checkout", CRATE).vis(visibility::PUB, Direct, Some("Check a cart out and charge it.")),
n(m(CART), "mod", Level::Module, "cart", Some(m(CRATE))).vis(visibility::PUB, Direct, None),
item(CART_T, "struct", "Cart", CART).vis(visibility::PUB, Direct, Some("A cart.")),
n(m(ITEMS), "field", Level::Part, "items", Some(m(CART_T))).ty("Vec<Item>"),
item(IMPL, "impl", "_", CART),
item(ADD, "method", "add", IMPL).vis(visibility::PUB, Direct, None),
n(m(ADD_ITEM), "param", Level::Part, "item", Some(m(ADD))).ty("Item"),
item(TOTAL, "method", "total", IMPL).vis(visibility::PUB, Direct, Some("The sum.")),
// `pub`, but reachable only through a re-export
item(CART_OPEN, "fn", "open", CART).vis(visibility::PUB, Reexported, None),
// the SAME key twice with two payloads: a producer collision
item(HELPER, "fn", "helper", CART),
helper_again,
n(m(PAY), "mod", Level::Module, "pay", Some(m(CRATE))).vis(visibility::PRIVATE, Internal, None),
// `pub` in a private module nobody re-exports: not API
item(CHARGE, "fn", "charge", PAY).cfg("feature = \"stripe\"").vis(visibility::PUB, Internal, None),
item(AUDIT, "fn", "audit", PAY).vis(visibility::PRIVATE, Internal, Some("Write the audit line.")),
item(PAY_OPEN, "fn", "open", PAY).vis(visibility::PUB_CRATE, Internal, None),
item(WRITE, "ffi", "libc_write", PAY),
n(stripe(), "crate", Level::Crate, "stripe", None).stub(),
n(send(), "method", Level::Item, "send", Some(moniker::moniker("stripe", "2.0.0", "Client#"))).stub(),
];
let c = |f: &str, t: &str| e(&m(f), &m(t), Contains, 1);
let edges = vec![
c(CRATE, CART),
c(CRATE, PAY),
c(CRATE, CHECKOUT),
c(CART, CART_T),
c(CART_T, ITEMS),
c(CART, IMPL),
c(IMPL, ADD),
c(IMPL, TOTAL),
c(ADD, ADD_ITEM),
c(CART, CART_OPEN),
c(CART, HELPER),
c(PAY, CHARGE),
c(PAY, AUDIT),
c(PAY, PAY_OPEN),
c(PAY, WRITE),
e(&m(CHECKOUT), &m(TOTAL), Calls, 1),
e(&m(CHECKOUT), &m(CHARGE), Calls, 3),
e(&m(CHARGE), &send(), Calls, 1),
e(&m(CHARGE), &m(AUDIT), Calls, 2),
e(&m(AUDIT), &m(WRITE), Calls, 1),
e(&m(TOTAL), &m(CART_OPEN), Calls, 1),
e(&m(CHECKOUT), &m(CART_T), UsesType, 1),
e(&m(IMPL), &m(CART_T), ForType, 1),
e(&m(CRATE), &stripe(), DependsOn, 1),
];
let spans = vec![
span(&m(CRATE), "src/lib.rs", 1, 40),
span(&m(CHECKOUT), "src/lib.rs", 10, 20),
span(&m(CART), "src/cart.rs", 1, 60),
span(&m(CART_T), "src/cart.rs", 3, 6),
span(&m(ITEMS), "src/cart.rs", 4, 4),
span(&m(IMPL), "src/cart.rs", 8, 30),
span(&m(ADD), "src/cart.rs", 9, 14),
span(&m(ADD_ITEM), "src/cart.rs", 9, 9),
span(&m(TOTAL), "src/cart.rs", 16, 22),
span(&m(CART_OPEN), "src/cart.rs", 40, 44),
span(&m(HELPER), "src/cart.rs", 46, 47),
span(&m(PAY), "src/pay.rs", 1, 60),
span(&m(CHARGE), "src/pay.rs", 5 + down, 20 + down),
span(&m(AUDIT), "src/pay.rs", 22, 30),
span(&m(PAY_OPEN), "src/pay.rs", 32, 36),
span(&m(WRITE), "src/pay.rs", 48, 48),
site(&m(CHECKOUT), &m(TOTAL), Calls, "src/lib.rs", 12),
site(&m(CHECKOUT), &m(CHARGE), Calls, "src/lib.rs", 14),
site(&m(CHECKOUT), &m(CHARGE), Calls, "src/lib.rs", 15),
site(&m(CHECKOUT), &m(CHARGE), Calls, "src/lib.rs", 18),
site(&m(CHARGE), &send(), Calls, "src/pay.rs", 9 + down),
site(&m(CHARGE), &m(AUDIT), Calls, "src/pay.rs", 11 + down),
site(&m(CHARGE), &m(AUDIT), Calls, "src/pay.rs", 17 + down),
site(&m(AUDIT), &m(WRITE), Calls, "src/pay.rs", 25),
site(&m(TOTAL), &m(CART_OPEN), Calls, "src/cart.rs", 18),
site(&m(CHECKOUT), &m(CART_T), UsesType, "src/lib.rs", 11),
];
(nodes, edges, spans)
}
/// The test harness unit: the tests, and what it compiles again.
fn harness(moved: bool) -> CrateDump {
let (nodes, edges, spans) = harness_rows(moved);
unit(TEST, nodes, edges, spans)
}
fn harness_rows(moved: bool) -> Rows {
use EdgeKind::*;
let down = if moved { 2 } else { 0 };
let nodes = vec![
n(m(TESTS_MOD), "mod", Level::Module, "tests", Some(m(CART))).cfg("test"),
item(ADDS_UP, "fn", "adds_up", TESTS_MOD).test(),
item(CHARGES, "fn", "charges_once", PAY).test().before_schema_3(),
// compiled again by the harness — identically …
item(ADD, "method", "add", IMPL).vis(visibility::PUB, EffectiveVisibility::Direct, None),
item(TOTAL, "method", "total", IMPL).vis(visibility::PUB, EffectiveVisibility::Direct, Some("The sum.")),
item(CHARGE, "fn", "charge", PAY).cfg("feature = \"stripe\"").vis(visibility::PUB, EffectiveVisibility::Internal, None),
// … except audit, which the test build sees with another type
item(AUDIT, "fn", "audit", PAY).ty("fn() /* cfg(test) body */").vis(visibility::PRIVATE, EffectiveVisibility::Internal, Some("Write the audit line.")),
];
let edges = vec![
e(&m(CART), &m(TESTS_MOD), Contains, 1),
e(&m(TESTS_MOD), &m(ADDS_UP), Contains, 1),
e(&m(PAY), &m(CHARGES), Contains, 1),
e(&m(ADDS_UP), &m(ADD), Calls, 2),
e(&m(ADDS_UP), &m(TOTAL), Calls, 1),
e(&m(CHARGES), &m(CHARGE), Calls, 1),
e(&m(ADDS_UP), &m(ADD), Tests, 1),
e(&m(ADDS_UP), &m(TOTAL), Tests, 1),
e(&m(CHARGES), &m(CHARGE), Tests, 1),
// the same edge the lib unit carries, with the same two sites
e(&m(CHARGE), &m(AUDIT), Calls, 2),
];
let spans = vec![
span(&m(TESTS_MOD), "src/cart.rs", 49, 59),
span(&m(ADDS_UP), "src/cart.rs", 50, 58),
span(&m(CHARGES), "src/pay.rs", 40, 46),
site(&m(ADDS_UP), &m(ADD), Calls, "src/cart.rs", 52),
site(&m(ADDS_UP), &m(ADD), Calls, "src/cart.rs", 53),
site(&m(ADDS_UP), &m(TOTAL), Calls, "src/cart.rs", 55),
site(&m(CHARGES), &m(CHARGE), Calls, "src/pay.rs", 42),
site(&m(CHARGE), &m(AUDIT), Calls, "src/pay.rs", 11 + down),
site(&m(CHARGE), &m(AUDIT), Calls, "src/pay.rs", 17 + down),
];
(nodes, edges, spans)
}
fn sym(id: &str, symbol: &str, demangled: Option<&str>, r: &str, size: Option<u64>) -> SymbolRow {
SymbolRow {
id: id.into(),
symbol: symbol.into(),
demangled: demangled.map(str::to_string),
role: r.into(),
krate: "shop".into(),
version: "0.1.0".into(),
binary: Some("shop".into()),
section: size.map(|_| ".text".to_string()),
addr: size.map(|_| 0x1000),
size,
provenance: Provenance::BinaryOnly,
valid_from_sha: None,
valid_to_sha: None,
}
}
fn artifact() -> BinaryDump {
let mut import = n("extern write".into(), "ffi_import", Level::Item, "write", None).0;
import.provenance = Provenance::BinaryOnly;
import.origin = Origin::Library;
BinaryDump {
artifact: ARTIFACT.into(),
nodes: vec![mimir_schema::nodes_batch(&[import]).unwrap()],
edges: vec![],
symbols: vec![
mimir_schema::symbols_batch(&[
sym(&m(CHECKOUT), "_Rcheckout", Some("shop::checkout"), role::ITEM, Some(120)),
sym(&m(CHARGE), "_Rcharge", Some("shop::pay::charge"), role::ITEM, Some(300)),
sym(&m(CHARGE), "_Rcharge_closure0", None, role::CLOSURE, Some(40)),
sym("extern write", "write", None, role::IMPORT, None),
])
.unwrap(),
],
ledger: None,
ms: 0,
}
}
fn shop_commit(moved: bool) -> CommitDump {
CommitDump {
toolchain: "nightly-fixture".into(),
workspace_crates: [LIB.to_string(), TEST.to_string()].into(),
workspace_targets: ["shop:lib".to_string(), "shop:bin:shop".to_string()].into(),
failed_units: BTreeSet::new(),
owner_disambiguations: 0,
crates: vec![lib(moved), harness(moved)],
binary: true,
binaries: vec![artifact()],
}
}
/// What an UNCOMMITTED tree of `shop` dumps, on top of its consumed state
/// (seq 2): every node row of the two units goes through `edit`, which may
/// change it or return `false` to drop it (the item is gone from the tree).
/// `version` other than `0.1.0` is a version bump: every id of the crate and
/// both owner ids move with it.
pub fn shop_tree(version: &str, edit: impl Fn(&mut NodeRow) -> bool) -> CommitDump {
let (was, now) = ("shop 0.1.0 ", format!("shop {version} "));
let at = |s: &str| s.replace(was, &now);
let owner = |o: &str| o.replace("shop@0.1.0", &format!("shop@{version}"));
let rebuilt = |name: &str, (nodes, edges, spans): Rows| {
let mut rows = Vec::new();
for mut n in nodes.into_iter().map(|n| n.0) {
if !edit(&mut n) {
continue;
}
if n.krate == "shop" {
n.version = version.to_string();
}
n.id = at(&n.id);
n.parent = n.parent.as_deref().map(at);
rows.push(N(n));
}
let edges = edges.into_iter().map(|e| EdgeRow { from: at(&e.from), to: at(&e.to), ..e }).collect();
let spans = spans.into_iter().map(|s| SpanRow { key: at(&s.key), ..s }).collect();
unit(&owner(name), rows, edges, spans)
};
CommitDump {
toolchain: "nightly-fixture".into(),
workspace_crates: [owner(LIB), owner(TEST)].into(),
workspace_targets: ["shop:lib".to_string(), "shop:bin:shop".to_string()].into(),
failed_units: BTreeSet::new(),
owner_disambiguations: 0,
crates: vec![rebuilt(LIB, lib_rows(true)), rebuilt(TEST, harness_rows(true))],
binary: false,
binaries: vec![],
}
}
fn web_commit() -> CommitDump {
let nodes = vec![n(web(), "crate", Level::Crate, "web", None), n(render(), "fn", Level::Item, "render", Some(web())), item(CHECKOUT, "fn", "checkout", CRATE).stub()];
let edges = vec![e(&web(), &render(), EdgeKind::Contains, 1), e(&render(), &m(CHECKOUT), EdgeKind::Calls, 1)];
let spans = vec![span(&web(), "src/lib.rs", 1, 9), span(&render(), "src/lib.rs", 3, 8), site(&render(), &m(CHECKOUT), EdgeKind::Calls, "src/lib.rs", 5)];
CommitDump {
toolchain: "nightly-fixture".into(),
workspace_crates: ["web@0.2.0:lib".to_string()].into(),
workspace_targets: ["web:lib".to_string()].into(),
failed_units: BTreeSet::new(),
owner_disambiguations: 0,
crates: vec![unit("web@0.2.0:lib", nodes, edges, spans)],
binary: false,
binaries: vec![],
}
}
/// Hands out prepared dumps, one per commit.
pub struct Prepared(pub Vec<CommitDump>);
impl Dumper for Prepared {
fn dump(&mut self, _: &Path, _: &str) -> anyhow::Result<CommitDump> {
Ok(self.0.remove(0))
}
}
pub async fn consume_dumps(log: EventLog, tmp: &Path, name: &str, dumps: Vec<CommitDump>) -> EventLog {
scratch(&tmp.join(format!("src-{name}")), dumps.len());
let mut c = Consumer::boot(log, Prepared(dumps)).await.unwrap();
let rep = c.run(&repo_spec(tmp, name)).await.unwrap();
assert!(rep.iter().all(|r| r.status == "ok"), "{rep:?}");
c.into_parts().0
}
/// `shop` seq 1..2 (seq 2 moves `charge`), `web` seq 1.
pub async fn shop_log(tmp: &Path) -> EventLog {
let log = open_log(tmp).await;
let log = consume_dumps(log, tmp, SHOP, vec![shop_commit(false), shop_commit(true)]).await;
consume_dumps(log, tmp, WEB, vec![web_commit()]).await
}
/// A node batch with a column no producer writes — what a producer might add
/// next (a fn's arity).
pub fn nodes_with_extras(rows: &[(NodeRow, Option<u32>)]) -> RecordBatch {
use skade::arrow_array::{ArrayRef, UInt32Array};
use skade::arrow_schema::{DataType, Field, Schema};
use std::sync::Arc;
let base = mimir_schema::nodes_batch(&rows.iter().map(|r| r.0.clone()).collect::<Vec<_>>()).unwrap();
let mut fields: Vec<Field> = base.schema().fields().iter().map(|f| f.as_ref().clone()).collect();
fields.push(Field::new("arity", DataType::UInt32, true));
let mut cols: Vec<ArrayRef> = base.columns().to_vec();
cols.push(Arc::new(UInt32Array::from(rows.iter().map(|r| r.1).collect::<Vec<_>>())));
RecordBatch::try_new(Arc::new(Schema::new(fields).with_metadata(base.schema().metadata().clone())), cols).unwrap()
}
/// A moniker of the tiny crate `v`.
pub fn v(d: &str) -> String {
moniker::moniker("v", "1.0.0", d)
}
/// `v`'s cargo feature `fast`.
pub fn v_fast() -> String {
moniker::feature("v", "1.0.0", "fast")
}
/// The item `v` compiles OUT when `fast` is on: a token-level stub.
pub fn v_legacy() -> String {
moniker::cfg_gated_out(&v(""), "legacy().", "cfg(not(feature = \"fast\"))")
}
/// The node rows of the tiny crate `v` (each with its hypothetical `arity`):
///
/// ```text
/// v feature `fast` (declared, and compiled with)
/// ├─ api() pub, documented #[cfg(feature = "fast")] → GATED_BY fast
/// ├─ inner() private, undocumented a `cfg!(feature = "fast")` inside → GATED_BY fast (partial)
/// ├─ slow_test #[test] #[ignore]
/// └─ legacy() #[cfg(not(feature = "fast"))]: compiled OUT → a cfg_gated_out stub, GATED_BY fast (negated)
/// ```
pub fn extras_rows() -> Vec<(NodeRow, Option<u32>)> {
use EffectiveVisibility::*;
let root = Some(v("crate/"));
let mut legacy = n(v_legacy(), mimir_schema::kind::CFG_GATED_OUT, Level::Item, "legacy", root.clone()).cfg("not(feature = \"fast\")").ty("fn").0;
legacy.visibility = Some(visibility::PUB.into());
vec![
(n(v("crate/"), "crate", Level::Crate, "v", None).0, None),
(n(v("api()."), "fn", Level::Item, "api", root.clone()).cfg("feature = \"fast\"").vis(visibility::PUB, Direct, Some("The API.")).0, Some(2)),
(n(v("inner()."), "fn", Level::Item, "inner", root.clone()).vis(visibility::PRIVATE, Internal, None).0, Some(0)),
(n(v("slow_test()."), "fn", Level::Item, "slow_test", root.clone()).test().ignored().vis(visibility::PRIVATE, Internal, None).0, Some(0)),
(n(v_fast(), mimir_schema::kind::FEATURE, Level::Item, "fast", root).0, None),
(legacy, None),
]
}
/// One commit of the tiny crate `v` from a prepared node batch.
pub fn tiny_dump(nodes: RecordBatch) -> CommitDump {
use EdgeKind::*;
let gate = |from: &str, negated: bool, partial: bool| {
let mut row = EdgeRow::new(from, v_fast(), GatedBy);
row.negated = Some(negated);
row.partial = Some(partial);
row
};
let edges = vec![
e(&v("crate/"), &v("api()."), Contains, 1),
e(&v("crate/"), &v("inner()."), Contains, 1),
e(&v("crate/"), &v("slow_test()."), Contains, 1),
e(&v("crate/"), &v_fast(), Contains, 1),
e(&v("crate/"), &v_legacy(), Contains, 1),
e(&v("api()."), &v("inner()."), Calls, 1),
e(&v("slow_test()."), &v("api()."), Calls, 1),
e(&v("slow_test()."), &v("api()."), Tests, 1),
gate(&v("api()."), false, false),
gate(&v("inner()."), false, true),
gate(&v_legacy(), true, false),
// the build's own selection: `v` was compiled with `fast`
e(&v("crate/"), &v_fast(), Enables, 1),
];
let spans = vec![
span(&v("crate/"), "src/lib.rs", 1, 30),
span(&v("api()."), "src/lib.rs", 4, 8),
span(&v("inner()."), "src/lib.rs", 10, 14),
span(&v("slow_test()."), "src/lib.rs", 20, 24),
span(&v_legacy(), "src/lib.rs", 16, 18),
site(&v("api()."), &v_fast(), GatedBy, "src/lib.rs", 3),
site(&v("inner()."), &v_fast(), GatedBy, "src/lib.rs", 12),
site(&v_legacy(), &v_fast(), GatedBy, "src/lib.rs", 15),
site(&v("api()."), &v("inner()."), Calls, "src/lib.rs", 6),
];
CommitDump {
toolchain: "nightly-fixture".into(),
workspace_crates: ["v@1.0.0:lib".to_string()].into(),
workspace_targets: ["v:lib".to_string()].into(),
failed_units: BTreeSet::new(),
owner_disambiguations: 0,
crates: vec![CrateDump {
krate: "v@1.0.0:lib".into(),
universe: false,
nodes: vec![nodes],
edges: vec![mimir_schema::edges_batch(&edges).unwrap()],
spans: vec![mimir_schema::spans_batch(&spans).unwrap()],
}],
binary: false,
binaries: vec![],
}
}
/// The tiny crate `v` in the plain mimir-schema payload.
pub fn tiny_commit() -> CommitDump {
let rows: Vec<NodeRow> = extras_rows().into_iter().map(|r| r.0).collect();
tiny_dump(mimir_schema::nodes_batch(&rows).unwrap())
}