Add regression tests and update guidelines
This commit is contained in:
parent
6adb5d382b
commit
b45b199ee5
2 changed files with 168 additions and 0 deletions
|
|
@ -8,3 +8,4 @@
|
|||
## Build Checks
|
||||
|
||||
- Run `cargo check` after changes (patches, features, or other code edits).
|
||||
- Create atomic commits after changes.
|
||||
|
|
|
|||
167
src/main.rs
167
src/main.rs
|
|
@ -2791,3 +2791,170 @@ async fn process_queue(state: std::sync::Arc<AppState>) -> Result<()> {
|
|||
*queue = remaining;
|
||||
save_queue(&state.queue_path, &queue)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn entry(text: &str) -> EntryBlock {
|
||||
EntryBlock::from_text(text)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_markdown_links_replaces_single_link() {
|
||||
let input = "See [post](https://example.com/post) now";
|
||||
let (out, changed) = normalize_markdown_links(input);
|
||||
assert!(changed);
|
||||
assert_eq!(out, "See https://example.com/post now");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_markdown_links_replaces_multiple_links() {
|
||||
let input = "[a](one) and [b](two)";
|
||||
let (out, changed) = normalize_markdown_links(input);
|
||||
assert!(changed);
|
||||
assert_eq!(out, "one and two");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_markdown_links_ignores_invalid_markup() {
|
||||
let input = "broken [link](missing";
|
||||
let (out, changed) = normalize_markdown_links(input);
|
||||
assert!(!changed);
|
||||
assert_eq!(out, input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_entry_markdown_links_updates_entry() {
|
||||
let entry = EntryBlock::from_text("foo [x](url)\nbar");
|
||||
let normalized = normalize_entry_markdown_links(&entry).unwrap();
|
||||
let block = normalized.block_string();
|
||||
assert!(block.contains("foo url"));
|
||||
assert!(!block.contains("[x]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek_indices_filters_and_pages() {
|
||||
let entries: Vec<EntryBlock> = (0..6)
|
||||
.map(|i| entry(&format!("item {}", i)))
|
||||
.collect();
|
||||
let mut peeked = HashSet::new();
|
||||
peeked.insert(entries[1].block_string());
|
||||
peeked.insert(entries[3].block_string());
|
||||
|
||||
assert_eq!(count_unpeeked_entries(&entries, &peeked), 4);
|
||||
assert_eq!(
|
||||
peek_indices(&entries, &peeked, ListMode::Top, 0),
|
||||
vec![0, 2, 4]
|
||||
);
|
||||
assert_eq!(
|
||||
peek_indices(&entries, &peeked, ListMode::Top, 1),
|
||||
vec![5]
|
||||
);
|
||||
assert_eq!(
|
||||
peek_indices(&entries, &peeked, ListMode::Bottom, 0),
|
||||
vec![5, 4, 2]
|
||||
);
|
||||
assert_eq!(
|
||||
peek_indices(&entries, &peeked, ListMode::Bottom, 1),
|
||||
vec![0]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_peek_view_shows_all_peeked_message() {
|
||||
let entries = vec![entry("one"), entry("two")];
|
||||
let session = ListSession {
|
||||
id: "session".to_string(),
|
||||
kind: SessionKind::List,
|
||||
entries: entries.clone(),
|
||||
view: ListView::Peek {
|
||||
mode: ListMode::Top,
|
||||
page: 0,
|
||||
},
|
||||
seen_random: HashSet::new(),
|
||||
message_id: None,
|
||||
};
|
||||
let mut peeked = HashSet::new();
|
||||
for entry in &entries {
|
||||
peeked.insert(entry.block_string());
|
||||
}
|
||||
let (text, _kb) = build_peek_view("session", &session, ListMode::Top, 0, &peeked);
|
||||
assert!(text.contains("Everything's been peeked already."));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_undos_view_includes_labels_and_previews() {
|
||||
let record_one = UndoRecord {
|
||||
id: "one".to_string(),
|
||||
kind: UndoKind::Delete,
|
||||
entry: entry("alpha").block_string(),
|
||||
expires_at: now_ts() + 10,
|
||||
};
|
||||
let record_two = UndoRecord {
|
||||
id: "two".to_string(),
|
||||
kind: UndoKind::MoveToFinished,
|
||||
entry: entry("beta").block_string(),
|
||||
expires_at: now_ts() + 10,
|
||||
};
|
||||
let (text, _kb) = build_undos_view("session", &[record_one, record_two]);
|
||||
assert!(text.contains("Undos (2)"));
|
||||
assert!(text.contains("1) Deleted"));
|
||||
assert!(text.contains("2) Moved to finished"));
|
||||
assert!(text.contains("alpha"));
|
||||
assert!(text.contains("beta"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn displayed_indices_for_selected_view() {
|
||||
let entries = vec![entry("one"), entry("two"), entry("three")];
|
||||
let session = ListSession {
|
||||
id: "session".to_string(),
|
||||
kind: SessionKind::List,
|
||||
entries,
|
||||
view: ListView::Selected {
|
||||
return_to: Box::new(ListView::Menu),
|
||||
index: 1,
|
||||
},
|
||||
seen_random: HashSet::new(),
|
||||
message_id: None,
|
||||
};
|
||||
let peeked = HashSet::new();
|
||||
assert_eq!(displayed_indices_for_view(&session, &peeked), vec![1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norm_target_index_prefers_single_peek_item() {
|
||||
let entries = vec![entry("one"), entry("two")];
|
||||
let mut peeked = HashSet::new();
|
||||
peeked.insert(entries[0].block_string());
|
||||
let session = ListSession {
|
||||
id: "session".to_string(),
|
||||
kind: SessionKind::List,
|
||||
entries: entries.clone(),
|
||||
view: ListView::Peek {
|
||||
mode: ListMode::Top,
|
||||
page: 0,
|
||||
},
|
||||
seen_random: HashSet::new(),
|
||||
message_id: None,
|
||||
};
|
||||
assert_eq!(norm_target_index(&session, &peeked), Some(1));
|
||||
|
||||
let session_multi = ListSession {
|
||||
entries,
|
||||
..session
|
||||
};
|
||||
let empty_peeked = HashSet::new();
|
||||
assert_eq!(norm_target_index(&session_multi, &empty_peeked), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_keywords_are_case_insensitive() {
|
||||
assert!(is_norm_message("NoRm"));
|
||||
assert!(is_instant_delete_message("DEL"));
|
||||
assert!(is_instant_delete_message("Delete"));
|
||||
assert!(!is_instant_delete_message("remove"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue