//! End-to-end check: run the JSON fixture and verify the resulting bindings //! match the `DB.InMemoryTest` "matches evalConjunction on three-atom chain" //! case from `external/geolog/geolog-lang/test/DB/InMemoryTest.hs`. //! //! For `node = {e1, e2, e3}` and `edge = {(e1,e2,ee1), (e2,e3,ee2)}` the //! conjunction `node(a), edge(a, b, _), edge(b, c, _)` has exactly one //! solution: `(a=e1, b=e2, c=e3)`. use std::collections::BTreeMap; use glog_runner::run_json; use storage::value::Value; fn fixture() -> &'static str { include_str!("../fixtures/three_atom_chain.json") } fn ent(path: &str, id: u32) -> Value { Value::Str(format!("{path}:{id}")) } fn project<'a>( columns: &'a [String], row: &'a [Value], keep: &'a [&'a str], ) -> BTreeMap<&'a str, &'a Value> { keep.iter() .map(|name| { let pos = columns .iter() .position(|c| c == name) .expect("column missing"); (*name, &row[pos]) }) .collect() } #[test] fn three_atom_chain_matches_haskell_oracle() { let result = run_json(fixture()).expect("fixture should execute"); // The plan's root keeps every variable, including the per-atom wildcards // `_r1` and `_r2`. The oracle only asserts the (a, b, c) projection. let keep = ["a", "b", "c"]; let mut projected: Vec> = result .rows .iter() .map(|row| project(&result.columns, row, &keep)) .collect(); projected.sort_by_key(|m| format!("{m:?}")); let e1 = ent("node", 1); let e2 = ent("node", 2); let e3 = ent("node", 3); let expected = vec![BTreeMap::from([("a", &e1), ("b", &e2), ("c", &e3)])]; assert_eq!(projected, expected); } #[test] fn root_columns_cover_a_b_c_plus_two_wildcards() { // The exporter emits unique wildcard variable names for the entity-id // column of each edge atom (e.g. `_w0_2`, `_w1_2`); their exact spelling // is an implementation detail of the exporter, so this test only checks // that the named variables are all present and that the total column // count is the three named ones plus two anonymous wildcards. let result = run_json(fixture()).expect("fixture should execute"); let cols: std::collections::HashSet<&str> = result.columns.iter().map(String::as_str).collect(); for expected in ["a", "b", "c"] { assert!(cols.contains(expected), "missing column {expected}"); } assert_eq!(result.columns.len(), 5, "expected 3 named + 2 wildcards"); }