diff --git a/README.md b/README.md
index 552c16e8..72da963f 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,9 @@ OSXPhotos provides the ability to interact with and query Apple's Photos.app lib
## Supported operating systems
-Only works on MacOS (aka Mac OS X). Tested on MacOS 10.12.6 / Photos 2.0, 10.13.6 / Photos 3.0, MacOS 10.14.5, 10.14.6 / Photos 4.0, MacOS 10.15.1 - 10.15.6 / Photos 5.0.
+Only works on MacOS (aka Mac OS X). Tested on MacOS 10.12.6 / Photos 2.0, 10.13.6 / Photos 3.0, MacOS 10.14.5, 10.14.6 / Photos 4.0, MacOS 10.15.1 - 10.15.6 / Photos 5.0.
+
+Alpha support for MacOS 10.16/MacOS 11 Big Sur Beta / Photos 6.0.
Requires python >= 3.7.
diff --git a/osxphotos/_constants.py b/osxphotos/_constants.py
index 1c3a60f2..8b19b79b 100644
--- a/osxphotos/_constants.py
+++ b/osxphotos/_constants.py
@@ -10,18 +10,42 @@ import os.path
# Photos 4.0 (10.14.5) == 4016
# Photos 4.0 (10.14.6) == 4025
# Photos 5.0 (10.15.0) == 6000
-# TODO: Should this also use compatibleBackToVersion from LiGlobals?
_TESTED_DB_VERSIONS = ["6000", "4025", "4016", "3301", "2622"]
+# database model versions (applies to Photos 5, Photos 6)
+# these come from PLModelVersion key in binary plist in Z_METADATA.Z_PLIST
+# Photos 5 (10.15.1) == 13537
+# Photos 5 (10.15.4, 10.15.5, 10.15.6) == 13703
+# Photos 6 (10.16.0 Beta) == 14104
+_TEST_MODEL_VERSIONS = ["13537", "13703", "14104"]
+
# only version 3 - 4 have RKVersion.selfPortrait
_PHOTOS_3_VERSION = "3301"
# versions 5.0 and later have a different database structure
_PHOTOS_4_VERSION = "4025" # latest Mojove version on 10.14.6
-_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.15.5
+_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.15.6
+
+# Ranges for model version by Photos version
+_PHOTOS_5_MODEL_VERSION = [13000, 13999]
+_PHOTOS_6_MODEL_VERSION = [14000, 14999]
+
+# some table names differ between Photos 5 and Photos 6
+_DB_TABLE_NAMES = {
+ 5: {
+ "ASSET": "ZGENERICASSET",
+ "KEYWORD_JOIN": "Z_1KEYWORDS.Z_37KEYWORDS",
+ "ALBUM_JOIN": "Z_26ASSETS.Z_34ASSETS",
+ },
+ 6: {
+ "ASSET": "ZASSET",
+ "KEYWORD_JOIN": "Z_1KEYWORDS.Z_36KEYWORDS",
+ "ALBUM_JOIN": "Z_26ASSETS.Z_3ASSETS",
+ },
+}
# which major version operating systems have been tested
-_TESTED_OS_VERSIONS = ["12", "13", "14", "15"]
+_TESTED_OS_VERSIONS = ["12", "13", "14", "15", "16"]
# Photos 5 has persons who are empty string if unidentified face
_UNKNOWN_PERSON = "_UNKNOWN_"
diff --git a/osxphotos/_version.py b/osxphotos/_version.py
index ca5b4390..c6b18673 100644
--- a/osxphotos/_version.py
+++ b/osxphotos/_version.py
@@ -1,3 +1,3 @@
""" version info """
-__version__ = "0.31.2"
+__version__ = "0.32.0"
diff --git a/osxphotos/photosdb/__init__.py b/osxphotos/photosdb/__init__.py
index c06d208a..3147548d 100644
--- a/osxphotos/photosdb/__init__.py
+++ b/osxphotos/photosdb/__init__.py
@@ -4,3 +4,4 @@ Processes a Photos.app library database to extract information about photos
"""
from .photosdb import PhotosDB
+from .photosdb_utils import get_db_version, get_db_model_version, get_model_version
diff --git a/osxphotos/photosdb/_photosdb_process_exif.py b/osxphotos/photosdb/_photosdb_process_exif.py
index d76e2ac4..cd8eb53f 100644
--- a/osxphotos/photosdb/_photosdb_process_exif.py
+++ b/osxphotos/photosdb/_photosdb_process_exif.py
@@ -3,9 +3,9 @@
import logging
-from .._constants import _PHOTOS_4_VERSION
+from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
from ..utils import _db_is_locked, _debug, _open_sql_file
-
+from .photosdb_utils import get_db_version
def _process_exifinfo(self):
""" load the exif data from the database
@@ -35,14 +35,16 @@ def _process_exifinfo_5(photosdb):
db = photosdb._tmp_db
+ asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
+
(conn, cursor) = _open_sql_file(db)
result = conn.execute(
- """
- SELECT ZGENERICASSET.ZUUID, ZEXTENDEDATTRIBUTES.*
- FROM ZGENERICASSET
+ f"""
+ SELECT {asset_table}.ZUUID, ZEXTENDEDATTRIBUTES.*
+ FROM {asset_table}
JOIN ZEXTENDEDATTRIBUTES
- ON ZEXTENDEDATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
+ ON ZEXTENDEDATTRIBUTES.ZASSET = {asset_table}.Z_PK
"""
)
diff --git a/osxphotos/photosdb/_photosdb_process_faceinfo.py b/osxphotos/photosdb/_photosdb_process_faceinfo.py
index f35b4b30..53212ce5 100644
--- a/osxphotos/photosdb/_photosdb_process_faceinfo.py
+++ b/osxphotos/photosdb/_photosdb_process_faceinfo.py
@@ -3,8 +3,9 @@
import logging
-from .._constants import _PHOTOS_4_VERSION
+from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
from ..utils import _open_sql_file
+from .photosdb_utils import get_db_version
"""
@@ -180,13 +181,15 @@ def _process_faceinfo_5(photosdb):
db = photosdb._tmp_db
+ asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
+
(conn, cursor) = _open_sql_file(db)
result = cursor.execute(
- """
+ f"""
SELECT
ZDETECTEDFACE.Z_PK,
- ZGENERICASSET.ZUUID,
+ {asset_table}.ZUUID,
ZDETECTEDFACE.ZUUID,
ZDETECTEDFACE.ZPERSON,
ZPERSON.ZFULLNAME,
@@ -225,7 +228,7 @@ def _process_faceinfo_5(photosdb):
ZDETECTEDFACE.ZYAW,
ZDETECTEDFACE.ZMASTERIDENTIFIER
FROM ZDETECTEDFACE
- JOIN ZGENERICASSET ON ZGENERICASSET.Z_PK = ZDETECTEDFACE.ZASSET
+ JOIN {asset_table} ON {asset_table}.Z_PK = ZDETECTEDFACE.ZASSET
JOIN ZPERSON ON ZPERSON.Z_PK = ZDETECTEDFACE.ZPERSON;
"""
)
diff --git a/osxphotos/photosdb/_photosdb_process_scoreinfo.py b/osxphotos/photosdb/_photosdb_process_scoreinfo.py
index fe286240..c3060986 100644
--- a/osxphotos/photosdb/_photosdb_process_scoreinfo.py
+++ b/osxphotos/photosdb/_photosdb_process_scoreinfo.py
@@ -4,8 +4,9 @@
import logging
-from .._constants import _PHOTOS_4_VERSION
+from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION
from ..utils import _open_sql_file
+from .photosdb_utils import get_db_version
"""
This module should be imported in the class defintion of PhotosDB in photosdb.py
@@ -45,16 +46,18 @@ def _process_scoreinfo_5(photosdb):
db = photosdb._tmp_db
+ asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
+
(conn, cursor) = _open_sql_file(db)
result = cursor.execute(
- """
+ f"""
SELECT
- ZGENERICASSET.ZUUID,
- ZGENERICASSET.ZOVERALLAESTHETICSCORE,
- ZGENERICASSET.ZCURATIONSCORE,
- ZGENERICASSET.ZPROMOTIONSCORE,
- ZGENERICASSET.ZHIGHLIGHTVISIBILITYSCORE,
+ {asset_table}.ZUUID,
+ {asset_table}.ZOVERALLAESTHETICSCORE,
+ {asset_table}.ZCURATIONSCORE,
+ {asset_table}.ZPROMOTIONSCORE,
+ {asset_table}.ZHIGHLIGHTVISIBILITYSCORE,
ZCOMPUTEDASSETATTRIBUTES.ZBEHAVIORALSCORE,
ZCOMPUTEDASSETATTRIBUTES.ZFAILURESCORE,
ZCOMPUTEDASSETATTRIBUTES.ZHARMONIOUSCOLORSCORE,
@@ -78,8 +81,8 @@ def _process_scoreinfo_5(photosdb):
ZCOMPUTEDASSETATTRIBUTES.ZWELLCHOSENSUBJECTSCORE,
ZCOMPUTEDASSETATTRIBUTES.ZWELLFRAMEDSUBJECTSCORE,
ZCOMPUTEDASSETATTRIBUTES.ZWELLTIMEDSHOTSCORE
- FROM ZGENERICASSET
- JOIN ZCOMPUTEDASSETATTRIBUTES ON ZCOMPUTEDASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
+ FROM {asset_table}
+ JOIN ZCOMPUTEDASSETATTRIBUTES ON ZCOMPUTEDASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
"""
)
diff --git a/osxphotos/photosdb/photosdb.py b/osxphotos/photosdb/photosdb.py
index cb2cbe05..1d3a417d 100644
--- a/osxphotos/photosdb/photosdb.py
+++ b/osxphotos/photosdb/photosdb.py
@@ -16,6 +16,7 @@ from pprint import pformat
from shutil import copyfile
from .._constants import (
+ _DB_TABLE_NAMES,
_MOVIE_TYPE,
_PHOTO_TYPE,
_PHOTOS_3_VERSION,
@@ -45,6 +46,7 @@ from ..utils import (
_open_sql_file,
get_last_library_path,
)
+from .photosdb_utils import get_db_version, get_db_model_version
# TODO: Add test for imageTimeZoneOffsetSeconds = None
# TODO: Add test for __str__
@@ -267,7 +269,7 @@ class PhotosDB:
if _db_is_locked(self._dbfile):
self._tmp_db = self._copy_db_file(self._dbfile)
- self._db_version = self._get_db_version(self._tmp_db)
+ self._db_version = get_db_version(self._tmp_db)
# If Photos >= 5, actual data isn't in photos.db but in Photos.sqlite
if int(self._db_version) > int(_PHOTOS_4_VERSION):
@@ -530,34 +532,6 @@ class PhotosDB:
return dest_path
- def _get_db_version(self, db_file):
- """ Gets the Photos DB version from LiGlobals table
-
- Args:
- db_file: path to database file containing LiGlobals table
-
- Returns: version as str
- """
-
- version = None
-
- (conn, c) = _open_sql_file(db_file)
-
- # get database version
- c.execute(
- "SELECT value from LiGlobals where LiGlobals.keyPath is 'libraryVersion'"
- )
- version = c.fetchone()[0]
- conn.close()
-
- if version not in _TESTED_DB_VERSIONS:
- print(
- f"WARNING: Only tested on database versions [{', '.join(_TESTED_DB_VERSIONS)}]"
- + f" You have database version={version} which has not been tested"
- )
-
- return version
-
def _process_database4(self):
""" process the Photos database to extract info
works on Photos version <= 4.0 """
@@ -1436,7 +1410,7 @@ class PhotosDB:
def _process_database5(self):
""" process the Photos database to extract info
- works on Photos version >= 5.0
+ works on Photos version 5 and version 6
This is a big hairy 700 line function that should probably be refactored
but it works so don't touch it.
@@ -1448,6 +1422,12 @@ class PhotosDB:
# Epoch is Jan 1, 2001
td = (datetime(2001, 1, 1, 0, 0) - datetime(1970, 1, 1, 0, 0)).total_seconds()
+ photos_ver = get_db_model_version(self._tmp_db)
+ self._photos_ver = photos_ver
+ asset_table = _DB_TABLE_NAMES[photos_ver]["ASSET"]
+ keyword_join = _DB_TABLE_NAMES[photos_ver]["KEYWORD_JOIN"]
+ album_join = _DB_TABLE_NAMES[photos_ver]["ALBUM_JOIN"]
+
(conn, c) = _open_sql_file(self._tmp_db)
# Look for all combinations of persons and pictures
@@ -1496,14 +1476,14 @@ class PhotosDB:
# get info on keyface -- some photos have null keyface so can't do a single query
# (at least not with my SQL skills)
c.execute(
- """ SELECT
+ f""" SELECT
ZPERSON.Z_PK,
ZPERSON.ZKEYFACE,
- ZGENERICASSET.ZUUID,
+ {asset_table}.ZUUID,
ZDETECTEDFACE.ZUUID
- FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET
+ FROM ZPERSON, ZDETECTEDFACE, {asset_table}
WHERE ZDETECTEDFACE.Z_PK = ZPERSON.ZKEYFACE AND
- ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK
+ ZDETECTEDFACE.ZASSET = {asset_table}.Z_PK
"""
)
@@ -1522,12 +1502,12 @@ class PhotosDB:
# get information on detected faces
c.execute(
- """ SELECT
+ f""" SELECT
ZPERSON.Z_PK,
- ZGENERICASSET.ZUUID
- FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET
+ {asset_table}.ZUUID
+ FROM ZPERSON, ZDETECTEDFACE, {asset_table}
WHERE ZDETECTEDFACE.ZPERSON = ZPERSON.Z_PK AND
- ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK
+ ZDETECTEDFACE.ZASSET = {asset_table}.Z_PK
"""
)
@@ -1556,12 +1536,12 @@ class PhotosDB:
# get details about albums
c.execute(
- """ SELECT
+ f""" SELECT
ZGENERICALBUM.ZUUID,
- ZGENERICASSET.ZUUID,
- Z_26ASSETS.Z_FOK_34ASSETS
- FROM ZGENERICASSET
- JOIN Z_26ASSETS ON Z_26ASSETS.Z_34ASSETS = ZGENERICASSET.Z_PK
+ {asset_table}.ZUUID,
+ {album_join}
+ FROM {asset_table}
+ JOIN Z_26ASSETS ON {album_join} = {asset_table}.Z_PK
JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS
"""
)
@@ -1668,11 +1648,11 @@ class PhotosDB:
# get details on keywords
c.execute(
- "SELECT ZKEYWORD.ZTITLE, ZGENERICASSET.ZUUID "
- "FROM ZGENERICASSET "
- "JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
- "JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK "
- "JOIN ZKEYWORD ON ZKEYWORD.Z_PK = Z_1KEYWORDS.Z_37KEYWORDS "
+ f"""SELECT ZKEYWORD.ZTITLE, {asset_table}.ZUUID
+ FROM {asset_table}
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
+ JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK
+ JOIN ZKEYWORD ON ZKEYWORD.Z_PK = {keyword_join} """
)
for keyword in c:
if not keyword[1] in self._dbkeywords_uuid:
@@ -1699,45 +1679,45 @@ class PhotosDB:
# get details about photos
logging.debug(f"Getting information about photos")
c.execute(
- """SELECT ZGENERICASSET.ZUUID,
+ f"""SELECT {asset_table}.ZUUID,
ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT,
ZADDITIONALASSETATTRIBUTES.ZTITLE,
ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME,
- ZGENERICASSET.ZMODIFICATIONDATE,
- ZGENERICASSET.ZDATECREATED,
+ {asset_table}.ZMODIFICATIONDATE,
+ {asset_table}.ZDATECREATED,
ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET,
ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET,
ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME,
- ZGENERICASSET.ZHIDDEN,
- ZGENERICASSET.ZFAVORITE,
- ZGENERICASSET.ZDIRECTORY,
- ZGENERICASSET.ZFILENAME,
- ZGENERICASSET.ZLATITUDE,
- ZGENERICASSET.ZLONGITUDE,
- ZGENERICASSET.ZHASADJUSTMENTS,
- ZGENERICASSET.ZCLOUDBATCHPUBLISHDATE,
- ZGENERICASSET.ZKIND,
- ZGENERICASSET.ZUNIFORMTYPEIDENTIFIER,
- ZGENERICASSET.ZAVALANCHEUUID,
- ZGENERICASSET.ZAVALANCHEPICKTYPE,
- ZGENERICASSET.ZKINDSUBTYPE,
- ZGENERICASSET.ZCUSTOMRENDEREDVALUE,
+ {asset_table}.ZHIDDEN,
+ {asset_table}.ZFAVORITE,
+ {asset_table}.ZDIRECTORY,
+ {asset_table}.ZFILENAME,
+ {asset_table}.ZLATITUDE,
+ {asset_table}.ZLONGITUDE,
+ {asset_table}.ZHASADJUSTMENTS,
+ {asset_table}.ZCLOUDBATCHPUBLISHDATE,
+ {asset_table}.ZKIND,
+ {asset_table}.ZUNIFORMTYPEIDENTIFIER,
+ {asset_table}.ZAVALANCHEUUID,
+ {asset_table}.ZAVALANCHEPICKTYPE,
+ {asset_table}.ZKINDSUBTYPE,
+ {asset_table}.ZCUSTOMRENDEREDVALUE,
ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE,
- ZGENERICASSET.ZCLOUDASSETGUID,
+ {asset_table}.ZCLOUDASSETGUID,
ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA,
- ZGENERICASSET.ZMOMENT,
+ {asset_table}.ZMOMENT,
ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE,
- ZGENERICASSET.ZTRASHEDSTATE,
- ZGENERICASSET.ZHEIGHT,
- ZGENERICASSET.ZWIDTH,
- ZGENERICASSET.ZORIENTATION,
+ {asset_table}.ZTRASHEDSTATE,
+ {asset_table}.ZHEIGHT,
+ {asset_table}.ZWIDTH,
+ {asset_table}.ZORIENTATION,
ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT,
ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH,
ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION,
ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE
- FROM ZGENERICASSET
- JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
- ORDER BY ZGENERICASSET.ZUUID """
+ FROM {asset_table}
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
+ ORDER BY {asset_table}.ZUUID """
)
# Order of results
# 0 SELECT ZGENERICASSET.ZUUID,
@@ -1973,12 +1953,12 @@ class PhotosDB:
# Get extended description
c.execute(
- "SELECT ZGENERICASSET.ZUUID, "
- "ZASSETDESCRIPTION.ZLONGDESCRIPTION "
- "FROM ZGENERICASSET "
- "JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
- "JOIN ZASSETDESCRIPTION ON ZASSETDESCRIPTION.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSETDESCRIPTION "
- "ORDER BY ZGENERICASSET.ZUUID "
+ f"""SELECT {asset_table}.ZUUID,
+ ZASSETDESCRIPTION.ZLONGDESCRIPTION
+ FROM {asset_table}
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
+ JOIN ZASSETDESCRIPTION ON ZASSETDESCRIPTION.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSETDESCRIPTION
+ ORDER BY {asset_table}.ZUUID """
)
for row in c:
uuid = row[0]
@@ -1992,12 +1972,12 @@ class PhotosDB:
# get information about adjusted/edited photos
c.execute(
- "SELECT ZGENERICASSET.ZUUID, "
- "ZGENERICASSET.ZHASADJUSTMENTS, "
- "ZUNMANAGEDADJUSTMENT.ZADJUSTMENTFORMATIDENTIFIER "
- "FROM ZGENERICASSET, ZUNMANAGEDADJUSTMENT "
- "JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK "
- "WHERE ZADDITIONALASSETATTRIBUTES.ZUNMANAGEDADJUSTMENT = ZUNMANAGEDADJUSTMENT.Z_PK "
+ f"""SELECT {asset_table}.ZUUID,
+ {asset_table}.ZHASADJUSTMENTS,
+ ZUNMANAGEDADJUSTMENT.ZADJUSTMENTFORMATIDENTIFIER
+ FROM {asset_table}, ZUNMANAGEDADJUSTMENT
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
+ WHERE ZADDITIONALASSETATTRIBUTES.ZUNMANAGEDADJUSTMENT = ZUNMANAGEDADJUSTMENT.Z_PK """
)
for row in c:
uuid = row[0]
@@ -2016,12 +1996,12 @@ class PhotosDB:
# Get info on remote/local availability for photos in shared albums
c.execute(
- """ SELECT
- ZGENERICASSET.ZUUID,
+ f""" SELECT
+ {asset_table}.ZUUID,
ZINTERNALRESOURCE.ZLOCALAVAILABILITY,
ZINTERNALRESOURCE.ZREMOTEAVAILABILITY
- FROM ZGENERICASSET
- JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
+ FROM {asset_table}
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET
WHERE ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 """
)
@@ -2047,11 +2027,11 @@ class PhotosDB:
# get information on local/remote availability
c.execute(
- """ SELECT ZGENERICASSET.ZUUID,
+ f""" SELECT {asset_table}.ZUUID,
ZINTERNALRESOURCE.ZLOCALAVAILABILITY,
ZINTERNALRESOURCE.ZREMOTEAVAILABILITY
- FROM ZGENERICASSET
- JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
+ FROM {asset_table}
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZFINGERPRINT = ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT """
)
@@ -2075,11 +2055,11 @@ class PhotosDB:
# get information about cloud sync state
c.execute(
- """ SELECT
- ZGENERICASSET.ZUUID,
+ f""" SELECT
+ {asset_table}.ZUUID,
ZCLOUDMASTER.ZCLOUDLOCALSTATE
- FROM ZCLOUDMASTER, ZGENERICASSET
- WHERE ZGENERICASSET.ZMASTER = ZCLOUDMASTER.Z_PK """
+ FROM ZCLOUDMASTER, {asset_table}
+ WHERE {asset_table}.ZMASTER = ZCLOUDMASTER.Z_PK """
)
for row in c:
uuid = row[0]
@@ -2090,15 +2070,15 @@ class PhotosDB:
# get information about associted RAW images
# RAW images have ZDATASTORESUBTYPE = 17
c.execute(
- """ SELECT
- ZGENERICASSET.ZUUID,
+ f""" SELECT
+ {asset_table}.ZUUID,
ZINTERNALRESOURCE.ZDATALENGTH,
ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER,
ZINTERNALRESOURCE.ZDATASTORESUBTYPE,
ZINTERNALRESOURCE.ZRESOURCETYPE
- FROM ZGENERICASSET
+ FROM {asset_table}
JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET
- JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZGENERICASSET.Z_PK
+ JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK = ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER
WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17
"""
diff --git a/osxphotos/photosdb/photosdb_utils.py b/osxphotos/photosdb/photosdb_utils.py
new file mode 100644
index 00000000..da6c5309
--- /dev/null
+++ b/osxphotos/photosdb/photosdb_utils.py
@@ -0,0 +1,84 @@
+""" utility functions used by PhotosDB """
+
+import logging
+import plistlib
+
+from .._constants import (
+ _PHOTOS_5_MODEL_VERSION,
+ _PHOTOS_6_MODEL_VERSION,
+ _TESTED_DB_VERSIONS,
+)
+from ..utils import _open_sql_file
+
+
+def get_db_version(db_file):
+ """ Gets the Photos DB version from LiGlobals table
+
+ Args:
+ db_file: path to photos.db database file containing LiGlobals table
+
+ Returns: version as str
+ """
+
+ version = None
+
+ (conn, c) = _open_sql_file(db_file)
+
+ # get database version
+ c.execute("SELECT value from LiGlobals where LiGlobals.keyPath is 'libraryVersion'")
+ version = c.fetchone()[0]
+ conn.close()
+
+ if version not in _TESTED_DB_VERSIONS:
+ print(
+ f"WARNING: Only tested on database versions [{', '.join(_TESTED_DB_VERSIONS)}]"
+ + f" You have database version={version} which has not been tested"
+ )
+
+ return version
+
+
+def get_model_version(db_file):
+ """ Returns the database model version from Z_METADATA
+
+ Args:
+ db_file: path to Photos.sqlite database file containing Z_METADATA table
+
+ Returns: model version as str
+ """
+
+ version = None
+
+ (conn, c) = _open_sql_file(db_file)
+
+ # get database version
+ c.execute("SELECT MAX(Z_VERSION), Z_PLIST FROM Z_METADATA")
+ results = c.fetchone()
+
+ conn.close()
+
+ plist = plistlib.loads(results[1])
+ return plist["PLModelVersion"]
+
+
+def get_db_model_version(db_file):
+ """ Returns Photos version based on model version found in db_file
+
+ Args:
+ db_file: path to Photos.sqlite file
+
+ Returns: int of major Photos version number (e.g. 5 or 6).
+ If unknown model version found, logs warning and returns most current Photos version.
+ """
+
+ model_ver = get_model_version(db_file)
+ if _PHOTOS_5_MODEL_VERSION[0] <= model_ver <= _PHOTOS_5_MODEL_VERSION[1]:
+ db_ver = 5
+ elif _PHOTOS_6_MODEL_VERSION[0] <= model_ver <= _PHOTOS_6_MODEL_VERSION[1]:
+ db_ver = 6
+ else:
+ logging.warning(f"Unknown model version: {model_ver}")
+ # cross our fingers and try latest version
+ db_ver = 6
+
+ return db_ver
diff --git a/tests/Test-10.16.0.photoslibrary/database/DataModelVersion.plist b/tests/Test-10.16.0.photoslibrary/database/DataModelVersion.plist
new file mode 100644
index 00000000..be9740fe
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/database/DataModelVersion.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ LibrarySchemaVersion
+ 5001
+ MetaSchemaVersion
+ 3
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite
new file mode 100644
index 00000000..d4cc056d
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-shm b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-shm
new file mode 100644
index 00000000..74770d55
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-wal b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-wal
new file mode 100644
index 00000000..f8160ace
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite-wal differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite.lock b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite.lock
new file mode 100644
index 00000000..65649889
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/database/Photos.sqlite.lock
@@ -0,0 +1,16 @@
+
+
+
+
+ hostname
+ Rhets-MacBook-Pro.local
+ hostuuid
+ 9575E48B-8D5F-5654-ABAC-4431B1167324
+ pid
+ 434
+ processname
+ photolibraryd
+ uid
+ 501
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/database/metaSchema.db b/tests/Test-10.16.0.photoslibrary/database/metaSchema.db
new file mode 100644
index 00000000..2d75bd40
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/metaSchema.db differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/photos.db b/tests/Test-10.16.0.photoslibrary/database/photos.db
new file mode 100644
index 00000000..2d75bd40
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/photos.db differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/protection b/tests/Test-10.16.0.photoslibrary/database/protection
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/graphDataProgress.plist b/tests/Test-10.16.0.photoslibrary/database/search/graphDataProgress.plist
new file mode 100644
index 00000000..c4e5e427
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/search/graphDataProgress.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite b/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite
new file mode 100644
index 00000000..3f06de8f
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite-shm b/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite-wal b/tests/Test-10.16.0.photoslibrary/database/search/psi.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/searchMetadata.plist b/tests/Test-10.16.0.photoslibrary/database/search/searchMetadata.plist
new file mode 100644
index 00000000..3eec4180
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/database/search/searchMetadata.plist
@@ -0,0 +1,188 @@
+
+
+
+
+ BlacklistedMeaningsByMeaning
+
+ MePersonUUID
+ 39488755-78C0-40B2-B378-EDA280E1823C
+ SceneWhitelist
+
+ Graduation
+ Aquarium
+ Food
+ Ice Skating
+ Mountain
+ Cliff
+ Basketball
+ Tennis
+ Jewelry
+ Cheese
+ Softball
+ Football
+ Circus
+ Jet Ski
+ Playground
+ Carousel
+ Paint Ball
+ Windsurfing
+ Sailboat
+ Sunbathing
+ Dam
+ Fireplace
+ Flower
+ Scuba
+ Hiking
+ Cetacean
+ Pier
+ Bowling
+ Snowboarding
+ Zoo
+ Snowmobile
+ Theater
+ Boat
+ Casino
+ Car
+ Diving
+ Cycling
+ Musical Instrument
+ Board Game
+ Castle
+ Sunset Sunrise
+ Martial Arts
+ Motocross
+ Submarine
+ Cat
+ Snow
+ Kiteboarding
+ Squash
+ Geyser
+ Music
+ Archery
+ Desert
+ Blackjack
+ Fireworks
+ Sportscar
+ Feline
+ Soccer
+ Museum
+ Baby
+ Fencing
+ Railroad
+ Nascar
+ Sky Surfing
+ Bird
+ Games
+ Baseball
+ Dressage
+ Snorkeling
+ Pyramid
+ Kite
+ Rowboat
+ Golf
+ Watersports
+ Lightning
+ Canyon
+ Auditorium
+ Night Sky
+ Karaoke
+ Skiing
+ Parade
+ Forest
+ Hot Air Balloon
+ Dragon Parade
+ Easter Egg
+ Monument
+ Jungle
+ Thanksgiving
+ Jockey Horse
+ Stadium
+ Airplane
+ Ballet
+ Yoga
+ Coral Reef
+ Skating
+ Wrestling
+ Bicycle
+ Tattoo
+ Amusement Park
+ Canoe
+ Cheerleading
+ Ping Pong
+ Fishing
+ Magic
+ Reptile
+ Winter Sport
+ Waterfall
+ Train
+ Bonsai
+ Surfing
+ Dog
+ Cake
+ Sledding
+ Sandcastle
+ Glacier
+ Lighthouse
+ Equestrian
+ Rafting
+ Shore
+ Hockey
+ Santa Claus
+ Formula One Car
+ Sport
+ Vehicle
+ Boxing
+ Rollerskating
+ Underwater
+ Orchestra
+ Carnival
+ Rocket
+ Skateboarding
+ Helicopter
+ Performance
+ Oktoberfest
+ Water Polo
+ Skate Park
+ Animal
+ Nightclub
+ String Instrument
+ Dinosaur
+ Gymnastics
+ Cricket
+ Volcano
+ Lake
+ Aurora
+ Dancing
+ Concert
+ Rock Climbing
+ Hang Glider
+ Rodeo
+ Fish
+ Art
+ Motorcycle
+ Volleyball
+ Wake Boarding
+ Badminton
+ Motor Sport
+ Sumo
+ Parasailing
+ Skydiving
+ Kickboxing
+ Pinata
+ Foosball
+ Go Kart
+ Poker
+ Kayak
+ Swimming
+ Atv
+ Beach
+ Dartboard
+ Athletics
+ Camping
+ Tornado
+ Billiards
+ Rugby
+ Airshow
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/searchProgress.plist b/tests/Test-10.16.0.photoslibrary/database/search/searchProgress.plist
new file mode 100644
index 00000000..ad779080
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/database/search/searchProgress.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ insertAlbum
+
+ insertAsset
+
+ insertHighlight
+
+ insertMemory
+
+ insertMoment
+
+ removeAlbum
+
+ removeAsset
+
+ removeHighlight
+
+ removeMemory
+
+ removeMoment
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/searchSystemInfo.plist b/tests/Test-10.16.0.photoslibrary/database/search/searchSystemInfo.plist
new file mode 100644
index 00000000..f6d69ef7
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/database/search/searchSystemInfo.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ embeddingVersion
+ 1
+ localeIdentifier
+ en_US
+ sceneTaxonomySHA
+ 87914a047c69fbe8013fad2c70fa70c6c03b08b56190fe4054c880e6b9f57cc3
+ searchIndexVersion
+ 10
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/synonymsProcess.plist b/tests/Test-10.16.0.photoslibrary/database/search/synonymsProcess.plist
new file mode 100644
index 00000000..58e48cc1
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/search/synonymsProcess.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/database/search/zeroKeywords.data b/tests/Test-10.16.0.photoslibrary/database/search/zeroKeywords.data
new file mode 100644
index 00000000..5d03620c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/database/search/zeroKeywords.data differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/1/1EB2B765-0765-43BA-A90C-0D0580E6172C.jpeg b/tests/Test-10.16.0.photoslibrary/originals/1/1EB2B765-0765-43BA-A90C-0D0580E6172C.jpeg
new file mode 100644
index 00000000..136dfe8d
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/1/1EB2B765-0765-43BA-A90C-0D0580E6172C.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907.jpeg b/tests/Test-10.16.0.photoslibrary/originals/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907.jpeg
new file mode 100644
index 00000000..ca03f665
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96.jpeg b/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96.jpeg
new file mode 100755
index 00000000..143e9532
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4.cr2 b/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4.cr2
new file mode 100755
index 00000000..f2adc62f
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4.cr2 differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.jpeg b/tests/Test-10.16.0.photoslibrary/originals/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.jpeg
new file mode 100644
index 00000000..31eb2ab3
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/6/6FD38366-3BF2-407D-81FE-7153EB6125B6.jpeg b/tests/Test-10.16.0.photoslibrary/originals/6/6FD38366-3BF2-407D-81FE-7153EB6125B6.jpeg
new file mode 100644
index 00000000..88caa537
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/6/6FD38366-3BF2-407D-81FE-7153EB6125B6.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/7/71E3E212-00EB-430D-8A63-5E294B268554.jpeg b/tests/Test-10.16.0.photoslibrary/originals/7/71E3E212-00EB-430D-8A63-5E294B268554.jpeg
new file mode 100644
index 00000000..829a2345
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/7/71E3E212-00EB-430D-8A63-5E294B268554.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/8/8846E3E6-8AC8-4857-8448-E3D025784410.tiff b/tests/Test-10.16.0.photoslibrary/originals/8/8846E3E6-8AC8-4857-8448-E3D025784410.tiff
new file mode 100644
index 00000000..69654411
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/8/8846E3E6-8AC8-4857-8448-E3D025784410.tiff differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91.jpeg b/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91.jpeg
new file mode 100755
index 00000000..c1872812
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4.cr2 b/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4.cr2
new file mode 100755
index 00000000..6cd12fb4
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4.cr2 differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068.dng b/tests/Test-10.16.0.photoslibrary/originals/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068.dng
new file mode 100755
index 00000000..1f96242c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068.dng differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/D/D79B8D77-BFFC-460B-9312-034F2877D35B.jpeg b/tests/Test-10.16.0.photoslibrary/originals/D/D79B8D77-BFFC-460B-9312-034F2877D35B.jpeg
new file mode 100644
index 00000000..f23a024a
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/D/D79B8D77-BFFC-460B-9312-034F2877D35B.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/D/DC99FBDD-7A52-4100-A5BB-344131646C30.jpeg b/tests/Test-10.16.0.photoslibrary/originals/D/DC99FBDD-7A52-4100-A5BB-344131646C30.jpeg
new file mode 100644
index 00000000..e5a6b0bd
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/D/DC99FBDD-7A52-4100-A5BB-344131646C30.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.jpeg b/tests/Test-10.16.0.photoslibrary/originals/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.jpeg
new file mode 100644
index 00000000..ad8137e3
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/originals/F/F12384F6-CD17-4151-ACBA-AE0E3688539E.jpeg b/tests/Test-10.16.0.photoslibrary/originals/F/F12384F6-CD17-4151-ACBA-AE0E3688539E.jpeg
new file mode 100644
index 00000000..b1615930
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/originals/F/F12384F6-CD17-4151-ACBA-AE0E3688539E.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/.metadata_never_index b/tests/Test-10.16.0.photoslibrary/private/.metadata_never_index
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos.Migration/appPrivateData.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos.Migration/appPrivateData.plist
new file mode 100644
index 00000000..651ed0ad
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos.Migration/appPrivateData.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ MigrationService
+
+ State
+ 4
+
+ MigrationService.LastCompletedTask
+ 12
+ MigrationService.ValidationCounts
+
+ MigrationDetectedFaceprint
+ 6
+ MigrationManagedAsset
+ 0
+ MigrationSceneClassification
+ 44
+ MigrationUnmanagedAdjustment
+ 0
+ RDVersion.cloudLocalState.CPLIsNotPushed
+ 7
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos/appPrivateData.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos/appPrivateData.plist
new file mode 100644
index 00000000..40d5b4f7
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.Photos/appPrivateData.plist
@@ -0,0 +1,53 @@
+
+
+
+
+ CollapsedSidebarSectionIdentifiers
+
+ ExpandedSidebarItemIdentifiers
+
+ 92D68107-B6C7-453B-96D2-97B0F26D5B8B/L0/020
+ 88A5F8B8-5B9A-43C7-BB85-3952B81580EB/L0/020
+ 29EF7A97-7E76-4D5F-A5E0-CC0A93E8524C/L0/020
+ 2C2AF115-BD1D-4434-A747-D1C8BD8E2045/L0/020
+ CB051A4C-2CB7-4B90-B59B-08CC4D0C2823/L0/020
+
+ Photos
+
+ CollapsedSidebarSectionIdentifiers
+
+ ExpandedSidebarItemIdentifiers
+
+ TopLevelAlbums
+ TopLevelSlideshows
+
+ IPXWorkspaceControllerZoomLevelsKey
+
+ kZoomLevelIdentifierAlbums
+ 7
+ kZoomLevelIdentifierVersions
+ 7
+
+ lastAddToDestination
+
+ key
+ 1
+ lastKnownDisplayName
+ September 28, 2018
+ type
+ album
+ uuid
+ DFFKmHt3Tk+AGzZLe2Xq+g
+
+ lastKnownItemCounts
+
+ other
+ 0
+ photos
+ 7
+ videos
+ 0
+
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db b/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db
new file mode 100644
index 00000000..9f719ca2
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm
new file mode 100644
index 00000000..28af3ebf
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite
new file mode 100644
index 00000000..b2a22026
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm
new file mode 100644
index 00000000..5a588562
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite
new file mode 100644
index 00000000..fa6011dd
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite-shm
new file mode 100644
index 00000000..e1f50db6
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.Nature.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite
new file mode 100644
index 00000000..9512bfd3
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm
new file mode 100644
index 00000000..c6d19902
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite
new file mode 100644
index 00000000..b07c8c9a
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm
new file mode 100644
index 00000000..4ef6a565
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite
new file mode 100644
index 00000000..4ab71e6c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm
new file mode 100644
index 00000000..73656d14
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal
new file mode 100644
index 00000000..eab46f86
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite
new file mode 100644
index 00000000..4ad6beb0
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm
new file mode 100644
index 00000000..8470135e
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite
new file mode 100644
index 00000000..e934fdda
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite
new file mode 100644
index 00000000..35d2bb8e
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm
new file mode 100644
index 00000000..3299391e
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist
new file mode 100644
index 00000000..0ffe7e55
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSharingFeatureExtractorRecords.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSharingFeatureExtractorRecords.plist
new file mode 100644
index 00000000..0de953ba
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSharingFeatureExtractorRecords.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist
new file mode 100644
index 00000000..1ef03cbf
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ BackgroundHighlightCollection
+ 2020-06-24T04:02:13Z
+ BackgroundHighlightEnrichment
+ 2020-06-24T04:02:12Z
+ BackgroundJobAssetRevGeocode
+ 2020-06-24T04:02:13Z
+ BackgroundJobSearch
+ 2020-06-24T04:02:13Z
+ BackgroundPeopleSuggestion
+ 2020-06-24T04:02:12Z
+ BackgroundUserBehaviorProcessor
+ 2020-06-24T04:02:13Z
+ PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey
+ 2020-05-30T02:16:06Z
+ PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate
+ 2020-05-29T04:31:37Z
+ PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate
+ 2020-06-24T04:02:13Z
+ SiriPortraitDonation
+ 2020-06-24T04:02:13Z
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb
new file mode 100644
index 00000000..4ab71e6c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb
new file mode 100644
index 00000000..4ab71e6c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/liveupdate-photosgraph.kgdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb
new file mode 100644
index 00000000..4ab71e6c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb
new file mode 100644
index 00000000..9a0064df
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb-shm
new file mode 100644
index 00000000..9292bfe0
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist
new file mode 100644
index 00000000..8eb87588
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/ftemetrics b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/ftemetrics
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/revgeoprovider.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/revgeoprovider.plist
new file mode 100644
index 00000000..bf8f1e5d
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/graph/revgeoprovider.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ revgeoprovider
+ 7618
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/4E294112-DC9D-4B49-9561-1946B53A4E19.cmap b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/4E294112-DC9D-4B49-9561-1946B53A4E19.cmap
new file mode 100644
index 00000000..cca93d7c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/4E294112-DC9D-4B49-9561-1946B53A4E19.cmap differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/9A5E0437-04AA-45DC-AAA7-FDC74A91F170.cmap b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/9A5E0437-04AA-45DC-AAA7-FDC74A91F170.cmap
new file mode 100644
index 00000000..40018f76
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/9A5E0437-04AA-45DC-AAA7-FDC74A91F170.cmap differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/AlgoFaceClusterCache.data b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/AlgoFaceClusterCache.data
new file mode 100644
index 00000000..f16b4a76
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/AlgoFaceClusterCache.data differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PersonPromoter b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PersonPromoter
new file mode 100644
index 00000000..5feb64f2
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PersonPromoter
@@ -0,0 +1,14 @@
+
+
+
+
+ NumberOfFacesProcessedOnLastRun
+ 7
+ ProcessedInQuiescentState
+
+ SuggestedMeIdentifier
+
+ Version
+ 4
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist
new file mode 100644
index 00000000..bdd3d753
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ FaceIDModelLastGenerationKey
+ 2020-05-29T03:44:04Z
+ LastContactClassificationKey
+ 2020-05-29T04:31:40Z
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/clustererState.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/clustererState.plist
new file mode 100644
index 00000000..cb4560b6
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/clustererState.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ PVClustererBringUpState
+ 50
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/faceWorkerState.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/faceWorkerState.plist
new file mode 100644
index 00000000..c36206de
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/faceWorkerState.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ IncrementalPersonProcessingStage
+ 6
+ PersonBuilderLastMinimumFaceGroupSizeForCreatingMergeCandidates
+ 15
+ PersonBuilderMergeCandidatesEnabled
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin
new file mode 100644
index 00000000..211a83f7
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotoAnalysisServicePreferences.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotoAnalysisServicePreferences.plist
new file mode 100644
index 00000000..be5ca4c7
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotoAnalysisServicePreferences.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate
+ 2019-08-07T02:26:15Z
+ PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate
+ 2019-08-17T14:26:34Z
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb
new file mode 100644
index 00000000..96fee1ce
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/construction-photosgraph.graphdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb
new file mode 100644
index 00000000..4d8a5dfb
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/liveupdate-photosgraph.graphdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb
new file mode 100644
index 00000000..96fee1ce
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph-tmp.graphdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb
new file mode 100644
index 00000000..147ce400
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb-shm b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb-shm
new file mode 100644
index 00000000..fe9ac284
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb-shm differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb-wal b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/graph/PhotosGraph/photosgraph.graphdb-wal
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap
new file mode 100644
index 00000000..4aaf1638
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/AlgoFaceClusterCache.data b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/AlgoFaceClusterCache.data
new file mode 100644
index 00000000..1f14d535
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/AlgoFaceClusterCache.data differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap
new file mode 100644
index 00000000..1d6b6446
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap differ
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/PersonPromoter b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/PersonPromoter
new file mode 100644
index 00000000..4fdc85b4
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/PersonPromoter
@@ -0,0 +1,12 @@
+
+
+
+
+ ProcessedInQuiescentState
+
+ SuggestedMeIdentifier
+
+ Version
+ 3
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/clustererState.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/clustererState.plist
new file mode 100644
index 00000000..cb4560b6
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/clustererState.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ PVClustererBringUpState
+ 50
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/faceWorkerState.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/faceWorkerState.plist
new file mode 100644
index 00000000..736db69d
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photoanalysisd/vision/faceWorkerState.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ IncrementalPersonProcessingStage
+ 0
+ PersonBuilderLastMinimumFaceGroupSizeForCreatingMergeCandidates
+ 15
+ PersonBuilderMergeCandidatesEnabled
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photolibraryd/appPrivateData.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photolibraryd/appPrivateData.plist
new file mode 100644
index 00000000..2120d8ee
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photolibraryd/appPrivateData.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ PLLibraryServicesManager.LocaleIdentifier
+ en_US
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/private/com.apple.photomodel/appPrivateData.plist b/tests/Test-10.16.0.photoslibrary/private/com.apple.photomodel/appPrivateData.plist
new file mode 100644
index 00000000..106cedb0
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/private/com.apple.photomodel/appPrivateData.plist
@@ -0,0 +1,11 @@
+
+
+
+
+ LithiumMessageTracer
+
+ LastReportedDate
+ 2019-08-04T13:32:55Z
+
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/.metadata_never_index b/tests/Test-10.16.0.photoslibrary/resources/.metadata_never_index
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_1_105_c.jpeg
new file mode 100644
index 00000000..8a612cdc
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_1_105_c.jpeg
new file mode 100644
index 00000000..c19de1d4
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_100_o.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_100_o.jpeg
new file mode 100644
index 00000000..d5ece67d
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_100_o.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_105_c.jpeg
new file mode 100644
index 00000000..bb5e38af
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_105_c.jpeg
new file mode 100644
index 00000000..c36ba3a5
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_1_105_c.jpeg
new file mode 100644
index 00000000..4b8730c6
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/7/71E3E212-00EB-430D-8A63-5E294B268554_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/7/71E3E212-00EB-430D-8A63-5E294B268554_1_105_c.jpeg
new file mode 100644
index 00000000..ccbb2fd0
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/7/71E3E212-00EB-430D-8A63-5E294B268554_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8846E3E6-8AC8-4857-8448-E3D025784410_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8846E3E6-8AC8-4857-8448-E3D025784410_1_105_c.jpeg
new file mode 100644
index 00000000..539b4e59
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8846E3E6-8AC8-4857-8448-E3D025784410_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_1_105_c.jpeg
new file mode 100644
index 00000000..312b01d2
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_1_105_c.jpeg
new file mode 100644
index 00000000..f8943c5c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_1_105_c.jpeg
new file mode 100644
index 00000000..82af4102
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_100_o.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_100_o.jpeg
new file mode 100644
index 00000000..03d2c6ce
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_100_o.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_105_c.jpeg
new file mode 100644
index 00000000..82a19c3a
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D79B8D77-BFFC-460B-9312-034F2877D35B_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D79B8D77-BFFC-460B-9312-034F2877D35B_1_105_c.jpeg
new file mode 100644
index 00000000..4f0c1479
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/D79B8D77-BFFC-460B-9312-034F2877D35B_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_105_c.jpeg
new file mode 100644
index 00000000..5a00c324
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_105_c.jpeg
new file mode 100644
index 00000000..db88ba04
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_1_105_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_1_105_c.jpeg
new file mode 100644
index 00000000..6881aa31
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_1_105_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_4_5005_c.jpeg
new file mode 100644
index 00000000..839cdcbd
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/1/1EB2B765-0765-43BA-A90C-0D0580E6172C_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_4_5005_c.jpeg
new file mode 100644
index 00000000..e68f1ee6
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/3/3DD2C897-F19E-4CA6-8C22-B027D5A71907_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4_5005_c.jpeg
new file mode 100644
index 00000000..a4a8a5ed
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/4/4D521201-92AC-43E5-8F7C-59BC41C37A96_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_4_5005_c.jpeg
new file mode 100644
index 00000000..4e1d70f6
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_4_5005_c.jpeg
new file mode 100644
index 00000000..03d0ff79
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/6/6FD38366-3BF2-407D-81FE-7153EB6125B6_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/7/71E3E212-00EB-430D-8A63-5E294B268554_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/7/71E3E212-00EB-430D-8A63-5E294B268554_4_5005_c.jpeg
new file mode 100644
index 00000000..c48aa6ea
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/7/71E3E212-00EB-430D-8A63-5E294B268554_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8846E3E6-8AC8-4857-8448-E3D025784410_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8846E3E6-8AC8-4857-8448-E3D025784410_4_5005_c.jpeg
new file mode 100644
index 00000000..a2680855
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8846E3E6-8AC8-4857-8448-E3D025784410_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_4_5005_c.jpeg
new file mode 100644
index 00000000..c0d826ff
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/8/8E1D7BC9-9321-44F9-8CFB-4083F6B9232A_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_4_5005_c.jpeg
new file mode 100644
index 00000000..b3e0f930
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4_5005_c.jpeg
new file mode 100644
index 00000000..c41dcce5
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/A/A92D9C26-3A50-4197-9388-CB5F7DB9FA91_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_4_5005_c.jpeg
new file mode 100644
index 00000000..f4939048
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D79B8D77-BFFC-460B-9312-034F2877D35B_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D79B8D77-BFFC-460B-9312-034F2877D35B_4_5005_c.jpeg
new file mode 100644
index 00000000..3cdee08c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/D79B8D77-BFFC-460B-9312-034F2877D35B_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/DC99FBDD-7A52-4100-A5BB-344131646C30_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/DC99FBDD-7A52-4100-A5BB-344131646C30_4_5005_c.jpeg
new file mode 100644
index 00000000..6e9e2b12
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/D/DC99FBDD-7A52-4100-A5BB-344131646C30_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_4_5005_c.jpeg
new file mode 100644
index 00000000..f510f714
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_4_5005_c.jpeg b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_4_5005_c.jpeg
new file mode 100644
index 00000000..95c0ea85
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/masters/F/F12384F6-CD17-4151-ACBA-AE0E3688539E_4_5005_c.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/3305.ithmb b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/3305.ithmb
new file mode 100644
index 00000000..08e0011f
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/3305.ithmb differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4031.ithmb b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4031.ithmb
new file mode 100644
index 00000000..f3eaf950
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4031.ithmb differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4132.ithmb b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4132.ithmb
new file mode 100644
index 00000000..595ff63c
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/4132.ithmb differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/thumbnailConfiguration b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/thumbnailConfiguration
new file mode 100644
index 00000000..8c122be1
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/derivatives/thumbs/thumbnailConfiguration
@@ -0,0 +1,10 @@
+
+
+
+
+ PLThumbnailManagerThumbnailFormatKey
+ 5005
+ PLThumbnailManagerVersionKey
+ 28
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Album-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Album-change.plj
new file mode 100644
index 00000000..b20737cd
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Album-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Album-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Album-snapshot.plj
new file mode 100644
index 00000000..242008b2
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Album-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Album.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Album.plist
new file mode 100644
index 00000000..523b84b5
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Album.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2020-04-11T19:26:12Z
+ coalescePayloadVersion
+ 1
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-change.plj
new file mode 100644
index 00000000..2a28aff6
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-snapshot.plj
new file mode 100644
index 00000000..5d4b6fe5
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Asset.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset.plist
new file mode 100644
index 00000000..05ab2fca
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Asset.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2020-05-29T15:20:05Z
+ coalescePayloadVersion
+ 10
+ currentPayloadVersion
+ 25
+ snapshotDate
+ 2019-11-11T04:16:28Z
+ snapshotPayloadVersion
+ 10
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/DeferredRebuildFace-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/DeferredRebuildFace-snapshot.plj
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/DeferredRebuildFace.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/DeferredRebuildFace.plist
new file mode 100644
index 00000000..3a4b9140
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/DeferredRebuildFace.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:57Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-change.plj
new file mode 100644
index 00000000..c86a4796
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-snapshot.plj
new file mode 100644
index 00000000..1a00fa8d
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace.plist
new file mode 100644
index 00000000..a7b3527b
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/DetectedFace.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2019-10-27T15:36:05Z
+ coalescePayloadVersion
+ 1
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/FetchingAlbum-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/FetchingAlbum-snapshot.plj
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/FetchingAlbum.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/FetchingAlbum.plist
new file mode 100644
index 00000000..3ece9a2c
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/FetchingAlbum.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume-snapshot.plj
new file mode 100644
index 00000000..71155590
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume.plist
new file mode 100644
index 00000000..ac1db136
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/FileSystemVolume.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2020-05-29T15:20:05Z
+ coalescePayloadVersion
+ 1
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-change.plj
new file mode 100644
index 00000000..2a0e7fde
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-snapshot.plj
new file mode 100644
index 00000000..2e6a4601
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Folder.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder.plist
new file mode 100644
index 00000000..ac1db136
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Folder.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2020-05-29T15:20:05Z
+ coalescePayloadVersion
+ 1
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/HistoryToken.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/HistoryToken.plist
new file mode 100644
index 00000000..f0162126
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/HistoryToken.plist differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-change.plj
new file mode 100644
index 00000000..9f5e1c56
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-snapshot.plj
new file mode 100644
index 00000000..b70f6df4
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession.plist
new file mode 100644
index 00000000..ac1db136
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/ImportSession.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ coalesceDate
+ 2020-05-29T15:20:05Z
+ coalescePayloadVersion
+ 1
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-change.plj
new file mode 100644
index 00000000..bc1570ab
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-snapshot.plj
new file mode 100644
index 00000000..f512308e
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword.plist
new file mode 100644
index 00000000..3ece9a2c
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Keyword.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Memory-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Memory-snapshot.plj
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Memory.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Memory.plist
new file mode 100644
index 00000000..3ece9a2c
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Memory.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-change.plj
new file mode 100644
index 00000000..8d3b6eb4
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-snapshot.plj
new file mode 100644
index 00000000..d5eda50a
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory.plist
new file mode 100644
index 00000000..c5c87982
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/MigrationHistory.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2020-08-09T15:25:21Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Person-change.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Person-change.plj
new file mode 100644
index 00000000..bb5e8461
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Person-change.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Person-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/Person-snapshot.plj
new file mode 100644
index 00000000..8e7d5719
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/journals/Person-snapshot.plj differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/Person.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/Person.plist
new file mode 100644
index 00000000..3ece9a2c
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/Person.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/ProjectAlbum-snapshot.plj b/tests/Test-10.16.0.photoslibrary/resources/journals/ProjectAlbum-snapshot.plj
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/Test-10.16.0.photoslibrary/resources/journals/ProjectAlbum.plist b/tests/Test-10.16.0.photoslibrary/resources/journals/ProjectAlbum.plist
new file mode 100644
index 00000000..3ece9a2c
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/journals/ProjectAlbum.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ currentPayloadVersion
+ 1
+ snapshotDate
+ 2019-10-27T15:02:55Z
+ snapshotPayloadVersion
+ 1
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.plist b/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.plist
new file mode 100644
index 00000000..b69a9147
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ adjustmentBaseVersion
+ 0
+ adjustmentData
+
+ bZBNS8NAEIb/y5xDaGxTSa62Yi8VFFQQD5PspJmS3Q27k15C/ruTBBTB68zzfsyMcKMQ
+ 2buTazyUI1QDd+Y82IoClJAVj8UeEsC+f1u5eZhnaVakWb7RTaxbsvhCN163WQJ9h9L4
+ YBV9fv2AKQFLggYF5wCLUSi8s5EWyrvN7l4F3FPHjn4jVJfu1H2Fn4gvraj3dp8n4AOT
+ E5Q1Tt3nLJQfsTZAcx2iWMUilJ/jPwQ5rDoyUEoYSK8gEXaXOBekpqH6L7xMzmhJq20P
+ h4DqxvWD9918HRsN4oaXjx0XFqav6Rs=
+
+ adjustmentEditorBundleID
+ com.apple.Photos
+ adjustmentFormatIdentifier
+ com.apple.photo
+ adjustmentFormatVersion
+ 1.4
+ adjustmentTimestamp
+ 2020-05-29T03:39:38Z
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_201_a.jpeg b/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_201_a.jpeg
new file mode 100644
index 00000000..c2b53111
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/renders/6/6191423D-8DB8-4D4C-92BE-9BBBA308AAC4_1_201_a.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30.plist b/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30.plist
new file mode 100644
index 00000000..b298f6be
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30.plist
@@ -0,0 +1,20 @@
+
+
+
+
+ adjustmentBaseVersion
+ 0
+ adjustmentData
+
+ shkyAAAAAAACAAAA
+
+ adjustmentEditorBundleID
+ com.apple.Photos
+ adjustmentFormatIdentifier
+ com.apple.Photos.externalEdit
+ adjustmentFormatVersion
+ 1
+ adjustmentTimestamp
+ 2019-12-01T15:27:48Z
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_201_a.jpeg b/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_201_a.jpeg
new file mode 100644
index 00000000..7bcb36b9
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/renders/D/DC99FBDD-7A52-4100-A5BB-344131646C30_1_201_a.jpeg differ
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.plist b/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.plist
new file mode 100644
index 00000000..4117c731
--- /dev/null
+++ b/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.plist
@@ -0,0 +1,25 @@
+
+
+
+
+ adjustmentBaseVersion
+ 0
+ adjustmentData
+
+ bVFNT4RADP0vPSNh+FgWbsbE6MVNNFET42F2KVADAxnKqiH8dwvIukZP0+l77XtvZoAj
+ 2o4ac2vyBtIB9j1V2V1f79FCCmp7rQIfHNBt+7gQpRuEkXJjV/meIN2hxFrf45EWVDnQ
+ VprzxtZC3T08w+hAjawzzXpSqHXHaJ8o4xJS3wu3MkAtVmTwR0Lm3FC2L+QbpKJk2R1s
+ YgcaS2hY8yIn2yctzadhcaCzt77jWmgdpC/DPww0el9hBinbHiUFMpMpuslgeVLzI0HY
+ 6umO5tIUFUJ64TlwaMzcN/ydQ3rvS6Uif+PAx85SQWYGPtdanQ+umTwJQJk4pZzmN7+y
+ TTu9eM/zh6znHx/eb5VVPk5E5hRBJdGZgcQbx/F1/AI=
+
+ adjustmentEditorBundleID
+ com.apple.photos
+ adjustmentFormatIdentifier
+ com.apple.photo
+ adjustmentFormatVersion
+ 1.4
+ adjustmentRenderTypes
+ 0
+
+
diff --git a/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_201_a.jpeg b/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_201_a.jpeg
new file mode 100644
index 00000000..88caa537
Binary files /dev/null and b/tests/Test-10.16.0.photoslibrary/resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_201_a.jpeg differ
diff --git a/tests/test_bigsur_10_16_0.py b/tests/test_bigsur_10_16_0.py
new file mode 100644
index 00000000..11906c95
--- /dev/null
+++ b/tests/test_bigsur_10_16_0.py
@@ -0,0 +1,1069 @@
+import pytest
+
+from osxphotos._constants import _UNKNOWN_PERSON
+
+
+PHOTOS_DB = "tests/Test-10.16.0.photoslibrary/database/photos.db"
+PHOTOS_DB_PATH = "/Test-10.16.0.photoslibrary/database/photos.db"
+PHOTOS_LIBRARY_PATH = "/Test-10.16.0.photoslibrary"
+
+PHOTOS_DB_LEN = 15
+PHOTOS_NOT_IN_TRASH_LEN = 13
+PHOTOS_IN_TRASH_LEN = 2
+
+KEYWORDS = [
+ "Kids",
+ "wedding",
+ "flowers",
+ "England",
+ "London",
+ "London 2018",
+ "St. James's Park",
+ "UK",
+ "United Kingdom",
+]
+# Photos 5 includes blank person for detected face
+PERSONS = ["Katie", "Suzy", "Maria", _UNKNOWN_PERSON]
+ALBUMS = [
+ "Pumpkin Farm",
+ "Test Album", # there are 2 albums named "Test Album" for testing duplicate album names
+ "AlbumInFolder",
+ "Raw",
+ "I have a deleted twin", # there's an empty album with same name that has been deleted
+ "EmptyAlbum",
+]
+KEYWORDS_DICT = {
+ "Kids": 4,
+ "wedding": 3,
+ "flowers": 1,
+ "England": 1,
+ "London": 1,
+ "London 2018": 1,
+ "St. James's Park": 1,
+ "UK": 1,
+ "United Kingdom": 1,
+}
+PERSONS_DICT = {"Katie": 3, "Suzy": 2, "Maria": 2, _UNKNOWN_PERSON: 1}
+ALBUM_DICT = {
+ "Pumpkin Farm": 3,
+ "Test Album": 2,
+ "AlbumInFolder": 2,
+ "Raw": 4,
+ "I have a deleted twin": 1,
+ "EmptyAlbum": 0,
+} # Note: there are 2 albums named "Test Album" for testing duplicate album names
+
+UUID_DICT = {
+ "missing": "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
+ "favorite": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
+ "not_favorite": "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
+ "hidden": "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
+ "not_hidden": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
+ "has_adjustments": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
+ "no_adjustments": "D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068",
+ "location": "DC99FBDD-7A52-4100-A5BB-344131646C30",
+ "no_location": "6191423D-8DB8-4D4C-92BE-9BBBA308AAC4",
+ "external_edit": "DC99FBDD-7A52-4100-A5BB-344131646C30",
+ "no_external_edit": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
+ "export": "D79B8D77-BFFC-460B-9312-034F2877D35B", # "Pumkins2.jpg"
+ "export_tif": "8846E3E6-8AC8-4857-8448-E3D025784410",
+ "in_album": "D79B8D77-BFFC-460B-9312-034F2877D35B", # "Pumkins2.jpg"
+ "date_invalid": "8846E3E6-8AC8-4857-8448-E3D025784410",
+ "intrash": "71E3E212-00EB-430D-8A63-5E294B268554",
+ "not_intrash": "DC99FBDD-7A52-4100-A5BB-344131646C30",
+ "intrash_person_keywords": "6FD38366-3BF2-407D-81FE-7153EB6125B6",
+}
+
+UUID_PUMPKIN_FARM = [
+ "F12384F6-CD17-4151-ACBA-AE0E3688539E",
+ "D79B8D77-BFFC-460B-9312-034F2877D35B",
+ "1EB2B765-0765-43BA-A90C-0D0580E6172C",
+]
+
+ALBUM_SORT_ORDER = [
+ "1EB2B765-0765-43BA-A90C-0D0580E6172C",
+ "F12384F6-CD17-4151-ACBA-AE0E3688539E",
+ "D79B8D77-BFFC-460B-9312-034F2877D35B",
+]
+ALBUM_KEY_PHOTO = "D79B8D77-BFFC-460B-9312-034F2877D35B"
+
+
+def test_init1():
+ # test named argument
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ assert isinstance(photosdb, osxphotos.PhotosDB)
+
+
+def test_init2():
+ # test positional argument
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(PHOTOS_DB)
+ assert isinstance(photosdb, osxphotos.PhotosDB)
+
+
+def test_init3():
+ # test positional and named argument (raises exception)
+ import osxphotos
+
+ with pytest.raises(Exception):
+ assert osxphotos.PhotosDB(PHOTOS_DB, dbfile=PHOTOS_DB)
+
+
+def test_init4():
+ # test invalid db
+ import os
+ import tempfile
+ import osxphotos
+
+ (bad_db, bad_db_name) = tempfile.mkstemp(suffix=".db", prefix="osxphotos-")
+ os.close(bad_db)
+
+ with pytest.raises(Exception):
+ assert osxphotos.PhotosDB(bad_db_name)
+
+ with pytest.raises(Exception):
+ assert osxphotos.PhotosDB(dbfile=bad_db_name)
+
+ try:
+ os.remove(bad_db_name)
+ except:
+ pass
+
+
+def test_init5(mocker):
+ # test failed get_last_library_path
+ import osxphotos
+
+ def bad_library():
+ return None
+
+ # get_last_library actually in utils but need to patch it in photosdb because it's imported into photosdb
+ # because of the layout of photosdb/ need to patch it this way...don't really understand why, but it works
+ mocker.patch("osxphotos.photosdb.photosdb.get_last_library_path", new=bad_library)
+
+ with pytest.raises(Exception):
+ assert osxphotos.PhotosDB()
+
+
+def test_db_len():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ # assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS
+ assert len(photosdb) == PHOTOS_DB_LEN
+
+
+def test_db_version():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ # assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS
+ assert photosdb.db_version == "6000"
+
+
+def test_persons():
+ import osxphotos
+ import collections
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ assert "Katie" in photosdb.persons
+ assert collections.Counter(PERSONS) == collections.Counter(photosdb.persons)
+
+
+def test_keywords():
+ import osxphotos
+ import collections
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ assert "wedding" in photosdb.keywords
+ assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
+
+
+def test_album_names():
+ import osxphotos
+ import collections
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ assert "Pumpkin Farm" in photosdb.albums
+ assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
+
+
+def test_keywords_dict():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ keywords = photosdb.keywords_as_dict
+ assert keywords["wedding"] == 3
+ assert keywords == KEYWORDS_DICT
+
+
+def test_persons_as_dict():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ persons = photosdb.persons_as_dict
+ assert persons["Maria"] == 2
+ assert persons == PERSONS_DICT
+
+
+def test_albums_as_dict():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ albums = photosdb.albums_as_dict
+ assert albums["Pumpkin Farm"] == 3
+ assert albums == ALBUM_DICT
+
+
+def test_album_sort_order():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ album = [a for a in photosdb.album_info if a.title == "Pumpkin Farm"][0]
+ photos = album.photos
+
+ uuids = [p.uuid for p in photos]
+ assert uuids == ALBUM_SORT_ORDER
+
+
+def test_album_empty_album():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ album = [a for a in photosdb.album_info if a.title == "EmptyAlbum"][0]
+ photos = album.photos
+ assert photos == []
+
+
+def test_attributes():
+ import datetime
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=["D79B8D77-BFFC-460B-9312-034F2877D35B"])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.keywords == ["Kids"]
+ assert p.original_filename == "Pumkins2.jpg"
+ assert p.filename == "D79B8D77-BFFC-460B-9312-034F2877D35B.jpeg"
+ assert p.date == datetime.datetime(
+ 2018, 9, 28, 16, 7, 7, 0, datetime.timezone(datetime.timedelta(seconds=-14400))
+ )
+ assert p.description == "Girl holding pumpkin"
+ assert p.title == "I found one!"
+ assert sorted(p.albums) == ["Pumpkin Farm", "Test Album"]
+ assert p.persons == ["Katie"]
+ assert p.path.endswith(
+ "tests/Test-10.16.0.photoslibrary/originals/D/D79B8D77-BFFC-460B-9312-034F2877D35B.jpeg"
+ )
+ assert p.ismissing == False
+
+
+def test_attributes_2():
+ """ Test attributes including height, width, etc """
+ import datetime
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.keywords == ["wedding"]
+ assert p.original_filename == "wedding.jpg"
+ assert p.filename == "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.jpeg"
+ assert p.date == datetime.datetime(
+ 2019,
+ 4,
+ 15,
+ 14,
+ 40,
+ 24,
+ 86000,
+ datetime.timezone(datetime.timedelta(seconds=-14400)),
+ )
+ assert p.description == "Bride Wedding day"
+ assert p.title is None
+ assert sorted(p.albums) == ["AlbumInFolder", "I have a deleted twin"]
+ assert p.persons == ["Maria"]
+ assert p.path.endswith(
+ "tests/Test-10.16.0.photoslibrary/originals/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51.jpeg"
+ )
+ assert not p.ismissing
+ assert p.hasadjustments
+ assert p.height == 1325
+ assert p.width == 1526
+ assert p.original_height == 1367
+ assert p.original_width == 2048
+ assert p.orientation == 1
+ assert p.original_orientation == 1
+ assert p.original_filesize == 460483
+
+
+def test_missing():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["missing"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.path is None
+ assert p.ismissing == True
+
+
+def test_favorite():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["favorite"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.favorite == True
+
+
+def test_not_favorite():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["not_favorite"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.favorite == False
+
+
+def test_hidden():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["hidden"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.hidden == True
+
+
+def test_not_hidden():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["not_hidden"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.hidden == False
+
+
+def test_location_1():
+ # test photo with lat/lon info
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["location"]])
+ assert len(photos) == 1
+ p = photos[0]
+ lat, lon = p.location
+ assert lat == pytest.approx(51.50357167)
+ assert lon == pytest.approx(-0.1318055)
+
+
+def test_location_2():
+ # test photo with no location info
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["no_location"]])
+ assert len(photos) == 1
+ p = photos[0]
+ lat, lon = p.location
+ assert lat is None
+ assert lon is None
+
+
+def test_hasadjustments1():
+ # test hasadjustments == True
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.hasadjustments == True
+
+
+def test_hasadjustments2():
+ # test hasadjustments == False
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.hasadjustments == False
+
+
+def test_external_edit1():
+ # test image has been edited in external editor
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["external_edit"]])
+ assert len(photos) == 1
+ p = photos[0]
+
+ assert p.external_edit == True
+
+
+def test_external_edit2():
+ # test image has not been edited in external editor
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["no_external_edit"]])
+ assert len(photos) == 1
+ p = photos[0]
+
+ assert p.external_edit == False
+
+
+def test_path_edited1():
+ # test a valid edited path
+ import os.path
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=["E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51"])
+ assert len(photos) == 1
+ p = photos[0]
+ path = p.path_edited
+ assert path.endswith(
+ "resources/renders/E/E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51_1_201_a.jpeg"
+ )
+ assert os.path.exists(path)
+
+
+def test_path_edited2():
+ # test an invalid edited path
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
+ assert len(photos) == 1
+ p = photos[0]
+ path = p.path_edited
+ assert path is None
+
+
+def test_count():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos()
+ assert len(photos) == PHOTOS_NOT_IN_TRASH_LEN
+
+
+def test_photos_intrash_1():
+ """ test PhotosDB.photos(intrash=True) """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(intrash=True)
+ assert len(photos) == PHOTOS_IN_TRASH_LEN
+
+
+def test_photos_intrash_2():
+ """ test PhotosDB.photos(intrash=True) """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(intrash=True)
+ for p in photos:
+ assert p.intrash
+
+
+def test_photos_intrash_3():
+ """ test PhotosDB.photos(intrash=False) """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(intrash=False)
+ for p in photos:
+ assert not p.intrash
+
+
+def test_photoinfo_intrash_1():
+ """ Test PhotoInfo.intrash """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(uuid=[UUID_DICT["intrash"]], intrash=True)[0]
+ assert p.intrash
+
+
+def test_photoinfo_intrash_2():
+ """ Test PhotoInfo.intrash and intrash=default"""
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(uuid=[UUID_DICT["intrash"]])
+ assert not p
+
+
+def test_photoinfo_intrash_3():
+ """ Test PhotoInfo.intrash and photo has keyword and person """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(uuid=[UUID_DICT["intrash_person_keywords"]], intrash=True)[0]
+ assert p.intrash
+ assert "Maria" in p.persons
+ assert "wedding" in p.keywords
+
+
+def test_photoinfo_intrash_4():
+ """ Test PhotoInfo.intrash and photo has keyword and person """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(persons=["Maria"], intrash=True)[0]
+ assert p.intrash
+ assert "Maria" in p.persons
+ assert "wedding" in p.keywords
+
+
+def test_photoinfo_intrash_5():
+ """ Test PhotoInfo.intrash and photo has keyword and person """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(keywords=["wedding"], intrash=True)[0]
+ assert p.intrash
+ assert "Maria" in p.persons
+ assert "wedding" in p.keywords
+
+
+def test_photoinfo_not_intrash():
+ """ Test PhotoInfo.intrash """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ p = photosdb.photos(uuid=[UUID_DICT["not_intrash"]])[0]
+ assert not p.intrash
+
+
+def test_keyword_2():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(keywords=["wedding"])
+ assert len(photos) == 2 # won't show the one in the trash
+
+
+def test_keyword_not_in_album():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+
+ # find all photos with keyword "Kids" not in the album "Pumpkin Farm"
+ photos1 = photosdb.photos(albums=["Pumpkin Farm"])
+ photos2 = photosdb.photos(keywords=["Kids"])
+ photos3 = [p for p in photos2 if p not in photos1]
+ assert len(photos3) == 1
+ assert photos3[0].uuid == "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C"
+
+
+def test_album_folder_name():
+ """Test query with album name same as a folder name """
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+
+ photos = photosdb.photos(albums=["Pumpkin Farm"])
+ assert sorted(p.uuid for p in photos) == sorted(UUID_PUMPKIN_FARM)
+
+
+def test_multi_person():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(PHOTOS_DB)
+ photos = photosdb.photos(persons=["Katie", "Suzy"])
+
+ assert len(photos) == 3
+
+
+def test_get_db_path():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ db_path = photosdb.db_path
+ assert db_path.endswith(PHOTOS_DB_PATH)
+
+
+def test_get_library_path():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ lib_path = photosdb.library_path
+ assert lib_path.endswith(PHOTOS_LIBRARY_PATH)
+
+
+def test_get_db_connection():
+ """ Test PhotosDB.get_db_connection """
+ import osxphotos
+ import sqlite3
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ conn, cursor = photosdb.get_db_connection()
+
+ assert isinstance(conn, sqlite3.Connection)
+ assert isinstance(cursor, sqlite3.Cursor)
+
+ results = conn.execute(
+ "SELECT ZUUID FROM ZASSET WHERE ZFAVORITE = 1;"
+ ).fetchall()
+ assert len(results) == 1
+ assert results[0][0] == "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51" # uuid
+
+ conn.close()
+
+
+def test_export_1():
+ # test basic export
+ # get an unedited image and export it using default filename
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ filename = photos[0].filename
+ expected_dest = os.path.join(dest, filename)
+ got_dest = photos[0].export(dest)[0]
+
+ assert got_dest == expected_dest
+ assert os.path.isfile(got_dest)
+
+
+def test_export_2():
+ # test export with user provided filename
+ import os
+ import os.path
+ import tempfile
+ import time
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-2-test-{timestamp}.jpg"
+ expected_dest = os.path.join(dest, filename)
+ got_dest = photos[0].export(dest, filename)[0]
+
+ assert got_dest == expected_dest
+ assert os.path.isfile(got_dest)
+
+
+def test_export_3():
+ # test file already exists and test increment=True (default)
+ import os
+ import os.path
+ import pathlib
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ filename = photos[0].filename
+ filename2 = pathlib.Path(filename)
+ filename2 = f"{filename2.stem} (1){filename2.suffix}"
+ expected_dest_2 = os.path.join(dest, filename2)
+
+ got_dest = photos[0].export(dest)[0]
+ got_dest_2 = photos[0].export(dest)[0]
+
+ assert got_dest_2 == expected_dest_2
+ assert os.path.isfile(got_dest_2)
+
+
+def test_export_4():
+ # test user supplied file already exists and test increment=True (default)
+ import os
+ import os.path
+ import pathlib
+ import tempfile
+ import time
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-2-test-{timestamp}.jpg"
+ filename2 = f"osxphotos-export-2-test-{timestamp} (1).jpg"
+ expected_dest_2 = os.path.join(dest, filename2)
+
+ got_dest = photos[0].export(dest, filename)[0]
+ got_dest_2 = photos[0].export(dest, filename)[0]
+
+ assert got_dest_2 == expected_dest_2
+ assert os.path.isfile(got_dest_2)
+
+
+def test_export_5():
+ # test file already exists and test increment=True (default)
+ # and overwrite = True
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ filename = photos[0].filename
+ expected_dest = os.path.join(dest, filename)
+
+ got_dest = photos[0].export(dest)[0]
+ got_dest_2 = photos[0].export(dest, overwrite=True)[0]
+
+ assert got_dest_2 == got_dest
+ assert got_dest_2 == expected_dest
+ assert os.path.isfile(got_dest_2)
+
+
+def test_export_6():
+ # test user supplied file already exists and test increment=True (default)
+ # and overwrite = True
+ import os
+ import os.path
+ import pathlib
+ import tempfile
+ import time
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-test-{timestamp}.jpg"
+ expected_dest = os.path.join(dest, filename)
+
+ got_dest = photos[0].export(dest, filename)[0]
+ got_dest_2 = photos[0].export(dest, filename, overwrite=True)[0]
+
+ assert got_dest_2 == got_dest
+ assert got_dest_2 == expected_dest
+ assert os.path.isfile(got_dest_2)
+
+
+def test_export_7():
+ # test file already exists and test increment=False (not default), overwrite=False (default)
+ # should raise exception
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ filename = photos[0].filename
+
+ got_dest = photos[0].export(dest)[0]
+ with pytest.raises(Exception) as e:
+ # try to export again with increment = False
+ assert photos[0].export(dest, increment=False)
+ assert e.type == type(FileExistsError())
+
+
+def test_export_8():
+ # try to export missing file
+ # should raise exception
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["missing"]])
+
+ filename = photos[0].filename
+
+ with pytest.raises(Exception) as e:
+ assert photos[0].export(dest)[0]
+ assert e.type == type(FileNotFoundError())
+
+
+def test_export_9():
+ # try to export edited file that's not edited
+ # should raise exception
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
+
+ filename = photos[0].filename
+
+ with pytest.raises(Exception) as e:
+ assert photos[0].export(dest, edited=True)
+ assert e.type == ValueError
+
+
+def test_export_10():
+ # try to export edited file that's not edited and name provided
+ # should raise exception
+ import os
+ import os.path
+ import tempfile
+ import time
+
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-test-{timestamp}.jpg"
+
+ with pytest.raises(Exception) as e:
+ assert photos[0].export(dest, filename, edited=True)
+ assert e.type == ValueError
+
+
+def test_export_11():
+ # export edited file with name provided
+ import os
+ import os.path
+ import tempfile
+ import time
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-test-{timestamp}.jpg"
+ expected_dest = os.path.join(dest, filename)
+
+ got_dest = photos[0].export(dest, filename, edited=True)[0]
+ assert got_dest == expected_dest
+
+
+def test_export_12():
+ # export edited file with default name
+ import os
+ import os.path
+ import pathlib
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
+
+ edited_name = pathlib.Path(photos[0].path_edited).name
+ edited_suffix = pathlib.Path(edited_name).suffix
+ filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix
+ expected_dest = os.path.join(dest, filename)
+
+ got_dest = photos[0].export(dest, edited=True)[0]
+ assert got_dest == expected_dest
+
+
+def test_export_13():
+ # export to invalid destination
+ # should raise exception
+ import os
+ import os.path
+ import tempfile
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+
+ # create a folder that doesn't exist
+ i = 0
+ while os.path.isdir(dest):
+ dest = os.path.join(dest, str(i))
+ i += 1
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export"]])
+
+ filename = photos[0].filename
+
+ with pytest.raises(Exception) as e:
+ assert photos[0].export(dest)
+ assert e.type == type(FileNotFoundError())
+
+
+def test_export_14(caplog):
+ # test export with user provided filename with different (but valid) extension than source
+ import os
+ import os.path
+ import tempfile
+ import time
+
+ import osxphotos
+
+ tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
+ dest = tempdir.name
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["export_tif"]])
+
+ timestamp = time.time()
+ filename = f"osxphotos-export-2-test-{timestamp}.tif"
+ expected_dest = os.path.join(dest, filename)
+ got_dest = photos[0].export(dest, filename)[0]
+
+ assert got_dest == expected_dest
+ assert os.path.isfile(got_dest)
+
+ assert "Invalid destination suffix" not in caplog.text
+
+
+def test_eq():
+ """ Test equality of two PhotoInfo objects """
+ import osxphotos
+
+ photosdb1 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos1 = photosdb1.photos(uuid=[UUID_DICT["export"]])
+ photos2 = photosdb2.photos(uuid=[UUID_DICT["export"]])
+ assert photos1[0] == photos2[0]
+
+
+def test_eq_2():
+ """ Test equality of two PhotoInfo objects when one has memoized property """
+ import osxphotos
+
+ photosdb1 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos1 = photosdb1.photos(uuid=[UUID_DICT["in_album"]])
+ photos2 = photosdb2.photos(uuid=[UUID_DICT["in_album"]])
+
+ # memoize a value
+ albums = photos1[0].albums
+ assert albums
+
+ assert photos1[0] == photos2[0]
+
+
+def test_not_eq():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos1 = photosdb.photos(uuid=[UUID_DICT["export"]])
+ photos2 = photosdb.photos(uuid=[UUID_DICT["missing"]])
+ assert photos1[0] != photos2[0]
+
+
+def test_photosdb_repr():
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photosdb2 = eval(repr(photosdb))
+
+ ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name"]
+ assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
+ k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
+ }
+
+
+def test_photosinfo_repr():
+ import osxphotos
+ import datetime
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["favorite"]])
+ photo = photos[0]
+ photo2 = eval(repr(photo))
+
+ assert {k: str(v).encode("utf-8") for k, v in photo.__dict__.items()} == {
+ k: str(v).encode("utf-8") for k, v in photo2.__dict__.items()
+ }
+
+
+def test_from_to_date():
+ import osxphotos
+ import datetime as dt
+
+ photosdb = osxphotos.PhotosDB(PHOTOS_DB)
+
+ photos = photosdb.photos(from_date=dt.datetime(2018, 10, 28))
+ assert len(photos) == 6
+
+ photos = photosdb.photos(to_date=dt.datetime(2018, 10, 28))
+ assert len(photos) == 7
+
+ photos = photosdb.photos(
+ from_date=dt.datetime(2018, 9, 28), to_date=dt.datetime(2018, 9, 29)
+ )
+ assert len(photos) == 4
+
+
+def test_date_invalid():
+ """ Test date is invalid """
+ from datetime import datetime, timedelta, timezone
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
+ assert len(photos) == 1
+ p = photos[0]
+ delta = timedelta(seconds=p.tzoffset)
+ tz = timezone(delta)
+ assert p.date == datetime(1970, 1, 1).astimezone(tz=tz)
+
+
+def test_date_modified_invalid():
+ """ Test date modified is invalid """
+ from datetime import datetime, timedelta, timezone
+ import osxphotos
+
+ photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
+ photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
+ assert len(photos) == 1
+ p = photos[0]
+ assert p.date_modified is None