use super::*;
use crate::core::config::ExcludeConfig;
use crate::core::ir::UnsupportedPublicItem;
fn generic_unsupported_item(kind: &str, name: &str) -> UnsupportedPublicItem {
UnsupportedPublicItem {
item_kind: kind.to_string(),
item_path: format!("my_crate::{name}"),
reason: format!("public generic {kind}s cannot be represented without explicit monomorphization metadata"),
suggested_fix: "exclude the item, configure an opaque/bridge policy, or provide explicit \
monomorphization metadata"
.to_string(),
}
}
#[test]
fn generic_public_item_is_redundant_not_unmatched() {
let mut surface = surface_with(vec![make_typedef("Kept")], vec![]);
surface.unsupported_public_items = vec![generic_unsupported_item("struct", "RetryConfig")];
let exclude = ExcludeConfig {
types: vec!["RetryConfig".to_string()],
functions: vec![],
methods: vec![],
fields: vec![],
};
assert_eq!(
redundant_generic_exclude_entries(&surface, &exclude),
vec![("types", "RetryConfig".to_string())],
"a known-generic entry must be classified as redundant"
);
assert!(
unmatched_exclude_entries(&surface, &exclude).is_empty(),
"a known-generic entry must not also be reported as unmatched"
);
}
#[test]
fn private_item_name_is_unmatched_not_redundant() {
let surface = surface_with(vec![make_typedef("Kept")], vec![]);
let exclude = ExcludeConfig {
types: vec!["InternalRetryState".to_string()],
functions: vec![],
methods: vec![],
fields: vec![],
};
assert!(
redundant_generic_exclude_entries(&surface, &exclude).is_empty(),
"a private item's name carries no generic diagnostic and must not be classified as redundant"
);
assert_eq!(
unmatched_exclude_entries(&surface, &exclude),
vec![("types", "InternalRetryState".to_string())],
"a private item's name must still be reported as unmatched, exactly like a typo"
);
}
#[test]
fn genuine_typo_is_unmatched_not_redundant() {
let surface = surface_with(vec![make_typedef("Kept")], vec![]);
let exclude = ExcludeConfig {
types: vec!["RetryConfg".to_string()],
functions: vec!["cuont_tokens".to_string()],
methods: vec!["Kept.walk".to_string()],
fields: vec![],
};
assert!(
redundant_generic_exclude_entries(&surface, &exclude).is_empty(),
"a typo must never be classified as a redundant generic exclusion"
);
let mut unmatched = unmatched_exclude_entries(&surface, &exclude);
unmatched.sort();
assert_eq!(
unmatched,
vec![
("functions", "cuont_tokens".to_string()),
("methods", "Kept.walk".to_string()),
("types", "RetryConfg".to_string()),
],
"every typo'd entry across all three lists must still warn"
);
}
#[test]
fn unsupported_item_with_non_generic_reason_is_not_classified_as_redundant() {
let mut surface = surface_with(vec![make_typedef("Kept")], vec![]);
surface.unsupported_public_items = vec![UnsupportedPublicItem {
item_kind: "function".to_string(),
item_path: "my_crate::do_thing".to_string(),
reason: "public async trait methods are not yet representable".to_string(),
suggested_fix: "exclude the item".to_string(),
}];
let exclude = ExcludeConfig {
types: vec![],
functions: vec!["do_thing".to_string()],
methods: vec![],
fields: vec![],
};
assert!(
redundant_generic_exclude_entries(&surface, &exclude).is_empty(),
"a non-generic unsupported-item reason must not be classified as redundant"
);
assert!(
unmatched_exclude_entries(&surface, &exclude).is_empty(),
"a recorded (if non-generic) diagnostic is still a match, so it must not warn either"
);
}