use crate::handlers::models::*;
pub fn parse_kinds(kinds: &str) -> Result<Vec<&str>, String> {
let cats: Vec<&str> = if kinds.trim().is_empty() {
DEFAULT_VISIBLE_KINDS.split(',').map(str::trim).collect()
} else {
kinds.split(',').map(str::trim).collect()
};
for cat in &cats {
if !VALID_KIND_CATEGORIES.contains(cat) {
return Err(format!(
"Invalid kind category '{}'. Valid values: {}",
cat,
VALID_KIND_CATEGORIES.join(", ")
));
}
}
let mut visible = Vec::new();
for cat in cats {
match cat {
"classes" => visible.extend_from_slice(KIND_CATEGORY_CLASSES),
"interfaces" => visible.extend_from_slice(KIND_CATEGORY_INTERFACES),
"functions" => visible.extend_from_slice(KIND_CATEGORY_FUNCTIONS),
"other" => {
}
_ => {}
}
}
Ok(visible)
}
pub fn includes_other(kinds: &str) -> bool {
if kinds.trim().is_empty() {
return DEFAULT_VISIBLE_KINDS.contains("other");
}
kinds.split(',').any(|c| c.trim() == "other")
}
pub fn parse_direction(direction: &str) -> knot::models::SubgraphDirection {
match direction {
"incoming" => knot::models::SubgraphDirection::Incoming,
"outgoing" => knot::models::SubgraphDirection::Outgoing,
_ => knot::models::SubgraphDirection::Both,
}
}
pub fn parse_relationships(relationships: &str) -> Result<Vec<&str>, String> {
let parsed: Vec<&str> = if relationships.trim().is_empty() {
vec!["CALLS"]
} else {
relationships.split(',').map(|s| s.trim()).collect()
};
for rel in &parsed {
if !VALID_RELATIONSHIPS.contains(rel) {
return Err(format!(
"Invalid relationship type '{}'. Valid types: {}",
rel,
VALID_RELATIONSHIPS.join(", ")
));
}
}
Ok(parsed)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_relationships_accepts_calls() {
let parsed = parse_relationships("CALLS").expect("CALLS must be accepted");
assert_eq!(parsed, vec!["CALLS"]);
}
#[test]
fn parse_relationships_accepts_overrides() {
let parsed = parse_relationships("OVERRIDES").expect("OVERRIDES must be accepted");
assert_eq!(parsed, vec!["OVERRIDES"]);
}
#[test]
fn parse_relationships_accepts_overrides_combined_with_others() {
let parsed = parse_relationships("CALLS,OVERRIDES,IMPLEMENTS").unwrap();
assert_eq!(parsed, vec!["CALLS", "OVERRIDES", "IMPLEMENTS"]);
}
#[test]
fn parse_relationships_rejects_lowercase_overrides() {
assert!(parse_relationships("overrides").is_err());
}
#[test]
fn parse_relationships_rejects_unknown_type() {
let err = parse_relationships("OVERRIDE").unwrap_err();
assert!(
err.contains("OVERRIDES"),
"error should advertise the valid type"
);
}
#[test]
fn overrides_is_not_in_default_overview() {
assert!(!DEFAULT_RELATIONSHIPS_OVERVIEW.contains("OVERRIDES"));
assert!(!DEFAULT_RELATIONSHIPS_SUBGRAPH.contains("OVERRIDES"));
}
#[test]
fn parse_relationships_accepts_varnish_types() {
for rel in [
"USES_BACKEND",
"USES_PROBE",
"USES_ACL",
"INCLUDES",
"IMPORTS_VMOD",
"DECLARED_UNUSED",
] {
let parsed =
parse_relationships(rel).unwrap_or_else(|e| panic!("{rel} must be accepted: {e}"));
assert_eq!(parsed, vec![rel]);
}
}
}