#![cfg_attr(coverage_nightly, coverage(off))]
use super::boxdraw::{visible_width, BODY_WIDTH};
use crate::tdg::UngradedFile;
pub(crate) const UNGRADED_SHOWN: usize = 10;
const ENTRY_INDENT: usize = 4;
const ENTRY_BUDGET: usize = BODY_WIDTH - ENTRY_INDENT;
fn one_line(reason: &str) -> String {
reason.split_whitespace().collect::<Vec<_>>().join(" ")
}
fn keep_tail(text: &str, budget: usize) -> String {
if visible_width(text) <= budget || budget == 0 {
return text.to_string();
}
let chars: Vec<char> = text.chars().collect();
let keep = budget.saturating_sub(1); let mut start = chars.len() - keep.min(chars.len());
if let Some(off) = chars[start..].iter().position(|c| *c == '/') {
if off < 12 && start + off + 1 < chars.len() {
start += off + 1;
}
}
format!("…{}", chars[start..].iter().collect::<String>())
}
fn keep_head(text: &str, budget: usize) -> String {
if visible_width(text) <= budget {
return text.to_string();
}
if budget == 0 {
return String::new();
}
let head: String = text.chars().take(budget.saturating_sub(1)).collect();
format!("{head}…")
}
fn entry(path: &str, reason: &str, budget: Option<usize>) -> String {
let reason = one_line(reason);
let Some(budget) = budget else {
return if reason.is_empty() {
path.to_string()
} else {
format!("{path} — {reason}")
};
};
if reason.is_empty() {
return keep_tail(path, budget);
}
const SEP: &str = " — ";
let sep_w = visible_width(SEP);
let reason_shown = keep_head(&reason, budget / 3);
let path_budget = budget
.saturating_sub(sep_w)
.saturating_sub(visible_width(&reason_shown));
format!("{}{SEP}{reason_shown}", keep_tail(path, path_budget))
}
fn count_line(n: usize) -> String {
format!("Not Graded: {n} file(s) walked, not measured")
}
fn more_line(hidden: usize) -> String {
format!("… and {hidden} more (--format json lists every one under \"ungraded_files\")")
}
pub(crate) fn ungraded_markdown_lines(files: &[UngradedFile]) -> Vec<String> {
if files.is_empty() {
return Vec::new();
}
let mut lines = vec![format!("**{}**", count_line(files.len()))];
for f in files.iter().take(UNGRADED_SHOWN) {
let reason = one_line(&f.reason);
lines.push(if reason.is_empty() {
format!("- `{}`", f.path)
} else {
format!("- `{}` — {reason}", f.path)
});
}
if files.len() > UNGRADED_SHOWN {
lines.push(format!("- {}", more_line(files.len() - UNGRADED_SHOWN)));
}
lines
}
pub(crate) fn ungraded_rows(files: &[UngradedFile], budget: Option<usize>) -> Vec<String> {
if files.is_empty() {
return Vec::new();
}
let mut rows = Vec::with_capacity(files.len().min(UNGRADED_SHOWN) + 2);
rows.push(count_line(files.len()));
for f in files.iter().take(UNGRADED_SHOWN) {
rows.push(format!(
"{}{}",
" ".repeat(ENTRY_INDENT),
entry(&f.path, &f.reason, budget)
));
}
if files.len() > UNGRADED_SHOWN {
rows.push(format!(
"{}{}",
" ".repeat(ENTRY_INDENT),
more_line(files.len() - UNGRADED_SHOWN)
));
}
rows
}
pub(crate) const fn box_entry_budget() -> usize {
ENTRY_BUDGET
}
#[cfg(test)]
mod tests {
use super::*;
fn f(path: &str, reason: &str) -> UngradedFile {
UngradedFile {
path: path.to_string(),
reason: reason.to_string(),
}
}
#[test]
fn nothing_refused_discloses_nothing() {
assert!(ungraded_rows(&[], Some(ENTRY_BUDGET)).is_empty());
}
#[test]
fn a_long_path_keeps_its_tail() {
let rows = ungraded_rows(
&[f(
"/home/noah/src/aprender/crates/aprender-core/src/oracle/coursera/arxiv_entries.rs",
"expected `;`",
)],
Some(ENTRY_BUDGET),
);
let line = &rows[1];
assert!(
line.contains("arxiv_entries.rs"),
"the file name must survive the width limit, got: {line:?}"
);
assert!(
line.starts_with(" …"),
"an elided path must say it was elided, got: {line:?}"
);
assert!(
visible_width(line) <= BODY_WIDTH,
"entry must fit the frame body ({BODY_WIDTH}), got {} in {line:?}",
visible_width(line)
);
}
#[test]
fn two_files_under_one_root_stay_distinguishable() {
let rows = ungraded_rows(
&[
f(
"/very/long/shared/root/prefix/src/alpha_entries.rs",
"expected `;`",
),
f(
"/very/long/shared/root/prefix/src/beta_entries.rs",
"expected `;`",
),
],
Some(ENTRY_BUDGET),
);
assert_ne!(
rows[1], rows[2],
"clipped to the shared prefix, got: {rows:?}"
);
assert!(rows[1].contains("alpha_entries.rs"), "{rows:?}");
assert!(rows[2].contains("beta_entries.rs"), "{rows:?}");
}
#[test]
fn a_long_reason_never_costs_the_file_name() {
let rows = ungraded_rows(
&[f(
"/a/b/c/d/e/f/g/needle.rs",
"cannot parse string into token stream: unexpected end of input while looking for `}`",
)],
Some(ENTRY_BUDGET),
);
assert!(rows[1].contains("needle.rs"), "got: {rows:?}");
assert!(visible_width(&rows[1]) <= BODY_WIDTH, "got: {rows:?}");
}
#[test]
fn the_list_is_capped_and_says_how_many_it_hid() {
let files: Vec<UngradedFile> = (0..25)
.map(|i| f(&format!("src/frag_{i}.rs"), "expected `;`"))
.collect();
let rows = ungraded_rows(&files, Some(ENTRY_BUDGET));
assert_eq!(rows[0], "Not Graded: 25 file(s) walked, not measured");
assert_eq!(rows.len(), 1 + UNGRADED_SHOWN + 1);
assert!(rows.last().unwrap().contains("and 15 more"), "{rows:?}");
assert!(rows.last().unwrap().contains("json"), "{rows:?}");
}
#[test]
fn a_full_but_uncapped_list_has_no_more_line() {
let files: Vec<UngradedFile> = (0..UNGRADED_SHOWN)
.map(|i| f(&format!("src/frag_{i}.rs"), ""))
.collect();
let rows = ungraded_rows(&files, Some(ENTRY_BUDGET));
assert_eq!(rows.len(), 1 + UNGRADED_SHOWN);
assert!(!rows.last().unwrap().contains("more"), "{rows:?}");
}
#[test]
fn unbudgeted_rows_are_not_elided() {
let long =
"/home/noah/src/aprender/crates/aprender-core/src/oracle/coursera/arxiv_entries.rs";
let rows = ungraded_rows(&[f(long, "expected `;`")], None);
assert!(rows[1].contains(long), "got: {rows:?}");
assert!(rows[1].contains("expected `;`"), "got: {rows:?}");
}
#[test]
fn markdown_keeps_the_path_in_its_own_code_span() {
let lines = ungraded_markdown_lines(&[f("src/oracle/arxiv_entries.rs", "expected `;`")]);
assert_eq!(lines[0], "**Not Graded: 1 file(s) walked, not measured**");
assert_eq!(lines[1], "- `src/oracle/arxiv_entries.rs` — expected `;`");
}
#[test]
fn markdown_is_capped_the_same_way_the_boxes_are() {
let files: Vec<UngradedFile> = (0..12)
.map(|i| f(&format!("src/frag_{i}.rs"), "expected `;`"))
.collect();
let lines = ungraded_markdown_lines(&files);
assert_eq!(lines.len(), 1 + UNGRADED_SHOWN + 1);
assert!(
lines.last().unwrap().starts_with("- … and 2 more"),
"{lines:?}"
);
}
#[test]
fn markdown_discloses_nothing_when_nothing_was_refused() {
assert!(ungraded_markdown_lines(&[]).is_empty());
}
}