mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-25 08:47:18 +02:00
Add more tests
This commit is contained in:
parent
4da96f4864
commit
6c336c472f
4 changed files with 276 additions and 31 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
@ -41,6 +41,7 @@ jobs:
|
|||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all -- --test-threads=1
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
|
|
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -15,6 +15,15 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
|
@ -488,6 +497,12 @@ version = "0.23.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.2"
|
||||
|
@ -608,7 +623,10 @@ version = "1.4.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -791,6 +809,7 @@ dependencies = [
|
|||
"crossterm",
|
||||
"itertools",
|
||||
"rand",
|
||||
"regex",
|
||||
"rustyline",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -820,6 +839,15 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
|
|
|
@ -18,6 +18,7 @@ default = ["crossterm-backend"]
|
|||
crossterm-backend = ["tui/crossterm", "crossterm"]
|
||||
|
||||
[dependencies]
|
||||
regex = "1"
|
||||
itertools = "0.9"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
|
271
src/app.rs
271
src/app.rs
|
@ -45,6 +45,8 @@ use rustyline::Word;
|
|||
use std::io;
|
||||
use tui::{backend::CrosstermBackend, Terminal};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
const MAX_LINE: usize = 4096;
|
||||
|
||||
pub fn cmp(t1: &Task, t2: &Task) -> Ordering {
|
||||
|
@ -675,7 +677,6 @@ impl TTApp {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let selected = self.task_table_state.selected().unwrap_or_default();
|
||||
let header = headers.iter();
|
||||
let mut rows = vec![];
|
||||
|
@ -1377,8 +1378,12 @@ impl TTApp {
|
|||
if (reference - chrono::Duration::nanoseconds(1)).month() % 4 == now.month() % 4 {
|
||||
add_tag(&mut task, "QUARTER".to_string());
|
||||
}
|
||||
if reference.year() == now.year() {
|
||||
add_tag(&mut task, "YEAR".to_string());
|
||||
}
|
||||
match get_date_state(&d, self.config.due) {
|
||||
DateState::EarlierToday | DateState::LaterToday => {
|
||||
add_tag(&mut task, "DUE".to_string());
|
||||
add_tag(&mut task, "TODAY".to_string());
|
||||
add_tag(&mut task, "DUETODAY".to_string());
|
||||
}
|
||||
|
@ -1387,9 +1392,6 @@ impl TTApp {
|
|||
if reference.day() == now.day() + 1 {
|
||||
add_tag(&mut task, "TOMORROW".to_string());
|
||||
}
|
||||
if reference.year() == now.year() {
|
||||
add_tag(&mut task, "YEAR".to_string());
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -1723,6 +1725,8 @@ pub fn remove_tag(task: &mut Task, tag: String) {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tui::backend::TestBackend;
|
||||
use tui::buffer::Buffer;
|
||||
|
||||
#[test]
|
||||
fn test_app() {
|
||||
|
@ -1742,21 +1746,10 @@ mod tests {
|
|||
|
||||
let app = TTApp::new().unwrap();
|
||||
let task = app.task_by_id(11).unwrap();
|
||||
let tags = vec![
|
||||
"COLOR",
|
||||
"PENDING",
|
||||
"ANNOTATED",
|
||||
"TAGGED",
|
||||
// "MONTH",
|
||||
// "QUARTER",
|
||||
// "DUE",
|
||||
// "TOMORROW",
|
||||
// "YEAR",
|
||||
]
|
||||
let tags = vec!["finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
dbg!(task.tags());
|
||||
for tag in tags {
|
||||
assert!(task.tags().unwrap().contains(&tag));
|
||||
}
|
||||
|
@ -1767,19 +1760,19 @@ mod tests {
|
|||
let app = TTApp::new().unwrap();
|
||||
let task = app.task_by_id(1).unwrap();
|
||||
for r in vec![
|
||||
"deleted",
|
||||
"completed",
|
||||
"active",
|
||||
"keyword.",
|
||||
"tag.",
|
||||
"project.",
|
||||
"overdue",
|
||||
"scheduled",
|
||||
"due.today",
|
||||
"due",
|
||||
"blocked",
|
||||
"blocking",
|
||||
"completed",
|
||||
"deleted",
|
||||
"due",
|
||||
"due.today",
|
||||
"keyword.",
|
||||
"overdue",
|
||||
"project.",
|
||||
"recurring",
|
||||
"scheduled",
|
||||
"tag.",
|
||||
"tagged",
|
||||
"uda.",
|
||||
] {
|
||||
|
@ -1787,13 +1780,10 @@ mod tests {
|
|||
}
|
||||
let style = app.style_for_task(&task);
|
||||
|
||||
dbg!(style);
|
||||
assert_eq!(style, Style::default().fg(Color::Indexed(2)));
|
||||
|
||||
let task = app.task_by_id(11).unwrap();
|
||||
dbg!(task.tags().unwrap());
|
||||
let style = app.style_for_task(&task);
|
||||
dbg!(style);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1831,4 +1821,229 @@ mod tests {
|
|||
assert_eq!(app.tasks.lock().unwrap().len(), 26);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task_tomorrow() {
|
||||
let total_tasks: u64 = 26;
|
||||
|
||||
let mut app = TTApp::new().unwrap();
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), total_tasks as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
|
||||
let now = Local::now();
|
||||
let now = TimeZone::from_utc_datetime(now.offset(), &now.naive_utc());
|
||||
|
||||
let mut command = Command::new("task");
|
||||
command.arg("add");
|
||||
let message = format!(
|
||||
"'new task for testing tomorrow' due:{:04}-{:02}-{:02}",
|
||||
now.year(),
|
||||
now.month(),
|
||||
now.day() + 1
|
||||
);
|
||||
|
||||
let shell = message.as_str().replace("'", "\\'");
|
||||
let cmd = shlex::split(&shell).unwrap();
|
||||
for s in cmd {
|
||||
command.arg(&s);
|
||||
}
|
||||
let output = command.output().unwrap();
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
let re = Regex::new(r"^Created task (?P<task_id>\d+).\n$").unwrap();
|
||||
let caps = re.captures(&s).unwrap();
|
||||
let task_id = caps["task_id"].parse::<u64>().unwrap();
|
||||
assert_eq!(task_id, total_tasks + 1);
|
||||
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), (total_tasks + 1) as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
|
||||
let task = app.task_by_id(task_id).unwrap();
|
||||
|
||||
for s in &[
|
||||
"DUE",
|
||||
"MONTH",
|
||||
"PENDING",
|
||||
"QUARTER",
|
||||
"TOMORROW",
|
||||
"UDA",
|
||||
"UNBLOCKED",
|
||||
"YEAR",
|
||||
] {
|
||||
assert!(task.tags().unwrap().contains(&s.to_string()));
|
||||
}
|
||||
|
||||
let output = Command::new("task")
|
||||
.arg("rc.confirmation=off")
|
||||
.arg("undo")
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let mut app = TTApp::new().unwrap();
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), total_tasks as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task_earlier_today() {
|
||||
let total_tasks: u64 = 26;
|
||||
|
||||
let mut app = TTApp::new().unwrap();
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), total_tasks as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
|
||||
let now = Local::now();
|
||||
let now = TimeZone::from_utc_datetime(now.offset(), &now.naive_utc());
|
||||
|
||||
let mut command = Command::new("task");
|
||||
command.arg("add");
|
||||
let message = format!(
|
||||
"'new task for testing earlier today' due:{:04}-{:02}-{:02}",
|
||||
now.year(),
|
||||
now.month(),
|
||||
now.day()
|
||||
);
|
||||
|
||||
let shell = message.as_str().replace("'", "\\'");
|
||||
let cmd = shlex::split(&shell).unwrap();
|
||||
for s in cmd {
|
||||
command.arg(&s);
|
||||
}
|
||||
let output = command.output().unwrap();
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
let re = Regex::new(r"^Created task (?P<task_id>\d+).\n$").unwrap();
|
||||
let caps = re.captures(&s).unwrap();
|
||||
let task_id = caps["task_id"].parse::<u64>().unwrap();
|
||||
assert_eq!(task_id, total_tasks + 1);
|
||||
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), (total_tasks + 1) as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
|
||||
let task = app.task_by_id(task_id).unwrap();
|
||||
for s in &[
|
||||
"DUE",
|
||||
"DUETODAY",
|
||||
"MONTH",
|
||||
"OVERDUE",
|
||||
"PENDING",
|
||||
"QUARTER",
|
||||
"TODAY",
|
||||
"UDA",
|
||||
"UNBLOCKED",
|
||||
"YEAR",
|
||||
] {
|
||||
assert!(task.tags().unwrap().contains(&s.to_string()));
|
||||
}
|
||||
|
||||
let output = Command::new("task")
|
||||
.arg("rc.confirmation=off")
|
||||
.arg("undo")
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let mut app = TTApp::new().unwrap();
|
||||
assert!(app.get_context().is_ok());
|
||||
assert!(app.update().is_ok());
|
||||
assert_eq!(app.tasks.lock().unwrap().len(), total_tasks as usize);
|
||||
assert_eq!(app.current_context_filter, "");
|
||||
}
|
||||
|
||||
use tui::widgets::{BarChart, Block, Borders};
|
||||
#[test]
|
||||
fn test_draw_task_report() {
|
||||
let test_case = |expected: &Buffer| {
|
||||
let mut app = TTApp::new().unwrap();
|
||||
|
||||
app.task_report_next();
|
||||
app.context_next();
|
||||
|
||||
let backend = TestBackend::new(50, 15);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
app.draw(f);
|
||||
app.draw(f);
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(terminal.backend().size().unwrap(), expected.area);
|
||||
terminal.backend().assert_buffer(expected);
|
||||
};
|
||||
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"╭Task|Calendar───────────────────────────────────╮",
|
||||
"│ ID Age Deps P Proj Tag Due Until Descr Urg │",
|
||||
"│ │",
|
||||
"│• 8 4mo U Run … 23.00│",
|
||||
"│ 10 4mo colo COLOR -8d … [2] 14.80│",
|
||||
"╰────────────────────────────────────────────────╯",
|
||||
"╭Task 8──────────────────────────────────────────╮",
|
||||
"│ │",
|
||||
"│Name Value │",
|
||||
"│----------- ------------------------------------│",
|
||||
"│ID 8 │",
|
||||
"╰────────────────────────────────────────────────╯",
|
||||
"╭Filter Tasks────────────────────────────────────╮",
|
||||
"│status:pending -private │",
|
||||
"╰────────────────────────────────────────────────╯",
|
||||
]);
|
||||
|
||||
for i in 1..=4 {
|
||||
// Task
|
||||
expected
|
||||
.get_mut(i, 0)
|
||||
.set_style(Style::default().add_modifier(Modifier::BOLD));
|
||||
}
|
||||
for i in 6..=13 {
|
||||
// Calendar
|
||||
expected
|
||||
.get_mut(i, 0)
|
||||
.set_style(Style::default().add_modifier(Modifier::DIM));
|
||||
}
|
||||
|
||||
for r in &[
|
||||
1..=4, // ID
|
||||
6..=8, // Age
|
||||
10..=13, // Deps
|
||||
15..=15, // P
|
||||
17..=20, // Proj
|
||||
22..=26, // Tag
|
||||
28..=30, // Due
|
||||
32..=36, // Until
|
||||
38..=42, // Descr
|
||||
44..=48, // Urg
|
||||
] {
|
||||
for i in r.clone().into_iter() {
|
||||
expected
|
||||
.get_mut(i, 1)
|
||||
.set_style(Style::default().add_modifier(Modifier::UNDERLINED));
|
||||
}
|
||||
}
|
||||
|
||||
for i in 1..expected.area().width - 1 {
|
||||
expected.get_mut(i, 3).set_style(
|
||||
Style::default()
|
||||
.fg(Color::Indexed(0))
|
||||
.bg(Color::Indexed(15))
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
}
|
||||
|
||||
for i in 1..expected.area().width - 1 {
|
||||
expected
|
||||
.get_mut(i, 4)
|
||||
.set_style(Style::default().fg(Color::Indexed(9)).bg(Color::Indexed(4)));
|
||||
}
|
||||
|
||||
test_case(&expected);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue