* Began refactoring for improving unicode handling * Added platform and unicode modules * Added tests for unicode utilities * Added tests for unicode utilities * Added tests for unicode utilities * Added tests for unicode utilities * Fixed unicode tests for linux * Fixed unicode tests for linux * Fixed duplicate alubm name with --add-to-album * Fixed test for linux * Fix for duplicate unicode kewyords, see #907, #1085
366 lines
11 KiB
Python
366 lines
11 KiB
Python
""" pytest test configuration """
|
|
import os
|
|
import pathlib
|
|
import shutil
|
|
import tempfile
|
|
import time
|
|
|
|
import pytest
|
|
|
|
from osxphotos.platform import is_macos
|
|
|
|
if is_macos:
|
|
import photoscript
|
|
from applescript import AppleScript
|
|
from photoscript.utils import ditto
|
|
|
|
from .test_catalina_10_15_7 import UUID_DICT_LOCAL
|
|
|
|
from osxphotos.exiftool import _ExifToolProc
|
|
|
|
# run timewarp tests (configured with --timewarp)
|
|
TEST_TIMEWARP = False
|
|
|
|
# run import tests (configured with --test-import)
|
|
TEST_IMPORT = False
|
|
|
|
# run sync tests (configured with --test-sync)
|
|
TEST_SYNC = False
|
|
|
|
# run add-locations tests (configured with --test-add-locations)
|
|
TEST_ADD_LOCATIONS = False
|
|
|
|
# run batch-edit tests (configured with --test-batch-edit)
|
|
TEST_BATCH_EDIT = False
|
|
|
|
# don't clean up crash logs (configured with --no-cleanup)
|
|
NO_CLEANUP = False
|
|
|
|
|
|
def get_os_version():
|
|
if not is_macos:
|
|
return (None, None, None)
|
|
|
|
import platform
|
|
|
|
# returns tuple containing OS version
|
|
# e.g. 10.13.6 = (10, 13, 6)
|
|
version = platform.mac_ver()[0].split(".")
|
|
if len(version) == 2:
|
|
(ver, major) = version
|
|
minor = "0"
|
|
elif len(version) == 3:
|
|
(ver, major, minor) = version
|
|
else:
|
|
raise (
|
|
ValueError(
|
|
f"Could not parse version string: {platform.mac_ver()} {version}"
|
|
)
|
|
)
|
|
return (ver, major, minor)
|
|
|
|
|
|
OS_VER = get_os_version() if is_macos else [None, None]
|
|
if OS_VER[0] == "10" and OS_VER[1] == "15":
|
|
# Catalina
|
|
TEST_LIBRARY = "tests/Test-10.15.7.photoslibrary"
|
|
TEST_LIBRARY_IMPORT = TEST_LIBRARY
|
|
TEST_LIBRARY_SYNC = TEST_LIBRARY
|
|
from tests.config_timewarp_catalina import TEST_LIBRARY_TIMEWARP
|
|
|
|
TEST_LIBRARY_ADD_LOCATIONS = None
|
|
elif OS_VER[0] == "13":
|
|
# Ventura
|
|
TEST_LIBRARY = "tests/Test-13.0.0.photoslibrary"
|
|
TEST_LIBRARY_IMPORT = TEST_LIBRARY
|
|
TEST_LIBRARY_SYNC = TEST_LIBRARY
|
|
from tests.config_timewarp_ventura import TEST_LIBRARY_TIMEWARP
|
|
|
|
TEST_LIBRARY_ADD_LOCATIONS = "tests/Test-13.0.0.photoslibrary"
|
|
else:
|
|
TEST_LIBRARY = None
|
|
TEST_LIBRARY_TIMEWARP = None
|
|
TEST_LIBRARY_SYNC = None
|
|
TEST_LIBRARY_ADD_LOCATIONS = None
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=is_macos)
|
|
def setup_photos_timewarp():
|
|
if not TEST_TIMEWARP:
|
|
return
|
|
copy_photos_library(TEST_LIBRARY_TIMEWARP, delay=5)
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=is_macos)
|
|
def setup_photos_import():
|
|
if not TEST_IMPORT:
|
|
return
|
|
copy_photos_library(TEST_LIBRARY_IMPORT, delay=10)
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=is_macos)
|
|
def setup_photos_sync():
|
|
if not TEST_SYNC:
|
|
return
|
|
copy_photos_library(TEST_LIBRARY_SYNC, delay=10)
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=is_macos)
|
|
def setup_photos_add_locations():
|
|
if not TEST_ADD_LOCATIONS:
|
|
return
|
|
copy_photos_library(TEST_LIBRARY_ADD_LOCATIONS, delay=10)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_singletons():
|
|
"""Need to clean up any ExifTool singletons between tests"""
|
|
_ExifToolProc.instance = None
|
|
|
|
|
|
def pytest_addoption(parser):
|
|
parser.addoption(
|
|
"--addalbum",
|
|
action="store_true",
|
|
default=False,
|
|
help="run --add-exported-to-album tests",
|
|
)
|
|
parser.addoption(
|
|
"--timewarp", action="store_true", default=False, help="run --timewarp tests"
|
|
)
|
|
parser.addoption(
|
|
"--test-import",
|
|
action="store_true",
|
|
default=False,
|
|
help="run `osxphotos import` tests",
|
|
)
|
|
parser.addoption("--test-batch-edit", action="store_true", default=False)
|
|
parser.addoption(
|
|
"--test-sync",
|
|
action="store_true",
|
|
default=False,
|
|
help="run `osxphotos sync` tests",
|
|
)
|
|
parser.addoption(
|
|
"--test-add-locations",
|
|
action="store_true",
|
|
default=False,
|
|
help="run `osxphotos add-locations` tests",
|
|
)
|
|
parser.addoption(
|
|
"--no-cleanup",
|
|
action="store_true",
|
|
default=False,
|
|
help="don't clean up crash logs after tests",
|
|
)
|
|
|
|
|
|
def pytest_configure(config):
|
|
if (
|
|
sum(
|
|
bool(x)
|
|
for x in [
|
|
config.getoption("--addalbum"),
|
|
config.getoption("--timewarp"),
|
|
config.getoption("--test-import"),
|
|
config.getoption("--test-sync"),
|
|
config.getoption("--test-batch-edit"),
|
|
0,
|
|
]
|
|
)
|
|
> 1
|
|
):
|
|
pytest.exit(
|
|
"--addalbum, --timewarp, --test-import, --test-sync, --test-batch-edit are mutually exclusive"
|
|
)
|
|
|
|
config.addinivalue_line(
|
|
"markers", "addalbum: mark test as requiring --addalbum to run"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "timewarp: mark test as requiring --timewarp to run"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "test_import: mark test as requiring --test-import to run"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "test_sync: mark test as requiring --test-sync to run"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers",
|
|
"test_add_locations: mark test as requiring --test-add-locations to run",
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "test_batch_edit: mark test as requiring --test-batch-edit to run"
|
|
)
|
|
|
|
# this is hacky but I can't figure out how to check config options in other fixtures
|
|
if config.getoption("--timewarp"):
|
|
global TEST_TIMEWARP
|
|
TEST_TIMEWARP = True
|
|
|
|
if config.getoption("--test-import"):
|
|
global TEST_IMPORT
|
|
TEST_IMPORT = True
|
|
|
|
if config.getoption("--test-sync"):
|
|
global TEST_SYNC
|
|
TEST_SYNC = True
|
|
|
|
if config.getoption("--test-add-locations"):
|
|
global TEST_ADD_LOCATIONS
|
|
TEST_ADD_LOCATIONS = True
|
|
|
|
if config.getoption("--no-cleanup"):
|
|
global NO_CLEANUP
|
|
NO_CLEANUP = True
|
|
|
|
if config.getoption("--test-batch-edit"):
|
|
global TEST_BATCH_EDIT
|
|
TEST_BATCH_EDIT = True
|
|
|
|
|
|
def pytest_collection_modifyitems(config, items):
|
|
if not (config.getoption("--addalbum") and TEST_LIBRARY is not None):
|
|
skip_addalbum = pytest.mark.skip(reason="need --addalbum option to run")
|
|
for item in items:
|
|
if "addalbum" in item.keywords:
|
|
item.add_marker(skip_addalbum)
|
|
|
|
if not (config.getoption("--timewarp") and TEST_LIBRARY_TIMEWARP is not None):
|
|
skip_timewarp = pytest.mark.skip(reason="need --timewarp option to run")
|
|
for item in items:
|
|
if "timewarp" in item.keywords:
|
|
item.add_marker(skip_timewarp)
|
|
|
|
if not (config.getoption("--test-import") and TEST_LIBRARY_IMPORT is not None):
|
|
skip_test_import = pytest.mark.skip(reason="need --test-import option to run")
|
|
for item in items:
|
|
if "test_import" in item.keywords:
|
|
item.add_marker(skip_test_import)
|
|
|
|
if not (config.getoption("--test-sync") and TEST_LIBRARY_SYNC is not None):
|
|
skip_test_sync = pytest.mark.skip(reason="need --test-sync option to run")
|
|
for item in items:
|
|
if "test_sync" in item.keywords:
|
|
item.add_marker(skip_test_sync)
|
|
|
|
if not (config.getoption("--test-batch-edit")):
|
|
skip_test_batch_edit = pytest.mark.skip(
|
|
reason="need --test-batch-edit option to run"
|
|
)
|
|
for item in items:
|
|
if "test_batch_edit" in item.keywords:
|
|
item.add_marker(skip_test_batch_edit)
|
|
|
|
if not (
|
|
config.getoption("--test-add-locations")
|
|
and TEST_LIBRARY_ADD_LOCATIONS is not None
|
|
):
|
|
skip_test_sync = pytest.mark.skip(
|
|
reason="need --test-add-locations option and MacOS Ventura to run"
|
|
)
|
|
for item in items:
|
|
if "test_add_locations" in item.keywords:
|
|
item.add_marker(skip_test_sync)
|
|
|
|
|
|
def copy_photos_library(photos_library, delay=0, open=True):
|
|
"""copy the test library and open Photos, returns path to copied library"""
|
|
|
|
# quit Photos if it's running
|
|
photoslib = photoscript.PhotosLibrary()
|
|
photoslib.quit()
|
|
|
|
src = pathlib.Path(os.getcwd()) / photos_library
|
|
picture_folder = (
|
|
pathlib.Path(os.environ["PHOTOSCRIPT_PICTURES_FOLDER"])
|
|
if "PHOTOSCRIPT_PICTURES_FOLDER" in os.environ
|
|
else pathlib.Path("~/Pictures")
|
|
)
|
|
picture_folder = picture_folder.expanduser()
|
|
if not picture_folder.is_dir():
|
|
pytest.exit(f"Invalid picture folder: '{picture_folder}'")
|
|
dest = picture_folder / pathlib.Path(photos_library).name
|
|
|
|
# copy src directory to dest directory, removing it if it already exists
|
|
shutil.rmtree(str(dest), ignore_errors=True)
|
|
|
|
print(f"copying {src} to {picture_folder} ...")
|
|
copyFolder = AppleScript(
|
|
"""
|
|
on copyFolder(sourceFolder, destinationFolder)
|
|
-- sourceFolder and destinationFolder are strings of POSIX paths
|
|
set sourceFolder to POSIX file sourceFolder
|
|
set destinationFolder to POSIX file destinationFolder
|
|
tell application "Finder"
|
|
duplicate sourceFolder to destinationFolder
|
|
end tell
|
|
end copyFolder
|
|
"""
|
|
)
|
|
copyFolder.call("copyFolder", str(src), str(picture_folder))
|
|
|
|
# open Photos
|
|
if open:
|
|
# sometimes doesn't open the first time
|
|
time.sleep(delay)
|
|
photoslib.open(str(dest))
|
|
time.sleep(delay)
|
|
photoslib.open(str(dest))
|
|
|
|
return dest
|
|
|
|
|
|
@pytest.fixture
|
|
def addalbum_library():
|
|
copy_photos_library(TEST_LIBRARY, delay=10)
|
|
|
|
|
|
def copy_photos_library_to_path(photos_library_path: str, dest_path: str) -> str:
|
|
"""Copy a photos library to a folder"""
|
|
if is_macos:
|
|
ditto(photos_library_path, dest_path)
|
|
else:
|
|
shutil.copytree(photos_library_path, dest_path)
|
|
return dest_path
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def delete_crash_logs():
|
|
"""Delete left over crash logs from tests that were supposed to crash"""
|
|
yield
|
|
path = pathlib.Path(os.getcwd()) / "osxphotos_crash.log"
|
|
if path.is_file() and not NO_CLEANUP:
|
|
path.unlink()
|
|
|
|
|
|
@pytest.fixture
|
|
def photoslib():
|
|
return photoscript.PhotosLibrary()
|
|
|
|
|
|
@pytest.fixture
|
|
def suspend_capture(pytestconfig):
|
|
class suspend_guard:
|
|
def __init__(self):
|
|
self.capmanager = pytestconfig.pluginmanager.getplugin("capturemanager")
|
|
|
|
def __enter__(self):
|
|
self.capmanager.suspend_global_capture(in_=True)
|
|
|
|
def __exit__(self, _1, _2, _3):
|
|
self.capmanager.resume_global_capture()
|
|
|
|
yield suspend_guard()
|
|
|
|
|
|
@pytest.fixture
|
|
def output_file():
|
|
"""Create a temporary filename for writing output"""
|
|
tempdir = tempfile.gettempdir()
|
|
fd, filename = tempfile.mkstemp(dir=tempdir)
|
|
os.close(fd)
|
|
yield filename
|
|
os.remove(filename)
|