add a basic generate() test
This commit is contained in:
parent
e605ba84e5
commit
5f2490ff0c
8 changed files with 244 additions and 25 deletions
102
Cargo.lock
generated
102
Cargo.lock
generated
|
@ -8,6 +8,15 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned-vec"
|
||||
version = "0.5.0"
|
||||
|
@ -295,6 +304,29 @@ version = "1.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"jiff",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
|
@ -471,6 +503,30 @@ version = "1.0.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.33"
|
||||
|
@ -665,7 +721,9 @@ version = "0.2.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"image",
|
||||
"log",
|
||||
"mktemp",
|
||||
"serde",
|
||||
"serde_yml",
|
||||
|
@ -691,6 +749,21 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
|
@ -858,6 +931,35 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.50"
|
||||
|
|
|
@ -10,7 +10,9 @@ edition = "2024"
|
|||
[dependencies]
|
||||
anyhow = "^1.0"
|
||||
clap = { version = "^4.5", features = ["derive"] }
|
||||
env_logger = "^0.11.8"
|
||||
image = "^0.25.6"
|
||||
log = "^0.4.27"
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_yml = "^0.0.12"
|
||||
thiserror = "^2.0"
|
||||
|
|
2
Makefile
2
Makefile
|
@ -24,7 +24,7 @@ lint:
|
|||
cargo clippy
|
||||
|
||||
test:
|
||||
cargo test
|
||||
RUST_BACKTRACE=1 cargo test
|
||||
|
||||
|
||||
test-watch:
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use anyhow::Context;
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
#[serde(default)]
|
||||
struct Config {
|
||||
thumbnail_size: (u32, u32),
|
||||
view_size: (u32, u32),
|
||||
output_dir: PathBuf,
|
||||
pub struct Config {
|
||||
pub thumbnail_size: (u32, u32),
|
||||
pub view_size: (u32, u32),
|
||||
pub output_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn from_album(path: PathBuf) -> anyhow::Result<Config> {
|
||||
let content = fs::read(path.join("photojawn.conf.yml"))?;
|
||||
let cfg = serde_yml::from_slice(&content)?;
|
||||
pub fn from_album(path: PathBuf) -> anyhow::Result<Config> {
|
||||
let config_path = path.join("photojawn.conf.yml");
|
||||
let content = fs::read(&config_path)
|
||||
.with_context(|| format!("Failed to read config from {}", config_path.display()))?;
|
||||
let cfg = serde_yml::from_slice(&content)
|
||||
.with_context(|| format!("Failed to parse config from {}", config_path.display()))?;
|
||||
Ok(cfg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
mod album_dir;
|
||||
|
||||
use album_dir::AlbumDir;
|
||||
use crate::config::Config;
|
||||
pub use album_dir::AlbumDir;
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
const OUTPUT_PATH: &'static str = "site";
|
||||
|
||||
pub fn generate(root_path: &PathBuf) -> anyhow::Result<()> {
|
||||
pub fn generate(root_path: &PathBuf) -> anyhow::Result<PathBuf> {
|
||||
let config = Config::from_album(root_path.to_path_buf())?;
|
||||
let orig_path = env::current_dir()?;
|
||||
let album = AlbumDir::try_from(root_path)?;
|
||||
env::set_current_dir(&root_path)?;
|
||||
|
||||
generate_images(&album)?;
|
||||
generate_html(&album)?;
|
||||
generate_images(&config, &album)?;
|
||||
generate_html(&config, &album)?;
|
||||
|
||||
env::set_current_dir(orig_path)?;
|
||||
Ok(root_path.join(config.output_dir))
|
||||
}
|
||||
|
||||
fn generate_images(config: &Config, album: &AlbumDir) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_images(album: &AlbumDir) -> anyhow::Result<()> {
|
||||
let output_path = album.path.join(OUTPUT_PATH);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_html(album: &AlbumDir) -> anyhow::Result<()> {
|
||||
fn generate_html(config: &Config, album: &AlbumDir) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ impl TryFrom<&PathBuf> for AlbumDir {
|
|||
let entry_path = entry?.path();
|
||||
|
||||
if entry_path.is_file() {
|
||||
println!("Found file: {}", entry_path.display());
|
||||
if let Some(filename) = entry_path.file_name() {
|
||||
if filename == "description.txt" {
|
||||
description = fs::read_to_string(entry_path)?;
|
||||
|
@ -65,8 +64,6 @@ impl TryFrom<&PathBuf> for AlbumDir {
|
|||
}
|
||||
}
|
||||
} else if entry_path.is_dir() {
|
||||
println!("Found dir: {}", entry_path.display());
|
||||
|
||||
if let Some(dirname) = entry_path.file_name().and_then(|n| n.to_str()) {
|
||||
if dirname.starts_with("_") {
|
||||
// Likely a templates or static dir
|
||||
|
|
|
@ -4,8 +4,8 @@ use photojawn::skel::make_skeleton;
|
|||
use std::path::Path;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
let cli = Cli::parse();
|
||||
|
||||
let album_path = Path::new(&cli.album_path);
|
||||
|
||||
match cli.subcommand {
|
||||
|
|
115
tests/generate.rs
Normal file
115
tests/generate.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
// TODO: Is this really an intergration test? Or should it go into generate.rs?
|
||||
// orrrr make a function in our CLI which does everything and test _that_
|
||||
use mktemp::Temp;
|
||||
use photojawn::generate::generate;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[test]
|
||||
/// Test that the generate function creates a rendered site as we expect it
|
||||
fn test_generate() {
|
||||
init();
|
||||
let album_path = make_test_album();
|
||||
let output_path = generate(&album_path.to_path_buf()).unwrap();
|
||||
|
||||
check_album(output_path).unwrap();
|
||||
}
|
||||
|
||||
fn init() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
}
|
||||
|
||||
/// Copies the test album to a tempdir and returns the path to it
|
||||
fn make_test_album() -> Temp {
|
||||
let tmpdir = Temp::new_dir().unwrap();
|
||||
let source_path = Path::new("resources/test_album");
|
||||
|
||||
let mut dirs: VecDeque<PathBuf> = VecDeque::from([source_path.to_path_buf()]);
|
||||
while let Some(dir) = dirs.pop_front() {
|
||||
for entry in dir.read_dir().unwrap() {
|
||||
let entry_path = entry.unwrap().path();
|
||||
let path_in_album = entry_path.strip_prefix(&source_path).unwrap();
|
||||
if entry_path.is_dir() {
|
||||
dirs.push_back(entry_path);
|
||||
} else {
|
||||
let dest_path = tmpdir.join(&path_in_album);
|
||||
fs::create_dir_all(dest_path.parent().unwrap()).unwrap();
|
||||
fs::copy(&entry_path, &dest_path).unwrap();
|
||||
log::debug!("{} -> {}", entry_path.display(), dest_path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmpdir
|
||||
}
|
||||
|
||||
/// Does basic sanity checks on an output album
|
||||
fn check_album(album_dir: PathBuf) -> anyhow::Result<()> {
|
||||
log::debug!("Checking dir {}", album_dir.display());
|
||||
|
||||
let mut dirs: VecDeque<PathBuf> = VecDeque::from([album_dir]);
|
||||
while let Some(dir) = dirs.pop_front() {
|
||||
for entry in dir.read_dir().unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
if path.is_dir() {
|
||||
check_album(path.clone())?;
|
||||
}
|
||||
let files: Vec<PathBuf> = path
|
||||
.read_dir()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|e| e.unwrap().path())
|
||||
.filter(|e| e.is_file())
|
||||
.collect();
|
||||
|
||||
// There should be an index.html
|
||||
assert!(path.join("index.html").exists());
|
||||
|
||||
// There should be a cover image
|
||||
let cover_path = path.join("cover.jpg");
|
||||
assert!(&cover_path.exists());
|
||||
|
||||
// The cover should be equal contents to some other image
|
||||
let cover_contents = fs::read(&cover_path).unwrap();
|
||||
let mut found = false;
|
||||
for file in &files {
|
||||
if file != &cover_path {
|
||||
let file_contents = fs::read(file).unwrap();
|
||||
if file_contents == cover_contents {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
panic!(
|
||||
"cover.jpg in {} does not have a matching file",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
|
||||
// There should be a slides dir
|
||||
let slides_path = path.join("slides");
|
||||
assert!(slides_path.is_dir());
|
||||
|
||||
// For each image in the album (including the cover), in slides there should be a:
|
||||
// - <image>.html
|
||||
// - <image>.screen.<ext>
|
||||
// - <image>.thumb.<ext>
|
||||
for file in &files {
|
||||
for ext in ["html", "screen.jpg", "thumb.jpg"] {
|
||||
assert!(slides_path.join(file.with_extension(ext)).exists());
|
||||
}
|
||||
}
|
||||
|
||||
// There shouldn't be any .txt or .md files hanging around
|
||||
for file in &files {
|
||||
if let Some(ext) = file.extension() {
|
||||
assert_ne!(ext, "md");
|
||||
assert_ne!(ext, "txt");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Reference in a new issue