//! Copy read from a content file is written out, once per entry. //! //! The production quasicoherent `98fbee62` added, tested where it can be: //! `CARGO_MANIFEST_DIR` is what the path resolves against, so this has to be an //! ordinary integration test of this crate rather than a trybuild case, whose //! generated project has a manifest directory of its own. //! //! What is asserted is that the loop is gone. Two entries in the file produce //! two rows built by one description that names neither of them, which is only //! true if the macro read the file and wrote the members out. use quasi_declare::declare; declare! { /// Every row the fixture names, in the order it names them. shape rows() -> Node; region "copy" as Pane { list { for entry in copy "tests/content/copy.toml" as rows { row entry.label { secondary entry.detail; } } } } } declare! { /// A brace in copy, which is text and not a hole. shape braces() -> Node; region "braces" as Pane { for entry in copy "tests/content/copy.toml" as braced { text entry.label; } } } #[test] fn the_file_supplies_one_member_per_entry() { let rendered = format!("{:?}", rows()); assert!(rendered.contains("First"), "the first row is missing"); assert!( rendered.contains("the one at the top"), "its detail is missing" ); assert!(rendered.contains("Second"), "the second row is missing"); assert!( rendered.contains("the one under it"), "its detail is missing" ); } declare! { /// A binding named `copy`, which is a hole root and not the production. shape bound(copy: &Fixture) -> Node; region "bound" as Pane { for word in copy.words.iter() { text word; } } } /// Something to bind, so the case above is a real declaration rather than a /// name that happens to parse. pub struct Fixture { pub words: Vec, } #[test] fn a_binding_called_copy_is_still_a_binding() { // audiofiles' `importing` has one: `for weight in copy.weight.iter()`. The // production is told from it by the string literal that follows the word, // so adding it took no name away from any declaration in the tree. let fixture = Fixture { words: vec!["read".to_owned(), "me".to_owned()], }; let rendered = format!("{:?}", bound(&fixture)); assert!(rendered.contains("read"), "the loop ran over the binding"); assert!(rendered.contains("me"), "the loop ran over the binding"); } declare! { /// A list field, read by a nested loop. shape listed() -> Node; region "listed" as Pane { for profile in copy "tests/content/copy.toml" as listed { section profile.title; list { for feature in profile.features { row feature; } } } } } /// Both loops are gone, the inner one as much as the outer. /// /// Five rows from two entries is the assertion that matters: an inner loop that /// survived would draw one row per entry, and one that ran once would draw two. /// The binder of the inner loop is the element itself, which is what tells a /// list read from a record read. #[test] fn a_list_field_is_unrolled_per_element() { let rendered = format!("{:?}", listed()); for feature in [ "Lossless upload", "Chapters", "Cover art", "Markdown", "Scheduled publishing", ] { assert!(rendered.contains(feature), "{feature} is missing"); } assert!(rendered.contains("Musicians"), "the first title is missing"); assert!(rendered.contains("Writers"), "the second title is missing"); } #[test] fn a_brace_in_copy_is_a_brace() { let rendered = format!("{:?}", braces()); assert!( rendered.contains("{not a hole}"), "a brace in copy was read as an interpolation" ); }