Add even more tests
This commit is contained in:
+2
-1
@@ -2,4 +2,5 @@
|
||||
.vscode
|
||||
*.sif
|
||||
*.ipynb
|
||||
backups
|
||||
backups
|
||||
.pytest_cache
|
||||
+181
-1
@@ -1,5 +1,6 @@
|
||||
import zipfile
|
||||
import datetime
|
||||
from unittest.mock import patch
|
||||
from utils import backup
|
||||
|
||||
|
||||
@@ -31,4 +32,183 @@ def test_backup_creates_zip(tmp_path, monkeypatch):
|
||||
assert any('file2.txt' in n for n in names)
|
||||
|
||||
# Cleanup: remove the backup file after test
|
||||
backup_path.unlink()
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
def test_backup_with_subdirectories(tmp_path, monkeypatch):
|
||||
# Setup fake web folder with subdirectories
|
||||
web_folder = tmp_path / 'plots'
|
||||
web_folder.mkdir()
|
||||
(web_folder / 'file1.txt').write_text('content1')
|
||||
|
||||
subdir = web_folder / 'subdir'
|
||||
subdir.mkdir()
|
||||
(subdir / 'file2.txt').write_text('content2')
|
||||
|
||||
nested_subdir = subdir / 'nested'
|
||||
nested_subdir.mkdir()
|
||||
(nested_subdir / 'file3.txt').write_text('content3')
|
||||
|
||||
backup_folder = tmp_path / 'backups'
|
||||
backup_folder.mkdir()
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that backup was created with all files
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
backup_name = f'backup-{today}.zip'
|
||||
backup_path = backup_folder / backup_name
|
||||
|
||||
assert backup_path.exists()
|
||||
with zipfile.ZipFile(backup_path, 'r') as z:
|
||||
names = z.namelist()
|
||||
assert any('file1.txt' in n for n in names)
|
||||
assert any('file2.txt' in n for n in names)
|
||||
assert any('file3.txt' in n for n in names)
|
||||
|
||||
# Cleanup
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
def test_backup_existing_file(tmp_path, monkeypatch, capsys):
|
||||
# Setup fake web folder
|
||||
web_folder = tmp_path / 'plots'
|
||||
web_folder.mkdir()
|
||||
(web_folder / 'file1.txt').write_text('abc')
|
||||
|
||||
backup_folder = tmp_path / 'backups'
|
||||
backup_folder.mkdir()
|
||||
|
||||
# Create existing backup file
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
backup_name = f'backup-{today}.zip'
|
||||
backup_path = backup_folder / backup_name
|
||||
backup_path.write_text('existing backup')
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that message about existing backup was printed
|
||||
captured = capsys.readouterr()
|
||||
assert f"Backup already exists: {backup_path}" in captured.out
|
||||
|
||||
# Cleanup
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
def test_backup_empty_folder(tmp_path, monkeypatch):
|
||||
# Setup empty web folder
|
||||
web_folder = tmp_path / 'plots'
|
||||
web_folder.mkdir()
|
||||
|
||||
backup_folder = tmp_path / 'backups'
|
||||
backup_folder.mkdir()
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that backup was created (empty)
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
backup_name = f'backup-{today}.zip'
|
||||
backup_path = backup_folder / backup_name
|
||||
|
||||
assert backup_path.exists()
|
||||
with zipfile.ZipFile(backup_path, 'r') as z:
|
||||
assert len(z.namelist()) == 0
|
||||
|
||||
# Cleanup
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
def test_backup_nonexistent_web_folder(tmp_path, monkeypatch):
|
||||
# Setup nonexistent web folder
|
||||
web_folder = tmp_path / 'nonexistent_plots'
|
||||
backup_folder = tmp_path / 'backups'
|
||||
backup_folder.mkdir()
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that backup was created (empty since source doesn't exist)
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
backup_name = f'backup-{today}.zip'
|
||||
backup_path = backup_folder / backup_name
|
||||
|
||||
assert backup_path.exists()
|
||||
with zipfile.ZipFile(backup_path, 'r') as z:
|
||||
assert len(z.namelist()) == 0
|
||||
|
||||
# Cleanup
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
@patch('datetime.date')
|
||||
def test_backup_with_custom_date(mock_date, tmp_path, monkeypatch):
|
||||
# Mock date to return a specific date
|
||||
mock_date.today.return_value.strftime.return_value = "20230908"
|
||||
|
||||
# Setup fake web folder
|
||||
web_folder = tmp_path / 'plots'
|
||||
web_folder.mkdir()
|
||||
(web_folder / 'file1.txt').write_text('test')
|
||||
|
||||
backup_folder = tmp_path / 'backups'
|
||||
backup_folder.mkdir()
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that backup was created with custom date
|
||||
backup_path = backup_folder / "backup-20230908.zip"
|
||||
assert backup_path.exists()
|
||||
|
||||
# Cleanup
|
||||
backup_path.unlink()
|
||||
|
||||
|
||||
def test_backup_folder_creation(tmp_path, monkeypatch):
|
||||
# Setup fake web folder
|
||||
web_folder = tmp_path / 'plots'
|
||||
web_folder.mkdir()
|
||||
(web_folder / 'file1.txt').write_text('test')
|
||||
|
||||
# Don't create backup folder - let function create it
|
||||
backup_folder = tmp_path / 'new_backups'
|
||||
|
||||
# Patch the module variables
|
||||
monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
|
||||
monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)
|
||||
|
||||
# Call the backup function
|
||||
backup.create_backup()
|
||||
|
||||
# Check that backup folder was created
|
||||
assert backup_folder.exists()
|
||||
assert backup_folder.is_dir()
|
||||
|
||||
# Check that backup file was created
|
||||
today = datetime.date.today().strftime('%Y%m%d')
|
||||
backup_name = f'backup-{today}.zip'
|
||||
backup_path = backup_folder / backup_name
|
||||
assert backup_path.exists()
|
||||
@@ -1,3 +1,7 @@
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import pytest
|
||||
import yaml
|
||||
from utils import config
|
||||
|
||||
|
||||
@@ -25,3 +29,169 @@ def test_metadata_config_defaults():
|
||||
mc = config.MetadataConfig()
|
||||
assert mc.cache_enabled is True
|
||||
assert mc.inherit_from_parent is True
|
||||
assert mc.supported_formats == ['.yaml', '.yml', '.json']
|
||||
|
||||
|
||||
def test_metadata_config_custom():
|
||||
mc = config.MetadataConfig(
|
||||
cache_enabled=False,
|
||||
inherit_from_parent=False,
|
||||
supported_formats=['.yaml']
|
||||
)
|
||||
assert mc.cache_enabled is False
|
||||
assert mc.inherit_from_parent is False
|
||||
assert mc.supported_formats == ['.yaml']
|
||||
|
||||
|
||||
def test_gallery_item():
|
||||
item = config.GalleryItem(name="test", path=Path("/test/path"))
|
||||
assert item.name == "test"
|
||||
assert item.path == Path("/test/path")
|
||||
|
||||
|
||||
def test_config_creation():
|
||||
paths = config.PathConfig(work_dir="/work", web_folder="/web")
|
||||
gallery = config.GalleryConfig(
|
||||
plot_root="plots", png_dpi=300, backup_folder="backups")
|
||||
ui = config.UIConfig(max_recent_plots=5, search_debounce_ms=100)
|
||||
metadata = config.MetadataConfig()
|
||||
|
||||
cfg = config.Config(
|
||||
paths=paths,
|
||||
gallery=gallery,
|
||||
ui=ui,
|
||||
metadata=metadata
|
||||
)
|
||||
|
||||
assert cfg.paths == paths
|
||||
assert cfg.gallery == gallery
|
||||
assert cfg.ui == ui
|
||||
assert cfg.metadata == metadata
|
||||
assert cfg.sources == []
|
||||
|
||||
|
||||
def test_config_backward_compatibility_properties():
|
||||
paths = config.PathConfig(work_dir="/work", web_folder="/web")
|
||||
gallery = config.GalleryConfig(
|
||||
plot_root="plots", png_dpi=300, backup_folder="backups")
|
||||
ui = config.UIConfig(max_recent_plots=5, search_debounce_ms=100)
|
||||
metadata = config.MetadataConfig()
|
||||
|
||||
cfg = config.Config(
|
||||
paths=paths,
|
||||
gallery=gallery,
|
||||
ui=ui,
|
||||
metadata=metadata
|
||||
)
|
||||
|
||||
assert cfg.web_folder == "/web"
|
||||
assert cfg.png_dpi == 300
|
||||
assert cfg.plot_root == "plots"
|
||||
assert cfg.backup_folder == "backups"
|
||||
|
||||
|
||||
def test_config_from_yaml(tmp_path):
|
||||
yaml_content = {
|
||||
'paths': {
|
||||
'work_dir': '/test/work',
|
||||
'web_folder': '/test/web'
|
||||
},
|
||||
'gallery': {
|
||||
'plot_root': 'test_plots',
|
||||
'png_dpi': 200,
|
||||
'backup_folder': 'test_backups'
|
||||
},
|
||||
'ui': {
|
||||
'max_recent_plots': 15,
|
||||
'search_debounce_ms': 300
|
||||
},
|
||||
'metadata': {
|
||||
'cache_enabled': False,
|
||||
'inherit_from_parent': False
|
||||
},
|
||||
'sources': [
|
||||
{'name': 'source1', 'path': '/path1'},
|
||||
{'name': 'source2', 'path': '/path2'}
|
||||
]
|
||||
}
|
||||
|
||||
yaml_file = tmp_path / 'test_config.yaml'
|
||||
with yaml_file.open('w') as f:
|
||||
yaml.dump(yaml_content, f)
|
||||
|
||||
cfg = config.Config.from_yaml(str(yaml_file))
|
||||
|
||||
assert cfg.paths.work_dir == '/test/work'
|
||||
assert cfg.paths.web_folder == '/test/web'
|
||||
assert cfg.gallery.plot_root == 'test_plots'
|
||||
assert cfg.gallery.png_dpi == 200
|
||||
assert cfg.ui.max_recent_plots == 15
|
||||
assert cfg.metadata.cache_enabled is False
|
||||
assert len(cfg.sources) == 2
|
||||
assert cfg.sources[0].name == 'source1'
|
||||
assert cfg.sources[0].path == Path('/path1')
|
||||
|
||||
|
||||
def test_config_from_yaml_missing_file():
|
||||
with pytest.raises(FileNotFoundError):
|
||||
config.Config.from_yaml('/nonexistent/file.yaml')
|
||||
|
||||
|
||||
def test_config_from_yaml_malformed():
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml',
|
||||
delete=False) as f:
|
||||
f.write('invalid: yaml: content: [')
|
||||
f.flush()
|
||||
|
||||
with pytest.raises(yaml.YAMLError):
|
||||
config.Config.from_yaml(f.name)
|
||||
|
||||
|
||||
def test_config_to_yaml(tmp_path):
|
||||
paths = config.PathConfig(work_dir="/work", web_folder="/web")
|
||||
gallery = config.GalleryConfig(
|
||||
plot_root="plots", png_dpi=300, backup_folder="backups")
|
||||
ui = config.UIConfig(max_recent_plots=5, search_debounce_ms=100)
|
||||
metadata = config.MetadataConfig()
|
||||
sources = [config.GalleryItem(name="test", path=Path("/test"))]
|
||||
|
||||
cfg = config.Config(
|
||||
paths=paths,
|
||||
gallery=gallery,
|
||||
ui=ui,
|
||||
metadata=metadata,
|
||||
sources=sources
|
||||
)
|
||||
|
||||
yaml_file = tmp_path / 'output_config.yaml'
|
||||
cfg.to_yaml(str(yaml_file))
|
||||
|
||||
assert yaml_file.exists()
|
||||
|
||||
# Load back and verify
|
||||
with yaml_file.open('r') as f:
|
||||
loaded_data = yaml.safe_load(f)
|
||||
|
||||
assert loaded_data['paths']['work_dir'] == "/work"
|
||||
assert loaded_data['gallery']['png_dpi'] == 300
|
||||
assert len(loaded_data['sources']) == 1
|
||||
|
||||
|
||||
def test_config_from_yaml_partial_data(tmp_path):
|
||||
# Test with minimal YAML data
|
||||
yaml_content = {
|
||||
'paths': {'work_dir': '/min', 'web_folder': '/min_web'},
|
||||
'gallery': {'plot_root': 'min_plots', 'png_dpi': 100,
|
||||
'backup_folder': 'min_backup'},
|
||||
'ui': {'max_recent_plots': 3, 'search_debounce_ms': 50}
|
||||
}
|
||||
|
||||
yaml_file = tmp_path / 'minimal_config.yaml'
|
||||
with yaml_file.open('w') as f:
|
||||
yaml.dump(yaml_content, f)
|
||||
|
||||
cfg = config.Config.from_yaml(str(yaml_file))
|
||||
|
||||
# Should use defaults for metadata and empty sources
|
||||
assert cfg.metadata.cache_enabled is True # default
|
||||
assert cfg.sources == [] # default empty list
|
||||
|
||||
@@ -17,8 +17,8 @@ def test_python_version():
|
||||
def test_required_modules():
|
||||
"""Test that required Python modules are installed."""
|
||||
try:
|
||||
import jinja2 # type: ignore
|
||||
import yaml # type: ignore
|
||||
import jinja2 # noqa: F401
|
||||
import yaml # noqa: F401
|
||||
except ImportError as e:
|
||||
pytest.fail(f"Required module not found: {e}")
|
||||
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
from generate_gallery import (
|
||||
convert_pdf_to_png,
|
||||
needs_update,
|
||||
build_gallery,
|
||||
calculate_directory_stats,
|
||||
format_file_size,
|
||||
datetime_from_timestamp,
|
||||
strftime_filter
|
||||
)
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def test_format_file_size():
|
||||
assert format_file_size(0) == "0 B"
|
||||
assert format_file_size(1) == "1.0 B"
|
||||
assert format_file_size(1024) == "1.0 KB"
|
||||
assert format_file_size(1048576) == "1.0 MB"
|
||||
assert format_file_size(1073741824) == "1.0 GB"
|
||||
assert format_file_size(1099511627776) == "1.0 TB"
|
||||
|
||||
|
||||
def test_format_file_size_edge_cases():
|
||||
assert format_file_size(1023) == "1023.0 B"
|
||||
assert format_file_size(1536) == "1.5 KB"
|
||||
assert format_file_size(2621440) == "2.5 MB"
|
||||
|
||||
|
||||
def test_needs_update_missing_target(tmp_path):
|
||||
source = tmp_path / "source.txt"
|
||||
target = tmp_path / "target.txt"
|
||||
source.write_text("test content")
|
||||
|
||||
assert needs_update(source, target) is True
|
||||
|
||||
|
||||
def test_needs_update_target_newer(tmp_path):
|
||||
source = tmp_path / "source.txt"
|
||||
target = tmp_path / "target.txt"
|
||||
|
||||
source.write_text("test")
|
||||
target.write_text("test")
|
||||
|
||||
# Make target newer by modifying its timestamp
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
target.touch()
|
||||
|
||||
assert needs_update(source, target) is False
|
||||
|
||||
|
||||
def test_needs_update_source_newer(tmp_path):
|
||||
source = tmp_path / "source.txt"
|
||||
target = tmp_path / "target.txt"
|
||||
|
||||
target.write_text("test")
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
source.write_text("test")
|
||||
|
||||
assert needs_update(source, target) is True
|
||||
|
||||
|
||||
@patch('subprocess.run')
|
||||
def test_convert_pdf_to_png_success(mock_run, tmp_path):
|
||||
pdf_path = tmp_path / "test.pdf"
|
||||
png_path = tmp_path / "test.png"
|
||||
pdf_path.write_text("fake pdf")
|
||||
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
|
||||
convert_pdf_to_png(pdf_path)
|
||||
|
||||
mock_run.assert_called_once()
|
||||
call_args = mock_run.call_args[0][0]
|
||||
assert call_args[0] == "convert"
|
||||
assert str(pdf_path) in call_args
|
||||
assert str(png_path) in call_args
|
||||
|
||||
|
||||
@patch('subprocess.run')
|
||||
def test_convert_pdf_to_png_already_exists_newer(mock_run, tmp_path):
|
||||
pdf_path = tmp_path / "test.pdf"
|
||||
png_path = tmp_path / "test.png"
|
||||
|
||||
pdf_path.write_text("fake pdf")
|
||||
png_path.write_text("fake png")
|
||||
|
||||
# Make PNG much newer than PDF
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
png_path.touch()
|
||||
|
||||
convert_pdf_to_png(pdf_path)
|
||||
|
||||
# Should not call subprocess since PNG is newer
|
||||
mock_run.assert_not_called()
|
||||
|
||||
|
||||
@patch('subprocess.run')
|
||||
def test_convert_pdf_to_png_pdf_newer(mock_run, tmp_path):
|
||||
pdf_path = tmp_path / "test.pdf"
|
||||
png_path = tmp_path / "test.png"
|
||||
|
||||
png_path.write_text("fake png")
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
pdf_path.write_text("fake pdf")
|
||||
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
|
||||
convert_pdf_to_png(pdf_path)
|
||||
|
||||
# Should call subprocess since PDF is newer
|
||||
mock_run.assert_called_once()
|
||||
|
||||
|
||||
def test_calculate_directory_stats_empty(tmp_path):
|
||||
stats = calculate_directory_stats(tmp_path)
|
||||
|
||||
assert stats["file_count"] == 0
|
||||
assert stats["folder_count"] == 0
|
||||
assert stats["total_size"] == 0
|
||||
assert stats["pdf_size"] == 0
|
||||
assert stats["png_size"] == 0
|
||||
|
||||
|
||||
def test_calculate_directory_stats_with_files(tmp_path):
|
||||
# Create test files
|
||||
(tmp_path / "test.pdf").write_text("pdf content")
|
||||
(tmp_path / "test.png").write_text("png content")
|
||||
(tmp_path / "test.txt").write_text("txt content")
|
||||
|
||||
# Create subdirectory
|
||||
subdir = tmp_path / "subdir"
|
||||
subdir.mkdir()
|
||||
(subdir / "nested.pdf").write_text("nested pdf")
|
||||
|
||||
stats = calculate_directory_stats(tmp_path)
|
||||
|
||||
assert stats["file_count"] == 4
|
||||
assert stats["folder_count"] == 1
|
||||
assert stats["total_size"] > 0
|
||||
assert stats["pdf_size"] > 0
|
||||
assert stats["png_size"] > 0
|
||||
|
||||
|
||||
def test_calculate_directory_stats_nonexistent():
|
||||
nonexistent = Path("/nonexistent/path")
|
||||
stats = calculate_directory_stats(nonexistent)
|
||||
|
||||
assert stats["file_count"] == 0
|
||||
assert stats["folder_count"] == 0
|
||||
assert stats["total_size"] == 0
|
||||
|
||||
|
||||
def test_datetime_from_timestamp():
|
||||
timestamp = 1630000000 # Some Unix timestamp
|
||||
dt = datetime_from_timestamp(timestamp)
|
||||
|
||||
assert isinstance(dt, datetime)
|
||||
assert dt.timestamp() == timestamp
|
||||
|
||||
|
||||
def test_strftime_filter():
|
||||
dt = datetime(2023, 9, 8, 14, 30, 0)
|
||||
formatted = strftime_filter(dt, "%Y-%m-%d %H:%M")
|
||||
|
||||
assert formatted == "2023-09-08 14:30"
|
||||
|
||||
|
||||
@patch('generate_gallery.template')
|
||||
@patch('generate_gallery.save_metadata_cache')
|
||||
@patch('generate_gallery.resolve_metadata_for_plot')
|
||||
@patch('generate_gallery.merge_metadata')
|
||||
@patch('generate_gallery.load_folder_metadata')
|
||||
@patch('generate_gallery.convert_pdf_to_png')
|
||||
@patch('shutil.copy2')
|
||||
def test_build_gallery_basic(
|
||||
mock_copy,
|
||||
mock_convert,
|
||||
mock_load_folder,
|
||||
mock_merge,
|
||||
mock_resolve,
|
||||
mock_save_cache,
|
||||
mock_template,
|
||||
tmp_path
|
||||
):
|
||||
source_dir = tmp_path / "source"
|
||||
web_dir = tmp_path / "web"
|
||||
source_dir.mkdir()
|
||||
web_dir.mkdir()
|
||||
|
||||
# Create a test PDF
|
||||
pdf_file = source_dir / "test.pdf"
|
||||
pdf_file.write_text("fake pdf content")
|
||||
|
||||
# Create corresponding PNG
|
||||
png_file = source_dir / "test.png"
|
||||
png_file.write_text("fake png content")
|
||||
|
||||
# Mock returns
|
||||
mock_load_folder.return_value = {"folder": "metadata"}
|
||||
mock_merge.return_value = {"merged": "metadata"}
|
||||
mock_resolve.return_value = {"plot": "metadata"}
|
||||
mock_template.render.return_value = "<html>test</html>"
|
||||
|
||||
build_gallery(source_dir, web_dir)
|
||||
|
||||
# Verify mocks were called
|
||||
mock_load_folder.assert_called_once_with(source_dir)
|
||||
mock_convert.assert_called_once_with(pdf_file)
|
||||
mock_copy.assert_called() # Should be called for PDF and PNG
|
||||
mock_save_cache.assert_called_once()
|
||||
|
||||
# Check HTML file was created
|
||||
html_file = web_dir / "index.html"
|
||||
assert html_file.exists()
|
||||
|
||||
|
||||
@patch('generate_gallery.template')
|
||||
@patch('generate_gallery.save_metadata_cache')
|
||||
@patch('generate_gallery.load_folder_metadata')
|
||||
def test_build_gallery_with_subdirs(
|
||||
mock_load_folder,
|
||||
mock_save_cache,
|
||||
mock_template,
|
||||
tmp_path
|
||||
):
|
||||
source_dir = tmp_path / "source"
|
||||
web_dir = tmp_path / "web"
|
||||
source_dir.mkdir()
|
||||
web_dir.mkdir()
|
||||
|
||||
# Create subdirectory
|
||||
subdir = source_dir / "subdir"
|
||||
subdir.mkdir()
|
||||
|
||||
mock_load_folder.return_value = {}
|
||||
mock_template.render.return_value = "<html>test</html>"
|
||||
|
||||
build_gallery(source_dir, web_dir)
|
||||
|
||||
# Check subdirectory was created in web
|
||||
web_subdir = web_dir / "subdir"
|
||||
assert web_subdir.exists()
|
||||
assert web_subdir.is_dir()
|
||||
|
||||
|
||||
@patch('generate_gallery.needs_update')
|
||||
@patch('shutil.copy2')
|
||||
def test_build_gallery_skip_up_to_date(mock_copy, mock_needs_update, tmp_path):
|
||||
source_dir = tmp_path / "source"
|
||||
web_dir = tmp_path / "web"
|
||||
source_dir.mkdir()
|
||||
web_dir.mkdir()
|
||||
|
||||
# Create test files
|
||||
pdf_file = source_dir / "test.pdf"
|
||||
png_file = source_dir / "test.png"
|
||||
pdf_file.write_text("pdf")
|
||||
png_file.write_text("png")
|
||||
|
||||
# Create target files
|
||||
web_pdf = web_dir / "test.pdf"
|
||||
web_png = web_dir / "test.png"
|
||||
web_pdf.write_text("pdf")
|
||||
web_png.write_text("png")
|
||||
|
||||
# Mock needs_update to return False (up to date)
|
||||
mock_needs_update.return_value = False
|
||||
|
||||
with patch('generate_gallery.template') as mock_template:
|
||||
mock_template.render.return_value = "<html>test</html>"
|
||||
build_gallery(source_dir, web_dir)
|
||||
|
||||
# copy2 should not be called since files are up to date
|
||||
mock_copy.assert_not_called()
|
||||
+178
-1
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import pytest
|
||||
from utils import metadata
|
||||
import yaml
|
||||
|
||||
@@ -22,4 +23,180 @@ def test_load_metadata_file_json(tmp_path):
|
||||
def test_load_metadata_file_missing(tmp_path):
|
||||
missing_path = tmp_path / 'nope.yaml'
|
||||
result = metadata.load_metadata_file(missing_path)
|
||||
assert result == {}
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_load_metadata_file_yml_extension(tmp_path):
|
||||
data = {'test': 'yml_format'}
|
||||
yml_path = tmp_path / 'meta.yml'
|
||||
yml_path.write_text(yaml.dump(data))
|
||||
result = metadata.load_metadata_file(yml_path)
|
||||
assert result == data
|
||||
|
||||
|
||||
def test_load_metadata_file_unknown_format(tmp_path):
|
||||
txt_path = tmp_path / 'meta.txt'
|
||||
txt_path.write_text('some text')
|
||||
result = metadata.load_metadata_file(txt_path)
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_load_metadata_file_malformed_yaml(tmp_path):
|
||||
yaml_path = tmp_path / 'bad.yaml'
|
||||
yaml_path.write_text('invalid: yaml: content: [')
|
||||
with pytest.raises(yaml.YAMLError):
|
||||
metadata.load_metadata_file(yaml_path)
|
||||
|
||||
|
||||
def test_load_metadata_file_malformed_json(tmp_path):
|
||||
json_path = tmp_path / 'bad.json'
|
||||
json_path.write_text('{"invalid": json}')
|
||||
with pytest.raises(json.JSONDecodeError):
|
||||
metadata.load_metadata_file(json_path)
|
||||
|
||||
|
||||
def test_load_folder_metadata_yaml(tmp_path):
|
||||
data = {'folder': 'metadata'}
|
||||
metadata_path = tmp_path / 'metadata.yaml'
|
||||
metadata_path.write_text(yaml.dump(data))
|
||||
result = metadata.load_folder_metadata(tmp_path)
|
||||
assert result == data
|
||||
|
||||
|
||||
def test_load_folder_metadata_yml(tmp_path):
|
||||
data = {'folder': 'metadata_yml'}
|
||||
metadata_path = tmp_path / 'metadata.yml'
|
||||
metadata_path.write_text(yaml.dump(data))
|
||||
result = metadata.load_folder_metadata(tmp_path)
|
||||
assert result == data
|
||||
|
||||
|
||||
def test_load_folder_metadata_json(tmp_path):
|
||||
data = {'folder': 'metadata_json'}
|
||||
metadata_path = tmp_path / 'metadata.json'
|
||||
metadata_path.write_text(json.dumps(data))
|
||||
result = metadata.load_folder_metadata(tmp_path)
|
||||
assert result == data
|
||||
|
||||
|
||||
def test_load_folder_metadata_missing(tmp_path):
|
||||
result = metadata.load_folder_metadata(tmp_path)
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_get_metadata_file_path_existing_yaml(tmp_path):
|
||||
metadata_path = tmp_path / 'metadata.yaml'
|
||||
metadata_path.write_text('test: data')
|
||||
result = metadata.get_metadata_file_path(tmp_path)
|
||||
assert result == str(metadata_path)
|
||||
|
||||
|
||||
def test_get_metadata_file_path_existing_yml(tmp_path):
|
||||
metadata_path = tmp_path / 'metadata.yml'
|
||||
metadata_path.write_text('test: data')
|
||||
result = metadata.get_metadata_file_path(tmp_path)
|
||||
assert result == str(metadata_path)
|
||||
|
||||
|
||||
def test_get_metadata_file_path_existing_json(tmp_path):
|
||||
metadata_path = tmp_path / 'metadata.json'
|
||||
metadata_path.write_text('{"test": "data"}')
|
||||
result = metadata.get_metadata_file_path(tmp_path)
|
||||
assert result == str(metadata_path)
|
||||
|
||||
|
||||
def test_get_metadata_file_path_none_existing(tmp_path):
|
||||
result = metadata.get_metadata_file_path(tmp_path)
|
||||
expected = str(tmp_path / 'metadata.yaml')
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_merge_metadata():
|
||||
parent = {'project': 'Test', 'version': '1.0', 'author': 'Parent'}
|
||||
child = {'experiment': 'A', 'version': '1.1'}
|
||||
merged = metadata.merge_metadata(parent, child)
|
||||
expected = {'project': 'Test', 'version': '1.1',
|
||||
'author': 'Parent', 'experiment': 'A'}
|
||||
assert merged == expected
|
||||
|
||||
|
||||
def test_merge_metadata_empty_parent():
|
||||
parent = {}
|
||||
child = {'experiment': 'A', 'version': '1.1'}
|
||||
merged = metadata.merge_metadata(parent, child)
|
||||
assert merged == child
|
||||
|
||||
|
||||
def test_merge_metadata_empty_child():
|
||||
parent = {'project': 'Test', 'version': '1.0'}
|
||||
child = {}
|
||||
merged = metadata.merge_metadata(parent, child)
|
||||
assert merged == parent
|
||||
|
||||
|
||||
def test_resolve_metadata_for_plot_with_specific_yaml(tmp_path):
|
||||
# Create plot-specific metadata file
|
||||
plot_path = tmp_path / 'test_plot.pdf'
|
||||
plot_metadata_path = tmp_path / 'test_plot.yaml'
|
||||
plot_metadata = {'specific': 'plot_data', 'override': 'plot_value'}
|
||||
plot_metadata_path.write_text(yaml.dump(plot_metadata))
|
||||
|
||||
inherited = {'general': 'data', 'override': 'inherited_value'}
|
||||
result = metadata.resolve_metadata_for_plot(plot_path, inherited)
|
||||
|
||||
expected = {'general': 'data',
|
||||
'override': 'plot_value', 'specific': 'plot_data'}
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_resolve_metadata_for_plot_with_specific_json(tmp_path):
|
||||
plot_path = tmp_path / 'test_plot.pdf'
|
||||
plot_metadata_path = tmp_path / 'test_plot.json'
|
||||
plot_metadata = {'specific': 'plot_data_json'}
|
||||
plot_metadata_path.write_text(json.dumps(plot_metadata))
|
||||
|
||||
inherited = {'general': 'data'}
|
||||
result = metadata.resolve_metadata_for_plot(plot_path, inherited)
|
||||
|
||||
expected = {'general': 'data', 'specific': 'plot_data_json'}
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_resolve_metadata_for_plot_no_specific(tmp_path):
|
||||
plot_path = tmp_path / 'test_plot.pdf'
|
||||
inherited = {'general': 'data', 'inherited': 'value'}
|
||||
result = metadata.resolve_metadata_for_plot(plot_path, inherited)
|
||||
|
||||
# Should return copy of inherited metadata
|
||||
assert result == inherited
|
||||
assert result is not inherited # Should be a copy
|
||||
|
||||
|
||||
def test_save_metadata_cache(tmp_path):
|
||||
cache_data = {
|
||||
'plot1': {'title': 'Plot 1', 'author': 'Test'},
|
||||
'plot2': {'title': 'Plot 2', 'experiment': 'B'}
|
||||
}
|
||||
|
||||
metadata.save_metadata_cache(tmp_path, cache_data)
|
||||
|
||||
cache_file = tmp_path / 'meta_cache.json'
|
||||
assert cache_file.exists()
|
||||
|
||||
with cache_file.open('r') as f:
|
||||
loaded_data = json.load(f)
|
||||
|
||||
assert loaded_data == cache_data
|
||||
|
||||
|
||||
def test_save_metadata_cache_empty(tmp_path):
|
||||
cache_data = {}
|
||||
metadata.save_metadata_cache(tmp_path, cache_data)
|
||||
|
||||
cache_file = tmp_path / 'meta_cache.json'
|
||||
assert cache_file.exists()
|
||||
|
||||
with cache_file.open('r') as f:
|
||||
loaded_data = json.load(f)
|
||||
|
||||
assert loaded_data == {}
|
||||
|
||||
Reference in New Issue
Block a user