test_lsdir.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from pathlib import Path
  2. from ..lsdir import GooeyLsDir
  3. import stat
  4. from unittest.mock import patch
  5. from datalad.api import create
  6. from datalad.support.exceptions import IncompleteResultsError
  7. from datalad.tests.utils_pytest import (
  8. assert_equal,
  9. assert_in,
  10. assert_raises,
  11. get_deeply_nested_structure,
  12. has_symlink_capability,
  13. with_tempfile,
  14. with_tree,
  15. )
  16. dataset_content = [
  17. {'path': 'directory_untracked', 'type': 'directory'},
  18. {'path': 'link2dir', 'type': 'symlink'},
  19. {'path': 'link2subdsdir', 'type': 'symlink'},
  20. {'path': 'link2subdsroot', 'type': 'symlink'},
  21. {'path': 'subdir', 'type': 'directory'},
  22. {'path': '.datalad', 'type': 'directory'},
  23. {'path': '.gitattributes', 'type': 'file'},
  24. {'path': '.gitmodules', 'type': 'file'},
  25. {'path': 'subds_modified', 'type': 'dataset'},
  26. ]
  27. content_wo_symlinks = [
  28. item for item in dataset_content if item.get('type') != 'symlink'
  29. ]
  30. # Test _lsfiles with dataset
  31. @with_tempfile
  32. def test_lsfiles(path=None):
  33. ds = get_deeply_nested_structure(path)
  34. abnormal_filename = list(Path(path).glob('*file_modified_'))[0]
  35. abnormal_filename.unlink()
  36. # Since this is a dataset, check that _lsfiles is called and not _iterdir
  37. with patch("datalad_gooey.lsdir._iterdir") as _iterdir,\
  38. patch("datalad_gooey.lsdir._lsfiles") as _lsfiles:
  39. GooeyLsDir.__call__(ds.pathobj)
  40. _lsfiles.assert_called()
  41. _iterdir.assert_not_called()
  42. # Write results to list
  43. lsfiles_res = list(GooeyLsDir.__call__(ds.pathobj))
  44. # In case we are on a filesystem without symlink capability,
  45. # use content without symlinks
  46. content = dataset_content
  47. if not has_symlink_capability():
  48. content = content_wo_symlinks
  49. # Test result outputs
  50. assert_equal(len(lsfiles_res), len(content))
  51. for item in lsfiles_res:
  52. assert_in(
  53. {
  54. 'path': Path(item.get('path')).name,
  55. 'type': item.get('type'),
  56. }, content)
  57. # test inaccessible directory (except on a crippled filesystem)
  58. if not ds.repo.is_managed_branch():
  59. new_dir = Path(path) / 'interim_dir' / 'inaccessible_dir'
  60. new_dir.mkdir(parents=True)
  61. existing_permissions = stat.S_IMODE(new_dir.stat().st_mode)
  62. new_permissions = existing_permissions ^ stat.S_IXUSR ^ stat.S_IRUSR ^ stat.S_IWUSR
  63. new_dir.chmod(new_permissions)
  64. with assert_raises(IncompleteResultsError):
  65. res = list(GooeyLsDir.__call__(Path(path) / 'interim_dir'))
  66. assert_equal(len(res), 1)
  67. assert_equal(res[0].get('status'), 'error')
  68. assert_equal(res[0].get('message'), 'Permissions denied')
  69. dir_tree = {
  70. "random_file1.txt": "some content",
  71. "some_dir": {
  72. "file_in_dir.txt": "some content in file in dir",
  73. },
  74. "subdataset": {
  75. "random_file2.txt": "some content in file in subdataset",
  76. }
  77. }
  78. directory_content = [
  79. {'path': 'random_file1.txt', 'type': 'file', 'state': 'untracked'},
  80. {'path': 'subdataset', 'type': 'dataset', 'state': 'untracked'},
  81. {'path': 'some_dir', 'type': 'directory', 'state': 'untracked'}
  82. ]
  83. # Test _iterdir with directory tree not in dataset/git repo
  84. @with_tree(tree=dir_tree)
  85. def test_iterdir(root=None, mockdef=None):
  86. # Create and save subdataset
  87. sub_ds = create(Path(root) / "subdataset", force=True)
  88. sub_ds.save(to_git=True)
  89. # Since this is a directory (not git repo or dataset),
  90. # check that _iterdir is called
  91. with patch("datalad_gooey.lsdir._iterdir") as _iterdir:
  92. GooeyLsDir.__call__(Path(root))
  93. _iterdir.assert_called()
  94. # Write results to list and test outputs
  95. iterdir_res = list(GooeyLsDir.__call__(Path(root)))
  96. assert_equal(len(iterdir_res), len(directory_content))
  97. for item in iterdir_res:
  98. assert_in(
  99. {
  100. 'path': Path(item.get('path')).name,
  101. 'type': item.get('type'),
  102. 'state': item.get('state'),
  103. }, directory_content)
  104. # Test .git
  105. @with_tempfile(mkdir=True)
  106. def test_git_directory(temp_dir_name: str = ""):
  107. new_dir = Path(temp_dir_name) / '.git'
  108. new_dir.mkdir()
  109. res = list(GooeyLsDir.__call__(Path(temp_dir_name)))
  110. assert_equal(len(res), 0)