use super::*;
#[test]
fn test_count_sdp_violations_excludes_suppressed() {
let analysis = crate::adapters::analyzers::coupling::CouplingAnalysis {
metrics: vec![],
cycles: vec![],
sdp_violations: vec![
crate::adapters::analyzers::coupling::sdp::SdpViolation {
from_module: "a".into(),
to_module: "b".into(),
from_instability: 0.2,
to_instability: 0.8,
suppressed: true,
},
crate::adapters::analyzers::coupling::sdp::SdpViolation {
from_module: "c".into(),
to_module: "d".into(),
from_instability: 0.3,
to_instability: 0.9,
suppressed: false,
},
],
graph: crate::adapters::analyzers::coupling::ModuleGraph::default(),
};
let config = crate::config::sections::CouplingConfig::default();
let mut summary = Summary::from_results(&[]);
count_sdp_violations(Some(&analysis), &config, &mut summary);
assert_eq!(
summary.sdp_violations, 1,
"Only unsuppressed violations counted"
);
}
#[test]
fn dry_suppression_marks_every_group_kind() {
let sups = dry_suppression_at(4);
let (mut dup, mut rep, mut frag, mut bp) = dry_group_fixtures();
mark_dry_suppressions(std::slice::from_mut(&mut dup), &sups);
mark_dry_suppressions(std::slice::from_mut(&mut rep), &sups);
mark_dry_suppressions(std::slice::from_mut(&mut frag), &sups);
mark_dry_suppressions(std::slice::from_mut(&mut bp), &sups);
assert!(
dup.suppressed,
"duplicate group suppressed by qual:allow(dry)"
);
assert!(rep.suppressed, "repeated-match group suppressed");
assert!(frag.suppressed, "fragment group suppressed");
assert!(bp.suppressed, "boilerplate find suppressed");
}
#[test]
fn dry_targeted_suppression_is_per_kind() {
use crate::domain::SuppressionTarget;
let targeted = |target: &str| -> std::collections::HashMap<String, Vec<Suppression>> {
[(
"test.rs".to_string(),
vec![Suppression {
line: 4,
dimensions: vec![crate::findings::Dimension::Dry],
reason: Some("r".to_string()),
target: Some(SuppressionTarget::Boolean {
name: target.to_string(),
}),
}],
)]
.into()
};
let (mut dup, mut rep, mut frag, mut bp) = dry_group_fixtures();
let dup_only = targeted("duplicate");
mark_dry_suppressions(std::slice::from_mut(&mut dup), &dup_only);
mark_dry_suppressions(std::slice::from_mut(&mut rep), &dup_only);
mark_dry_suppressions(std::slice::from_mut(&mut frag), &dup_only);
mark_dry_suppressions(std::slice::from_mut(&mut bp), &dup_only);
assert!(
dup.suppressed,
"duplicate silenced by allow(dry, duplicate)"
);
assert!(!rep.suppressed, "repeated-match must NOT be silenced");
assert!(!frag.suppressed, "fragment must NOT be silenced");
assert!(!bp.suppressed, "boilerplate must NOT be silenced");
let (mut dup2, _, mut frag2, _) = dry_group_fixtures();
let frag_only = targeted("fragment");
mark_dry_suppressions(std::slice::from_mut(&mut dup2), &frag_only);
mark_dry_suppressions(std::slice::from_mut(&mut frag2), &frag_only);
assert!(
!dup2.suppressed,
"duplicate NOT silenced by fragment target"
);
assert!(
frag2.suppressed,
"fragment silenced by allow(dry, fragment)"
);
}
#[test]
fn test_duplicate_without_suppression_not_marked() {
use crate::adapters::analyzers::dry::functions::{
DuplicateEntry, DuplicateGroup, DuplicateKind,
};
let mut groups = vec![DuplicateGroup {
entries: vec![
DuplicateEntry {
name: "foo".to_string(),
qualified_name: "foo".to_string(),
file: "test.rs".to_string(),
line: 5,
},
DuplicateEntry {
name: "bar".to_string(),
qualified_name: "bar".to_string(),
file: "test.rs".to_string(),
line: 15,
},
],
kind: DuplicateKind::Exact,
suppressed: false,
}];
let suppression_lines: std::collections::HashMap<String, Vec<Suppression>> =
std::collections::HashMap::new();
mark_dry_suppressions(&mut groups, &suppression_lines);
assert!(
!groups[0].suppressed,
"Group without suppression should not be marked"
);
}
#[test]
fn test_inverse_annotation_suppresses_duplicate() {
use crate::adapters::analyzers::dry::functions::{
DuplicateEntry, DuplicateGroup, DuplicateKind,
};
let mut groups = vec![DuplicateGroup {
entries: vec![
DuplicateEntry {
name: "as_str".to_string(),
qualified_name: "Foo::as_str".to_string(),
file: "test.rs".to_string(),
line: 5,
},
DuplicateEntry {
name: "parse".to_string(),
qualified_name: "Foo::parse".to_string(),
file: "test.rs".to_string(),
line: 15,
},
],
kind: DuplicateKind::NearDuplicate { similarity: 0.91 },
suppressed: false,
}];
let inverse_lines: std::collections::HashMap<String, Vec<(usize, String)>> =
[("test.rs".to_string(), vec![(4, "parse".to_string())])].into();
mark_inverse_suppressions(&mut groups, &inverse_lines);
assert!(
groups[0].suppressed,
"Inverse-annotated pair should be suppressed"
);
}
#[test]
fn dry_suppression_must_cover_the_dry_dimension() {
use crate::adapters::analyzers::dry::functions::{
DuplicateEntry, DuplicateGroup, DuplicateKind,
};
let mut groups = vec![DuplicateGroup {
entries: vec![DuplicateEntry {
name: "foo".into(),
qualified_name: "foo".into(),
file: "test.rs".into(),
line: 5,
}],
kind: DuplicateKind::Exact,
suppressed: false,
}];
let sups: std::collections::HashMap<String, Vec<Suppression>> = [(
"test.rs".to_string(),
vec![Suppression {
line: 4,
dimensions: vec![crate::findings::Dimension::Complexity],
reason: None,
target: None,
}],
)]
.into();
mark_dry_suppressions(&mut groups, &sups);
assert!(
!groups[0].suppressed,
"an in-window marker for another dimension must not suppress DRY"
);
}
fn inverse_suppressed(inv_line: usize, as_line: usize) -> bool {
use crate::adapters::analyzers::dry::functions::{
DuplicateEntry, DuplicateGroup, DuplicateKind,
};
let mut groups = vec![DuplicateGroup {
entries: vec![
DuplicateEntry {
name: "as_str".into(),
qualified_name: "Foo::as_str".into(),
file: "test.rs".into(),
line: as_line,
},
DuplicateEntry {
name: "parse".into(),
qualified_name: "Foo::parse".into(),
file: "test.rs".into(),
line: 15,
},
],
kind: DuplicateKind::NearDuplicate { similarity: 0.91 },
suppressed: false,
}];
let inverse_lines: std::collections::HashMap<String, Vec<(usize, String)>> =
[("test.rs".to_string(), vec![(inv_line, "parse".to_string())])].into();
mark_inverse_suppressions(&mut groups, &inverse_lines);
groups[0].suppressed
}
#[test]
fn inverse_suppression_window_boundaries() {
assert!(
inverse_suppressed(1, 4),
"inverse pair at the window edge (diff 3) is suppressed"
);
assert!(
!inverse_suppressed(1, 10),
"inverse pair outside the window (diff 9) is not suppressed"
);
}
#[test]
fn test_inverse_annotation_must_target_group_member() {
use crate::adapters::analyzers::dry::functions::{
DuplicateEntry, DuplicateGroup, DuplicateKind,
};
let mut groups = vec![DuplicateGroup {
entries: vec![
DuplicateEntry {
name: "foo".to_string(),
qualified_name: "foo".to_string(),
file: "test.rs".to_string(),
line: 5,
},
DuplicateEntry {
name: "bar".to_string(),
qualified_name: "bar".to_string(),
file: "test.rs".to_string(),
line: 15,
},
],
kind: DuplicateKind::Exact,
suppressed: false,
}];
let inverse_lines: std::collections::HashMap<String, Vec<(usize, String)>> =
[("test.rs".to_string(), vec![(4, "baz".to_string())])].into();
mark_inverse_suppressions(&mut groups, &inverse_lines);
assert!(
!groups[0].suppressed,
"Inverse targeting non-member should not suppress"
);
}