From fd0972165d534a8fd217bc9e306c942371718963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A7=E6=9A=90?= Date: Fri, 25 Nov 2022 08:45:07 +0800 Subject: [PATCH] Add unit test for serveral mod (#7) * feat: add unit test * CodeCov test * Update README.md * feat: Add Makefile --- Makefile | 28 +++++ README.md | 23 ++-- src/application/app.rs | 2 +- src/common/system.rs | 110 ++++++++++++++++-- src/common/text.rs | 20 ++++ src/domain/entity/tag.rs | 24 ++++ src/domain/system/folder_observer.rs | 10 -- src/domain/system/init.rs | 32 ++++- src/domain/value_object/mod.rs | 10 +- src/infrastructure/repository/mod.rs | 28 +++++ .../repository/workspace_repository.rs | 1 - 11 files changed, 254 insertions(+), 34 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e25d583 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# This is a makefile just for maintainer who is using windows operation system as developing environment. + +.PHONY: all +all: + set RUSTFLAGS= + set LLVM_PROFILE_FILE= + cargo run + +.PHONY: lint +lint: + set RUSTFLAGS= + set LLVM_PROFILE_FILE= + cargo fmt --check -- --color always + cargo clippy --all-targets -- -D warnings + +.PHONY: clean +clean: + del *.profraw + +.PHONY: test +test: + set LLVM_PROFILE_FILE=ruscode-%p-%m.profraw + set "RUSTFLAGS=-Cinstrument-coverage -Ccodegen-units=1 -Clink-dead-code -Coverflow-checks=on" + cargo build + cargo test + set + grcov . --binary-path ./target/debug/ -s . -t html --branch --ignore-not-existing -o ./coverage/ + \ No newline at end of file diff --git a/README.md b/README.md index 950816f..613b0cd 100644 --- a/README.md +++ b/README.md @@ -11,22 +11,26 @@ Github Issue badge - + Lience badge + src="https://img.shields.io/github/workflow/status/MissterHao/ruscode/release?style=for-the-badge" alt="Github Release Action status badge" /> - + + codecov + + Rust badge +
Rust badge + src="https://img.shields.io/github/license/MissterHao/ruscode?style=for-the-badge" alt="Lience badge" /> -
- + codecov + src="https://img.shields.io/github/downloads/MissterHao/ruscode/total?style=for-the-badge&logo=Rust" alt="Rust badge" >
@@ -42,6 +46,11 @@ macOS supported badge +
+ + codecov +

diff --git a/src/application/app.rs b/src/application/app.rs index 4046420..37dd63b 100644 --- a/src/application/app.rs +++ b/src/application/app.rs @@ -207,7 +207,7 @@ impl<'a> App<'a> { /// Init environment pub fn init_environment(&mut self) -> Result<(), ApplicationError> { // Default app folder create - init_application_folders().expect("Failed to create application folders."); + init_application_folders(None).expect("Failed to create application folders."); // Make sure database is always exists self.create_database(SystemPaths::database().as_str()) diff --git a/src/common/system.rs b/src/common/system.rs index 7bfdef3..7d4a752 100644 --- a/src/common/system.rs +++ b/src/common/system.rs @@ -1,22 +1,30 @@ use crate::common::text::strip_trailing_newline; -use std::process::Command; +use std::process::{Command, Output}; use std::str; pub struct SystemPaths {} impl SystemPaths { + fn windows_user_home_dir() -> Output { + Command::new("cmd") + .args(["/C", "echo %userprofile%"]) + .output() + .expect("failed to execute process") + } + + fn ubuntu_user_home_dir() -> Output { + Command::new("sh") + .arg("-c") + .arg("getent passwd \"$USER\" | cut -d: -f6 ") + .output() + .expect("failed to execute process") + } + pub fn home_dir() -> String { let output = if cfg!(target_os = "windows") { - Command::new("cmd") - .args(["/C", "echo %userprofile%"]) - .output() - .expect("failed to execute process") + SystemPaths::windows_user_home_dir() } else { - Command::new("sh") - .arg("-c") - .arg("getent passwd \"$USER\" | cut -d: -f6 ") - .output() - .expect("failed to execute process") + SystemPaths::ubuntu_user_home_dir() }; let home = strip_trailing_newline(str::from_utf8(&output.stdout).unwrap()); @@ -75,4 +83,86 @@ mod test_system { fn test_systempaths_homedir_should_work_without_panic() { assert_eq!(type_of(SystemPaths::home_dir()), type_of(String::new())); } + + #[cfg(target_os = "windows")] + #[test] + fn test_systempaths_on_windows() { + SystemPaths::windows_user_home_dir(); + } + #[cfg(target_os = "windows")] + #[test] + fn test_systempaths_on_windows_re_format() { + let output = SystemPaths::windows_user_home_dir(); + let path = str::from_utf8(&output.stdout).unwrap(); + let re = regex::Regex::new(r".*\\Users\\.*").unwrap(); + assert!(re.is_match(path)); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_systempaths_on_linux() { + SystemPaths::ubuntu_user_home_dir(); + } + #[cfg(target_os = "linux")] + #[test] + fn test_systempaths_on_linux_re_format() { + let output = SystemPaths::ubuntu_user_home_dir(); + let path = str::from_utf8(&output.stdout).unwrap(); + let re = regex::Regex::new(r"/home/.*").unwrap(); + assert!(re.is_match(path)); + } + + #[test] + fn test_systempaths_get_home_dir() { + let home_dir = SystemPaths::home_dir(); + assert_eq!(type_of(&home_dir), type_of(&String::new())); + + let re = regex::Regex::new(r"\\\\").unwrap(); + assert_eq!(re.find_iter(home_dir.as_str()).count(), 0); + } + + #[cfg(target_os = "windows")] + #[test] + fn test_vscode_workspace_storage_path_on_windows() { + let path = SystemPaths::vscode_workspace_storage_path(); + let re = + regex::Regex::new(".*/AppData/Roaming/Code/User/workspaceStorage/.*/workspace.json") + .unwrap(); + + assert!(re.is_match(path.as_str())); + } + #[cfg(target_os = "linux")] + #[test] + #[should_panic] + fn test_vscode_workspace_storage_path_on_linux() { + SystemPaths::vscode_workspace_storage_path(); + } + + #[cfg(target_os = "windows")] + #[test] + fn test_application_data_folder_path_on_windows() { + let path = SystemPaths::application_data_folder(); + let re = regex::Regex::new(".*/AppData/Local/ruscode").unwrap(); + assert!(re.is_match(path.as_str())); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_application_data_folder_path_on_linux() { + let path = SystemPaths::application_data_folder(); + let re = regex::Regex::new("/var/lib/ruscode").unwrap(); + assert!(re.is_match(path.as_str())); + } + + #[test] + fn test_database_folder() { + let path = SystemPaths::application_data_folder(); + assert_eq!(format!("{}/database", path), SystemPaths::database_folder()); + } + + #[test] + fn test_database_file_path() { + let path = SystemPaths::database_folder(); + assert_eq!(format!("{}/data.db", path), SystemPaths::database()); + } } diff --git a/src/common/text.rs b/src/common/text.rs index 43dfe74..e47902a 100644 --- a/src/common/text.rs +++ b/src/common/text.rs @@ -4,3 +4,23 @@ pub fn strip_trailing_newline(input: &str) -> &str { .or_else(|| input.strip_suffix('\n')) .unwrap_or(input) } + +#[cfg(test)] +mod test_text { + use super::strip_trailing_newline; + + #[test] + fn strref_should_strip_newline() { + let input = "This is a sentence with newline\r\n"; + let input2 = "This is a sentence with newline\n"; + + assert_eq!( + strip_trailing_newline(input), + "This is a sentence with newline" + ); + assert_eq!( + strip_trailing_newline(input2), + "This is a sentence with newline" + ); + } +} diff --git a/src/domain/entity/tag.rs b/src/domain/entity/tag.rs index ebe41fd..87e3195 100644 --- a/src/domain/entity/tag.rs +++ b/src/domain/entity/tag.rs @@ -12,3 +12,27 @@ impl Tag { } } } + +#[cfg(test)] +mod test_tag_entity { + use super::Tag; + + #[test] + fn tag_entity_should_create_successfully_with_new_associate_function() { + assert_eq!(Tag::new().name, String::from("")); + } + + #[test] + fn tag_entity_should_create_successfully_with_init() { + let t = Tag { + name: String::new(), + }; + assert_eq!(t.name, String::new()); + } + + #[test] + fn tag_entity_should_print_successfully_in_debug_mode() { + let t = Tag::new(); + format!("{:?}", t); + } +} diff --git a/src/domain/system/folder_observer.rs b/src/domain/system/folder_observer.rs index 8c3f41d..5561655 100644 --- a/src/domain/system/folder_observer.rs +++ b/src/domain/system/folder_observer.rs @@ -36,15 +36,5 @@ mod test_folder_observer { fn test_last_modified() { // let sys_time = last_modified(); // let last_modified_secs = sys_time.duration_since(UNIX_EPOCH).unwrap().as_secs(); - - // println!( - // "{:?}", - // Utc.timestamp_opt(last_modified_secs as i64, 0) - // .unwrap() - // .format("%Y/%m/%d") - // .to_string() - // ); - - // println!("{:?}", last_modified_secs); } } diff --git a/src/domain/system/init.rs b/src/domain/system/init.rs index 745d838..bd6d651 100644 --- a/src/domain/system/init.rs +++ b/src/domain/system/init.rs @@ -3,9 +3,33 @@ use std::fs; use super::error::ApplicationInitError; use crate::common::system::SystemPaths; -pub fn init_application_folders() -> Result<(), ApplicationInitError> { - let database_path = SystemPaths::database_folder(); - fs::create_dir_all(database_path).expect("Cannot create application folders."); - +pub fn init_application_folders(path: Option) -> Result<(), ApplicationInitError> { + let create_path: String = match path { + Some(val) => val, + None => SystemPaths::database_folder(), + }; + fs::create_dir_all(create_path).expect("Cannot create application folders."); Ok(()) } + +#[cfg(test)] +mod test_system_init { + use std::fs; + + use super::init_application_folders; + + #[test] + fn test_fake_application_folder_creation() { + let fake_dir_path = "fake/dir/folder"; + let fake_dir_path_root = "fake"; + + match init_application_folders(Some(String::from(fake_dir_path))) { + Ok(_) => { + fs::remove_dir_all(fake_dir_path_root).expect("Remove fake dirs failed."); + } + Err(_) => { + panic!("Cannot create fake application folder."); + } + }; + } +} diff --git a/src/domain/value_object/mod.rs b/src/domain/value_object/mod.rs index 9105868..d752d65 100644 --- a/src/domain/value_object/mod.rs +++ b/src/domain/value_object/mod.rs @@ -16,7 +16,15 @@ mod test_workspacejson { }; assert_eq!(_w.folder, String::from("folder")); } - + #[test] + fn test_workspacejson_string_debug_format() { + format!( + "{:?}", + WorkspaceJson { + folder: String::from("") + } + ); + } #[test] fn test_workspacejson_is_deserializeable() { let _w = WorkspaceJson { diff --git a/src/infrastructure/repository/mod.rs b/src/infrastructure/repository/mod.rs index 1e89b41..7e5890d 100644 --- a/src/infrastructure/repository/mod.rs +++ b/src/infrastructure/repository/mod.rs @@ -61,3 +61,31 @@ pub fn get_db_connection(path: &str) -> Result { Ok(db_connection) } + +#[cfg(test)] +mod test_database { + use std::fs; + + use super::{create_database, get_db_connection}; + + #[test] + fn test_database_should_create_succesfully() { + let testing_database_path = "./test-database.sqlite3"; + if create_database(testing_database_path).is_ok() { + fs::remove_file(testing_database_path).unwrap(); + } else { + panic!("Database create failed!") + } + } + + #[test] + fn test_database_connection_should_succesfully() { + let testing_database_path = "./test-database-conn.sqlite3"; + if create_database(testing_database_path).is_ok() { + get_db_connection(testing_database_path).expect("Cannot get database connection!"); + fs::remove_file(testing_database_path).unwrap(); + } else { + panic!("Database create failed!") + } + } +} diff --git a/src/infrastructure/repository/workspace_repository.rs b/src/infrastructure/repository/workspace_repository.rs index 16c86dc..2cf4945 100644 --- a/src/infrastructure/repository/workspace_repository.rs +++ b/src/infrastructure/repository/workspace_repository.rs @@ -81,7 +81,6 @@ impl WorkspaceRepository { let db_connection = get_db_connection(SystemPaths::database().as_str()) .expect("Cannot get database connection."); - println!("{sql}"); let mut stmt = db_connection .prepare(&sql) .expect("Failed to select all workspaces.");