diff --git a/README.md b/README.md index 3239b12b..d254f1fb 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ cargo install sniffnet + ## Required dependencies diff --git a/resources/repository/pages/initial_page.png b/resources/repository/pages/initial_page.png index 6f4dee09..494c8a29 100644 Binary files a/resources/repository/pages/initial_page.png and b/resources/repository/pages/initial_page.png differ diff --git a/resources/repository/pages/notifications_page.png b/resources/repository/pages/notifications_page.png index a1cc825c..362d82ee 100644 Binary files a/resources/repository/pages/notifications_page.png and b/resources/repository/pages/notifications_page.png differ diff --git a/resources/repository/pages/overview_page.png b/resources/repository/pages/overview_page.png index c50cb0ca..980f62b1 100644 Binary files a/resources/repository/pages/overview_page.png and b/resources/repository/pages/overview_page.png differ diff --git a/resources/repository/pages/settings_page.png b/resources/repository/pages/settings_page.png index 1cc6ba5f..f6bf6d13 100644 Binary files a/resources/repository/pages/settings_page.png and b/resources/repository/pages/settings_page.png differ diff --git a/src/chart/manage_chart_data.rs b/src/chart/manage_chart_data.rs index ed118135..3c730bc1 100644 --- a/src/chart/manage_chart_data.rs +++ b/src/chart/manage_chart_data.rs @@ -78,3 +78,180 @@ fn get_max(deque: &VecDeque<(u32, i64)>) -> i64 { } max } + +#[cfg(test)] +mod tests { + use crate::chart::manage_chart_data::{get_max, get_min, update_charts_data}; + use crate::{ChartType, RunTimeData, TrafficChart}; + use std::collections::VecDeque; + + #[test] + fn test_chart_data_updates() { + let sent = VecDeque::from([ + (0, -500), + (1, -1000), + (2, -1000), + (3, -1000), + (4, -1000), + (5, -1000), + (6, -1000), + (7, -1000), + (8, -1000), + (9, -1000), + (10, -1000), + (11, -1000), + (12, -1000), + (13, -1000), + (14, -1000), + (15, -1000), + (16, -1000), + (17, -1000), + (18, -1000), + (19, -1000), + (20, -1000), + (21, -1000), + (22, -1000), + (23, -1000), + (24, -1000), + (25, -1000), + (26, -1000), + (27, -1000), + (28, -1000), + ]); + let received = VecDeque::from([ + (0, 1000), + (1, 21000), + (2, 21000), + (3, 21000), + (4, 21000), + (5, 21000), + (6, 21000), + (7, 21000), + (8, 21000), + (9, 21000), + (10, 21000), + (11, 21000), + (12, 21000), + (13, 21000), + (14, 21000), + (15, 21000), + (16, 21000), + (17, 21000), + (18, 21000), + (19, 21000), + (20, 21000), + (21, 21000), + (22, 21000), + (23, 21000), + (24, 21000), + (25, 21000), + (26, 21000), + (27, 21000), + (28, 21000), + ]); + let tot_sent = 1000 * 28 + 500; + let tot_received = 21000 * 28 + 1000; + let mut traffic_chart = TrafficChart { + ticks: 29, + sent_bytes: sent.clone(), + received_bytes: received.clone(), + sent_packets: sent.clone(), + received_packets: received.clone(), + min_sent_bytes: -1000, + max_received_bytes: 21000, + min_sent_packets: -1000, + max_received_packets: 21000, + color_mix: 0.0, + color_incoming: Default::default(), + color_outgoing: Default::default(), + color_font: Default::default(), + chart_type: ChartType::Packets, + language: Default::default(), + }; + let mut runtime_data = RunTimeData { + all_bytes: 0, + all_packets: 0, + tot_sent_bytes: tot_sent + 1111, + tot_received_bytes: tot_received + 2222, + tot_sent_packets: tot_sent + 3333, + tot_received_packets: tot_received + 4444, + tot_sent_bytes_prev: tot_sent, + tot_received_bytes_prev: tot_received, + tot_sent_packets_prev: tot_sent, + tot_received_packets_prev: tot_received, + logged_notifications: Default::default(), + tot_emitted_notifications: 0, + }; + + assert_eq!(get_min(&sent), -1000); + assert_eq!(get_max(&received), 21000); + + update_charts_data(&mut runtime_data, &mut traffic_chart); + + assert_eq!(get_min(&traffic_chart.sent_packets), -3333); + assert_eq!(get_max(&traffic_chart.received_bytes), 21000); + + // runtime_data correctly updated? + assert_eq!(runtime_data.tot_sent_bytes_prev, tot_sent + 1111); + assert_eq!(runtime_data.tot_received_bytes_prev, tot_received + 2222); + assert_eq!(runtime_data.tot_sent_packets_prev, tot_sent + 3333); + assert_eq!(runtime_data.tot_received_packets_prev, tot_received + 4444); + + let mut sent_bytes = sent.clone(); + sent_bytes.push_back((29, -1111)); + let mut received_packets = received.clone(); + received_packets.push_back((29, 4444)); + let mut sent_packets = sent; + sent_packets.push_back((29, -3333)); + let mut received_bytes = received; + received_bytes.push_back((29, 2222)); + + // traffic_chart correctly updated? + assert_eq!(traffic_chart.ticks, 30); + assert_eq!(traffic_chart.min_sent_bytes, -1111); + assert_eq!(traffic_chart.min_sent_packets, -3333); + assert_eq!(traffic_chart.max_received_bytes, 21000); + assert_eq!(traffic_chart.max_received_packets, 21000); + assert_eq!(traffic_chart.sent_bytes, sent_bytes); + assert_eq!(traffic_chart.received_packets, received_packets); + assert_eq!(traffic_chart.sent_packets, sent_packets); + assert_eq!(traffic_chart.received_bytes, received_bytes); + + runtime_data.tot_sent_bytes += 99; + runtime_data.tot_received_packets += 990; + runtime_data.tot_received_bytes += 2; + update_charts_data(&mut runtime_data, &mut traffic_chart); + runtime_data.tot_sent_bytes += 77; + runtime_data.tot_received_packets += 1; + runtime_data.tot_sent_packets += 220; + update_charts_data(&mut runtime_data, &mut traffic_chart); + + sent_bytes.pop_front(); + sent_bytes.pop_front(); + sent_bytes.push_back((30, -99)); + sent_bytes.push_back((31, -77)); + received_packets.pop_front(); + received_packets.pop_front(); + received_packets.push_back((30, 990)); + received_packets.push_back((31, 1)); + sent_packets.pop_front(); + sent_packets.pop_front(); + sent_packets.push_back((30, 0)); + sent_packets.push_back((31, -220)); + received_bytes.pop_front(); + received_bytes.pop_front(); + received_bytes.push_back((30, 2)); + received_bytes.push_back((31, 0)); + + // traffic_chart correctly updated? + assert_eq!(traffic_chart.ticks, 32); + assert_eq!(traffic_chart.min_sent_bytes, -1111); + assert_eq!(traffic_chart.min_sent_packets, -3333); + assert_eq!(traffic_chart.max_received_bytes, 21000); + assert_eq!(traffic_chart.max_received_packets, 21000); + assert_eq!(traffic_chart.sent_bytes, sent_bytes); + assert_eq!(traffic_chart.received_packets, received_packets); + assert_eq!(traffic_chart.sent_packets, sent_packets); + assert_eq!(traffic_chart.received_bytes, received_bytes); + } +} diff --git a/src/chart/types/traffic_chart.rs b/src/chart/types/traffic_chart.rs index 86f8b02f..a44e7eff 100644 --- a/src/chart/types/traffic_chart.rs +++ b/src/chart/types/traffic_chart.rs @@ -37,10 +37,10 @@ pub struct TrafficChart { pub min_sent_packets: i64, /// Minimum number of received packets per time interval (computed on last 30 intervals) pub max_received_packets: i64, - color_mix: f64, - color_incoming: RGBColor, - color_outgoing: RGBColor, - color_font: RGBColor, + pub color_mix: f64, + pub color_incoming: RGBColor, + pub color_outgoing: RGBColor, + pub color_font: RGBColor, pub chart_type: ChartType, pub language: Language, } diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs index 851686a9..fa4ee6a0 100644 --- a/src/gui/pages/overview_page.rs +++ b/src/gui/pages/overview_page.rs @@ -298,7 +298,6 @@ fn lazy_row_report( .push(Text::new("--------------------------------------------------------------------------------------------------------------------------").font(font)) ; let mut scroll_report = Column::new(); - // let info_traffic_lock = sniffer.info_traffic.lock().unwrap(); for key_val in get_report_entries(&sniffer.info_traffic.clone(), sniffer.report_type) { let entry_color = get_connection_color(key_val.1.traffic_type, sniffer.style); let mut entry_row = Row::new().align_items(Alignment::Center).push( @@ -355,7 +354,6 @@ fn lazy_row_report( .push(Text::new(" ").font(font)); scroll_report = scroll_report.push(entry_row); } - // drop(info_traffic_lock); col_report = col_report.push(Container::new( Scrollable::new(scroll_report) .horizontal_scroll(Properties::new()) diff --git a/src/gui/pages/types/running_page.rs b/src/gui/pages/types/running_page.rs index 54f287e9..39b51f10 100644 --- a/src/gui/pages/types/running_page.rs +++ b/src/gui/pages/types/running_page.rs @@ -38,3 +38,20 @@ impl RunningPage { } } } + +#[cfg(test)] +mod tests { + use crate::RunningPage; + + #[test] + fn test_previous_running_page() { + assert_eq!(RunningPage::Overview.previous(), RunningPage::Notifications); + assert_eq!(RunningPage::Notifications.previous(), RunningPage::Overview); + } + + #[test] + fn test_next_running_page() { + assert_eq!(RunningPage::Overview.next(), RunningPage::Notifications); + assert_eq!(RunningPage::Notifications.next(), RunningPage::Overview); + } +} diff --git a/src/gui/pages/types/settings_page.rs b/src/gui/pages/types/settings_page.rs index ad620ea8..d199d840 100644 --- a/src/gui/pages/types/settings_page.rs +++ b/src/gui/pages/types/settings_page.rs @@ -39,3 +39,28 @@ impl SettingsPage { } } } + +#[cfg(test)] +mod tests { + use crate::gui::pages::types::settings_page::SettingsPage; + + #[test] + fn test_previous_settings_page() { + assert_eq!( + SettingsPage::Notifications.previous(), + SettingsPage::Language + ); + assert_eq!( + SettingsPage::Appearance.previous(), + SettingsPage::Notifications + ); + assert_eq!(SettingsPage::Language.previous(), SettingsPage::Appearance); + } + + #[test] + fn test_next_settings_page() { + assert_eq!(SettingsPage::Notifications.next(), SettingsPage::Appearance); + assert_eq!(SettingsPage::Appearance.next(), SettingsPage::Language); + assert_eq!(SettingsPage::Language.next(), SettingsPage::Notifications); + } +} diff --git a/src/gui/styles/types/style_type.rs b/src/gui/styles/types/style_type.rs index 37cc2256..5d46a48b 100644 --- a/src/gui/styles/types/style_type.rs +++ b/src/gui/styles/types/style_type.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; /// Used to specify the kind of style of the application -#[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] pub enum StyleType { Night, Day, diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index bc2404c3..828ac97b 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -325,8 +325,9 @@ impl Sniffer { } else { info_traffic.favorite_connections.remove(&index); } - let key_val = info_traffic.map.get_index_mut(index).unwrap(); - key_val.1.is_favorite = add; + if let Some(key_val) = info_traffic.map.get_index_mut(index) { + key_val.1.is_favorite = add; + } drop(info_traffic); } @@ -439,3 +440,705 @@ impl Sniffer { Command::none() } } + +#[cfg(test)] +mod tests { + #![allow(unused_must_use)] + + use crate::gui::components::types::my_modal::MyModal; + use crate::gui::pages::types::settings_page::SettingsPage; + use crate::gui::styles::style_constants::get_color_mix_chart; + use crate::gui::styles::types::palette::to_rgb_color; + use crate::gui::types::message::Message; + use crate::notifications::types::logged_notification::{ + LoggedNotification, PacketsThresholdExceeded, + }; + use crate::notifications::types::notifications::{ + BytesNotification, FavoriteNotification, Notification, PacketsNotification, + }; + use crate::notifications::types::sound::Sound; + use crate::{ + get_colors, AppProtocol, ByteMultiple, ChartType, InfoTraffic, IpVersion, Language, + ReportType, RunningPage, Sniffer, Status, StyleType, TransProtocol, + }; + use std::collections::{HashSet, VecDeque}; + use std::sync::{Arc, Mutex}; + + #[test] + fn test_correctly_update_ip_version() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.filters.ip, IpVersion::Other); + sniffer.update(Message::IpVersionSelection(IpVersion::IPv6)); + assert_eq!(sniffer.filters.ip, IpVersion::IPv6); + sniffer.update(Message::IpVersionSelection(IpVersion::IPv4)); + assert_eq!(sniffer.filters.ip, IpVersion::IPv4); + sniffer.update(Message::IpVersionSelection(IpVersion::IPv4)); + assert_eq!(sniffer.filters.ip, IpVersion::IPv4); + sniffer.update(Message::IpVersionSelection(IpVersion::Other)); + assert_eq!(sniffer.filters.ip, IpVersion::Other); + } + + #[test] + fn test_correctly_update_transport_protocol() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.filters.transport, TransProtocol::Other); + sniffer.update(Message::TransportProtocolSelection(TransProtocol::UDP)); + assert_eq!(sniffer.filters.transport, TransProtocol::UDP); + sniffer.update(Message::TransportProtocolSelection(TransProtocol::UDP)); + assert_eq!(sniffer.filters.transport, TransProtocol::UDP); + sniffer.update(Message::TransportProtocolSelection(TransProtocol::TCP)); + assert_eq!(sniffer.filters.transport, TransProtocol::TCP); + sniffer.update(Message::TransportProtocolSelection(TransProtocol::Other)); + assert_eq!(sniffer.filters.transport, TransProtocol::Other); + } + + #[test] + fn test_correctly_update_application_protocol() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.filters.application, AppProtocol::Other); + sniffer.update(Message::AppProtocolSelection(AppProtocol::HTTPS)); + assert_eq!(sniffer.filters.application, AppProtocol::HTTPS); + sniffer.update(Message::AppProtocolSelection(AppProtocol::HTTP)); + assert_eq!(sniffer.filters.application, AppProtocol::HTTP); + sniffer.update(Message::AppProtocolSelection(AppProtocol::HTTP)); + assert_eq!(sniffer.filters.application, AppProtocol::HTTP); + sniffer.update(Message::AppProtocolSelection(AppProtocol::XMPP)); + assert_eq!(sniffer.filters.application, AppProtocol::XMPP); + } + + #[test] + fn test_correctly_update_chart_kind() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.traffic_chart.chart_type, ChartType::Packets); + sniffer.update(Message::ChartSelection(ChartType::Bytes)); + assert_eq!(sniffer.traffic_chart.chart_type, ChartType::Bytes); + sniffer.update(Message::ChartSelection(ChartType::Bytes)); + assert_eq!(sniffer.traffic_chart.chart_type, ChartType::Bytes); + sniffer.update(Message::ChartSelection(ChartType::Packets)); + assert_eq!(sniffer.traffic_chart.chart_type, ChartType::Packets); + } + + #[test] + fn test_correctly_update_report_kind() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.report_type, ReportType::MostRecent); + sniffer.update(Message::ReportSelection(ReportType::MostBytes)); + assert_eq!(sniffer.report_type, ReportType::MostBytes); + sniffer.update(Message::ReportSelection(ReportType::MostPackets)); + assert_eq!(sniffer.report_type, ReportType::MostPackets); + sniffer.update(Message::ReportSelection(ReportType::MostPackets)); + assert_eq!(sniffer.report_type, ReportType::MostPackets); + sniffer.update(Message::ReportSelection(ReportType::MostRecent)); + assert_eq!(sniffer.report_type, ReportType::MostRecent); + sniffer.update(Message::ReportSelection(ReportType::Favorites)); + assert_eq!(sniffer.report_type, ReportType::Favorites); + } + + #[test] + fn test_correctly_update_style() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + sniffer.update(Message::Style(StyleType::MonAmour)); + assert_eq!(sniffer.style, StyleType::MonAmour); + assert_eq!( + sniffer.traffic_chart.color_font, + to_rgb_color(get_colors(StyleType::MonAmour).text_body) + ); + assert_eq!( + sniffer.traffic_chart.color_outgoing, + to_rgb_color(get_colors(StyleType::MonAmour).outgoing) + ); + assert_eq!( + sniffer.traffic_chart.color_incoming, + to_rgb_color(get_colors(StyleType::MonAmour).secondary) + ); + assert_eq!( + sniffer.traffic_chart.color_mix, + get_color_mix_chart(StyleType::MonAmour) + ); + sniffer.update(Message::Style(StyleType::Day)); + assert_eq!(sniffer.style, StyleType::Day); + assert_eq!( + sniffer.traffic_chart.color_font, + to_rgb_color(get_colors(StyleType::Day).text_body) + ); + assert_eq!( + sniffer.traffic_chart.color_outgoing, + to_rgb_color(get_colors(StyleType::Day).outgoing) + ); + assert_eq!( + sniffer.traffic_chart.color_incoming, + to_rgb_color(get_colors(StyleType::Day).secondary) + ); + assert_eq!( + sniffer.traffic_chart.color_mix, + get_color_mix_chart(StyleType::Day) + ); + sniffer.update(Message::Style(StyleType::Night)); + assert_eq!(sniffer.style, StyleType::Night); + assert_eq!( + sniffer.traffic_chart.color_font, + to_rgb_color(get_colors(StyleType::Night).text_body) + ); + assert_eq!( + sniffer.traffic_chart.color_outgoing, + to_rgb_color(get_colors(StyleType::Night).outgoing) + ); + assert_eq!( + sniffer.traffic_chart.color_incoming, + to_rgb_color(get_colors(StyleType::Night).secondary) + ); + assert_eq!( + sniffer.traffic_chart.color_mix, + get_color_mix_chart(StyleType::Night) + ); + sniffer.update(Message::Style(StyleType::DeepSea)); + assert_eq!(sniffer.style, StyleType::DeepSea); + assert_eq!( + sniffer.traffic_chart.color_font, + to_rgb_color(get_colors(StyleType::DeepSea).text_body) + ); + assert_eq!( + sniffer.traffic_chart.color_outgoing, + to_rgb_color(get_colors(StyleType::DeepSea).outgoing) + ); + assert_eq!( + sniffer.traffic_chart.color_incoming, + to_rgb_color(get_colors(StyleType::DeepSea).secondary) + ); + assert_eq!( + sniffer.traffic_chart.color_mix, + get_color_mix_chart(StyleType::DeepSea) + ); + sniffer.update(Message::Style(StyleType::DeepSea)); + assert_eq!(sniffer.style, StyleType::DeepSea); + assert_eq!( + sniffer.traffic_chart.color_font, + to_rgb_color(get_colors(StyleType::DeepSea).text_body) + ); + assert_eq!( + sniffer.traffic_chart.color_outgoing, + to_rgb_color(get_colors(StyleType::DeepSea).outgoing) + ); + assert_eq!( + sniffer.traffic_chart.color_incoming, + to_rgb_color(get_colors(StyleType::DeepSea).secondary) + ); + assert_eq!( + sniffer.traffic_chart.color_mix, + get_color_mix_chart(StyleType::DeepSea) + ); + } + + #[test] + fn test_waiting_dots_update() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.waiting, ".".to_string()); + sniffer.update(Message::Waiting); + assert_eq!(sniffer.waiting, "..".to_string()); + + sniffer.update(Message::Waiting); + assert_eq!(sniffer.waiting, "...".to_string()); + + sniffer.update(Message::Waiting); + assert_eq!(sniffer.waiting, ".".to_string()); + } + + #[test] + fn test_modify_favorite_connections() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + // remove 1 + sniffer.update(Message::AddOrRemoveFavorite(1, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::new() + ); + // remove 2 + sniffer.update(Message::AddOrRemoveFavorite(2, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::new() + ); + // add 2 + sniffer.update(Message::AddOrRemoveFavorite(2, true)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([2]) + ); + // remove 1 + sniffer.update(Message::AddOrRemoveFavorite(1, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([2]) + ); + // add 2 + sniffer.update(Message::AddOrRemoveFavorite(2, true)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([2]) + ); + // add 1 + sniffer.update(Message::AddOrRemoveFavorite(1, true)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([1, 2]) + ); + // add 3 + sniffer.update(Message::AddOrRemoveFavorite(3, true)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([1, 2, 3]) + ); + // remove 2 + sniffer.update(Message::AddOrRemoveFavorite(2, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([1, 3]) + ); + // remove 3 + sniffer.update(Message::AddOrRemoveFavorite(3, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::from([1]) + ); + // remove 1 + sniffer.update(Message::AddOrRemoveFavorite(1, false)); + assert_eq!( + sniffer.info_traffic.lock().unwrap().favorite_connections, + HashSet::new() + ); + } + + #[test] + fn test_show_and_hide_modal_and_settings() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Notifications); + // open settings + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Notifications)); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Notifications); + // switch settings page + sniffer.update(Message::OpenSettings(SettingsPage::Appearance)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Appearance)); + sniffer.update(Message::OpenSettings(SettingsPage::Language)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Language)); + // try opening modal with settings opened + sniffer.update(Message::ShowModal(MyModal::Quit)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Language)); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Notifications); + // close settings + sniffer.update(Message::CloseSettings); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Language); + // reopen settings + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Language)); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Language); + // switch settings page + sniffer.update(Message::OpenSettings(SettingsPage::Appearance)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Appearance)); + // close settings + sniffer.update(Message::CloseSettings); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + + // open clear all modal + sniffer.update(Message::ShowModal(MyModal::ClearAll)); + assert_eq!(sniffer.modal, Some(MyModal::ClearAll)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // try opening settings with clear all modal opened + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.modal, Some(MyModal::ClearAll)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // try opening quit modal with clear all modal opened + sniffer.update(Message::ShowModal(MyModal::Quit)); + assert_eq!(sniffer.modal, Some(MyModal::ClearAll)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // close clear all modal + sniffer.update(Message::HideModal); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + + // open quit modal + sniffer.update(Message::ShowModal(MyModal::Quit)); + assert_eq!(sniffer.modal, Some(MyModal::Quit)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // try opening settings with clear all modal opened + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.modal, Some(MyModal::Quit)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // try opening clear all modal with quit modal opened + sniffer.update(Message::ShowModal(MyModal::ClearAll)); + assert_eq!(sniffer.modal, Some(MyModal::Quit)); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + // close quit modal + sniffer.update(Message::HideModal); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.last_opened_setting, SettingsPage::Appearance); + } + + #[test] + fn test_correctly_update_language() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + assert_eq!(sniffer.language, Language::EN); + assert_eq!(sniffer.traffic_chart.language, Language::EN); + sniffer.update(Message::LanguageSelection(Language::IT)); + assert_eq!(sniffer.language, Language::IT); + assert_eq!(sniffer.traffic_chart.language, Language::IT); + sniffer.update(Message::LanguageSelection(Language::IT)); + assert_eq!(sniffer.language, Language::IT); + assert_eq!(sniffer.traffic_chart.language, Language::IT); + sniffer.update(Message::LanguageSelection(Language::ZH)); + assert_eq!(sniffer.language, Language::ZH); + assert_eq!(sniffer.traffic_chart.language, Language::ZH); + } + + #[test] + fn test_correctly_update_notification_settings() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + // initial default state + assert_eq!(sniffer.notifications.volume, 60); + assert_eq!( + sniffer.notifications.packets_notification, + PacketsNotification { + threshold: None, + sound: Sound::Gulp, + previous_threshold: 750 + } + ); + assert_eq!( + sniffer.notifications.bytes_notification, + BytesNotification { + threshold: None, + byte_multiple: ByteMultiple::KB, + sound: Sound::Pop, + previous_threshold: 800000 + } + ); + assert_eq!( + sniffer.notifications.favorite_notification, + FavoriteNotification { + notify_on_favorite: false, + sound: Sound::Swhoosh, + } + ); + // change volume + sniffer.update(Message::ChangeVolume(95)); + assert_eq!(sniffer.notifications.volume, 95); + assert_eq!( + sniffer.notifications.packets_notification, + PacketsNotification { + threshold: None, + sound: Sound::Gulp, + previous_threshold: 750 + } + ); + assert_eq!( + sniffer.notifications.bytes_notification, + BytesNotification { + threshold: None, + byte_multiple: ByteMultiple::KB, + sound: Sound::Pop, + previous_threshold: 800000 + } + ); + assert_eq!( + sniffer.notifications.favorite_notification, + FavoriteNotification { + notify_on_favorite: false, + sound: Sound::Swhoosh, + } + ); + // change packets notifications + sniffer.update(Message::UpdateNotificationSettings( + Notification::Packets(PacketsNotification { + threshold: Some(1122), + sound: Sound::None, + previous_threshold: 1122, + }), + false, + )); + assert_eq!(sniffer.notifications.volume, 95); + assert_eq!( + sniffer.notifications.packets_notification, + PacketsNotification { + threshold: Some(1122), + sound: Sound::None, + previous_threshold: 1122 + } + ); + assert_eq!( + sniffer.notifications.bytes_notification, + BytesNotification { + threshold: None, + byte_multiple: ByteMultiple::KB, + sound: Sound::Pop, + previous_threshold: 800000 + } + ); + assert_eq!( + sniffer.notifications.favorite_notification, + FavoriteNotification { + notify_on_favorite: false, + sound: Sound::Swhoosh, + } + ); + // change bytes notifications + sniffer.update(Message::UpdateNotificationSettings( + Notification::Bytes(BytesNotification { + threshold: Some(3), + byte_multiple: ByteMultiple::GB, + sound: Sound::None, + previous_threshold: 3, + }), + true, + )); + assert_eq!(sniffer.notifications.volume, 95); + assert_eq!( + sniffer.notifications.packets_notification, + PacketsNotification { + threshold: Some(1122), + sound: Sound::None, + previous_threshold: 1122 + } + ); + assert_eq!( + sniffer.notifications.bytes_notification, + BytesNotification { + threshold: Some(3), + byte_multiple: ByteMultiple::GB, + sound: Sound::None, + previous_threshold: 3, + } + ); + assert_eq!( + sniffer.notifications.favorite_notification, + FavoriteNotification { + notify_on_favorite: false, + sound: Sound::Swhoosh, + } + ); + // change favorite notifications + sniffer.update(Message::UpdateNotificationSettings( + Notification::Favorite(FavoriteNotification { + notify_on_favorite: true, + sound: Sound::Pop, + }), + true, + )); + assert_eq!(sniffer.notifications.volume, 95); + assert_eq!( + sniffer.notifications.packets_notification, + PacketsNotification { + threshold: Some(1122), + sound: Sound::None, + previous_threshold: 1122 + } + ); + assert_eq!( + sniffer.notifications.bytes_notification, + BytesNotification { + threshold: Some(3), + byte_multiple: ByteMultiple::GB, + sound: Sound::None, + previous_threshold: 3, + } + ); + assert_eq!( + sniffer.notifications.favorite_notification, + FavoriteNotification { + notify_on_favorite: true, + sound: Sound::Pop + } + ); + } + + #[test] + fn test_clear_all_notifications() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + sniffer.runtime_data.logged_notifications = + VecDeque::from([LoggedNotification::PacketsThresholdExceeded( + PacketsThresholdExceeded { + threshold: 0, + incoming: 0, + outgoing: 0, + timestamp: "".to_string(), + }, + )]); + + assert_eq!(sniffer.modal, None); + sniffer.update(Message::ShowModal(MyModal::ClearAll)); + assert_eq!(sniffer.modal, Some(MyModal::ClearAll)); + assert_eq!(sniffer.runtime_data.logged_notifications.len(), 1); + sniffer.update(Message::ClearAllNotifications); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.runtime_data.logged_notifications.len(), 0); + } + + #[test] + fn test_correctly_switch_running_and_notification_pages() { + let mut sniffer = Sniffer::new( + Arc::new(Mutex::new(0)), + Arc::new(Mutex::new(InfoTraffic::new())), + Arc::new((Mutex::new(Status::Init), Default::default())), + &Default::default(), + &Default::default(), + Arc::new(Mutex::new(Err(String::new()))), + ); + + // initial status + assert_eq!(*sniffer.status_pair.0.lock().unwrap(), Status::Init); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + // nothing changes + sniffer.update(Message::SwitchPage(true)); + assert_eq!(*sniffer.status_pair.0.lock().unwrap(), Status::Init); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + // switch settings + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Notifications)); + assert_eq!(sniffer.running_page, RunningPage::Overview); + sniffer.update(Message::SwitchPage(false)); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Language)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + sniffer.update(Message::SwitchPage(true)); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Notifications)); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + sniffer.update(Message::CloseSettings); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + // change state to running + sniffer.update(Message::Start); + assert_eq!(*sniffer.status_pair.0.lock().unwrap(), Status::Running); + assert_eq!(sniffer.settings_page, None); + assert_eq!(sniffer.modal, None); + assert_eq!(sniffer.running_page, RunningPage::Overview); + // switch with closed setting => change running page + sniffer.update(Message::SwitchPage(true)); + assert_eq!(sniffer.running_page, RunningPage::Notifications); + assert_eq!(sniffer.settings_page, None); + // switch with opened settings => change settings + sniffer.update(Message::OpenLastSettings); + assert_eq!(sniffer.running_page, RunningPage::Notifications); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Notifications)); + sniffer.update(Message::SwitchPage(true)); + assert_eq!(sniffer.running_page, RunningPage::Notifications); + assert_eq!(sniffer.settings_page, Some(SettingsPage::Appearance)); + } +} diff --git a/src/gui/types/status.rs b/src/gui/types/status.rs index c8197dea..cb05ae8b 100644 --- a/src/gui/types/status.rs +++ b/src/gui/types/status.rs @@ -1,5 +1,5 @@ /// This enum represents the sniffing process status. -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Status { /// Sniffnet has just been launched/restarted and gui is in the main screen. Init,