use super::*;
use crate::loc::language::detect;
#[test]
fn mask_python() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![
"x = 1", "y = \"\"\"", "def foo():", " return 42", "\"\"\"", "z = 2", ]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
assert!(mask[2]);
assert!(mask[3]);
assert!(!mask[4]);
assert!(!mask[5]);
}
#[test]
fn mask_closing_with_code() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![
"x = \"\"\"", "docstring", "\"\"\" + y", ]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(mask[1]);
assert!(!mask[2]);
}
#[test]
fn mask_escaped_triple_quotes() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![r#"x = """has fake \"\"\" inside""""#, "y = 1 + 2"]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
}
#[test]
fn mask_non_triple_language() {
let spec = detect(std::path::Path::new("test.rs")).unwrap();
let lines: Vec<String> = vec!["let x = 1;", "let y = 2;"]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
}
#[test]
fn mask_single_quote_triple_python() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![
"x = '''", "interior", "'''", "y = 2", ]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]); assert!(mask[1]); assert!(!mask[2]); assert!(!mask[3]); }
#[test]
fn mask_single_line_single_quote_string() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec!["x = 'hello'", "y = 2"]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
}
#[test]
fn mask_advance_inside_triple_with_escape() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![
r#"x = """\""" not end yet""" "#, "y = 2",
]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
}
#[test]
fn mask_triple_opens_and_closes_same_line() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = vec![r#"x = """hello""""#, "y = 2"]
.into_iter()
.map(String::from)
.collect();
let mask = multi_line_string_mask(&lines, spec);
assert!(!mask[0]);
assert!(!mask[1]);
}
#[test]
fn demote_turns_string_interior_into_blank() {
let spec = detect(std::path::Path::new("test.kai")).unwrap();
let lines: Vec<String> = vec![
"fn banner() : String =",
" \"\"\"",
" if you match this",
" \"\"\"",
]
.into_iter()
.map(String::from)
.collect();
let kinds = vec![LineKind::Code; 4];
let demoted = demote_multi_line_strings(&lines, &kinds, spec);
assert_eq!(
demoted,
vec![
LineKind::Code,
LineKind::Code,
LineKind::Blank,
LineKind::Code
]
);
}
#[test]
fn demote_leaves_non_triple_languages_untouched() {
let spec = detect(std::path::Path::new("test.rs")).unwrap();
let lines: Vec<String> = vec!["let x = 1;", "let y = 2;"]
.into_iter()
.map(String::from)
.collect();
let kinds = vec![LineKind::Code, LineKind::Comment];
let demoted = demote_multi_line_strings(&lines, &kinds, spec);
assert_eq!(demoted, kinds);
}
#[test]
fn mask_empty_lines() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let mask = multi_line_string_mask(&[], spec);
assert!(mask.is_empty());
}
#[test]
fn starts_in_string_marks_the_closing_line() {
let spec = detect(std::path::Path::new("test.py")).unwrap();
let lines: Vec<String> = ["x = \"\"\"", "inside", "closing\"\"\" + y", "z = 2"]
.into_iter()
.map(String::from)
.collect();
assert_eq!(
starts_in_string_mask(&lines, spec),
[false, true, true, false]
);
}
#[test]
fn starts_in_string_without_triple_quotes() {
let spec = detect(std::path::Path::new("test.rs")).unwrap();
let lines = vec!["x = \"\"\"".to_string(), "inside".to_string()];
assert_eq!(starts_in_string_mask(&lines, spec), [false, false]);
}
fn view(file: &str, src: &str) -> (Vec<String>, Vec<LineKind>) {
let spec = detect(std::path::Path::new(file)).unwrap();
let lines: Vec<String> = src.lines().map(String::from).collect();
let kinds = crate::loc::counter::classify_reader(src.as_bytes(), spec);
let (lines, kinds) = code_view(&lines, &kinds, spec);
(lines.into_owned(), kinds)
}
#[test]
fn code_view_leaves_a_raw_string_empty() {
let (lines, kinds) = view(
"a.rs",
"let a = r#\"{ \"if\": \"while {\" }\"#;\nlet b = br\"x\" + 1;\n",
);
assert_eq!(
lines,
[
"let a = \"\" ;",
"let b = b\"\" + 1;"
]
);
assert_eq!(kinds, [LineKind::Code, LineKind::Code]);
}
#[test]
fn code_view_blanks_the_lines_inside_a_raw_string() {
let (lines, kinds) = view("a.rs", "let a = r#\"{\n if x {\n}\"#;\nlet b = 1;\n");
assert_eq!(lines, ["let a = \"\"", "", " ;", "let b = 1;"]);
assert_eq!(
kinds,
[
LineKind::Code,
LineKind::Blank,
LineKind::Code,
LineKind::Code
]
);
}
#[test]
fn code_view_borrows_what_holds_no_raw_string() {
let spec = detect(std::path::Path::new("a.rs")).unwrap();
let lines = vec!["let a = \"x\";".to_string()];
let (same, _) = code_view(&lines, &[LineKind::Code], spec);
assert!(matches!(same, Cow::Borrowed(_)));
let (lines, _) = view("a.c", "x = r#\"a\"#;\n");
assert_eq!(lines, ["x = r#\"a\"#;"]);
}
#[test]
fn code_view_still_demotes_the_interior_of_triple_quoted_strings() {
let (_, kinds) = view("a.py", "x = \"\"\"\nif a:\n\"\"\"\n");
assert_eq!(kinds[1], LineKind::Blank);
}