mod doc_extraction;
use doc_extraction::extraction::{DOC_TOML_BLOCKS, find_block_containing};
use rstest::fixture;
use rstest_bdd_macros::{given, scenario, then, when};
use std::cell::RefCell;
use toml::Table;
#[derive(Default)]
struct TomlWorld {
content: RefCell<String>,
parsed: RefCell<Option<Table>>,
error: RefCell<Option<String>>,
}
#[fixture]
fn toml_world() -> TomlWorld {
TomlWorld::default()
}
fn set_toml_content(toml_world: &TomlWorld, content: &str) {
toml_world.content.replace(content.to_owned());
}
#[given("a workspace metadata example for suite-only")]
fn given_suite_only_metadata(toml_world: &TomlWorld) {
let block = find_block_containing(r#"pattern = "whitaker_suite""#);
set_toml_content(toml_world, &block);
}
#[given("a workspace metadata example for individual crates")]
fn given_individual_crates_metadata(toml_world: &TomlWorld) {
let block = DOC_TOML_BLOCKS
.iter()
.find(|b| {
b.contains(r#"pattern = "crates/module_max_lines""#)
&& !b.contains("tag =")
&& !b.contains("rev =")
})
.expect("no individual crates TOML block found")
.clone();
set_toml_content(toml_world, &block);
}
#[given("a workspace metadata example with tag pinning")]
fn given_tag_pinning_metadata(toml_world: &TomlWorld) {
let block = find_block_containing(r#"tag = "v0.1.0""#);
set_toml_content(toml_world, &block);
}
#[given("a workspace metadata example with revision pinning")]
fn given_revision_pinning_metadata(toml_world: &TomlWorld) {
let block = find_block_containing(r#"rev = "abc123def456""#);
set_toml_content(toml_world, &block);
}
#[given("a workspace metadata example with pre-built path")]
fn given_prebuilt_path_metadata(toml_world: &TomlWorld) {
let block = find_block_containing("/whitaker/lints/");
set_toml_content(toml_world, &block);
}
#[given("a dylint.toml example with lint configuration")]
fn given_dylint_toml_config(toml_world: &TomlWorld) {
let block = find_block_containing("[module_max_lines]");
set_toml_content(toml_world, &block);
}
#[when("the TOML is parsed")]
fn when_toml_parsed(toml_world: &TomlWorld) {
let content = toml_world.content.borrow();
match content.parse::<Table>() {
Ok(table) => {
toml_world.parsed.replace(Some(table));
toml_world.error.replace(None);
}
Err(e) => {
toml_world.parsed.replace(None);
toml_world.error.replace(Some(e.to_string()));
}
}
}
fn get_first_library(table: &Table) -> &toml::Value {
table
.get("workspace")
.and_then(|w| w.get("metadata"))
.and_then(|m| m.get("dylint"))
.and_then(|d| d.get("libraries"))
.and_then(|l| l.as_array())
.and_then(|arr| arr.first())
.expect("expected workspace.metadata.dylint.libraries[0]")
}
fn get_library_string_field<'a>(table: &'a Table, field: &str) -> &'a str {
get_first_library(table)
.get(field)
.and_then(|v| v.as_str())
.unwrap_or_else(|| panic!("expected libraries[0].{field} to be a string"))
}
fn get_config_integer(table: &Table, section: &str, key: &str) -> i64 {
table
.get(section)
.and_then(|s| s.get(key))
.and_then(|v| v.as_integer())
.unwrap_or_else(|| panic!("expected {section}.{key} to be an integer"))
}
#[then("parsing succeeds")]
fn then_parsing_succeeds(toml_world: &TomlWorld) {
let error = toml_world.error.borrow();
assert!(
error.is_none(),
"expected TOML to parse successfully, but got error: {:?}",
error
);
}
#[then("the libraries pattern is {expected}")]
fn then_libraries_pattern_is(toml_world: &TomlWorld, expected: String) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let pattern = get_library_string_field(table, "pattern");
assert_eq!(pattern, expected);
}
#[then("the libraries pattern starts with {prefix}")]
fn then_libraries_pattern_starts_with(toml_world: &TomlWorld, prefix: String) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let pattern = get_library_string_field(table, "pattern");
assert!(
pattern.starts_with(&prefix),
"expected pattern to start with '{prefix}', got '{pattern}'"
);
}
#[then("the tag field is present")]
fn then_tag_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let tag = get_library_string_field(table, "tag");
assert_eq!(tag, "v0.1.0", "expected tag == \"v0.1.0\"");
}
#[then("the revision field is present")]
fn then_revision_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let rev = get_library_string_field(table, "rev");
assert_eq!(rev, "abc123def456", "expected rev == \"abc123def456\"");
}
#[then("the path field is present")]
fn then_path_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let path = get_library_string_field(table, "path");
assert!(
path.contains("/whitaker/lints/")
&& path.contains("/nightly-")
&& path.contains("/x86_64-unknown-linux-gnu/lib"),
"expected path to contain prebuilt lints layout, got: {path}"
);
}
#[then("module_max_lines configuration is present")]
fn then_module_max_lines_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let max_lines = get_config_integer(table, "module_max_lines", "max_lines");
assert_eq!(max_lines, 500);
}
#[then("conditional_max_n_branches configuration is present")]
fn then_conditional_max_branches_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let max_branches = get_config_integer(table, "conditional_max_n_branches", "max_branches");
assert_eq!(max_branches, 3);
}
#[then("no_expect_outside_tests additional_test_attributes configuration is present")]
fn then_no_expect_outside_tests_additional_test_attributes_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let attributes = table
.get("no_expect_outside_tests")
.and_then(|t| t.get("additional_test_attributes"))
.and_then(|a| a.as_array())
.expect("expected no_expect_outside_tests.additional_test_attributes array");
let values: Vec<_> = attributes
.iter()
.map(|v| {
v.as_str()
.expect("expected additional_test_attributes entries to be strings")
})
.collect();
assert_eq!(
values,
vec!["my_framework::test", "wasm_bindgen_test"],
"unexpected no_expect_outside_tests.additional_test_attributes"
);
}
#[then("no_unwrap_or_else_panic allow_in_main configuration is present")]
fn then_no_unwrap_or_else_panic_allow_in_main_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let allow_in_main = table
.get("no_unwrap_or_else_panic")
.and_then(|t| t.get("allow_in_main"))
.and_then(|v| v.as_bool())
.expect("expected no_unwrap_or_else_panic.allow_in_main boolean");
assert!(
allow_in_main,
"expected no_unwrap_or_else_panic.allow_in_main to be true"
);
}
#[then("locale configuration is present")]
fn then_locale_configuration_present(toml_world: &TomlWorld) {
let parsed = toml_world.parsed.borrow();
let table = parsed.as_ref().expect("expected parsed TOML");
let locale = table
.get("locale")
.and_then(|v| v.as_str())
.expect("expected locale string");
assert_eq!(locale, "cy", "expected locale == \"cy\"");
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "Suite-only workspace metadata is valid TOML"
)]
fn scenario_suite_only_metadata(toml_world: TomlWorld) {
let _ = toml_world;
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "Individual crates workspace metadata is valid TOML"
)]
fn scenario_individual_crates_metadata(toml_world: TomlWorld) {
let _ = toml_world;
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "Version-pinned workspace metadata with tag is valid TOML"
)]
fn scenario_tag_pinning_metadata(toml_world: TomlWorld) {
let _ = toml_world;
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "Version-pinned workspace metadata with revision is valid TOML"
)]
fn scenario_revision_pinning_metadata(toml_world: TomlWorld) {
let _ = toml_world;
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "Pre-built library path workspace metadata is valid TOML"
)]
fn scenario_prebuilt_path_metadata(toml_world: TomlWorld) {
let _ = toml_world;
}
#[scenario(
path = "tests/features/consumer_guidance.feature",
name = "dylint.toml lint configuration is valid TOML"
)]
fn scenario_dylint_toml_config(toml_world: TomlWorld) {
let _ = toml_world;
}