Integration tests covering 6 main scenarios
Covers - Add - Select - Select Top/Bottom - Move - Edit - Delete
This commit is contained in:
parent
d23f458444
commit
514c600bb1
@ -7,9 +7,6 @@ use tui_textarea::TextArea;
|
||||
|
||||
use crate::db;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Column {
|
||||
pub id: i64,
|
||||
|
@ -1 +0,0 @@
|
||||
// use super::*;
|
@ -3,7 +3,7 @@ use anyhow::Error;
|
||||
use rusqlite::{params, Connection, Result};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub struct DBConn(Connection);
|
||||
pub struct DBConn(pub Connection);
|
||||
|
||||
impl DerefMut for DBConn {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
|
19
src/ui.rs
19
src/ui.rs
@ -35,8 +35,6 @@ fn draw_tasks<B: Backend>(f: &mut Frame<'_, B>, area: Rect, state: &State<'_>) {
|
||||
span = Span::raw(&task.title);
|
||||
}
|
||||
span.style = style;
|
||||
// TODO: This is unoptimized, we can actually construct the list
|
||||
// inside a single ListItem it seems
|
||||
ListItem::new(vec![Spans::from(span)])
|
||||
})
|
||||
.collect();
|
||||
@ -202,24 +200,17 @@ fn draw_project_stats<B: Backend>(f: &mut Frame<'_, B>, area: Rect, state: &mut
|
||||
let c4_len = state.columns[3].tasks.len();
|
||||
let tocomplete_total = c1_len + c2_len + c3_len;
|
||||
let percentage = (c3_len as f32 / tocomplete_total as f32 * 100.0) as u8;
|
||||
let list = List::new(
|
||||
vec![
|
||||
ListItem::new(vec![
|
||||
let list = List::new(vec![ListItem::new(vec![
|
||||
Spans::from("Tasks per Column:"),
|
||||
Spans::from(format!(" Todo ({})", c1_len)),
|
||||
Spans::from(format!(" In Progress ({})", c2_len)),
|
||||
Spans::from(format!(" Done ({})", c3_len)),
|
||||
Spans::from(format!(" Ideas ({})", c4_len)),
|
||||
Spans::from(
|
||||
format!(
|
||||
Spans::from(format!(
|
||||
"Progress: {} / {} - {}%",
|
||||
c3_len,
|
||||
tocomplete_total,
|
||||
percentage
|
||||
))
|
||||
]
|
||||
)]
|
||||
)
|
||||
c3_len, tocomplete_total, percentage
|
||||
)),
|
||||
])])
|
||||
.block(block);
|
||||
|
||||
f.render_widget(list, area);
|
||||
|
322
tests/app_tests.rs
Normal file
322
tests/app_tests.rs
Normal file
@ -0,0 +1,322 @@
|
||||
// - [X] Adding
|
||||
// - [X] Selecting general
|
||||
// - [X] Selecting top/bottom
|
||||
// - [X] Moving
|
||||
// - [X] Editing
|
||||
// - [X] Deleting
|
||||
#[cfg(test)]
|
||||
mod app_tests {
|
||||
use anyhow::Error;
|
||||
use kanban_tui::State;
|
||||
use rusqlite::Connection;
|
||||
|
||||
fn create_connection() -> Result<Connection, Error> {
|
||||
let mut conn = Connection::open_in_memory()?;
|
||||
|
||||
let migrations = include_str!("../sql/migrations.sql");
|
||||
let migrations: Vec<&str> = migrations.split(';').collect();
|
||||
let tx = conn.transaction()?;
|
||||
for m in migrations {
|
||||
if !m.trim().is_empty() {
|
||||
tx.execute(m, ())?;
|
||||
}
|
||||
}
|
||||
tx.commit()?;
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_adds_tasks_to_different_columns() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
state.add_new_task(String::from("T2"), String::from("D2"))?;
|
||||
state.select_next_column()?;
|
||||
state.select_next_column()?;
|
||||
state.add_new_task(String::from("T3"), String::from("D3"))?;
|
||||
state.select_previous_column()?;
|
||||
state.add_new_task(String::from("T4"), String::from("D4"))?;
|
||||
|
||||
assert_eq!(state.columns[0].tasks.len(), 2);
|
||||
assert_eq!(state.columns[1].tasks.len(), 1);
|
||||
assert_eq!(state.columns[2].tasks.len(), 1);
|
||||
assert_eq!(&state.columns[0].tasks[0].title, "T1");
|
||||
assert_eq!(&state.columns[0].tasks[1].description, "D2");
|
||||
assert_eq!(&state.columns[1].tasks[0].title, "T4");
|
||||
assert_eq!(&state.columns[2].tasks[0].description, "D3");
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert_eq!(state.columns[0].tasks.len(), 2);
|
||||
assert_eq!(state.columns[1].tasks.len(), 1);
|
||||
assert_eq!(state.columns[2].tasks.len(), 1);
|
||||
assert_eq!(&state.columns[0].tasks[0].title, "T1");
|
||||
assert_eq!(&state.columns[0].tasks[1].description, "D2");
|
||||
assert_eq!(&state.columns[1].tasks[0].title, "T4");
|
||||
assert_eq!(&state.columns[2].tasks[0].description, "D3");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_selects_the_correct_tasks_and_stays_inbound() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
state.move_task_up()?;
|
||||
state.move_task_up()?;
|
||||
state.move_task_down()?;
|
||||
state.move_task_down()?;
|
||||
for _ in 0..10 {
|
||||
state.select_next_column()?;
|
||||
}
|
||||
for _ in 0..10 {
|
||||
state.select_previous_column()?;
|
||||
}
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.add_new_task(String::from("T2"), String::from("D2"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
for _ in 0..6 {
|
||||
state.select_next_column()?;
|
||||
}
|
||||
state.select_previous_column()?;
|
||||
state.add_new_task(String::from("T3"), String::from("D3"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
assert_eq!(state.get_selected_column().name, "Done");
|
||||
for _ in 0..6 {
|
||||
state.select_next_column()?;
|
||||
}
|
||||
for _ in 0..4 {
|
||||
state.select_previous_column()?;
|
||||
}
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_next_column()?;
|
||||
state.select_next_column()?;
|
||||
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let mut state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.select_next_task()?;
|
||||
state.select_next_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.select_previous_column()?;
|
||||
state.select_previous_column()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_next_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_selects_the_correct_first_and_last_task() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
for i in 1..11 {
|
||||
state.add_new_task(format!("T{i}"), format!("D{i}"))?;
|
||||
}
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T10");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T10");
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
for _ in 0..10 {
|
||||
state.move_task_down()?;
|
||||
}
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_last_task()?;
|
||||
state.select_previous_task()?;
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T9");
|
||||
for _ in 0..10 {
|
||||
state.move_task_up()?;
|
||||
}
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T9");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let mut state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T9");
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_moves_tasks_up_and_down_and_to_different_columns() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
state.add_new_task(String::from("T2"), String::from("D2"))?;
|
||||
state.select_previous_task()?;
|
||||
state.move_task_up()?;
|
||||
state.move_task_down()?;
|
||||
state.move_task_down()?;
|
||||
assert_eq!(&state.columns[0].tasks[1].title, "T1");
|
||||
assert_eq!(&state.columns[0].tasks[0].title, "T2");
|
||||
state.select_next_column()?;
|
||||
state.add_new_task(String::from("T3"), String::from("D3"))?;
|
||||
state.move_task_next_column()?;
|
||||
assert_eq!(state.columns[1].tasks.len(), 0);
|
||||
assert_eq!(state.columns[2].tasks.len(), 1);
|
||||
for _ in 0..5 {
|
||||
state.move_task_next_column()?;
|
||||
}
|
||||
for _ in 0..4 {
|
||||
state.move_task_previous_column()?;
|
||||
}
|
||||
assert_eq!(state.columns[0].tasks.len(), 3);
|
||||
assert_eq!(state.columns[1].tasks.len(), 0);
|
||||
assert_eq!(state.columns[2].tasks.len(), 0);
|
||||
assert_eq!(state.columns[3].tasks.len(), 0);
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.select_next_task()?;
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.select_previous_task()?;
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let mut state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_next_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_next_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.select_first_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
assert_eq!(state.columns[0].tasks.len(), 3);
|
||||
assert_eq!(state.columns[1].tasks.len(), 0);
|
||||
assert_eq!(state.columns[2].tasks.len(), 0);
|
||||
assert_eq!(state.columns[3].tasks.len(), 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_edits_a_task_and_updates_it() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D1");
|
||||
state.edit_task(String::from("T1"), String::from("D2"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D2");
|
||||
state.edit_task(String::from("T2"), String::from("D1"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D1");
|
||||
for _ in 0..4 {
|
||||
state.move_task_next_column()?;
|
||||
}
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D1");
|
||||
state.edit_task(String::from("T3"), String::from("D3"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D3");
|
||||
for _ in 0..4 {
|
||||
state.move_task_previous_column()?;
|
||||
}
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D3");
|
||||
state.edit_task(String::from("T3"), String::from("D3"))?;
|
||||
|
||||
assert_eq!(state.columns[0].tasks.len(), 1);
|
||||
assert_eq!(state.columns[1].tasks.len(), 0);
|
||||
assert_eq!(state.columns[2].tasks.len(), 0);
|
||||
assert_eq!(state.columns[3].tasks.len(), 0);
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
assert_eq!(state.get_selected_task().unwrap().description, "D1");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_deletes_a_task() -> Result<(), Error> {
|
||||
let mut state = State::new(create_connection()?)?;
|
||||
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
for col in state.columns.iter().skip(1) {
|
||||
assert_eq!(col.tasks.len(), 0);
|
||||
}
|
||||
state.delete_task()?;
|
||||
assert!(state.get_selected_task().is_none());
|
||||
for col in &state.columns {
|
||||
assert_eq!(col.tasks.len(), 0);
|
||||
}
|
||||
state.delete_task()?;
|
||||
|
||||
state.add_new_task(String::from("T1"), String::from("D1"))?;
|
||||
state.add_new_task(String::from("T2"), String::from("D2"))?;
|
||||
state.add_new_task(String::from("T3"), String::from("D3"))?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.delete_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.add_new_task(String::from("T3"), String::from("D3"))?;
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T2");
|
||||
state.delete_task()?;
|
||||
state.select_previous_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_last_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
state.add_new_task(String::from("T2"), String::from("D2"))?;
|
||||
for _ in 0..4 {
|
||||
state.move_task_up()?;
|
||||
}
|
||||
state.delete_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T1");
|
||||
state.select_next_task()?;
|
||||
assert_eq!(state.get_selected_task().unwrap().title, "T3");
|
||||
for _ in 0..4 {
|
||||
state.delete_task()?;
|
||||
}
|
||||
assert!(state.get_selected_task().is_none());
|
||||
for col in &state.columns {
|
||||
assert_eq!(col.tasks.len(), 0);
|
||||
}
|
||||
|
||||
// Reload the data from the database then rerun the asserts to
|
||||
// make sure everything was saved correctly
|
||||
let state = State::new(state.db_conn.0)?;
|
||||
|
||||
assert!(state.get_selected_task().is_none());
|
||||
for col in state.columns {
|
||||
assert_eq!(col.tasks.len(), 0);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user