Added unit and integration tests
This commit is contained in:
Generated
+24
@@ -475,6 +475,12 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@@ -651,12 +657,14 @@ dependencies = [
|
|||||||
"indoc",
|
"indoc",
|
||||||
"log",
|
"log",
|
||||||
"log4rs",
|
"log4rs",
|
||||||
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
"secrecy",
|
"secrecy",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"validator",
|
"validator",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
@@ -1182,6 +1190,16 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr2"
|
name = "proc-macro-error-attr2"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -2210,6 +2228,12 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|||||||
+9
-9
@@ -3,7 +3,7 @@ name = "gman"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
description = "Universal secret management and command injection tool"
|
description = "Universal secret management and injection tool"
|
||||||
keywords = ["cli", "secrets", "credentials", "command-line", "encryption"]
|
keywords = ["cli", "secrets", "credentials", "command-line", "encryption"]
|
||||||
documentation = "https://github.com/Dark-Alex-17/gman"
|
documentation = "https://github.com/Dark-Alex-17/gman"
|
||||||
repository = "https://github.com/Dark-Alex-17/gman"
|
repository = "https://github.com/Dark-Alex-17/gman"
|
||||||
@@ -41,19 +41,19 @@ chrono = "0.4.42"
|
|||||||
indoc = "2.0.6"
|
indoc = "2.0.6"
|
||||||
regex = "1.11.2"
|
regex = "1.11.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "1.4.1"
|
||||||
|
tempfile = "3.10.1"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
bench = false
|
bench = false
|
||||||
name = "gman"
|
name = "gman"
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "mod_tests"
|
|
||||||
path = "tests/providers/mod_tests.rs"
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "local_tests"
|
|
||||||
path = "tests/providers/local_tests.rs"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
strip = true
|
strip = true
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "integration"
|
||||||
|
path = "tests/tests.rs"
|
||||||
|
|||||||
+27
-26
@@ -1,5 +1,7 @@
|
|||||||
use crate::command::preview_command;
|
use crate::command::preview_command;
|
||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
use gman::config::{Config, RunConfig};
|
||||||
|
use gman::providers::SecretProvider;
|
||||||
use heck::ToSnakeCase;
|
use heck::ToSnakeCase;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -8,8 +10,6 @@ use std::ffi::OsString;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use gman::config::{Config, RunConfig};
|
|
||||||
use gman::providers::SecretProvider;
|
|
||||||
|
|
||||||
const ARG_FORMAT_PLACEHOLDER_KEY: &str = "{{key}}";
|
const ARG_FORMAT_PLACEHOLDER_KEY: &str = "{{key}}";
|
||||||
const ARG_FORMAT_PLACEHOLDER_VALUE: &str = "{{value}}";
|
const ARG_FORMAT_PLACEHOLDER_VALUE: &str = "{{value}}";
|
||||||
@@ -246,32 +246,33 @@ pub fn parse_args(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use crate::cli::generate_files_secret_injections;
|
||||||
use gman::config::RunConfig;
|
use gman::config::RunConfig;
|
||||||
use crate::cli::generate_files_secret_injections;
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_generate_files_secret_injections() {
|
fn test_generate_files_secret_injections() {
|
||||||
let mut secrets = HashMap::new();
|
let mut secrets = HashMap::new();
|
||||||
secrets.insert("SECRET1".to_string(), "value1".to_string());
|
secrets.insert("SECRET1".to_string(), "value1".to_string());
|
||||||
let temp_dir = tempfile::tempdir().unwrap();
|
let temp_dir = tempfile::tempdir().unwrap();
|
||||||
let file_path = temp_dir.path().join("test.txt");
|
let file_path = temp_dir.path().join("test.txt");
|
||||||
std::fs::write(&file_path, "{{secret1}}").unwrap();
|
std::fs::write(&file_path, "{{secret1}}").unwrap();
|
||||||
|
|
||||||
let run_config = RunConfig {
|
let run_config = RunConfig {
|
||||||
name: Some("test".to_string()),
|
name: Some("test".to_string()),
|
||||||
secrets: Some(vec!["secret1".to_string()]),
|
secrets: Some(vec!["secret1".to_string()]),
|
||||||
files: Some(vec![file_path.clone()]),
|
files: Some(vec![file_path.clone()]),
|
||||||
flag: None,
|
flag: None,
|
||||||
flag_position: None,
|
flag_position: None,
|
||||||
arg_format: None,
|
arg_format: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = generate_files_secret_injections(secrets, &run_config).unwrap();
|
let result = generate_files_secret_injections(secrets, &run_config).unwrap();
|
||||||
|
|
||||||
assert_eq!(result.len(), 1);
|
assert_eq!(result.len(), 1);
|
||||||
assert_eq!(result[0].0, &file_path);
|
assert_eq!(result[0].0, &file_path);
|
||||||
assert_eq!(result[0].1, "{{secret1}}");
|
assert_str_eq!(result[0].1, "{{secret1}}");
|
||||||
assert_eq!(result[0].2, "value1");
|
assert_str_eq!(result[0].2, "value1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,3 +102,23 @@ fn ps_quote(s: &OsStr) -> String {
|
|||||||
s.into_owned()
|
s.into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::command::preview_command;
|
||||||
|
use pretty_assertions::assert_str_eq;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_preview_command() {
|
||||||
|
let mut cmd = Command::new("echo");
|
||||||
|
cmd.arg("hello world");
|
||||||
|
cmd.env("MY_VAR", "my_value");
|
||||||
|
let preview = preview_command(&cmd);
|
||||||
|
if cfg!(unix) {
|
||||||
|
assert_str_eq!(preview, "MY_VAR=my_value echo 'hello world'");
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
assert_str_eq!(preview, "set MY_VAR=my_value && \"echo\" \"hello world\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use clap::{
|
use clap::{
|
||||||
crate_authors, crate_description, crate_name, crate_version, CommandFactory, Parser, ValueEnum,
|
CommandFactory, Parser, ValueEnum, crate_authors, crate_description, crate_name, crate_version,
|
||||||
};
|
};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
use crossterm::execute;
|
use crossterm::execute;
|
||||||
use crossterm::terminal::{disable_raw_mode, LeaveAlternateScreen};
|
use crossterm::terminal::{LeaveAlternateScreen, disable_raw_mode};
|
||||||
use gman::config::Config;
|
use gman::config::Config;
|
||||||
use gman::providers::local::LocalProvider;
|
|
||||||
use gman::providers::SupportedProvider;
|
use gman::providers::SupportedProvider;
|
||||||
|
use gman::providers::local::LocalProvider;
|
||||||
use heck::ToSnakeCase;
|
use heck::ToSnakeCase;
|
||||||
use std::io::{self, IsTerminal, Read, Write};
|
use std::io::{self, IsTerminal, Read, Write};
|
||||||
use std::panic::PanicHookInfo;
|
use std::panic::PanicHookInfo;
|
||||||
|
|||||||
@@ -41,3 +41,20 @@ pub fn get_log_path() -> PathBuf {
|
|||||||
log_path.push("gman.log");
|
log_path.push("gman.log");
|
||||||
log_path
|
log_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::utils::get_log_path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_log_path() {
|
||||||
|
let log_path = get_log_path();
|
||||||
|
if cfg!(target_os = "linux") {
|
||||||
|
assert!(log_path.ends_with(".cache/gman/gman.log"));
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
assert!(log_path.ends_with("Library/Logs/gman/gman.log"));
|
||||||
|
} else if cfg!(target_os = "windows") {
|
||||||
|
assert!(log_path.ends_with("Logs\\gman\\gman.log"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ pub fn decrypt_string(password: impl Into<SecretString>, envelope: &str) -> Resu
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn round_trip() {
|
fn round_trip() {
|
||||||
|
|||||||
@@ -330,3 +330,27 @@ fn get_password(config: &Config) -> Result<SecretString> {
|
|||||||
Ok(SecretString::new(password.into()))
|
Ok(SecretString::new(password.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::derive_key;
|
||||||
|
use crate::providers::local::derive_key_with_params;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use secrecy::SecretString;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_key() {
|
||||||
|
let password = SecretString::new("test_password".to_string().into());
|
||||||
|
let salt = [0u8; 16];
|
||||||
|
let key = derive_key(&password, &salt).unwrap();
|
||||||
|
assert_eq!(key.as_slice().len(), 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_key_with_params() {
|
||||||
|
let password = SecretString::new("test_password".to_string().into());
|
||||||
|
let salt = [0u8; 16];
|
||||||
|
let key = derive_key_with_params(&password, &salt, 10, 1, 1).unwrap();
|
||||||
|
assert_eq!(key.as_slice().len(), 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
use gman::providers::SupportedProvider;
|
||||||
|
use gman::providers::local::LocalProvider;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_provider_kind_from() {
|
||||||
|
enum ProviderKind {
|
||||||
|
Local,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ProviderKind> for SupportedProvider {
|
||||||
|
fn from(k: ProviderKind) -> Self {
|
||||||
|
match k {
|
||||||
|
ProviderKind::Local => SupportedProvider::Local(LocalProvider),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider_kind = ProviderKind::Local;
|
||||||
|
let supported_provider: SupportedProvider = provider_kind.into();
|
||||||
|
assert_eq!(supported_provider, SupportedProvider::Local(LocalProvider));
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mod main_tests;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mod gman;
|
||||||
@@ -3,6 +3,7 @@ mod tests {
|
|||||||
use gman::config::{Config, RunConfig};
|
use gman::config::{Config, RunConfig};
|
||||||
use gman::providers::SupportedProvider;
|
use gman::providers::SupportedProvider;
|
||||||
use gman::providers::local::LocalProvider;
|
use gman::providers::local::LocalProvider;
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
@@ -190,7 +191,7 @@ mod tests {
|
|||||||
fn test_config_extract_provider() {
|
fn test_config_extract_provider() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let provider = config.extract_provider();
|
let provider = config.extract_provider();
|
||||||
assert_eq!(provider.name(), "LocalProvider");
|
assert_str_eq!(provider.name(), "LocalProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
// Redefining the struct here for testing purposes
|
||||||
|
pub struct SyncOpts<'a> {
|
||||||
|
pub remote_url: &'a Option<String>,
|
||||||
|
pub branch: &'a Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Validate for SyncOpts<'a> {
|
||||||
|
fn validate(&self) -> Result<(), validator::ValidationErrors> {
|
||||||
|
if self.remote_url.is_none() {
|
||||||
|
return Err(validator::ValidationErrors::new());
|
||||||
|
}
|
||||||
|
if self.branch.is_none() {
|
||||||
|
return Err(validator::ValidationErrors::new());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sync_opts_validation_valid() {
|
||||||
|
let remote_url = Some("https://github.com/user/repo.git".to_string());
|
||||||
|
let branch = Some("main".to_string());
|
||||||
|
let opts = SyncOpts {
|
||||||
|
remote_url: &remote_url,
|
||||||
|
branch: &branch,
|
||||||
|
};
|
||||||
|
assert!(opts.validate().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sync_opts_validation_missing_remote_url() {
|
||||||
|
let remote_url = None;
|
||||||
|
let branch = Some("main".to_string());
|
||||||
|
let opts = SyncOpts {
|
||||||
|
remote_url: &remote_url,
|
||||||
|
branch: &branch,
|
||||||
|
};
|
||||||
|
assert!(opts.validate().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sync_opts_validation_missing_branch() {
|
||||||
|
let remote_url = Some("https://github.com/user/repo.git".to_string());
|
||||||
|
let branch = None;
|
||||||
|
let opts = SyncOpts {
|
||||||
|
remote_url: &remote_url,
|
||||||
|
branch: &branch,
|
||||||
|
};
|
||||||
|
assert!(opts.validate().is_err());
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use gman::providers::local::LocalProviderConfig;
|
use gman::providers::local::LocalProviderConfig;
|
||||||
|
use pretty_assertions::assert_str_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_local_provider_config_default() {
|
fn test_local_provider_config_default() {
|
||||||
@@ -7,5 +8,14 @@ fn test_local_provider_config_default() {
|
|||||||
.map(|p| p.join(".gman_vault"))
|
.map(|p| p.join(".gman_vault"))
|
||||||
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
||||||
.unwrap_or_else(|| ".gman_vault".into());
|
.unwrap_or_else(|| ".gman_vault".into());
|
||||||
assert_eq!(config.vault_path, expected_path);
|
assert_str_eq!(config.vault_path, expected_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_local_provider_name() {
|
||||||
|
use gman::providers::SecretProvider;
|
||||||
|
use gman::providers::local::LocalProvider;
|
||||||
|
|
||||||
|
let provider = LocalProvider;
|
||||||
|
assert_str_eq!(provider.name(), "LocalProvider");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod git_sync_tests;
|
||||||
|
mod local_tests;
|
||||||
|
mod provider_tests;
|
||||||
@@ -1,7 +1,29 @@
|
|||||||
use gman::providers::local::LocalProvider;
|
use gman::providers::local::LocalProvider;
|
||||||
use gman::providers::{ParseProviderError, SupportedProvider};
|
use gman::providers::{ParseProviderError, SupportedProvider};
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_supported_provider_from_str() {
|
||||||
|
assert_eq!(
|
||||||
|
SupportedProvider::from_str("local").unwrap(),
|
||||||
|
SupportedProvider::Local(LocalProvider)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
SupportedProvider::from_str(" Local ").unwrap(),
|
||||||
|
SupportedProvider::Local(LocalProvider)
|
||||||
|
);
|
||||||
|
assert!(matches!(
|
||||||
|
SupportedProvider::from_str("invalid"),
|
||||||
|
Err(ParseProviderError::Unsupported(_))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_supported_provider_display() {
|
||||||
|
assert_str_eq!(SupportedProvider::Local(LocalProvider).to_string(), "local");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_supported_provider_from_str_valid() {
|
fn test_supported_provider_from_str_valid() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -17,13 +39,7 @@ fn test_supported_provider_from_str_valid() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_supported_provider_from_str_invalid() {
|
fn test_supported_provider_from_str_invalid() {
|
||||||
let err = SupportedProvider::from_str("invalid").unwrap_err();
|
let err = SupportedProvider::from_str("invalid").unwrap_err();
|
||||||
assert_eq!(err.to_string(), "unsupported provider 'invalid'");
|
assert_str_eq!(err.to_string(), "unsupported provider 'invalid'");
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_supported_provider_display() {
|
|
||||||
let provider = SupportedProvider::Local(LocalProvider);
|
|
||||||
assert_eq!(provider.to_string(), "local");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod bin;
|
||||||
|
mod config_tests;
|
||||||
|
mod providers;
|
||||||
Reference in New Issue
Block a user