/target
-tests/fixtures/empty
-tests/fixtures/output
-tests/fixtures/output_gemini
-tests/fixtures/output_html
.DS_Store
*.tar.gz
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "page"
-version = "1.3.2"
+version = "1.4.0"
+dependencies = [
+ "test_utilities",
+]
+
+[[package]]
+name = "test_utilities"
+version = "1.4.0"
[package]
name = "page"
-version = "1.3.2"
+version = "1.4.0"
edition = "2021"
license = "AGPL-3.0-or-later"
description = "Command line tool to generate a static website and gemini capsule from a directory with gemtext."
[dependencies]
+[dev-dependencies]
+test_utilities = { path = "test_utilities" }
+
[profile.release]
strip = true
lto = true
#[cfg(test)]
mod tests {
- use super::*;
- use crate::file_handler::FileType;
use std::collections::HashSet;
+ use std::path::PathBuf;
use std::fs::create_dir_all;
- fn fixtures_dir() -> PathBuf {
- PathBuf::from("tests/fixtures")
- }
+ use super::*;
- fn get_paths(files: &Vec<File>) -> HashSet<String> {
+ use crate::file_handler::FileType;
+ use crate::file_handler::File;
+ use test_utilities::*;
+
+ fn get_paths(root_directory: &PathBuf, files: &Vec<File>) -> HashSet<String> {
files
.iter()
- .map(|f| f.path.strip_prefix(&fixtures_dir()).unwrap().to_string_lossy().to_string())
+ .map( |file|
+ file.path
+ .strip_prefix(root_directory)
+ .unwrap()
+ .to_string_lossy()
+ .to_string()
+ )
.collect()
}
#[test]
fn finds_all_files() {
- let files = find_files(&fixtures_dir());
- let paths = get_paths(&files);
+ let test_dir = setup_test_dir();
+ create_dir_all(&test_dir.join("nested"))
+ .expect("Could not create nested test directory");
+ create_dir_all(&test_dir.join("assets"))
+ .expect("Could not create assets test directory");
+ create_test_file(&test_dir.join("test1.gmi"), "");
+ create_test_file(&test_dir.join("_layout.html"), "");
+ create_test_file(&test_dir.join("nested/nested.gmi"), "");
+ create_test_file(&test_dir.join("assets/style.css"), "");
+ create_test_file(&test_dir.join("image.png"), "");
+
+ let files = find_files(&test_dir);
+ let paths = get_paths(&test_dir, &files);
assert!(paths.contains("test1.gmi"));
assert!(paths.contains("_layout.html"));
#[test]
fn identifies_correct_file_types() {
- let files = find_files(&fixtures_dir());
+ let test_dir = setup_test_dir();
+ create_dir_all(&test_dir.join("nested"))
+ .expect("Could not create nested test directory");
+ create_dir_all(&test_dir.join("assets"))
+ .expect("Could not create assets test directory");
+ create_test_file(&test_dir.join("_layout.html"), "");
+ create_test_file(&test_dir.join("nested/nested.gmi"), "");
+ create_test_file(&test_dir.join("assets/style.css"), "");
+ create_test_file(&test_dir.join("image.png"), "");
+ let files = find_files(&test_dir);
for file in files {
let extension = file.path.extension().and_then(|e| e.to_str());
#[test]
fn ignores_git_directory() {
- let files = find_files(&fixtures_dir());
- let paths = get_paths(&files);
+ let test_dir = setup_test_dir();
+ create_dir_all(&test_dir.join("nested"))
+ .expect("Could not create nested test directory");
+ create_dir_all(&test_dir.join("assets"))
+ .expect("Could not create assets test directory");
+ create_dir_all(&test_dir.join(".git"))
+ .expect("Could not create git test directory");
+ create_test_file(&test_dir.join("_layout.html"), "");
+ create_test_file(&test_dir.join("nested/nested.gmi"), "");
+ create_test_file(&test_dir.join("assets/style.css"), "");
+ create_test_file(&test_dir.join("image.png"), "");
+ create_test_file(&test_dir.join(".git/config"), "");
+ let files = find_files(&test_dir);
+
+ let paths = get_paths(&test_dir, &files);
- // These files should exist in the fixtures but not be included
assert!(!paths.iter().any(|p| p.starts_with(".git/")));
assert!(!paths.contains(".gitignore"));
}
- #[test]
- fn handles_nested_directories() {
- let files = find_files(&fixtures_dir());
- let paths = get_paths(&files);
-
- // Check that files in nested directories are found
- assert!(paths.contains("nested/nested.gmi"));
- assert!(paths.contains("assets/style.css"));
-
- // Verify directory structure is preserved in paths
- let nested_files: Vec<_> = files.iter()
- .filter(|f| f.path.starts_with(fixtures_dir().join("nested")))
- .collect();
- assert!(!nested_files.is_empty());
- }
-
#[test]
fn returns_empty_for_empty_directory() {
- let empty_dir = fixtures_dir().join("empty");
- let _ = create_dir_all(&empty_dir);
- let files = find_files(&empty_dir);
+ let test_dir = setup_test_dir();
+ let files = find_files(&test_dir);
assert!(files.is_empty());
}
}
// Step 1. Identify the files
let files = find_files(&source);
- // Step 2. Prepare the target priority
- match remove_dir_all(&html_destination) {
- _ => {}
- };
- create_dir_all(&html_destination)?;
- match remove_dir_all(&gemini_destination) {
- _ => {}
- };
- create_dir_all(&gemini_destination)?;
-
- // Step 3. Load the layout
+ // Step 2. Load the layout
let mut file_handler = FileHandler::default();
match file_handler.get_layout_or_panic(&files) {
Ok(_) => {},
}
}
+ // Step 3. Prepare the target priority
+ match remove_dir_all(&html_destination) {
+ _ => {}
+ };
+ match remove_dir_all(&gemini_destination) {
+ _ => {}
+ };
+
+ create_dir_all(&html_destination)
+ .expect("Could not create HTML directory.");
+ create_dir_all(&gemini_destination)
+ .expect("Could not create Gemini directory.");
+
// Step 4. Process all files
file_handler.handle_all(&source, &html_destination, &gemini_destination, &files);
Ok(())
--- /dev/null
+[package]
+name = "test_utilities"
+version = "1.4.0"
+edition = "2021"
+license = "AGPL-3.0-or-later"
+description = "Shared test utilities for page"
+homepage = "https://r.bdr.sh/page.html"
+authors = ["Rubén Beltrán del Río <page@r.bdr.sh>"]
+
+[dependencies]
--- /dev/null
+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!("page_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());
+}
--- /dev/null
+use std::env;
+use std::fs::read_to_string;
+use std::path::PathBuf;
+use std::process::Command;
+use test_utilities::*;
+
+struct TestDir {
+ paths: Vec<PathBuf>,
+}
+
+impl Drop for TestDir {
+ fn drop(&mut self) {
+ for path in &self.paths {
+ cleanup_test_dir(path);
+ }
+ }
+}
+
+#[test]
+fn test_basic_generation() {
+ let test_dir = setup_test_dir();
+ let dir_name = test_dir.file_name().unwrap().to_string_lossy();
+ let parent = test_dir.parent().unwrap();
+ let html_dir = parent.join(format!("{}_html", dir_name));
+ let gemini_dir = parent.join(format!("{}_gemini", dir_name));
+
+ let _cleanup = TestDir {
+ paths: vec![test_dir.clone(), html_dir.clone(), gemini_dir.clone()]
+ };
+
+ // Create test input files
+ create_test_file(&test_dir.join("_layout.html"), "\
+<html>
+<head><title>{{ title }}</title></head>
+<body>{{ content }}</body>
+</html>
+");
+ create_test_file(&test_dir.join("test.gmi"), "\
+--- title: Page Is Cool!
+# Test
+Hello world
+");
+ create_test_file(&test_dir.join("test.png"), "A picture of a cute cat");
+
+ // Run the program from the test directory
+ let status = Command::new(env!("CARGO_BIN_EXE_page"))
+ .current_dir(&test_dir)
+ .status()
+ .expect("Failed to execute command");
+
+ assert!(status.success());
+
+ assert!(html_dir.exists());
+ assert!(gemini_dir.exists());
+
+ let html_output = html_dir.join("test.html");
+ assert_file_contents(&html_output, "\
+<html>
+<head><title>Page Is Cool!</title></head>
+<body><section class=\"h1\">
+<h1> Test</h1>
+<p>Hello world</p>
+</section>
+</body>
+</html>
+");
+
+ let html_asset_output = html_dir.join("test.png");
+ assert_file_contents(&html_asset_output, "A picture of a cute cat");
+
+ let gemini_output = gemini_dir.join("test.gmi");
+ assert_file_contents(&gemini_output, "\
+# Test
+Hello world
+");
+
+ let gemini_asset_output = gemini_dir.join("test.png");
+ assert!(gemini_asset_output.exists());
+ let gemini_asset_content = read_to_string(gemini_asset_output).unwrap();
+ assert_eq!(gemini_asset_content, "A picture of a cute cat");
+}
+
+#[test]
+fn test_missing_layout() {
+ let test_dir = setup_test_dir();
+ let dir_name = test_dir.file_name().unwrap().to_string_lossy();
+ let parent = test_dir.parent().unwrap();
+ let html_dir = parent.join(format!("{}_html", dir_name));
+ let gemini_dir = parent.join(format!("{}_gemini", dir_name));
+
+ let _cleanup = TestDir {
+ paths: vec![test_dir.clone(), html_dir.clone(), gemini_dir.clone()]
+ };
+
+ // Create test input files
+ create_test_file(&test_dir.join("test.gmi"), "\
+--- title: Page Is Cool!
+# Test
+Hello world
+");
+ create_test_file(&test_dir.join("test.png"), "A picture of a cute cat");
+
+ // Run the program from the test directory
+ let status = Command::new(env!("CARGO_BIN_EXE_page"))
+ .current_dir(&test_dir)
+ .status()
+ .expect("Failed to execute command");
+
+ assert!(!status.success());
+
+ assert!(!html_dir.exists());
+ assert!(!gemini_dir.exists());
+}