use super::*;
const FUNCTION: &str = "deleted-bodies:function";
fn range(start: u32, end: u32) -> types::Range {
types::Range {
start: types::Position {
line: start,
column: 0,
},
end: types::Position {
line: end,
column: 0,
},
}
}
fn leaf(id: u32, alignment: u32, start: u32, end: u32) -> tree::Region {
tree::Region {
id,
fold_state_id: id,
range: range(start, end),
tags: vec![],
visibility: types::Visibility::default(),
node: tree::Node::Leaf {
alignment_id: alignment,
changed: vec![],
},
}
}
fn function(id: u32, start: u32, end: u32, children: Vec<tree::Region>) -> tree::Region {
tree::Region {
id,
fold_state_id: id,
range: range(start, end),
tags: vec![FUNCTION.to_owned()],
visibility: types::Visibility::default(),
node: tree::Node::Fold { children },
}
}
fn modified() -> FileChange {
FileChange {
file: Pairing::Both {
lhs: FileRef {
path: "a.py".to_owned(),
oid: String::new(),
mode: String::new(),
},
rhs: FileRef {
path: "a.py".to_owned(),
oid: String::new(),
mode: String::new(),
},
},
status: FileStatus::Modified,
tags: vec![],
}
}
#[test]
fn deleted_bodies_skip_folds_with_paired_content() {
let rewritten = function(1, 0, 20, vec![leaf(2, 0, 0, 20)]);
let removed = function(3, 20, 40, vec![leaf(4, 1, 20, 40)]);
let source = |regions| tree::Source {
text: String::new(),
regions,
};
let mut sides = tree::Pairing::Both {
lhs: source(vec![rewritten, removed]),
rhs: source(vec![leaf(5, 0, 0, 20)]),
};
run_trees(
"deleted-bodies",
json!({"min_lines": 3}),
&modified(),
&mut sides,
);
let lhs = &lhs(&sides).regions;
assert!(!lhs[0].visibility.collapsed, "a rewrite stays open");
assert!(lhs[1].visibility.collapsed);
assert_eq!(lhs[1].visibility.label, "20 lines removed");
}
#[test]
fn a_matched_function_whose_lines_all_went_away_is_a_removal() {
let moved = function(1, 0, 20, vec![leaf(2, 0, 0, 20)]);
let kept = function(3, 20, 40, vec![leaf(4, 1, 20, 40)]);
let mut kept_rhs = function(7, 0, 20, vec![leaf(8, 1, 0, 20)]);
kept_rhs.fold_state_id = 3;
let mut moved_rhs = function(5, 20, 40, vec![leaf(6, 2, 20, 40)]);
moved_rhs.fold_state_id = 1;
let source = |regions| tree::Source {
text: String::new(),
regions,
};
let mut sides = tree::Pairing::Both {
lhs: source(vec![moved, kept]),
rhs: source(vec![kept_rhs, moved_rhs]),
};
run_trees(
"deleted-bodies",
json!({"min_lines": 3}),
&modified(),
&mut sides,
);
let lhs = &lhs(&sides).regions;
assert!(lhs[0].visibility.collapsed);
assert_eq!(lhs[0].visibility.label, "20 lines removed");
assert!(
!lhs[1].visibility.collapsed,
"the function whose lines still align stays open"
);
}
fn docstrings(source: &tree::Source) -> Vec<(u32, u32, bool, String)> {
let mut out = Vec::new();
walk(&source.regions, &mut |region| {
if has_tag(region, "deleted-bodies:docstring") {
out.push((
region.range.start.line,
region.fold_state_id,
region.visibility.collapsed,
region.visibility.label.clone(),
));
}
});
out
}
fn collapsed_body(source: &tree::Source) -> u32 {
let mut states = Vec::new();
walk(&source.regions, &mut |region| {
if has_tag(region, FUNCTION) && region.visibility.collapsed {
states.push(region.fold_state_id);
}
});
assert_eq!(states.len(), 1, "{states:?}");
states[0]
}
#[test]
fn a_deleted_body_links_its_docstring_which_collapses_with_it() {
let before = "fn keep() {}\n\n/// Documented.\n/// Really.\nfn gone() -> u32 {\n let a = 1;\n let b = 2;\n a + b\n}\n";
let (file, mut sides) = project("a.rs", before, "fn keep() {}\n");
run("deleted-bodies", json!({"min_lines": 3}), &file, &mut sides);
let sides = trees(&sides);
let lhs = lhs(&sides);
let state = collapsed_body(lhs);
assert_eq!(docstrings(lhs), [(2, state, true, String::new())]);
let before = "def keep():\n pass\n\ndef gone(a):\n \"\"\"Double a.\n\n Returns an int.\n \"\"\"\n b = a\n return b * 2\n";
let (file, mut sides) = project("a.py", before, "def keep():\n pass\n");
run("deleted-bodies", json!({"min_lines": 3}), &file, &mut sides);
let sides = trees(&sides);
let lhs = self::lhs(&sides);
let state = collapsed_body(lhs);
assert_eq!(docstrings(lhs), [(4, state, true, String::new())]);
}
#[test]
fn deleted_bodies_collapse_when_large_and_one_sided() {
let before = "def gone():\n a()\n b()\n c()\n\ndef kept():\n a()\n b()\n c()\n\ndef tiny():\n a()\n";
let after = "def kept():\n a()\n b()\n c()\n";
let (file, mut sides) = project("m.py", before, after);
run("deleted-bodies", json!({"min_lines": 3}), &file, &mut sides);
let sides = trees(&sides);
let mut collapsed = Vec::new();
walk(&lhs(&sides).regions, &mut |region| {
if is_fold(region) && region.visibility.collapsed {
collapsed.push((region.range.start.line, region.visibility.label.clone()));
}
});
assert_eq!(collapsed, vec![(1, "3 lines removed".to_owned())]);
}