diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-05 20:52:26 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-05 20:52:26 +0100 |
| commit | 0fca7c5476099212ed1fa9ed812aa456ba004300 (patch) | |
| tree | 3acacb019691f56a510ddf21f929816e45d21d9a | |
| parent | b17907faf8d9693cef94a6048d802bd4ced9102f (diff) | |
Add tests for utils and metadata
| -rw-r--r-- | Cargo.lock | 5 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/metadata.rs | 65 | ||||
| -rw-r--r-- | src/utils.rs | 48 | ||||
| -rw-r--r-- | test_utilities/Cargo.toml | 10 | ||||
| -rw-r--r-- | test_utilities/src/lib.rs | 34 |
6 files changed, 165 insertions, 0 deletions
@@ -9,6 +9,7 @@ dependencies = [ "gema_texto", "serde", "serde_json", + "test_utilities", "time", ] @@ -119,6 +120,10 @@ dependencies = [ ] [[package]] +name = "test_utilities" +version = "7.1.0" + +[[package]] name = "time" version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -13,6 +13,9 @@ time = { version = "0.3.37", features = ["macros", "formatting"] } serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.134" +[dev-dependencies] +test_utilities = { path = "test_utilities" } + [profile.release] strip = true lto = true diff --git a/src/metadata.rs b/src/metadata.rs index fe657e4..d6b3d6a 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -13,6 +13,11 @@ pub struct Metadata { } impl Metadata { + /// Reads `Metadata` from a file or creates a new one. + /// + /// This method will create new metadata if it can't read the file, + /// whether it's because of malformed JSON, UTF-8 or because the file + /// is not readable. pub fn read_or_create(file_path: &PathBuf) -> Metadata { if let Some(metadata) = Metadata::read_metadata_file(file_path) { metadata @@ -28,6 +33,7 @@ impl Metadata { } } + /// Returns the metadata `created_on` as an RFC-2822 string. pub fn created_on_utc(&self) -> Option<String> { let date = OffsetDateTime::from_unix_timestamp_nanos((self.created_on * 1_000_000).into()).ok()?; @@ -41,3 +47,62 @@ impl Metadata { serde_json::from_str(&contents).ok() } } + +#[cfg(test)] +mod tests { + use std::fs::write; + + use super::*; + + use test_utilities::*; + + #[test] + fn test_reads_metadata_if_file_exists() { + let test_dir = setup_test_dir(); + create_test_file( + &test_dir.join("metadata.json"), + "\ +{ + \"id\": \"cool\", + \"created_on\": 1736105008957 +}", + ); + + let metadata = Metadata::read_or_create(&test_dir.join("metadata.json")); + + assert_eq!(metadata.id, "cool"); + assert_eq!(metadata.created_on, 1736105008957); + } + + #[test] + fn test_creates_metadata_if_file_does_not_exist() { + let test_dir = setup_test_dir(); + + assert!(!test_dir.join("metadata.json").exists()); + let metadata = Metadata::read_or_create(&test_dir.join("metadata.json")); + assert_eq!(metadata.created_on.to_string(), metadata.id); + } + + #[test] + fn test_creates_metadata_if_file_is_malformed() { + let test_dir = setup_test_dir(); + write(&test_dir.join("metadata.json"), vec![0xFF, 0xFF]).expect("Failed to write file"); + + let metadata = Metadata::read_or_create(&test_dir.join("metadata.json")); + assert_eq!(metadata.created_on.to_string(), metadata.id); + } + + #[test] + fn test_it_returns_created_on_as_rfc_2822_utc() { + let metadata = Metadata { + id: "cool".to_string(), + created_on: 1736035200000, + }; + + if let Some(created_on_utc) = metadata.created_on_utc() { + assert_eq!(created_on_utc, "Sun, 05 Jan 2025 00:00:00 +0000"); + } else { + panic!("Could not generate RFC-2822 string"); + } + } +} diff --git a/src/utils.rs b/src/utils.rs index 4522f4c..01b6cdf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,6 +2,7 @@ use std::fs::{copy, create_dir_all, read_dir}; use std::io::Result; use std::path::Path; +/// Recursively copies the contents of a directory. pub fn recursively_copy(source: &Path, target: &Path) -> Result<()> { let entries = read_dir(source)?; for entry in entries { @@ -21,3 +22,50 @@ pub fn recursively_copy(source: &Path, target: &Path) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use std::fs::create_dir_all; + + use super::*; + + use test_utilities::*; + + #[test] + fn test_recursively_copies_directories() { + let test_dir = setup_test_dir(); + let source_dir = test_dir.join("source"); + let target_dir = test_dir.join("target"); + let nested_dir = source_dir.join("nested"); + let hidden_dir = source_dir.join(".hidden"); + create_dir_all(&target_dir).expect("Could not create target test directory"); + create_dir_all(&nested_dir).expect("Could not create nested test directory"); + create_dir_all(&hidden_dir).expect("Could not create hidden test directory"); + create_test_file(&source_dir.join("image.png"), "A beautiful pencil"); + create_test_file(&nested_dir.join("hello.txt"), "I am here"); + create_test_file(&nested_dir.join(".hidden"), "I am not here?"); + create_test_file(&hidden_dir.join("in_plain_sight.mkv"), "Almost"); + create_test_file(&hidden_dir.join(".hidden"), "I'm double hidden"); + + recursively_copy(&source_dir, &target_dir).expect("Copy failed on test directory"); + + assert_file_contents(&target_dir.join("image.png"), "A beautiful pencil"); + assert_file_contents(&target_dir.join("nested/hello.txt"), "I am here"); + assert_file_contents(&target_dir.join("nested/.hidden"), "I am not here?"); + assert_file_contents(&target_dir.join(".hidden/in_plain_sight.mkv"), "Almost"); + assert_file_contents(&target_dir.join(".hidden/.hidden"), "I'm double hidden"); + } + + #[test] + fn test_empty_directory() { + let test_dir = setup_test_dir(); + let source_dir = test_dir.join("source"); + let target_dir = test_dir.join("target"); + create_dir_all(&source_dir).expect("Could not create source test directory"); + create_dir_all(&target_dir).expect("Could not create target test directory"); + + recursively_copy(&source_dir, &target_dir).expect("Copy failed on empty test directory"); + + assert_eq!(target_dir.read_dir().unwrap().count(), 0); + } +} diff --git a/test_utilities/Cargo.toml b/test_utilities/Cargo.toml new file mode 100644 index 0000000..57ed81a --- /dev/null +++ b/test_utilities/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test_utilities" +version = "7.1.0" +edition = "2021" +license = "AGPL-3.0-or-later" +description = "Shared test utilities for blog" +homepage = "https://r.bdr.sh/page.html" +authors = ["Rubén Beltrán del Río <page@r.bdr.sh>"] + +[dependencies] diff --git a/test_utilities/src/lib.rs b/test_utilities/src/lib.rs new file mode 100644 index 0000000..f5a7b39 --- /dev/null +++ b/test_utilities/src/lib.rs @@ -0,0 +1,34 @@ +use std::env::temp_dir; +use std::fs::{create_dir_all, read_to_string, remove_dir_all, File}; +use std::io::Write; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::process::id; + +pub fn setup_test_dir() -> PathBuf { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let process_id = id(); + let test_dir = temp_dir().join(format!("blog_test_{}_{}", timestamp, process_id)); + create_dir_all(&test_dir) + .expect("Could not create test directory"); + test_dir +} + +pub fn cleanup_test_dir(test_dir: &PathBuf) { + if test_dir.exists() { + remove_dir_all(test_dir).unwrap(); + } +} + +pub fn create_test_file(path: &PathBuf, content: &str) { + let mut file = File::create(path).unwrap(); + file.write_all(content.as_bytes()).unwrap(); +} + +pub fn assert_file_contents(path: &PathBuf, expected: &str) { + let content = read_to_string(path).unwrap(); + assert_eq!(content.trim(), expected.trim()); +} |