feature: add nord and nord-light colours (#406)

Adds colour schemes for Nord, along with a light variant.
This commit is contained in:
Clement Tsang 2021-02-15 14:12:43 -05:00 committed by GitHub
parent f2e6b9232d
commit fb7b1226fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 211 additions and 148 deletions

View file

@ -9,13 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Features ## Features
- [#263](https://github.com/ClementTsang/bottom/pull/263): Adds the option for fine-grained kill signals on Unix-like systems.
- [#333](https://github.com/ClementTsang/bottom/pull/333): Adds an "out of" indicator that can be enabled using `--show_table_scroll_position` (and its corresponding config option) to help keep track of scrolled position. - [#333](https://github.com/ClementTsang/bottom/pull/333): Adds an "out of" indicator that can be enabled using `--show_table_scroll_position` (and its corresponding config option) to help keep track of scrolled position.
- [#379](https://github.com/ClementTsang/bottom/pull/379): Adds `--process_command` flag and corresponding config option to default to showing a process' command. - [#379](https://github.com/ClementTsang/bottom/pull/379): Adds `--process_command` flag and corresponding config option to default to showing a process' command.
- [#381](https://github.com/ClementTsang/bottom/pull/381): Adds a filter in the config file for network interfaces. - [#381](https://github.com/ClementTsang/bottom/pull/381): Adds a filter in the config file for network interfaces.
## [0.5.8] - Unreleased - [#406](https://github.com/ClementTsang/bottom/pull/406): Adds the Nord colour scheme, as well as a light variant.
## Changes ## Changes

View file

@ -563,31 +563,31 @@ The following options can be set under `[flags]` to achieve the same effect as p
These are the following supported flag config values, which correspond to the flag of the same name described in [Flags](#flags): These are the following supported flag config values, which correspond to the flag of the same name described in [Flags](#flags):
| Field | Type | Functionality | | Field | Type | Functionality |
| ---------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------- | | ---------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. | | `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
| `dot_marker` | Boolean | Uses a dot marker for graphs. | | `dot_marker` | Boolean | Uses a dot marker for graphs. |
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. | | `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. | | `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. |
| `group_processes` | Boolean | Groups processes with the same name by default. | | `group_processes` | Boolean | Groups processes with the same name by default. |
| `case_sensitive` | Boolean | Enables case sensitivity by default. | | `case_sensitive` | Boolean | Enables case sensitivity by default. |
| `whole_word` | Boolean | Enables whole-word matching by default. | | `whole_word` | Boolean | Enables whole-word matching by default. |
| `regex` | Boolean | Enables regex by default. | | `regex` | Boolean | Enables regex by default. |
| `basic` | Boolean | Hides graphs and uses a more basic look. | | `basic` | Boolean | Hides graphs and uses a more basic look. |
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. | | `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
| `battery` | Boolean | Shows the battery widget. | | `battery` | Boolean | Shows the battery widget. |
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. | | `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. |
| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. | | `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. |
| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. | | `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. |
| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. | | `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. |
| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. | | `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. |
| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. | | `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. |
| `disable_click` | Boolean | Disables mouse clicks. | | `disable_click` | Boolean | Disables mouse clicks. |
| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light"]) | Use a color scheme, use --help for supported values. | | `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. |
| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. | | `mem_as_value` | Boolean | Defaults to showing process memory usage by value. |
| `tree` | Boolean | Defaults to showing the process widget in tree mode. | | `tree` | Boolean | Defaults to showing the process widget in tree mode. |
| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. | | `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. |
| `process_command` | Boolean | Show processes as their commands by default. | | `process_command` | Boolean | Show processes as their commands by default. |
#### Theming #### Theming

View file

@ -526,7 +526,7 @@ impl App {
); );
} }
self.did_config_fail_to_save = self.update_config_file().is_err(); // self.did_config_fail_to_save = self.update_config_file().is_err();
} }
} }
@ -586,7 +586,7 @@ impl App {
); );
} }
self.did_config_fail_to_save = self.update_config_file().is_err(); // self.did_config_fail_to_save = self.update_config_file().is_err();
} }
} }
@ -642,7 +642,7 @@ impl App {
); );
} }
self.did_config_fail_to_save = self.update_config_file().is_err(); // self.did_config_fail_to_save = self.update_config_file().is_err();
} }
} }
@ -1565,28 +1565,28 @@ impl App {
self.is_force_redraw = true; self.is_force_redraw = true;
} }
/// TODO: Disabled.
/// Call this whenever the config value is updated! /// Call this whenever the config value is updated!
fn update_config_file(&mut self) -> anyhow::Result<()> { // fn update_config_file(&mut self) -> anyhow::Result<()> {
// TODO: Disabled. // if self.app_config_fields.no_write {
// if self.app_config_fields.no_write { // // debug!("No write enabled. Config will not be written.");
// // debug!("No write enabled. Config will not be written."); // // Don't write!
// // Don't write! // // FIXME: [CONFIG] This should be made VERY clear to the user... make a thing saying "it will not write due to no_write option"
// // FIXME: [CONFIG] This should be made VERY clear to the user... make a thing saying "it will not write due to no_write option" // Ok(())
// Ok(()) // } else if let Some(config_path) = &self.config_path {
// } else if let Some(config_path) = &self.config_path { // // Update
// // Update // // debug!("Updating config file - writing to: {:?}", config_path);
// // debug!("Updating config file - writing to: {:?}", config_path); // std::fs::File::create(config_path)?
// std::fs::File::create(config_path)? // .write_all(self.config.get_config_as_bytes()?.as_ref())?;
// .write_all(self.config.get_config_as_bytes()?.as_ref())?; // Ok(())
// Ok(()) // } else {
// } else { // // FIXME: [CONFIG] Put an actual error message?
// // FIXME: [CONFIG] Put an actual error message? // Err(anyhow::anyhow!(
// Err(anyhow::anyhow!( // "Config path was missing, please try restarting bottom..."
// "Config path was missing, please try restarting bottom..." // ))
// )) // }
// } // Ok(())
Ok(()) // }
}
pub fn kill_highlighted_process(&mut self) -> Result<()> { pub fn kill_highlighted_process(&mut self) -> Result<()> {
if let BottomWidgetType::Proc = self.current_widget.widget_type { if let BottomWidgetType::Proc = self.current_widget.widget_type {

View file

@ -12,20 +12,24 @@ pub struct BottomLayout {
pub total_row_height_ratio: u32, pub total_row_height_ratio: u32,
} }
type WidgetMappings = (u32, BTreeMap<(u32, u32), u64>); // Represents a start and end coordinate in some dimension.
type ColumnRowMappings = (u32, BTreeMap<(u32, u32), WidgetMappings>); type LineSegment = (u32, u32);
type ColumnMappings = (u32, BTreeMap<(u32, u32), ColumnRowMappings>);
type WidgetMappings = (u32, BTreeMap<LineSegment, u64>);
type ColumnRowMappings = (u32, BTreeMap<LineSegment, WidgetMappings>);
type ColumnMappings = (u32, BTreeMap<LineSegment, ColumnRowMappings>);
impl BottomLayout { impl BottomLayout {
pub fn get_movement_mappings(&mut self) { pub fn get_movement_mappings(&mut self) {
fn is_intersecting(a: (u32, u32), b: (u32, u32)) -> bool { #[allow(clippy::suspicious_operation_groupings)] // Have to enable this, clippy really doesn't like me doing this with tuples...
fn is_intersecting(a: LineSegment, b: LineSegment) -> bool {
a.0 >= b.0 && a.1 <= b.1 a.0 >= b.0 && a.1 <= b.1
|| a.1 >= b.1 && a.0 <= b.0 || a.1 >= b.1 && a.0 <= b.0
|| a.0 <= b.0 && a.1 >= b.0 || a.0 <= b.0 && a.1 >= b.0
|| a.0 >= b.0 && a.0 < b.1 && a.1 >= b.1 || a.0 >= b.0 && a.0 < b.1 && a.1 >= b.1
} }
fn get_distance(target: (u32, u32), candidate: (u32, u32)) -> u32 { fn get_distance(target: LineSegment, candidate: LineSegment) -> u32 {
if candidate.0 < target.0 { if candidate.0 < target.0 {
candidate.1 - target.0 candidate.1 - target.0
} else if candidate.1 < target.1 { } else if candidate.1 < target.1 {
@ -38,20 +42,20 @@ impl BottomLayout {
// Now we need to create the correct mapping for moving from a specific // Now we need to create the correct mapping for moving from a specific
// widget to another // widget to another
let mut layout_mapping: BTreeMap<(u32, u32), ColumnMappings> = BTreeMap::new(); let mut layout_mapping: BTreeMap<LineSegment, ColumnMappings> = BTreeMap::new();
let mut total_height = 0; let mut total_height = 0;
for row in &self.rows { for row in &self.rows {
let mut row_width = 0; let mut row_width = 0;
let mut row_mapping: BTreeMap<(u32, u32), ColumnRowMappings> = BTreeMap::new(); let mut row_mapping: BTreeMap<LineSegment, ColumnRowMappings> = BTreeMap::new();
let mut is_valid_row = false; let mut is_valid_row = false;
for col in &row.children { for col in &row.children {
let mut col_row_height = 0; let mut col_row_height = 0;
let mut col_mapping: BTreeMap<(u32, u32), WidgetMappings> = BTreeMap::new(); let mut col_mapping: BTreeMap<LineSegment, WidgetMappings> = BTreeMap::new();
let mut is_valid_col = false; let mut is_valid_col = false;
for col_row in &col.children { for col_row in &col.children {
let mut widget_width = 0; let mut widget_width = 0;
let mut col_row_mapping: BTreeMap<(u32, u32), u64> = BTreeMap::new(); let mut col_row_mapping: BTreeMap<LineSegment, u64> = BTreeMap::new();
let mut is_valid_col_row = false; let mut is_valid_col_row = false;
for widget in &col_row.children { for widget in &col_row.children {
match widget.widget_type { match widget.widget_type {

View file

@ -27,7 +27,11 @@ impl Process {
} }
fn kill(self) -> Result<(), String> { fn kill(self) -> Result<(), String> {
unsafe { TerminateProcess(self.0, 1) }; let result = unsafe { TerminateProcess(self.0, 1) };
if result == 0 {
return Err("Failed to kill process".to_string());
}
Ok(()) Ok(())
} }
} }

View file

@ -625,34 +625,33 @@ impl Prefix {
is_ignoring_case, is_ignoring_case,
is_searching_with_regex, is_searching_with_regex,
); );
} else if let Some((prefix_type, query_content)) = &mut self.regex_prefix { } else if let Some((prefix_type, StringQuery::Value(regex_string))) = &mut self.regex_prefix
if let StringQuery::Value(regex_string) = query_content { {
match prefix_type { match prefix_type {
PrefixType::Pid | PrefixType::Name | PrefixType::State => { PrefixType::Pid | PrefixType::Name | PrefixType::State => {
let escaped_regex: String; let escaped_regex: String;
let final_regex_string = &format!( let final_regex_string = &format!(
"{}{}{}{}", "{}{}{}{}",
if is_searching_whole_word { "^" } else { "" }, if is_searching_whole_word { "^" } else { "" },
if is_ignoring_case { "(?i)" } else { "" }, if is_ignoring_case { "(?i)" } else { "" },
if !is_searching_with_regex { if !is_searching_with_regex {
escaped_regex = regex::escape(regex_string); escaped_regex = regex::escape(regex_string);
&escaped_regex &escaped_regex
} else { } else {
regex_string regex_string
}, },
if is_searching_whole_word { "$" } else { "" }, if is_searching_whole_word { "$" } else { "" },
); );
let taken_pwc = self.regex_prefix.take(); let taken_pwc = self.regex_prefix.take();
if let Some((taken_pt, _)) = taken_pwc { if let Some((taken_pt, _)) = taken_pwc {
self.regex_prefix = Some(( self.regex_prefix = Some((
taken_pt, taken_pt,
StringQuery::Regex(regex::Regex::new(final_regex_string)?), StringQuery::Regex(regex::Regex::new(final_regex_string)?),
)); ));
}
} }
_ => {}
} }
_ => {}
} }
} }

View file

@ -66,7 +66,8 @@ pub enum ColourScheme {
DefaultLight, DefaultLight,
Gruvbox, Gruvbox,
GruvboxLight, GruvboxLight,
// Nord, Nord,
NordLight,
Custom, Custom,
} }
@ -80,7 +81,8 @@ impl FromStr for ColourScheme {
"default-light" => Ok(ColourScheme::DefaultLight), "default-light" => Ok(ColourScheme::DefaultLight),
"gruvbox" => Ok(ColourScheme::Gruvbox), "gruvbox" => Ok(ColourScheme::Gruvbox),
"gruvbox-light" => Ok(ColourScheme::GruvboxLight), "gruvbox-light" => Ok(ColourScheme::GruvboxLight),
// "nord" => Ok(ColourScheme::Nord), "nord" => Ok(ColourScheme::Nord),
"nord-light" => Ok(ColourScheme::NordLight),
_ => Err(BottomError::ConfigError(format!( _ => Err(BottomError::ConfigError(format!(
"\"{}\" is an invalid built-in color scheme.", "\"{}\" is an invalid built-in color scheme.",
s s
@ -227,10 +229,14 @@ impl Painter {
self.colours self.colours
.set_colours_from_palette(&*GRUVBOX_LIGHT_COLOUR_PALETTE)?; .set_colours_from_palette(&*GRUVBOX_LIGHT_COLOUR_PALETTE)?;
} }
// ColourScheme::Nord => { ColourScheme::Nord => {
// self.colours self.colours
// .set_colours_from_palette(&*NORD_COLOUR_PALETTE)?; .set_colours_from_palette(&*NORD_COLOUR_PALETTE)?;
// } }
ColourScheme::NordLight => {
self.colours
.set_colours_from_palette(&*NORD_LIGHT_COLOUR_PALETTE)?;
}
ColourScheme::Custom => { ColourScheme::Custom => {
// This case should never occur, just do nothing. // This case should never occur, just do nothing.
} }

View file

@ -231,11 +231,22 @@ Use a pre-defined color scheme. Currently supported values are:
+------------------------------------------------------------+ +------------------------------------------------------------+
| gruvbox-light (gruvbox but for use with light backgrounds) | | gruvbox-light (gruvbox but for use with light backgrounds) |
+------------------------------------------------------------+ +------------------------------------------------------------+
| nord (an arctic, north-bluish color palette) |
+------------------------------------------------------------+
| nord-light (nord but for use with light backgrounds) |
+------------------------------------------------------------+
Defaults to \"default\". Defaults to \"default\".
\n\n", \n\n",
) )
.possible_values(&["default", "default-light", "gruvbox", "gruvbox-light"]) .possible_values(&[
"default",
"default-light",
"gruvbox",
"gruvbox-light",
"nord",
"nord-light",
])
.hide_possible_values(true); .hide_possible_values(true);
let mem_as_value = Arg::with_name("mem_as_value") let mem_as_value = Arg::with_name("mem_as_value")
.long("mem_as_value") .long("mem_as_value")

View file

@ -45,6 +45,7 @@ pub static DEFAULT_LIGHT_MODE_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(||
disabled_text_color: Some("gray".to_string()), disabled_text_color: Some("gray".to_string()),
..ConfigColours::default() ..ConfigColours::default()
}); });
pub static GRUVBOX_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours { pub static GRUVBOX_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours {
table_header_color: Some("#83a598".to_string()), table_header_color: Some("#83a598".to_string()),
all_cpu_color: Some("#8ec07c".to_string()), all_cpu_color: Some("#8ec07c".to_string()),
@ -89,6 +90,7 @@ pub static GRUVBOX_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColo
medium_battery_color: Some("#fabd2f".to_string()), medium_battery_color: Some("#fabd2f".to_string()),
low_battery_color: Some("#fb4934".to_string()), low_battery_color: Some("#fb4934".to_string()),
}); });
pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours { pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours {
table_header_color: Some("#076678".to_string()), table_header_color: Some("#076678".to_string()),
all_cpu_color: Some("#8ec07c".to_string()), all_cpu_color: Some("#8ec07c".to_string()),
@ -134,6 +136,72 @@ pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| Conf
low_battery_color: Some("#cc241d".to_string()), low_battery_color: Some("#cc241d".to_string()),
}); });
pub static NORD_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours {
table_header_color: Some("#81a1c1".to_string()),
all_cpu_color: Some("#88c0d0".to_string()),
avg_cpu_color: Some("#8fbcbb".to_string()),
cpu_core_colors: Some(vec![
"#5e81ac".to_string(),
"#81a1c1".to_string(),
"#d8dee9".to_string(),
"#b48ead".to_string(),
"#a3be8c".to_string(),
"#ebcb8b".to_string(),
"#d08770".to_string(),
"#bf616a".to_string(),
]),
ram_color: Some("#88c0d0".to_string()),
swap_color: Some("#d08770".to_string()),
rx_color: Some("#88c0d0".to_string()),
tx_color: Some("#d08770".to_string()),
rx_total_color: Some("#5e81ac".to_string()),
tx_total_color: Some("#8fbcbb".to_string()),
border_color: Some("#e5e9f0".to_string()),
highlighted_border_color: Some("#88c0d0".to_string()),
disabled_text_color: Some("#4c566a".to_string()),
text_color: Some("#e5e9f0".to_string()),
selected_text_color: Some("#2e3440".to_string()),
selected_bg_color: Some("#88c0d0".to_string()),
widget_title_color: Some("#e5e9f0".to_string()),
graph_color: Some("#e5e9f0".to_string()),
high_battery_color: Some("#a3be8c".to_string()),
medium_battery_color: Some("#ebcb8b".to_string()),
low_battery_color: Some("#bf616a".to_string()),
});
pub static NORD_LIGHT_COLOUR_PALETTE: Lazy<ConfigColours> = Lazy::new(|| ConfigColours {
table_header_color: Some("#5e81ac".to_string()),
all_cpu_color: Some("#81a1c1".to_string()),
avg_cpu_color: Some("#8fbcbb".to_string()),
cpu_core_colors: Some(vec![
"#5e81ac".to_string(),
"#88c0d0".to_string(),
"#4c566a".to_string(),
"#b48ead".to_string(),
"#a3be8c".to_string(),
"#ebcb8b".to_string(),
"#d08770".to_string(),
"#bf616a".to_string(),
]),
ram_color: Some("#81a1c1".to_string()),
swap_color: Some("#d08770".to_string()),
rx_color: Some("#81a1c1".to_string()),
tx_color: Some("#d08770".to_string()),
rx_total_color: Some("#5e81ac".to_string()),
tx_total_color: Some("#8fbcbb".to_string()),
border_color: Some("#2e3440".to_string()),
highlighted_border_color: Some("#5e81ac".to_string()),
disabled_text_color: Some("#d8dee9".to_string()),
text_color: Some("#2e3440".to_string()),
selected_text_color: Some("#f5f5f5".to_string()),
selected_bg_color: Some("#5e81ac".to_string()),
widget_title_color: Some("#2e3440".to_string()),
graph_color: Some("#2e3440".to_string()),
high_battery_color: Some("#a3be8c".to_string()),
medium_battery_color: Some("#ebcb8b".to_string()),
low_battery_color: Some("#bf616a".to_string()),
});
// Help text // Help text
pub const HELP_CONTENTS_TEXT: [&str; 8] = [ pub const HELP_CONTENTS_TEXT: [&str; 8] = [
"Press the corresponding numbers to jump to the section, or scroll:", "Press the corresponding numbers to jump to the section, or scroll:",

View file

@ -11,7 +11,7 @@ fn get_binary_location() -> String {
} }
#[test] #[test]
fn test_small_rate() -> Result<(), Box<dyn std::error::Error>> { fn test_small_rate() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-r") .arg("-r")
.arg("249") .arg("249")
@ -20,11 +20,10 @@ fn test_small_rate() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your update rate to be at least 250 milliseconds.", "set your update rate to be at least 250 milliseconds.",
)); ));
Ok(())
} }
#[test] #[test]
fn test_large_default_time() -> Result<(), Box<dyn std::error::Error>> { fn test_large_default_time() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-t") .arg("-t")
.arg("18446744073709551616") .arg("18446744073709551616")
@ -33,11 +32,10 @@ fn test_large_default_time() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your default value to be at most", "set your default value to be at most",
)); ));
Ok(())
} }
#[test] #[test]
fn test_small_default_time() -> Result<(), Box<dyn std::error::Error>> { fn test_small_default_time() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-t") .arg("-t")
.arg("900") .arg("900")
@ -46,11 +44,10 @@ fn test_small_default_time() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your default value to be at least", "set your default value to be at least",
)); ));
Ok(())
} }
#[test] #[test]
fn test_large_delta_time() -> Result<(), Box<dyn std::error::Error>> { fn test_large_delta_time() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-d") .arg("-d")
.arg("18446744073709551616") .arg("18446744073709551616")
@ -59,11 +56,10 @@ fn test_large_delta_time() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your time delta to be at most", "set your time delta to be at most",
)); ));
Ok(())
} }
#[test] #[test]
fn test_small_delta_time() -> Result<(), Box<dyn std::error::Error>> { fn test_small_delta_time() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-d") .arg("-d")
.arg("900") .arg("900")
@ -72,11 +68,10 @@ fn test_small_delta_time() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your time delta to be at least", "set your time delta to be at least",
)); ));
Ok(())
} }
#[test] #[test]
fn test_large_rate() -> Result<(), Box<dyn std::error::Error>> { fn test_large_rate() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-r") .arg("-r")
.arg("18446744073709551616") .arg("18446744073709551616")
@ -85,11 +80,10 @@ fn test_large_rate() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your update rate to be at most unsigned INT_MAX.", "set your update rate to be at most unsigned INT_MAX.",
)); ));
Ok(())
} }
#[test] #[test]
fn test_negative_rate() -> Result<(), Box<dyn std::error::Error>> { fn test_negative_rate() {
// This test should auto fail due to how clap works // This test should auto fail due to how clap works
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-r") .arg("-r")
@ -99,24 +93,20 @@ fn test_negative_rate() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"wasn't expected, or isn't valid in this context", "wasn't expected, or isn't valid in this context",
)); ));
Ok(())
} }
#[test] #[test]
fn test_invalid_rate() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_rate() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-r") .arg("-r")
.arg("100-1000") .arg("100-1000")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid digit")); .stderr(predicate::str::contains("invalid digit"));
Ok(())
} }
#[test] #[test]
fn test_conflicting_temps() -> Result<(), Box<dyn std::error::Error>> { fn test_conflicting_temps() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-c") .arg("-c")
.arg("-f") .arg("-f")
@ -125,24 +115,20 @@ fn test_conflicting_temps() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"cannot be used with one or more of the other specified arguments", "cannot be used with one or more of the other specified arguments",
)); ));
Ok(())
} }
#[test] #[test]
fn test_invalid_default_widget_1() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_default_widget_1() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("--default_widget_type") .arg("--default_widget_type")
.arg("fake_widget") .arg("fake_widget")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid widget name")); .stderr(predicate::str::contains("invalid widget name"));
Ok(())
} }
#[test] #[test]
fn test_invalid_default_widget_2() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_default_widget_2() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("--default_widget_type") .arg("--default_widget_type")
.arg("cpu") .arg("cpu")
@ -153,12 +139,10 @@ fn test_invalid_default_widget_2() -> Result<(), Box<dyn std::error::Error>> {
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"set your widget count to be at most unsigned INT_MAX", "set your widget count to be at most unsigned INT_MAX",
)); ));
Ok(())
} }
#[test] #[test]
fn test_missing_default_widget_type() -> Result<(), Box<dyn std::error::Error>> { fn test_missing_default_widget_type() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("--default_widget_count") .arg("--default_widget_count")
.arg("3") .arg("3")
@ -167,6 +151,4 @@ fn test_missing_default_widget_type() -> Result<(), Box<dyn std::error::Error>>
.stderr(predicate::str::contains( .stderr(predicate::str::contains(
"The following required arguments were not provided", "The following required arguments were not provided",
)); ));
Ok(())
} }

View file

@ -9,150 +9,137 @@ fn get_binary_location() -> String {
} }
#[test] #[test]
fn test_toml_mismatch_type() -> Result<(), Box<dyn std::error::Error>> { fn test_toml_mismatch_type() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/toml_mismatch_type.toml") .arg("./tests/invalid_configs/toml_mismatch_type.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid type")); .stderr(predicate::str::contains("invalid type"));
Ok(())
} }
#[test] #[test]
fn test_empty_layout() -> Result<(), Box<dyn std::error::Error>> { fn test_empty_layout() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/empty_layout.toml") .arg("./tests/invalid_configs/empty_layout.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("at least one widget")); .stderr(predicate::str::contains("at least one widget"));
Ok(())
} }
#[test] #[test]
fn test_invalid_layout_widget_type() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_layout_widget_type() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_layout_widget_type.toml") .arg("./tests/invalid_configs/invalid_layout_widget_type.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid widget name")); .stderr(predicate::str::contains("invalid widget name"));
Ok(())
} }
/// This test isn't really needed as this is technically covered by TOML spec. /// This test isn't really needed as this is technically covered by TOML spec.
/// However, I feel like it's worth checking anyways - not like it takes long. /// However, I feel like it's worth checking anyways - not like it takes long.
#[test] #[test]
fn test_duplicate_temp_type() -> Result<(), Box<dyn std::error::Error>> { fn test_duplicate_temp_type() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/duplicate_temp_type.toml") .arg("./tests/invalid_configs/duplicate_temp_type.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("duplicate field")); .stderr(predicate::str::contains("duplicate field"));
Ok(())
} }
/// Checks for if a hex is valid /// Checks for if a hex is valid
#[test] #[test]
fn test_invalid_colour_hex() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_hex() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_hex.toml") .arg("./tests/invalid_configs/invalid_colour_hex.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid hex colour")); .stderr(predicate::str::contains("invalid hex colour"));
Ok(())
} }
/// Checks for if a hex is too long /// Checks for if a hex is too long
#[test] #[test]
fn test_invalid_colour_hex_2() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_hex_2() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_hex_2.toml") .arg("./tests/invalid_configs/invalid_colour_hex_2.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid hex colour")); .stderr(predicate::str::contains("invalid hex colour"));
Ok(())
} }
/// Checks unicode hex because the way we originally did it could cause char /// Checks unicode hex because the way we originally did it could cause char
/// boundary errors! /// boundary errors!
#[test] #[test]
fn test_invalid_colour_hex_3() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_hex_3() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_hex_3.toml") .arg("./tests/invalid_configs/invalid_colour_hex_3.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid hex colour")); .stderr(predicate::str::contains("invalid hex colour"));
Ok(())
} }
#[test] #[test]
fn test_invalid_colour_name() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_name() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_name.toml") .arg("./tests/invalid_configs/invalid_colour_name.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid named colour")); .stderr(predicate::str::contains("invalid named colour"));
Ok(())
} }
#[test] #[test]
fn test_invalid_colour_rgb() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_rgb() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_rgb.toml") .arg("./tests/invalid_configs/invalid_colour_rgb.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid RGB")); .stderr(predicate::str::contains("invalid RGB"));
Ok(())
} }
#[test] #[test]
fn test_invalid_colour_rgb_2() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_rgb_2() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_rgb_2.toml") .arg("./tests/invalid_configs/invalid_colour_rgb_2.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid RGB")); .stderr(predicate::str::contains("invalid RGB"));
Ok(())
} }
#[test] #[test]
fn test_invalid_colour_string() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_colour_string() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_colour_string.toml") .arg("./tests/invalid_configs/invalid_colour_string.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid named colour")); .stderr(predicate::str::contains("invalid named colour"));
Ok(())
} }
#[test] #[test]
fn test_lone_default_widget_count() -> Result<(), Box<dyn std::error::Error>> { fn test_lone_default_widget_count() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/lone_default_widget_count.toml") .arg("./tests/invalid_configs/lone_default_widget_count.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("it must be used with")); .stderr(predicate::str::contains("it must be used with"));
Ok(())
} }
#[test] #[test]
fn test_invalid_default_widget_count() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_default_widget_count() {
Command::new(get_binary_location()) Command::new(get_binary_location())
.arg("-C") .arg("-C")
.arg("./tests/invalid_configs/invalid_default_widget_count.toml") .arg("./tests/invalid_configs/invalid_default_widget_count.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("invalid number")); .stderr(predicate::str::contains("invalid number"));
Ok(())
} }