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 @@
-
+
+ src="https://img.shields.io/github/workflow/status/MissterHao/ruscode/release?style=for-the-badge" alt="Github Release Action status badge" />
-
+
+
+
+
+
+ src="https://img.shields.io/github/license/MissterHao/ruscode?style=for-the-badge" alt="Lience badge" />
-
-
+
+ src="https://img.shields.io/github/downloads/MissterHao/ruscode/total?style=for-the-badge&logo=Rust" alt="Rust badge" >
@@ -42,6 +46,11 @@
+
+
+
+
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.");