from pathlib import Path from PIL import Image from src.py.builder import image_processor as ip def test_convert_and_resize_image_missing_input_logs_and_skips(tmp_path): output_path = tmp_path / "out.webp" ip.convert_and_resize_image(tmp_path / "missing.jpg", output_path) assert not output_path.exists() def test_convert_and_resize_image_resizes_down(tmp_path, make_image): input_path = make_image(tmp_path / "in.jpg", size=(2000, 1000)) output_path = tmp_path / "out.webp" ip.convert_and_resize_image(input_path, output_path, resize=True, max_width=1000) actual_output = output_path if output_path.exists() else output_path.with_suffix(".jpg") assert actual_output.exists() with Image.open(actual_output) as img: assert img.width == 1000 assert img.height == 500 def test_convert_and_resize_image_no_resize_keeps_dimensions(tmp_path, make_image): input_path = make_image(tmp_path / "in.jpg", size=(500, 300)) output_path = tmp_path / "out.webp" ip.convert_and_resize_image(input_path, output_path, resize=False) actual_output = output_path if output_path.exists() else output_path.with_suffix(".jpg") with Image.open(actual_output) as img: assert img.size == (500, 300) def test_convert_and_resize_image_preserves_icc_profile(tmp_path): input_path = tmp_path / "in.jpg" icc_bytes = b"fake-icc-profile-bytes" Image.new("RGB", (100, 80), (10, 20, 30)).save(input_path, "JPEG", icc_profile=icc_bytes) output_path = tmp_path / "out.webp" ip.convert_and_resize_image(input_path, output_path, resize=False) actual_output = output_path if output_path.exists() else output_path.with_suffix(".jpg") with Image.open(actual_output) as img: assert img.info.get("icc_profile") == icc_bytes def test_process_images_updates_src_to_processed_extension(tmp_path, make_image): img_dir = tmp_path / "photos" build_dir = tmp_path / "output" make_image(img_dir / "gallery" / "a.jpg", size=(200, 200)) images = [{"src": "gallery/a.jpg", "tags": []}] ip.process_images(images, resize_images=True, img_dir=img_dir, build_dir=build_dir) assert images[0]["src"] in ("gallery/a.webp", "gallery/a.jpg") produced = build_dir / "img" / images[0]["src"] assert produced.exists() def test_copy_original_images_copies_existing_and_skips_missing(tmp_path, make_image, caplog): img_dir = tmp_path / "photos" build_dir = tmp_path / "output" make_image(img_dir / "gallery" / "present.jpg") images = [{"src": "gallery/present.jpg"}, {"src": "gallery/absent.jpg"}] ip.copy_original_images(images, img_dir, build_dir) assert (build_dir / "img" / "gallery" / "present.jpg").exists() assert not (build_dir / "img" / "gallery" / "absent.jpg").exists() def test_get_favicon_path_missing_config_returns_none(tmp_path): assert ip.get_favicon_path({}, tmp_path) is None def test_get_favicon_path_relative_and_absolute(tmp_path, make_image): theme_dir = tmp_path / "theme" icon_path = make_image(theme_dir / "favicon.png", fmt="PNG") result = ip.get_favicon_path({"favicon": {"path": "favicon.png"}}, theme_dir) assert result == icon_path absolute_result = ip.get_favicon_path({"favicon": {"path": str(icon_path)}}, theme_dir) assert absolute_result == icon_path def test_get_favicon_path_file_not_found(tmp_path): result = ip.get_favicon_path({"favicon": {"path": "missing.png"}}, tmp_path) assert result is None def test_generate_favicons_from_logo_creates_all_sizes(tmp_path, make_image): theme_dir = tmp_path / "theme" make_image(theme_dir / "favicon.png", size=(256, 256), fmt="PNG") output_dir = tmp_path / "output" / "favicon" ip.generate_favicons_from_logo({"favicon": {"path": "favicon.png"}}, theme_dir, output_dir) expected = [ "favicon-32.png", "favicon-96.png", "favicon-128.png", "favicon-192.png", "favicon-196.png", "favicon-152.png", "favicon-180.png", ] for name in expected: assert (output_dir / name).exists() with Image.open(output_dir / "favicon-32.png") as img: assert img.size == (32, 32) def test_generate_favicons_from_logo_no_favicon_skips(tmp_path): output_dir = tmp_path / "output" / "favicon" ip.generate_favicons_from_logo({}, tmp_path, output_dir) assert not output_dir.exists() def test_generate_favicon_ico_creates_file(tmp_path, make_image): theme_dir = tmp_path / "theme" make_image(theme_dir / "favicon.png", size=(64, 64), fmt="PNG") output_path = tmp_path / "output" / "favicon.ico" ip.generate_favicon_ico({"favicon": {"path": "favicon.png"}}, theme_dir, output_path) assert output_path.exists() with Image.open(output_path) as img: assert img.format == "ICO" def test_generate_favicon_ico_no_favicon_skips(tmp_path): output_path = tmp_path / "output" / "favicon.ico" ip.generate_favicon_ico({}, tmp_path, output_path) assert not output_path.exists()