Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ dirs = "6.0.0"

keyring-lib = { version = "1.0.3", features = ["tokio"] }
ratatui = "0.30.2"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
reqwest = { version = "0.13.4", default-features = false, features = ["json"] }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1.52.3", features = ["full"] }

[dev-dependencies]
cargo-husky = { version = "1.5.0", default-features = false, features = [
"user-hooks",
] }
tempfile = "3"
103 changes: 103 additions & 0 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,106 @@ impl CacheStore {
Ok(format!("{}:{}", short_name.to_lowercase(), id.as_str()))
}
}

#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
use tempfile::TempDir;

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
struct MockUser {
name: String,
age: u8,
}

fn setup_temporary_cache() -> (CacheStore, TempDir) {
let temp_dir = TempDir::new().expect("Failed to create a temporary directory");
let path = temp_dir.path().join("test_cache.db");

let db = PickleDb::new(
&path,
pickledb::PickleDbDumpPolicy::AutoDump,
pickledb::SerializationMethod::Bin,
);

(CacheStore { db, path }, temp_dir)
}

#[test]
fn test_id_new_valid() {
let valid_str = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
let id_res = Id::<MockUser>::new(valid_str);

assert!(id_res.is_ok());
let id = id_res.unwrap();
assert_eq!(id.as_str(), valid_str);
assert_eq!(id.bytes(), valid_str.as_bytes());
}

#[test]
fn test_id_new_invalid_size() {
let short_str = "01ARZ3NDEKTSV4RRFFQ69G5FA";
let id_err = Id::<MockUser>::new(short_str);
assert!(id_err.is_err());

let long_str = "01ARZ3NDEKTSV4RRFFQ69G5FAVV";
let id_err = Id::<MockUser>::new(long_str);
assert!(id_err.is_err());
}

#[test]
fn test_id_debug_formatting() {
let valid_str = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
let id = Id::<MockUser>::new(valid_str).unwrap();

let debug_format = format!("{:?}", id);
assert_eq!(debug_format, "Id<MockUser>(01ARZ3NDEKTSV4RRFFQ69G5FAV)");
}

#[test]
fn test_cache_store_lifecycle() {
let (mut store, _temp_dir) = setup_temporary_cache();

let raw_id = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
let id = Id::<MockUser>::new(raw_id).unwrap();
let user = MockUser {
name: "Alice".to_string(),
age: 30,
};

assert!(!store.exists(id.clone()).unwrap(), "Key should not exist");
assert!(store.get(id.clone()).is_none(), "Get should return None");

let set_res = store.set(id.clone(), &user);
assert!(set_res.is_ok(), "Insertion failed: {:?}", set_res);

assert!(
store.exists(id.clone()).unwrap(),
"Key should exist after set"
);

let cached_user = store.get(id.clone());
assert!(cached_user.is_some(), "Value should have been retrieved");
assert_eq!(
cached_user.unwrap(),
user,
"Retrieved value does not match the inserted one"
);

let remove_res = store.remove(id.clone());
assert!(remove_res.is_ok());
assert!(remove_res.unwrap(), "Remove should have returned true");

assert!(
!store.exists(id.clone()).unwrap(),
"Key should no longer exist after removal"
);

let remove_again = store.remove(id.clone()).unwrap();
assert!(
!remove_again,
"Remove should have returned false for a non-existent key"
);
}
}
28 changes: 23 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,38 @@ mod error;
mod input;
mod state;

use std::{fs, path::PathBuf};

use app::App;
use ratatui::crossterm::event::{self, Event};
use state::ui;

pub const LOG_FILE: &str = "logs";

pub type Result<T> = anyhow::Result<T>;

#[tokio::main]
async fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
let log_file = std::fs::OpenOptions::new()
fn create_log_file() -> Result<fs::File> {
let mut path = if let Some(mut p) = dirs::cache_dir() {
p.push(env!("CARGO_PKG_NAME"));
p
} else {
PathBuf::new()
};

fs::create_dir_all(&path)?;

path.push(LOG_FILE);

Ok(fs::OpenOptions::new()
.create(true)
.append(true)
.open("vimstoat.log")
.expect("Failed to open log file");
.open(path)
.expect("Failed to open log file"))
}

#[tokio::main]
async fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
let log_file = create_log_file()?;
env_logger::builder()
.target(env_logger::Target::Pipe(Box::new(log_file)))
.filter_level(log::LevelFilter::Debug)
Expand Down