use std::sync::Arc;
use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Expr, Symbol};
use crate::doc::{
article, block_kind, blocks, citation, embed_block, equation, figure, prose, section, table,
};
use crate::lens::{
article_formatted, article_outline, article_source, export_intermediate, export_markdown,
};
fn cx() -> Cx {
let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
sim_test_support::register_core_classes(&mut cx);
let lisp = sim_codec_lisp::LispCodecLib::new(cx.registry_mut().fresh_codec_id()).unwrap();
cx.load_lib(&lisp).unwrap();
let json = sim_codec_json::JsonCodecLib::new(cx.registry_mut().fresh_codec_id());
cx.load_lib(&json).unwrap();
cx
}
fn sample_article() -> Expr {
article(
"On Topologies",
vec![
section("Introduction"),
prose("We study agent topologies."),
equation("E = mc^2"),
figure("A flow diagram", "flow.svg"),
table(vec![
vec![Expr::String("a".to_owned()), Expr::String("b".to_owned())],
vec![Expr::String("1".to_owned()), Expr::String("2".to_owned())],
]),
citation("knuth1984", "Knuth, Literate Programming, 1984"),
embed_block(
Expr::Map(vec![(
Expr::Symbol(Symbol::new("result")),
Expr::String("42".to_owned()),
)]),
"view:default",
),
],
)
}
#[test]
fn an_article_with_equation_and_embed_roundtrips_as_sim_data() {
let mut cx = cx();
let doc = sample_article();
let kinds: Vec<String> = blocks(&doc)
.iter()
.filter_map(|b| block_kind(b).map(|k| k.name.to_string()))
.collect();
assert!(kinds.contains(&"equation".to_owned()));
assert!(kinds.contains(&"embed".to_owned()));
for codec in ["lisp", "json"] {
let restored = sim_test_support::roundtrip(&mut cx, codec, &doc);
assert_eq!(
doc, restored,
"the article round-trips through codec:{codec}"
);
}
}
#[test]
fn the_formatted_and_source_lenses_render_the_same_document() {
let doc = sample_article();
let formatted = article_formatted(&doc);
let source = article_source(&doc);
sim_lib_scene::validate_scene(&formatted).expect("formatted view is a valid scene");
sim_lib_scene::validate_scene(&source).expect("source view is a valid scene");
sim_lib_scene::validate_scene(&article_outline(&doc)).expect("outline is a valid scene");
}
#[test]
fn an_embedded_block_renders_through_scene_embed() {
let doc = sample_article();
let formatted = article_formatted(&doc);
assert!(
contains_embed(&formatted),
"the embedded block renders as scene/embed"
);
}
#[test]
fn export_runs_over_a_stable_intermediate() {
let doc = sample_article();
let intermediate = export_intermediate(&doc);
assert_eq!(
intermediate,
export_intermediate(&intermediate),
"export IR is stable"
);
let markdown = export_markdown(&doc);
assert!(markdown.contains("# On Topologies"));
assert!(markdown.contains("E = mc^2"));
}
fn contains_embed(scene: &Expr) -> bool {
if sim_lib_scene::node_kind(scene).map(|k| k.name.to_string()) == Some("embed".to_owned()) {
return true;
}
match scene {
Expr::Map(entries) => entries.iter().any(|(_, v)| contains_embed(v)),
Expr::List(items) | Expr::Vector(items) => items.iter().any(contains_embed),
_ => false,
}
}