580 lines
16 KiB
Rust
580 lines
16 KiB
Rust
#[cfg(test)]
|
|
mod test {
|
|
use crate::app::{App, ServarrConfig};
|
|
use crate::models::servarr_models::{DiskSpace, RootFolder};
|
|
use crate::ui::styles::{ManagarrStyle, default_style, failure_style, secondary_style};
|
|
use crate::ui::utils::{
|
|
borderless_block, centered_rect, convert_to_minutes_hours_days, decorate_peer_style,
|
|
extract_monitored_disk_space_vec, extract_monitored_root_folders, get_width_from_percentage,
|
|
layout_block, layout_block_bottom_border, layout_block_top_border,
|
|
layout_block_top_border_with_title, layout_block_with_title, logo_block, style_block_highlight,
|
|
style_log_list_item, title_block, title_block_centered, title_style, unstyled_title_block,
|
|
};
|
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
|
use ratatui::layout::{Alignment, Rect};
|
|
use ratatui::style::{Color, Modifier, Style, Stylize};
|
|
use ratatui::text::{Span, Text};
|
|
use ratatui::widgets::{Block, BorderType, Borders, ListItem};
|
|
use rstest::rstest;
|
|
|
|
#[test]
|
|
fn test_layout_block() {
|
|
assert_eq!(
|
|
layout_block(),
|
|
Block::new()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_layout_block_with_title() {
|
|
let title_span = Span::styled(
|
|
"title",
|
|
Style::new()
|
|
.fg(Color::DarkGray)
|
|
.add_modifier(Modifier::BOLD),
|
|
);
|
|
let expected_block = Block::new()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
.title(title_span.clone());
|
|
|
|
assert_eq!(layout_block_with_title(title_span), expected_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_layout_block_top_border_with_title() {
|
|
let title_span = Span::styled(
|
|
"title",
|
|
Style::new()
|
|
.fg(Color::DarkGray)
|
|
.add_modifier(Modifier::BOLD),
|
|
);
|
|
let expected_block = Block::new()
|
|
.default_color()
|
|
.borders(Borders::TOP)
|
|
.title(title_span.clone());
|
|
|
|
assert_eq!(
|
|
layout_block_top_border_with_title(title_span),
|
|
expected_block
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_layout_block_top_border() {
|
|
assert_eq!(
|
|
layout_block_top_border(),
|
|
Block::new().borders(Borders::TOP).default_color()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_layout_block_bottom_border() {
|
|
assert_eq!(
|
|
layout_block_bottom_border(),
|
|
Block::new().borders(Borders::BOTTOM).default_color()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_borderless_block() {
|
|
assert_eq!(borderless_block(), Block::new().default_color());
|
|
}
|
|
|
|
#[test]
|
|
fn test_style_button_highlight_selected() {
|
|
let expected_style = Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD);
|
|
|
|
assert_eq!(style_block_highlight(true), expected_style);
|
|
}
|
|
|
|
#[test]
|
|
fn test_style_button_highlight_unselected() {
|
|
let expected_style = Style::new().fg(Color::White).add_modifier(Modifier::BOLD);
|
|
|
|
assert_eq!(style_block_highlight(false), expected_style);
|
|
}
|
|
|
|
#[test]
|
|
fn test_title_style() {
|
|
let expected_span = Span::styled(" test ", Style::new().add_modifier(Modifier::BOLD));
|
|
|
|
assert_eq!(title_style("test"), expected_span);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unstyled_title_block() {
|
|
let expected_block = Block::new()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
.title(Span::styled(
|
|
" test ",
|
|
Style::new().add_modifier(Modifier::BOLD),
|
|
));
|
|
|
|
assert_eq!(unstyled_title_block("test"), expected_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_title_block() {
|
|
let expected_block = Block::new()
|
|
.default_color()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
.title(Span::styled(
|
|
" test ",
|
|
Style::new().add_modifier(Modifier::BOLD),
|
|
));
|
|
|
|
assert_eq!(title_block("test"), expected_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_title_block_centered() {
|
|
let expected_block = Block::new()
|
|
.default_color()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
.title(Span::styled(
|
|
" test ",
|
|
Style::new().add_modifier(Modifier::BOLD),
|
|
))
|
|
.title_alignment(Alignment::Center);
|
|
|
|
assert_eq!(title_block_centered("test"), expected_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_logo_block() {
|
|
let expected_block = Block::new()
|
|
.default_color()
|
|
.borders(Borders::ALL)
|
|
.border_type(BorderType::Rounded)
|
|
.title(Span::styled(
|
|
" Managarr - A Servarr management TUI ",
|
|
Style::new()
|
|
.fg(Color::Magenta)
|
|
.add_modifier(Modifier::BOLD)
|
|
.add_modifier(Modifier::ITALIC),
|
|
));
|
|
|
|
assert_eq!(logo_block(), expected_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_centered_rect() {
|
|
let expected_rect = Rect {
|
|
x: 30,
|
|
y: 45,
|
|
width: 60,
|
|
height: 90,
|
|
};
|
|
|
|
assert_eq!(centered_rect(50, 50, rect()), expected_rect);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_width_from_percentage() {
|
|
assert_eq!(
|
|
get_width_from_percentage(
|
|
Rect {
|
|
x: 0,
|
|
y: 0,
|
|
width: 100,
|
|
height: 10,
|
|
},
|
|
30,
|
|
),
|
|
30
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_determine_log_style_by_level() {
|
|
let list_item = ListItem::new(Text::from(Span::raw("test")));
|
|
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "trace".to_string()),
|
|
list_item.clone().gray()
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "debug".to_string()),
|
|
list_item.clone().blue()
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "info".to_string()),
|
|
list_item.clone().style(default_style())
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "warn".to_string()),
|
|
list_item.clone().style(secondary_style())
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "error".to_string()),
|
|
list_item.clone().style(failure_style())
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "fatal".to_string()),
|
|
list_item.clone().style(failure_style().bold())
|
|
);
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "".to_string()),
|
|
list_item.style(default_style())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_determine_log_style_by_level_case_insensitive() {
|
|
let list_item = ListItem::new(Text::from(Span::raw("test")));
|
|
|
|
assert_eq!(
|
|
style_log_list_item(list_item.clone(), "TrAcE".to_string()),
|
|
list_item.gray()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_convert_to_minutes_hours_days_minutes() {
|
|
assert_str_eq!(convert_to_minutes_hours_days(0), "now");
|
|
assert_str_eq!(convert_to_minutes_hours_days(1), "1 minute");
|
|
assert_str_eq!(convert_to_minutes_hours_days(2), "2 minutes");
|
|
}
|
|
|
|
#[test]
|
|
fn test_convert_to_minutes_hours_days_hours() {
|
|
assert_str_eq!(convert_to_minutes_hours_days(60), "1 hour");
|
|
assert_str_eq!(convert_to_minutes_hours_days(120), "2 hours");
|
|
}
|
|
|
|
#[test]
|
|
fn test_convert_to_minutes_hours_days_days() {
|
|
assert_str_eq!(convert_to_minutes_hours_days(1440), "1 day");
|
|
assert_str_eq!(convert_to_minutes_hours_days(2880), "2 days");
|
|
}
|
|
|
|
#[rstest]
|
|
#[case(0, 0, PeerStyle::Failure)]
|
|
#[case(1, 2, PeerStyle::Warning)]
|
|
#[case(4, 2, PeerStyle::Success)]
|
|
fn test_decorate_peer_style(
|
|
#[case] seeders: u64,
|
|
#[case] leechers: u64,
|
|
#[case] expected_style: PeerStyle,
|
|
) {
|
|
use crate::ui::styles::ManagarrStyle;
|
|
let text = Text::from("test");
|
|
match expected_style {
|
|
PeerStyle::Failure => assert_eq!(
|
|
decorate_peer_style(seeders, leechers, text.clone()),
|
|
text.failure()
|
|
),
|
|
PeerStyle::Warning => assert_eq!(
|
|
decorate_peer_style(seeders, leechers, text.clone()),
|
|
text.warning()
|
|
),
|
|
PeerStyle::Success => assert_eq!(
|
|
decorate_peer_style(seeders, leechers, text.clone()),
|
|
text.success()
|
|
),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_collapses_subfolders() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec!["/nfs".to_owned()]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let root_folders = vec![
|
|
RootFolder {
|
|
id: 1,
|
|
path: "/nfs/cartoons".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 2,
|
|
path: "/nfs/tv".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 3,
|
|
path: "/nfs/reality".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders);
|
|
|
|
assert_eq!(monitored_root_folders.len(), 1);
|
|
assert_eq!(monitored_root_folders[0].path, "/nfs/[cartoons,reality,tv]");
|
|
assert_eq!(monitored_root_folders[0].free_space, 100);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_uses_most_specific_monitored_path() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec!["/nfs".to_owned(), "/".to_owned()]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let root_folders = vec![
|
|
RootFolder {
|
|
id: 1,
|
|
path: "/nfs/cartoons".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 2,
|
|
path: "/nfs/tv".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 3,
|
|
path: "/other/movies".to_string(),
|
|
accessible: true,
|
|
free_space: 200,
|
|
unmapped_folders: None,
|
|
},
|
|
];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders);
|
|
|
|
assert_eq!(monitored_root_folders.len(), 2);
|
|
assert_eq!(monitored_root_folders[0].path, "/[other]");
|
|
assert_eq!(monitored_root_folders[0].free_space, 200);
|
|
assert_eq!(monitored_root_folders[1].path, "/nfs/[cartoons,tv]");
|
|
assert_eq!(monitored_root_folders[1].free_space, 100);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_preserves_unmatched_folders() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec!["/nfs".to_owned()]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let root_folders = vec![
|
|
RootFolder {
|
|
id: 1,
|
|
path: "/nfs/tv".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 2,
|
|
path: "/other/movies".to_string(),
|
|
accessible: true,
|
|
free_space: 200,
|
|
unmapped_folders: None,
|
|
},
|
|
];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders);
|
|
|
|
assert_eq!(monitored_root_folders.len(), 2);
|
|
assert_eq!(monitored_root_folders[0].path, "/nfs/[tv]");
|
|
assert_eq!(monitored_root_folders[1].path, "/other/movies");
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_returns_all_when_monitored_storage_paths_is_empty() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec![]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let root_folders = vec![
|
|
RootFolder {
|
|
id: 1,
|
|
path: "/nfs".to_string(),
|
|
accessible: true,
|
|
free_space: 10,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 2,
|
|
path: "/nfs/some/subpath".to_string(),
|
|
accessible: true,
|
|
free_space: 10,
|
|
unmapped_folders: None,
|
|
},
|
|
];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders.clone());
|
|
|
|
assert_eq!(monitored_root_folders, root_folders);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_returns_all_when_monitored_storage_paths_is_none() {
|
|
let app = App::test_default();
|
|
let root_folders = vec![
|
|
RootFolder {
|
|
id: 1,
|
|
path: "/nfs".to_string(),
|
|
accessible: true,
|
|
free_space: 10,
|
|
unmapped_folders: None,
|
|
},
|
|
RootFolder {
|
|
id: 2,
|
|
path: "/nfs/some/subpath".to_string(),
|
|
accessible: true,
|
|
free_space: 10,
|
|
unmapped_folders: None,
|
|
},
|
|
];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders.clone());
|
|
|
|
assert_eq!(monitored_root_folders, root_folders);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_root_folders_exact_match_shows_no_brackets() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec!["/nfs/tv".to_owned()]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let root_folders = vec![RootFolder {
|
|
id: 1,
|
|
path: "/nfs/tv".to_string(),
|
|
accessible: true,
|
|
free_space: 100,
|
|
unmapped_folders: None,
|
|
}];
|
|
|
|
let monitored_root_folders = extract_monitored_root_folders(&app, root_folders);
|
|
|
|
assert_eq!(monitored_root_folders.len(), 1);
|
|
assert_eq!(monitored_root_folders[0].path, "/nfs/tv");
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_disk_space_vec() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(vec!["/data".to_owned(), "/downloads".to_owned()]),
|
|
..ServarrConfig::default()
|
|
});
|
|
let disk_space = DiskSpace {
|
|
path: Some("/data".to_string()),
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
};
|
|
let disk_space_2 = DiskSpace {
|
|
path: Some("/downloads".to_string()),
|
|
free_space: 100,
|
|
total_space: 10000,
|
|
};
|
|
let disk_space_with_empty_path = DiskSpace {
|
|
path: None,
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
};
|
|
let disk_spaces = vec![
|
|
disk_space.clone(),
|
|
disk_space_with_empty_path.clone(),
|
|
DiskSpace {
|
|
path: Some("/downloads/".to_string()),
|
|
free_space: 100,
|
|
total_space: 10000,
|
|
},
|
|
disk_space_2.clone(),
|
|
];
|
|
|
|
let monitored_disk_space = extract_monitored_disk_space_vec(&app, disk_spaces);
|
|
|
|
assert_eq!(
|
|
monitored_disk_space,
|
|
vec![disk_space, disk_space_with_empty_path, disk_space_2]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_disk_space_vec_returns_all_when_monitored_storage_paths_is_empty() {
|
|
let mut app = App::test_default();
|
|
app.server_tabs.tabs[0].config = Some(ServarrConfig {
|
|
monitored_storage_paths: Some(Vec::new()),
|
|
..ServarrConfig::default()
|
|
});
|
|
let disk_spaces = vec![
|
|
DiskSpace {
|
|
path: Some("/nfs".to_string()),
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
DiskSpace {
|
|
path: None,
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
DiskSpace {
|
|
path: Some("/nfs/some/subpath".to_string()),
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
];
|
|
|
|
let monitored_disk_space = extract_monitored_disk_space_vec(&app, disk_spaces.clone());
|
|
|
|
assert_eq!(monitored_disk_space, disk_spaces);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_monitored_disk_space_vec_returns_all_when_monitored_storage_paths_is_none() {
|
|
let app = App::test_default();
|
|
let disk_spaces = vec![
|
|
DiskSpace {
|
|
path: Some("/nfs".to_string()),
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
DiskSpace {
|
|
path: None,
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
DiskSpace {
|
|
path: Some("/nfs/some/subpath".to_string()),
|
|
free_space: 10,
|
|
total_space: 1000,
|
|
},
|
|
];
|
|
|
|
let monitored_disk_space = extract_monitored_disk_space_vec(&app, disk_spaces.clone());
|
|
|
|
assert_eq!(monitored_disk_space, disk_spaces);
|
|
}
|
|
|
|
enum PeerStyle {
|
|
Failure,
|
|
Warning,
|
|
Success,
|
|
}
|
|
|
|
fn rect() -> Rect {
|
|
Rect {
|
|
x: 0,
|
|
y: 0,
|
|
width: 120,
|
|
height: 180,
|
|
}
|
|
}
|
|
}
|