Compare commits
10 Commits
b6b810e232
...
096b907a23
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
096b907a23 | ||
|
|
46a1e8621f | ||
|
|
ebada59764 | ||
|
|
983c9f20fa | ||
|
|
ada0805671 | ||
|
|
3008f3fec0 | ||
|
|
8814d02264 | ||
|
|
52618586d1 | ||
|
|
6b34f2e226 | ||
|
|
ebefa22074 |
@@ -40,7 +40,6 @@ sha2 = "0.10.0"
|
|||||||
local-ip-address = "0.5.5"
|
local-ip-address = "0.5.5"
|
||||||
dns-lookup = "2.0.2"
|
dns-lookup = "2.0.2"
|
||||||
uzers = "0.11.3"
|
uzers = "0.11.3"
|
||||||
isatty = "0.1.9"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
|
|||||||
@@ -36,6 +36,24 @@ impl CompressionEngineProgram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_program_path(program: &str) -> Result<String> {
|
||||||
|
debug!("COMPRESSION: Looking for executable: {}", program);
|
||||||
|
if let Ok(path) = env::var("PATH") {
|
||||||
|
for p in path.split(':') {
|
||||||
|
let p_str = format!("{}/{}", p, program);
|
||||||
|
let stat = fs::metadata(p_str.clone());
|
||||||
|
if let Ok(stat) = stat {
|
||||||
|
let md = stat;
|
||||||
|
let permissions = md.permissions();
|
||||||
|
if md.is_file() && permissions.mode() & 0o111 != 0 {
|
||||||
|
return Ok(p_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow!("Unable to find binary {} in PATH", program))
|
||||||
|
}
|
||||||
|
|
||||||
impl CompressionEngine for CompressionEngineProgram {
|
impl CompressionEngine for CompressionEngineProgram {
|
||||||
fn is_supported(&self) -> bool {
|
fn is_supported(&self) -> bool {
|
||||||
self.supported
|
self.supported
|
||||||
@@ -94,21 +112,3 @@ impl CompressionEngine for CompressionEngineProgram {
|
|||||||
Ok(Box::new(process.stdin.unwrap()))
|
Ok(Box::new(process.stdin.unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_program_path(program: &str) -> Result<String> {
|
|
||||||
debug!("COMPRESSION: Looking for executable: {}", program);
|
|
||||||
if let Ok(path) = env::var("PATH") {
|
|
||||||
for p in path.split(':') {
|
|
||||||
let p_str = format!("{}/{}", p, program);
|
|
||||||
let stat = fs::metadata(p_str.clone());
|
|
||||||
if let Ok(stat) = stat {
|
|
||||||
let md = stat;
|
|
||||||
let permissions = md.permissions();
|
|
||||||
if md.is_file() && permissions.mode() & 0o111 != 0 {
|
|
||||||
return Ok(p_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(anyhow!("Unable to find binary {} in PATH", program))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ lazy_static! {
|
|||||||
FOREIGN KEY(id) REFERENCES items(id) ON DELETE CASCADE,
|
FOREIGN KEY(id) REFERENCES items(id) ON DELETE CASCADE,
|
||||||
PRIMARY KEY(id, name));"
|
PRIMARY KEY(id, name));"
|
||||||
),
|
),
|
||||||
|
M::up("CREATE INDEX idx_tags_name ON tags(name)"),
|
||||||
|
M::up("CREATE INDEX idx_metas_name ON metas(name)"),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/main.rs
25
src/main.rs
@@ -9,13 +9,9 @@ extern crate directories;
|
|||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
|
|
||||||
extern crate prettytable;
|
extern crate prettytable;
|
||||||
use prettytable::format;
|
|
||||||
use prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR;
|
|
||||||
use prettytable::format::{Alignment, TableFormat};
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
pub mod compression_engine;
|
pub mod compression_engine;
|
||||||
@@ -26,27 +22,6 @@ pub mod meta_plugin;
|
|||||||
|
|
||||||
extern crate term;
|
extern crate term;
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR: TableFormat =
|
|
||||||
format::FormatBuilder::new()
|
|
||||||
.column_separator('│')
|
|
||||||
.borders('│')
|
|
||||||
.separators(
|
|
||||||
&[format::LinePosition::Top],
|
|
||||||
format::LineSeparator::new('─', '┬', '┌', '┐')
|
|
||||||
)
|
|
||||||
.separators(
|
|
||||||
&[format::LinePosition::Title],
|
|
||||||
format::LineSeparator::new('─', '┼', '├', '┤')
|
|
||||||
)
|
|
||||||
.separators(
|
|
||||||
&[format::LinePosition::Bottom],
|
|
||||||
format::LineSeparator::new('─', '┴', '└', '┘')
|
|
||||||
)
|
|
||||||
.padding(1, 1)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main struct for command-line arguments.
|
* Main struct for command-line arguments.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ pub enum MetaPluginType {
|
|||||||
ReadRate,
|
ReadRate,
|
||||||
Hostname,
|
Hostname,
|
||||||
FullHostname,
|
FullHostname,
|
||||||
Tty,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MetaPlugin {
|
pub trait MetaPlugin {
|
||||||
@@ -76,7 +75,6 @@ pub fn get_meta_plugin(meta_plugin_type: MetaPluginType) -> Box<dyn MetaPlugin>
|
|||||||
MetaPluginType::ReadRate => Box::new(ReadRateMetaPlugin::new()),
|
MetaPluginType::ReadRate => Box::new(ReadRateMetaPlugin::new()),
|
||||||
MetaPluginType::Hostname => Box::new(HostnameMetaPlugin::new()),
|
MetaPluginType::Hostname => Box::new(HostnameMetaPlugin::new()),
|
||||||
MetaPluginType::FullHostname => Box::new(FullHostnameMetaPlugin::new()),
|
MetaPluginType::FullHostname => Box::new(FullHostnameMetaPlugin::new()),
|
||||||
MetaPluginType::Tty => Box::new(TtyMetaPlugin::new()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -359,42 +359,3 @@ impl MetaPlugin for FullHostnameMetaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct TtyMetaPlugin {
|
|
||||||
meta_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TtyMetaPlugin {
|
|
||||||
pub fn new() -> TtyMetaPlugin {
|
|
||||||
TtyMetaPlugin {
|
|
||||||
meta_name: "tty".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MetaPlugin for TtyMetaPlugin {
|
|
||||||
fn create(&self) -> Result<Box<dyn Write>> {
|
|
||||||
Ok(Box::new(io::sink()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finalize(&mut self) -> io::Result<String> {
|
|
||||||
// Use isatty::tty_path to get the current TTY path
|
|
||||||
match isatty::stdout_isatty() {
|
|
||||||
true => {
|
|
||||||
match isatty::tty_path() {
|
|
||||||
Ok(path) => Ok(path.to_string_lossy().to_string()),
|
|
||||||
Err(_) => Ok("unknown tty".to_string()),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => Ok("not a tty".to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, _data: &[u8]) {
|
|
||||||
// No update needed for TTY
|
|
||||||
}
|
|
||||||
|
|
||||||
fn meta_name(&mut self) -> String {
|
|
||||||
self.meta_name.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use crate::Alignment;
|
|
||||||
|
|
||||||
use crate::db::{get_items, get_items_matching};
|
use crate::db::{get_items, get_items_matching};
|
||||||
use crate::modes::common::ColumnType;
|
use crate::modes::common::ColumnType;
|
||||||
use crate::modes::common::{size_column, string_column};
|
use crate::modes::common::{size_column, string_column};
|
||||||
@@ -7,6 +5,7 @@ use anyhow::anyhow;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use prettytable::color;
|
use prettytable::color;
|
||||||
use prettytable::row;
|
use prettytable::row;
|
||||||
|
use prettytable::format::Alignment;
|
||||||
use prettytable::{Attr, Cell, Row, Table};
|
use prettytable::{Attr, Cell, Row, Table};
|
||||||
|
|
||||||
pub fn mode_list(
|
pub fn mode_list(
|
||||||
@@ -167,5 +166,3 @@ pub fn mode_list(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// These helper functions are needed for the mode_list function
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ use crate::compression_engine::COMPRESSION_PROGRAMS;
|
|||||||
use crate::compression_engine::CompressionType;
|
use crate::compression_engine::CompressionType;
|
||||||
use crate::compression_engine::program::CompressionEngineProgram;
|
use crate::compression_engine::program::CompressionEngineProgram;
|
||||||
|
|
||||||
use crate::FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR;
|
use crate::modes::common::get_format_box_chars_no_border_line_separator;
|
||||||
use crate::FORMAT_NO_BORDER_LINE_SEPARATOR;
|
|
||||||
use prettytable::color;
|
use prettytable::color;
|
||||||
use prettytable::row;
|
use prettytable::row;
|
||||||
use prettytable::{Attr, Cell, Row, Table};
|
use prettytable::{Attr, Cell, Row, Table};
|
||||||
|
use prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR;
|
||||||
|
|
||||||
use crate::meta_plugin;
|
use crate::meta_plugin;
|
||||||
use crate::meta_plugin::MetaPluginType;
|
use crate::meta_plugin::MetaPluginType;
|
||||||
@@ -21,7 +21,7 @@ fn build_path_table(data_path: PathBuf, db_path: PathBuf) -> Table {
|
|||||||
let mut path_table = Table::new();
|
let mut path_table = Table::new();
|
||||||
|
|
||||||
if std::io::stdout().is_terminal() {
|
if std::io::stdout().is_terminal() {
|
||||||
path_table.set_format(*FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR);
|
path_table.set_format(get_format_box_chars_no_border_line_separator());
|
||||||
} else {
|
} else {
|
||||||
path_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
path_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ fn build_path_table(data_path: PathBuf, db_path: PathBuf) -> Table {
|
|||||||
fn build_compression_table() -> Table {
|
fn build_compression_table() -> Table {
|
||||||
let mut compression_table = Table::new();
|
let mut compression_table = Table::new();
|
||||||
if std::io::stdout().is_terminal() {
|
if std::io::stdout().is_terminal() {
|
||||||
compression_table.set_format(*FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR);
|
compression_table.set_format(get_format_box_chars_no_border_line_separator());
|
||||||
} else {
|
} else {
|
||||||
compression_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
compression_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ fn build_compression_table() -> Table {
|
|||||||
fn build_meta_plugin_table(enabled_meta_plugins: &Vec<MetaPluginType>) -> Table {
|
fn build_meta_plugin_table(enabled_meta_plugins: &Vec<MetaPluginType>) -> Table {
|
||||||
let mut meta_plugin_table = Table::new();
|
let mut meta_plugin_table = Table::new();
|
||||||
if std::io::stdout().is_terminal() {
|
if std::io::stdout().is_terminal() {
|
||||||
meta_plugin_table.set_format(*FORMAT_BOX_CHARS_NO_BORDER_LINE_SEPARATOR);
|
meta_plugin_table.set_format(get_format_box_chars_no_border_line_separator());
|
||||||
} else {
|
} else {
|
||||||
meta_plugin_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
meta_plugin_table.set_format(*FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|||||||
532
src/tests.rs
532
src/tests.rs
@@ -1,6 +1,7 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
@@ -10,14 +11,27 @@ mod tests {
|
|||||||
|
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
// Helper function to run a command in sh -c
|
// Helper function to run the keep binary with arguments
|
||||||
fn run_sh(cmd: &str) -> std::process::Output {
|
fn run_keep(args: &[&str], stdin_data: Option<&str>, keep_dir: &Path) -> std::process::Output {
|
||||||
let output = Command::new("sh")
|
let mut cmd = Command::new(env!("CARGO_BIN_EXE_keep"));
|
||||||
.arg("-c")
|
cmd.args(args)
|
||||||
.arg(cmd)
|
.env("KEEP_DIR", keep_dir);
|
||||||
.output()
|
|
||||||
.expect("Failed to execute command");
|
if stdin_data.is_some() {
|
||||||
output
|
cmd.stdin(std::process::Stdio::piped());
|
||||||
|
} else {
|
||||||
|
cmd.stdin(std::process::Stdio::null());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut child = cmd.spawn().expect("Failed to execute keep command");
|
||||||
|
|
||||||
|
if let Some(data) = stdin_data {
|
||||||
|
if let Some(mut stdin) = child.stdin.take() {
|
||||||
|
stdin.write_all(data.as_bytes()).expect("Failed to write to stdin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
child.wait_with_output().expect("Failed to wait for command")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create a temporary test environment
|
// Helper function to create a temporary test environment
|
||||||
@@ -26,366 +40,248 @@ mod tests {
|
|||||||
F: FnOnce(&Path),
|
F: FnOnce(&Path),
|
||||||
{
|
{
|
||||||
let dir = tempdir().expect("Failed to create temporary directory");
|
let dir = tempdir().expect("Failed to create temporary directory");
|
||||||
let _db_path = dir.path().join("keep-1.db");
|
let data_path = dir.path();
|
||||||
|
|
||||||
// Create the data directory structure
|
// Create the data directory structure
|
||||||
fs::create_dir_all(dir.path()).expect("Failed to create directory");
|
fs::create_dir_all(data_path).expect("Failed to create directory");
|
||||||
|
|
||||||
// Run the test
|
// Run the test
|
||||||
f(dir.path());
|
f(data_path);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
dir.close().expect("Failed to remove temporary directory");
|
dir.close().expect("Failed to remove temporary directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create test items with specific content and tags
|
// Helper function to create test items with specific content and tags
|
||||||
fn create_test_items(dir: &Path) {
|
fn create_test_items(data_path: &Path) {
|
||||||
// Set the data directory for this test
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", dir.display());
|
|
||||||
|
|
||||||
// Create first item with tag_a and tag
|
// Create first item with tag_a and tag
|
||||||
let cmd = format!("echo {} | {} tag tag_a tag", INPUT_A, keep_cmd);
|
let output = run_keep(&["tag_a", "tag"], Some(INPUT_A), data_path);
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
"Command failed: {} {}",
|
"Failed to create first test item: {}",
|
||||||
cmd,
|
String::from_utf8_lossy(&output.stderr)
|
||||||
output.status
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create second item with tag_b and tag
|
// Create second item with tag_b and tag
|
||||||
let cmd = format!("echo {} | {} tag tag_b tag", INPUT_B, keep_cmd);
|
let output = run_keep(&["tag_b", "tag"], Some(INPUT_B), data_path);
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
"Command failed: {} {}",
|
"Failed to create second test item: {}",
|
||||||
cmd,
|
String::from_utf8_lossy(&output.stderr)
|
||||||
output.status
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to check if a file exists in the data directory
|
|
||||||
fn file_exists(data_dir: &Path, id: i64) -> bool {
|
|
||||||
let path = data_dir.join(id.to_string());
|
|
||||||
path.exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to get the content of a file
|
|
||||||
fn file_content(data_dir: &Path, id: i64) -> String {
|
|
||||||
let path = data_dir.join(id.to_string());
|
|
||||||
std::fs::read_to_string(path).expect("Failed to read file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test: Save an item and verify it's stored
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_save_item() {
|
fn test_save_item() {
|
||||||
with_temp_env(|data_dir| {
|
with_temp_env(|data_path| {
|
||||||
// Create test items with the common environment setup
|
|
||||||
create_test_items(data_dir);
|
|
||||||
// Set the data directory for this test
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
|
|
||||||
|
|
||||||
// Test content and tags
|
// Test content and tags
|
||||||
let input = "test content";
|
let input = "test content";
|
||||||
let tag = "tag";
|
let tag = "test_tag";
|
||||||
|
|
||||||
// Create a command that pipes input to keep with the specified environment
|
// Save an item
|
||||||
let cmd = format!("echo {} | {} {}", input, keep_cmd, tag);
|
let output = run_keep(&[tag], Some(input), data_path);
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
"Command failed: {} {}",
|
"Failed to save item: {}",
|
||||||
cmd,
|
String::from_utf8_lossy(&output.stderr)
|
||||||
output.status
|
);
|
||||||
|
|
||||||
|
// Verify item was saved by listing
|
||||||
|
let output = run_keep(&["--list"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to list items: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(
|
||||||
|
output_str.contains(tag),
|
||||||
|
"List output does not contain expected tag. Output: {}",
|
||||||
|
output_str
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_item() {
|
fn test_get_item() {
|
||||||
with_temp_env(|data_dir| {
|
with_temp_env(|data_path| {
|
||||||
// Create test items with the common environment setup
|
// Create test items
|
||||||
create_test_items(data_dir);
|
create_test_items(data_path);
|
||||||
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
|
// Get item by ID
|
||||||
|
let output = run_keep(&["--get", "1"], None, data_path);
|
||||||
let cmd = format!("{} --get 1", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
"Command failed: {} {}",
|
"Failed to get item by ID: {}",
|
||||||
cmd,
|
String::from_utf8_lossy(&output.stderr)
|
||||||
output.status
|
|
||||||
);
|
);
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
assert!(
|
assert!(
|
||||||
output_str.contains(INPUT_A),
|
output_str.contains(INPUT_A),
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
"Get output does not contain expected content. Output: {}",
|
||||||
cmd,
|
output_str
|
||||||
output_str,
|
|
||||||
INPUT_A
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let cmd = format!("{} -g 1", keep_cmd);
|
// Get item by tag
|
||||||
let output = run_sh(cmd.as_str());
|
let output = run_keep(&["--get", "tag_a"], None, data_path);
|
||||||
assert!(
|
assert!(
|
||||||
output.status.success(),
|
output.status.success(),
|
||||||
"Command failed: {} {}",
|
"Failed to get item by tag: {}",
|
||||||
cmd,
|
String::from_utf8_lossy(&output.stderr)
|
||||||
output.status
|
|
||||||
);
|
);
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
assert!(
|
assert!(
|
||||||
output_str.contains(INPUT_A),
|
output_str.contains(INPUT_A),
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
"Get by tag output does not contain expected content. Output: {}",
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_A
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} 1", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_A),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_A
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --get", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_B),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_B
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --get tag_a", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_A),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_A
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --get tag_b", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_B),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_B
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --get tag", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_B),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_B
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test: List items and verify the output
|
|
||||||
#[test]
|
|
||||||
fn test_list_items() {
|
|
||||||
with_temp_env(|data_dir| {
|
|
||||||
// Create test items with the common environment setup
|
|
||||||
create_test_items(data_dir);
|
|
||||||
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
|
|
||||||
|
|
||||||
let cmd = format!("{} --list", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} -l", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --list tag_a", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test: Delete an item and verify it's removed
|
|
||||||
#[test]
|
|
||||||
fn test_delete_item() {
|
|
||||||
with_temp_env(|data_dir| {
|
|
||||||
// Create test items with the common environment setup
|
|
||||||
create_test_items(data_dir);
|
|
||||||
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
|
|
||||||
|
|
||||||
let cmd = format!("{} --delete tag", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"Command succeeded when it should have failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --delete 1", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} -d 2", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --delete 9999", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
//assert!(!output.status.success(), "Command succeded when it should have failed: {} {}", cmd, output.status);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test: Diff two items and verify the output
|
|
||||||
#[test]
|
|
||||||
fn test_diff_items() {
|
|
||||||
with_temp_env(|data_dir| {
|
|
||||||
// Create test items with the common environment setup
|
|
||||||
create_test_items(data_dir);
|
|
||||||
|
|
||||||
let keep_cmd = format!("KEEP_DIR={} cargo run -- --verbose", data_dir.display());
|
|
||||||
|
|
||||||
let cmd = format!("{} --diff 1 2", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
output.status.success(),
|
|
||||||
"Command failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_A),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_A
|
|
||||||
);
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.contains(INPUT_B),
|
|
||||||
"Command output does not contain expected string. Command: {} Output: {} Expected: \"{}\"",
|
|
||||||
cmd,
|
|
||||||
output_str,
|
|
||||||
INPUT_B
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --diff tag_a tag_b", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"Command succeeded when it should have failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --diff tag_a 2", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"Command succeeded when it should have failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
let cmd = format!("{} --diff 9999 2", keep_cmd);
|
|
||||||
let output = run_sh(cmd.as_str());
|
|
||||||
assert!(
|
|
||||||
!output.status.success(),
|
|
||||||
"Command succeeded when it should have failed: {} {}",
|
|
||||||
cmd,
|
|
||||||
output.status
|
|
||||||
);
|
|
||||||
|
|
||||||
// Output should be empty for non-existent item
|
|
||||||
let output_str = String::from_utf8_lossy(&output.stdout).to_string();
|
|
||||||
assert!(
|
|
||||||
output_str.is_empty(),
|
|
||||||
"Command output is not empty. Command: {} Output: {}",
|
|
||||||
cmd,
|
|
||||||
output_str
|
output_str
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_items() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Create test items
|
||||||
|
create_test_items(data_path);
|
||||||
|
|
||||||
|
// List all items
|
||||||
|
let output = run_keep(&["--list"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to list items: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// List items with specific tag
|
||||||
|
let output = run_keep(&["--list", "tag_a"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to list items by tag: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_item() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Create test items
|
||||||
|
create_test_items(data_path);
|
||||||
|
|
||||||
|
// Try to delete with tag (should fail)
|
||||||
|
let output = run_keep(&["--delete", "tag"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
!output.status.success(),
|
||||||
|
"Delete with tag should have failed but succeeded"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete item by ID
|
||||||
|
let output = run_keep(&["--delete", "1"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to delete item by ID: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to delete non-existent item (should succeed silently)
|
||||||
|
let output = run_keep(&["--delete", "9999"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Delete non-existent item should succeed: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_diff_items() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Create test items
|
||||||
|
create_test_items(data_path);
|
||||||
|
|
||||||
|
// Diff two items by ID
|
||||||
|
let output = run_keep(&["--diff", "1", "2"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to diff items: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to diff with tag (should fail)
|
||||||
|
let output = run_keep(&["--diff", "tag_a", "tag_b"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
!output.status.success(),
|
||||||
|
"Diff with tags should have failed but succeeded"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to diff non-existent item (should fail)
|
||||||
|
let output = run_keep(&["--diff", "9999", "1"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
!output.status.success(),
|
||||||
|
"Diff with non-existent item should have failed but succeeded"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_info_item() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Create test items
|
||||||
|
create_test_items(data_path);
|
||||||
|
|
||||||
|
// Get info for item by ID
|
||||||
|
let output = run_keep(&["--info", "1"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to get item info: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get info for last item (need to provide an empty IDS_OR_TAGS parameter)
|
||||||
|
let output = run_keep(&["--info", ""], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to get last item info: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_item() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Create test items
|
||||||
|
create_test_items(data_path);
|
||||||
|
|
||||||
|
// Update item tags
|
||||||
|
let output = run_keep(&["--update", "1", "new_tag"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to update item: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify update by listing
|
||||||
|
let output = run_keep(&["--list"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to list items after update: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_status() {
|
||||||
|
with_temp_env(|data_path| {
|
||||||
|
// Get status
|
||||||
|
let output = run_keep(&["--status"], None, data_path);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to get status: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user