Improve code quality and add tests
This commit is contained in:
parent
b0280d4443
commit
a5347cfffe
|
@ -30,7 +30,7 @@ pub fn check_dependencies() -> bool {
|
||||||
let status = Command::new("notify-send")
|
let status = Command::new("notify-send")
|
||||||
.arg("-v")
|
.arg("-v")
|
||||||
.output();
|
.output();
|
||||||
if let Err(_) = status {
|
if status.is_err() {
|
||||||
println!("Error: 'notify-send' command is needed for espanso to work correctly, please install it.");
|
println!("Error: 'notify-send' command is needed for espanso to work correctly, please install it.");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ pub fn check_dependencies() -> bool {
|
||||||
let status = Command::new("xclip")
|
let status = Command::new("xclip")
|
||||||
.arg("-version")
|
.arg("-version")
|
||||||
.output();
|
.output();
|
||||||
if let Err(_) = status {
|
if status.is_err() {
|
||||||
println!("Error: 'xclip' command is needed for espanso to work correctly, please install it.");
|
println!("Error: 'xclip' command is needed for espanso to work correctly, please install it.");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ use walkdir::WalkDir;
|
||||||
|
|
||||||
pub(crate) mod runtime;
|
pub(crate) mod runtime;
|
||||||
|
|
||||||
// TODO: add documentation link
|
|
||||||
const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yml");
|
const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yml");
|
||||||
|
|
||||||
const DEFAULT_CONFIG_FILE_NAME : &str = "default.yml";
|
const DEFAULT_CONFIG_FILE_NAME : &str = "default.yml";
|
||||||
|
@ -162,7 +161,7 @@ impl Configs {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
let res = file.read_to_string(&mut contents);
|
let res = file.read_to_string(&mut contents);
|
||||||
|
|
||||||
if let Err(_) = res {
|
if res.is_err() {
|
||||||
return Err(ConfigLoadError::UnableToReadFile)
|
return Err(ConfigLoadError::UnableToReadFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +186,7 @@ impl Configs {
|
||||||
});
|
});
|
||||||
let parent_matches : Vec<Match> = self.matches.iter().filter(|&m| {
|
let parent_matches : Vec<Match> = self.matches.iter().filter(|&m| {
|
||||||
!trigger_set.contains(&m.trigger)
|
!trigger_set.contains(&m.trigger)
|
||||||
}).map(|m| m.clone()).collect();
|
}).cloned().collect();
|
||||||
|
|
||||||
merged_matches.extend(parent_matches);
|
merged_matches.extend(parent_matches);
|
||||||
self.matches = merged_matches;
|
self.matches = merged_matches;
|
||||||
|
@ -200,7 +199,7 @@ impl Configs {
|
||||||
});
|
});
|
||||||
let default_matches : Vec<Match> = default.matches.iter().filter(|&m| {
|
let default_matches : Vec<Match> = default.matches.iter().filter(|&m| {
|
||||||
!trigger_set.contains(&m.trigger)
|
!trigger_set.contains(&m.trigger)
|
||||||
}).map(|m| m.clone()).collect();
|
}).cloned().collect();
|
||||||
|
|
||||||
self.matches.extend(default_matches);
|
self.matches.extend(default_matches);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +325,7 @@ impl ConfigSet {
|
||||||
// Create the espanso dir if id doesn't exist
|
// Create the espanso dir if id doesn't exist
|
||||||
let res = create_dir_all(espanso_dir.as_path());
|
let res = create_dir_all(espanso_dir.as_path());
|
||||||
|
|
||||||
if let Ok(_) = res {
|
if res.is_ok() {
|
||||||
let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
||||||
|
|
||||||
// If config file does not exist, create one from template
|
// If config file does not exist, create one from template
|
||||||
|
@ -358,13 +357,12 @@ impl ConfigSet {
|
||||||
return ConfigSet::load(espanso_dir.as_path())
|
return ConfigSet::load(espanso_dir.as_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(ConfigLoadError::UnableToCreateDefaultConfig)
|
Err(ConfigLoadError::UnableToCreateDefaultConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_default_config_dir() -> PathBuf {
|
pub fn get_default_config_dir() -> PathBuf {
|
||||||
let home_dir = dirs::home_dir().expect("Unable to get home directory");
|
let home_dir = dirs::home_dir().expect("Unable to get home directory");
|
||||||
let espanso_dir = home_dir.join(".espanso");
|
home_dir.join(".espanso")
|
||||||
espanso_dir
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_default_packages_dir() -> PathBuf {
|
pub fn get_default_packages_dir() -> PathBuf {
|
||||||
|
|
|
@ -27,7 +27,7 @@ use std::fs;
|
||||||
use log::{info, error};
|
use log::{info, error};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
const STATUS_ICON_BINARY : &'static [u8] = include_bytes!("../res/mac/icon.png");
|
const STATUS_ICON_BINARY : &[u8] = include_bytes!("../res/mac/icon.png");
|
||||||
|
|
||||||
pub struct MacContext {
|
pub struct MacContext {
|
||||||
pub send_channel: Sender<Event>
|
pub send_channel: Sender<Event>
|
||||||
|
@ -42,7 +42,7 @@ impl MacContext {
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
error!("Accessibility must be enabled to make espanso work on MacOS.");
|
error!("Accessibility must be enabled to make espanso work on MacOS.");
|
||||||
error!("Please allow espanso in the Security & Privacy panel, then restart espanso.");
|
error!("Please allow espanso in the Security & Privacy panel, then restart espanso.");
|
||||||
error!("For more information: "); // TODO: add documentation link
|
error!("For more information: https://espanso.org/install/mac/");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ use std::{fs};
|
||||||
use widestring::U16CString;
|
use widestring::U16CString;
|
||||||
use log::{info};
|
use log::{info};
|
||||||
|
|
||||||
const BMP_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp");
|
const BMP_BINARY : &[u8] = include_bytes!("../res/win/espanso.bmp");
|
||||||
const ICO_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.ico");
|
const ICO_BINARY : &[u8] = include_bytes!("../res/win/espanso.ico");
|
||||||
|
|
||||||
pub struct WindowsContext {
|
pub struct WindowsContext {
|
||||||
send_channel: Sender<Event>,
|
send_channel: Sender<Event>,
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl <'a> EventManager for DefaultEventManager<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => panic!("Broken event channel"),
|
Err(e) => panic!("Broken event channel {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
src/main.rs
34
src/main.rs
|
@ -63,7 +63,7 @@ mod clipboard;
|
||||||
mod extension;
|
mod extension;
|
||||||
mod sysdaemon;
|
mod sysdaemon;
|
||||||
|
|
||||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const LOG_FILE: &str = "espanso.log";
|
const LOG_FILE: &str = "espanso.log";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -168,52 +168,52 @@ fn main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("dump") {
|
if matches.subcommand_matches("dump").is_some() {
|
||||||
println!("{:#?}", config_set);
|
println!("{:#?}", config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("detect") {
|
if matches.subcommand_matches("detect").is_some() {
|
||||||
detect_main();
|
detect_main();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("daemon") {
|
if matches.subcommand_matches("daemon").is_some() {
|
||||||
daemon_main(config_set);
|
daemon_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("register") {
|
if matches.subcommand_matches("register").is_some() {
|
||||||
register_main(config_set);
|
register_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("unregister") {
|
if matches.subcommand_matches("unregister").is_some() {
|
||||||
unregister_main(config_set);
|
unregister_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("log") {
|
if matches.subcommand_matches("log").is_some() {
|
||||||
log_main();
|
log_main();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("start") {
|
if matches.subcommand_matches("start").is_some() {
|
||||||
start_main(config_set);
|
start_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("status") {
|
if matches.subcommand_matches("status").is_some() {
|
||||||
status_main();
|
status_main();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("stop") {
|
if matches.subcommand_matches("stop").is_some() {
|
||||||
stop_main(config_set);
|
stop_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("restart") {
|
if matches.subcommand_matches("restart").is_some() {
|
||||||
restart_main(config_set);
|
restart_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ fn main() {
|
||||||
list_package_main(config_set, matches);
|
list_package_main(config_set, matches);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(_) = matches.subcommand_matches("refresh") {
|
if matches.subcommand_matches("refresh").is_some() {
|
||||||
update_index_main(config_set);
|
update_index_main(config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -525,22 +525,22 @@ fn detect_main() {
|
||||||
|
|
||||||
/// Send the given command to the espanso daemon
|
/// Send the given command to the espanso daemon
|
||||||
fn cmd_main(config_set: ConfigSet, matches: &ArgMatches) {
|
fn cmd_main(config_set: ConfigSet, matches: &ArgMatches) {
|
||||||
let command = if let Some(_) = matches.subcommand_matches("exit") {
|
let command = if matches.subcommand_matches("exit").is_some() {
|
||||||
Some(IPCCommand {
|
Some(IPCCommand {
|
||||||
id: String::from("exit"),
|
id: String::from("exit"),
|
||||||
payload: String::from(""),
|
payload: String::from(""),
|
||||||
})
|
})
|
||||||
}else if let Some(_) = matches.subcommand_matches("toggle") {
|
}else if matches.subcommand_matches("toggle").is_some() {
|
||||||
Some(IPCCommand {
|
Some(IPCCommand {
|
||||||
id: String::from("toggle"),
|
id: String::from("toggle"),
|
||||||
payload: String::from(""),
|
payload: String::from(""),
|
||||||
})
|
})
|
||||||
}else if let Some(_) = matches.subcommand_matches("enable") {
|
}else if matches.subcommand_matches("enable").is_some() {
|
||||||
Some(IPCCommand {
|
Some(IPCCommand {
|
||||||
id: String::from("enable"),
|
id: String::from("enable"),
|
||||||
payload: String::from(""),
|
payload: String::from(""),
|
||||||
})
|
})
|
||||||
}else if let Some(_) = matches.subcommand_matches("disable") {
|
}else if matches.subcommand_matches("disable").is_some() {
|
||||||
Some(IPCCommand {
|
Some(IPCCommand {
|
||||||
id: String::from("disable"),
|
id: String::from("disable"),
|
||||||
payload: String::from(""),
|
payload: String::from(""),
|
||||||
|
@ -748,7 +748,7 @@ fn acquire_lock() -> Option<File> {
|
||||||
|
|
||||||
let res = file.try_lock_exclusive();
|
let res = file.try_lock_exclusive();
|
||||||
|
|
||||||
if let Ok(_) = res {
|
if res.is_ok() {
|
||||||
return Some(file)
|
return Some(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ impl <'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMa
|
||||||
if m == config.toggle_key {
|
if m == config.toggle_key {
|
||||||
let mut toggle_press_time = self.toggle_press_time.borrow_mut();
|
let mut toggle_press_time = self.toggle_press_time.borrow_mut();
|
||||||
if let Ok(elapsed) = toggle_press_time.elapsed() {
|
if let Ok(elapsed) = toggle_press_time.elapsed() {
|
||||||
if elapsed.as_millis() < config.toggle_interval as u128 {
|
if elapsed.as_millis() < u128::from(config.toggle_interval) {
|
||||||
self.toggle();
|
self.toggle();
|
||||||
|
|
||||||
let is_enabled = self.is_enabled.borrow();
|
let is_enabled = self.is_enabled.borrow();
|
||||||
|
|
|
@ -117,16 +117,14 @@ impl DefaultPackageManager {
|
||||||
}else{
|
}else{
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
}else{
|
}else if started {
|
||||||
if started {
|
let caps = FIELD_REGEX.captures(&line);
|
||||||
let caps = FIELD_REGEX.captures(&line);
|
if let Some(caps) = caps {
|
||||||
if let Some(caps) = caps {
|
let property = caps.get(1);
|
||||||
let property = caps.get(1);
|
let value = caps.get(2);
|
||||||
let value = caps.get(2);
|
if property.is_some() && value.is_some() {
|
||||||
if property.is_some() && value.is_some() {
|
fields.insert(property.unwrap().as_str().to_owned(),
|
||||||
fields.insert(property.unwrap().as_str().to_owned(),
|
value.unwrap().as_str().to_owned());
|
||||||
value.unwrap().as_str().to_owned());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +159,7 @@ impl DefaultPackageManager {
|
||||||
return local_index.last_update
|
return local_index.last_update
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_local_packages_names(&self) -> Vec<String> {
|
fn list_local_packages_names(&self) -> Vec<String> {
|
||||||
|
@ -260,14 +258,14 @@ impl super::PackageManager for DefaultPackageManager {
|
||||||
let readme_path = temp_package_dir.join("README.md");
|
let readme_path = temp_package_dir.join("README.md");
|
||||||
|
|
||||||
let package = Self::parse_package_from_readme(&readme_path);
|
let package = Self::parse_package_from_readme(&readme_path);
|
||||||
if !package.is_some() {
|
if package.is_none() {
|
||||||
return Ok(InstallResult::UnableToParsePackageInfo); // TODO: test
|
return Ok(InstallResult::UnableToParsePackageInfo);
|
||||||
}
|
}
|
||||||
let package = package.unwrap();
|
let package = package.unwrap();
|
||||||
|
|
||||||
let source_dir = temp_package_dir.join(package.version);
|
let source_dir = temp_package_dir.join(package.version);
|
||||||
if !source_dir.exists() {
|
if !source_dir.exists() {
|
||||||
return Ok(InstallResult::MissingPackageVersion); // TODO: test
|
return Ok(InstallResult::MissingPackageVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_dir = &self.package_dir.join(name);
|
let target_dir = &self.package_dir.join(name);
|
||||||
|
@ -317,7 +315,7 @@ mod tests {
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::package::PackageManager;
|
use crate::package::PackageManager;
|
||||||
use std::fs::{create_dir, create_dir_all};
|
use std::fs::{create_dir, create_dir_all};
|
||||||
use crate::package::InstallResult::{Installed, NotFoundInRepo};
|
use crate::package::InstallResult::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
const OUTDATED_INDEX_CONTENT : &str = include_str!("../res/test/outdated_index.json");
|
const OUTDATED_INDEX_CONTENT : &str = include_str!("../res/test/outdated_index.json");
|
||||||
|
@ -496,6 +494,36 @@ mod tests {
|
||||||
assert_eq!(temp.package_manager.install_package("not-existing").unwrap(), NotFoundInRepo);
|
assert_eq!(temp.package_manager.install_package("not-existing").unwrap(), NotFoundInRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_package_missing_version() {
|
||||||
|
let mut temp = create_temp_package_manager(|_, data_dir| {
|
||||||
|
let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE);
|
||||||
|
std::fs::write(index_file, INSTALL_PACKAGE_INDEX);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(temp.package_manager.install_package("dummy-package2").unwrap(), MissingPackageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_package_missing_readme_unable_to_parse_package_info() {
|
||||||
|
let mut temp = create_temp_package_manager(|_, data_dir| {
|
||||||
|
let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE);
|
||||||
|
std::fs::write(index_file, INSTALL_PACKAGE_INDEX);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(temp.package_manager.install_package("dummy-package3").unwrap(), UnableToParsePackageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_package_bad_readme_unable_to_parse_package_info() {
|
||||||
|
let mut temp = create_temp_package_manager(|_, data_dir| {
|
||||||
|
let index_file = data_dir.join(DEFAULT_PACKAGE_INDEX_FILE);
|
||||||
|
std::fs::write(index_file, INSTALL_PACKAGE_INDEX);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(temp.package_manager.install_package("dummy-package4").unwrap(), UnableToParsePackageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_local_packages() {
|
fn test_list_local_packages() {
|
||||||
let mut temp = create_temp_package_manager(|_, data_dir| {
|
let mut temp = create_temp_package_manager(|_, data_dir| {
|
||||||
|
|
|
@ -12,6 +12,36 @@
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "dummy-package2",
|
||||||
|
"title": "Dummy Package",
|
||||||
|
"version": "9.9.9",
|
||||||
|
"repo": "https://github.com/federico-terzi/espanso-hub-core",
|
||||||
|
"desc": "Dummy package",
|
||||||
|
"author": "Federico Terzi"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "dummy-package3",
|
||||||
|
"title": "Dummy Package",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"repo": "https://github.com/federico-terzi/espanso-hub-core",
|
||||||
|
"desc": "Dummy package",
|
||||||
|
"author": "Federico Terzi"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "dummy-package4",
|
||||||
|
"title": "Dummy Package",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"repo": "https://github.com/federico-terzi/espanso-hub-core",
|
||||||
|
"desc": "Dummy package",
|
||||||
|
"author": "Federico Terzi"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "italian-accents",
|
"name": "italian-accents",
|
||||||
|
|
|
@ -22,7 +22,7 @@ use super::MenuItem;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
const LINUX_ICON_CONTENT : &'static [u8] = include_bytes!("../res/linux/icon.png");
|
const LINUX_ICON_CONTENT : &[u8] = include_bytes!("../res/linux/icon.png");
|
||||||
|
|
||||||
pub struct LinuxUIManager {
|
pub struct LinuxUIManager {
|
||||||
icon_path: PathBuf,
|
icon_path: PathBuf,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user