123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- #
- # Copyright (c) Contributors to the Open 3D Engine Project.
- # For complete copyright and license terms please see the LICENSE at the root of this distribution.
- #
- # SPDX-License-Identifier: Apache-2.0 OR MIT
- #
- #
- import unittest
- from unittest.mock import patch
- from snapshot_folder.snapshot_folder import FolderSnapshot
- class empty_object():
- pass
- def fakestat(file_path):
- f = empty_object()
- f.st_mtime = 12345
- return f
- @patch('os.stat', side_effect=fakestat)
- @patch('os.walk')
- def test_CreateSnapshot_sanity(mock_os_walk, mock_os_stat):
- mock_os_walk.return_value = [
- # this mocks os.walk, which always returns a tuple of (root name, folder names, file names)
- ( '', # root name
- ['subfolder1', 'subfolder2', 'subfolder3'], # folders in here
- ['file1.cpp'], # files in here
- ),
- ( 'subfolder1',
- [],
- ['file1.cpp', 'file2.cpp'], # file1 is same name as above, but different folder name!
- ),
- ( 'subfolder2',
- [''],
- [], # empty folders still get tracked
- ),
- ( 'subfolder3',
- ['subfolder4'], # folders only containing folders
- [],
- ),
- ( 'subfolder3/subfolder4',
- [],
- ['file4.cpp'],
- )
- ]
- snap = FolderSnapshot.CreateSnapshot('.', ignore_patterns=[])
-
- assert 'subfolder1' in snap.folder_paths
- assert 'subfolder2' in snap.folder_paths
- assert 'subfolder3' in snap.folder_paths
- assert 'subfolder3/subfolder4' in snap.folder_paths
- assert 'file1.cpp' in snap.file_modtimes
- assert 'subfolder1/file1.cpp' in snap.file_modtimes
- assert 'subfolder1/file2.cpp' in snap.file_modtimes
- assert 'subfolder3/subfolder4/file4.cpp' in snap.file_modtimes
-
- @patch('os.stat', side_effect=fakestat)
- @patch('os.walk')
- def test_CreateSnapshot_obeys_exclusions(mock_os_walk, mock_os_stat):
- mock_os_walk.return_value = [
- ( '.',
- ['sub_buildfolder', 'build', 'build_mac', 'normal_subfolder'], # sneaky trap, sub_buildfolder should not be ignored
- ['file.tif', 'file_not_a_tif.bmp'],
- ),
- ( 'sub_buildfolder', # should not be ignored, its not a match to build_*
- [],
- ['file2.cpp', 'file2.tif'],
- ),
- ( 'build_mac',
- ['normalfolder'], # does not have build in its name but should still be ignored because parent is
- ['file3.cpp'], # even though it doesnt match a rule itself, it should be omitted since its in build
- ),
- ( 'build_mac/normalfolder',
- [],
- ['file4.cpp'], # even though it doesnt match a rule itself, it should be omitted since its in build
- ),
- ( 'build',
- [],
- ['file4.cpp'], # even though it doesnt match a rule itself, it should be omitted since its in build
- ),
- ( 'normal_subfolder',
- ['build'], # a matching folder in a subfolder
- [],
- ),
- ( 'normal_subfolder/build',
- ['file.txt'], # a matching folder in a subfolder
- [],
- )
- ]
- snap = FolderSnapshot.CreateSnapshot('.', ignore_patterns=['*.tif', 'build', 'build_*'])
-
- assert 'sub_buildfolder' in snap.folder_paths
- assert 'file_not_a_tif.bmp' in snap.file_modtimes
- assert 'sub_buildfolder/file2.cpp' in snap.file_modtimes
- assert 'normal_subfolder' in snap.folder_paths
- assert 'build' not in snap.folder_paths
- assert 'build_mac' not in snap.folder_paths
- assert 'normal_subfolder/build' not in snap.folder_paths
- assert 'build_mac/normalfolder' not in snap.folder_paths
- assert 'file1.tif' not in snap.file_modtimes
- assert 'sub_buildfolder/file2.tif' not in snap.file_modtimes
- assert 'build/file3.cpp' not in snap.file_modtimes
- assert 'build_mac/file4.cpp' not in snap.file_modtimes
- assert 'build_mac/normalfolder/file4.cpp' not in snap.file_modtimes
- assert 'normal_subfolder/build/file.txt' not in snap.file_modtimes
-
- def test_CompareSnapshots_identical_snapshots_nodiffs():
- # emulate identical snapshots
- snap1 = FolderSnapshot()
- snap1.folder_paths = ['myfolder1', 'myfolder2']
- snap1.file_modtimes = {
- 'rootfile.txt' : 12345,
- 'myfolder1/file.txt' : 12345
- }
-
- snap2 = FolderSnapshot()
- snap2.folder_paths = ['myfolder1', 'myfolder2']
- snap2.file_modtimes = {
- 'rootfile.txt' : 12345,
- 'myfolder1/file.txt' : 12345
- }
- changes = FolderSnapshot.CompareSnapshots(snap1, snap2)
- assert not changes.any_changed()
- changed_things = [c for c in changes.enumerate_changes()]
- assert not changed_things
- def test_CompareSnapshots_two_of_each_kind_of_change():
- # emulate identical snapshots
- snap1 = FolderSnapshot()
- snap1.folder_paths = ['myfolder1', 'myfolder2', 'myfolder3', 'myfolder4']
- snap1.file_modtimes = {
- 'rootfile.txt' : 12345,
- 'rootfile2.txt' : 12345,
- 'rootfile3.txt' : 12345,
- 'myfolder1/file.txt' : 12345,
- 'myfolder2/file2.txt' : 12345,
- 'myfolder2/file3.txt' : 12345,
- }
-
- snap2 = FolderSnapshot()
- # myfolder1 deleted
- # myfolder2 unchanged
- # myfolder3 unchanged
- # myfolder4 deleted
- # myfolder5 as well as its subfolder, myfolder6 added
- snap2.folder_paths = ['myfolder3', 'myfolder2', 'myfolder5', 'myfolder5/myfolder6']
- snap2.file_modtimes = {
- 'rootfile2.txt' : 12345, # unchanged, in root
- 'rootfile3.txt' : 33333, # modified
- 'rootfile4.txt' : 12345, # a new file
- # myfolder1 is deleted, so myfolder1/file.txt should show up as deleted
- 'myfolder2/file2.txt' : 12345, # unchanged, but in subfolder
- 'myfolder2/file3.txt' : 33333, # modified in subfolder
- 'myfolder5/file4.txt' : 12345, # a new file in a new folder
- }
- changes = FolderSnapshot.CompareSnapshots(snap1, snap2)
- assert changes.any_changed()
- changed_things = [c for c in changes.enumerate_changes()]
- # folders
- for expected_element in [
- ('FOLDER_ADDED', 'myfolder5'),
- ('FOLDER_ADDED', 'myfolder5/myfolder6'),
- ('FOLDER_DELETED', 'myfolder1'),
- ('FOLDER_DELETED', 'myfolder4'),
- ('DELETED', 'rootfile.txt'),
- ('DELETED', 'myfolder1/file.txt'),
- ('ADDED', 'rootfile4.txt'),
- ('ADDED', 'myfolder5/file4.txt'),
- ('CHANGED', 'rootfile3.txt'),
- ('CHANGED', 'myfolder2/file3.txt')
- ]:
- assert expected_element in changed_things
- changed_things.remove(expected_element)
- # every time we did an assert above, we removed the matching element
- # from the change list. This means that the change list should now be empty
- # since everything that changed has been accounted for
- assert not changed_things, f"Unexpected change {changed_things}"
|