edq-utils 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edq/__init__.py +5 -0
- edq/cli/__init__.py +0 -0
- edq/cli/config/__init__.py +3 -0
- edq/cli/config/list.py +69 -0
- edq/cli/http/__init__.py +3 -0
- edq/cli/http/exchange-server.py +71 -0
- edq/cli/http/send-exchange.py +45 -0
- edq/cli/http/verify-exchanges.py +38 -0
- edq/cli/testing/__init__.py +3 -0
- edq/cli/testing/cli-test.py +49 -0
- edq/cli/version.py +28 -0
- edq/core/__init__.py +0 -0
- edq/core/argparser.py +137 -0
- edq/core/argparser_test.py +124 -0
- edq/core/config.py +268 -0
- edq/core/config_test.py +1038 -0
- edq/core/log.py +101 -0
- edq/core/version.py +6 -0
- edq/procedure/__init__.py +0 -0
- edq/procedure/verify_exchanges.py +85 -0
- edq/py.typed +0 -0
- edq/testing/__init__.py +3 -0
- edq/testing/asserts.py +65 -0
- edq/testing/cli.py +360 -0
- edq/testing/cli_test.py +15 -0
- edq/testing/httpserver.py +578 -0
- edq/testing/httpserver_test.py +424 -0
- edq/testing/run.py +142 -0
- edq/testing/testdata/cli/data/configs/empty/edq-config.json +1 -0
- edq/testing/testdata/cli/data/configs/simple-1/edq-config.json +4 -0
- edq/testing/testdata/cli/data/configs/simple-2/edq-config.json +3 -0
- edq/testing/testdata/cli/data/configs/value-number/edq-config.json +3 -0
- edq/testing/testdata/cli/tests/config/list/config_list_base.txt +16 -0
- edq/testing/testdata/cli/tests/config/list/config_list_config_value_number.txt +10 -0
- edq/testing/testdata/cli/tests/config/list/config_list_ignore_config.txt +14 -0
- edq/testing/testdata/cli/tests/config/list/config_list_no_config.txt +8 -0
- edq/testing/testdata/cli/tests/config/list/config_list_show_origin.txt +13 -0
- edq/testing/testdata/cli/tests/config/list/config_list_skip_header.txt +10 -0
- edq/testing/testdata/cli/tests/help_base.txt +9 -0
- edq/testing/testdata/cli/tests/platform_skip.txt +5 -0
- edq/testing/testdata/cli/tests/version_base.txt +6 -0
- edq/testing/testdata/http/exchanges/simple.httpex.json +5 -0
- edq/testing/testdata/http/exchanges/simple_anchor.httpex.json +5 -0
- edq/testing/testdata/http/exchanges/simple_file.httpex.json +10 -0
- edq/testing/testdata/http/exchanges/simple_file_binary.httpex.json +10 -0
- edq/testing/testdata/http/exchanges/simple_file_get_params.httpex.json +14 -0
- edq/testing/testdata/http/exchanges/simple_file_multiple.httpex.json +13 -0
- edq/testing/testdata/http/exchanges/simple_file_name.httpex.json +11 -0
- edq/testing/testdata/http/exchanges/simple_file_post_multiple.httpex.json +13 -0
- edq/testing/testdata/http/exchanges/simple_file_post_params.httpex.json +14 -0
- edq/testing/testdata/http/exchanges/simple_headers.httpex.json +8 -0
- edq/testing/testdata/http/exchanges/simple_jsonresponse_dict.httpex.json +7 -0
- edq/testing/testdata/http/exchanges/simple_jsonresponse_list.httpex.json +9 -0
- edq/testing/testdata/http/exchanges/simple_params.httpex.json +9 -0
- edq/testing/testdata/http/exchanges/simple_post.httpex.json +5 -0
- edq/testing/testdata/http/exchanges/simple_post_params.httpex.json +9 -0
- edq/testing/testdata/http/exchanges/simple_post_urlparams.httpex.json +5 -0
- edq/testing/testdata/http/exchanges/simple_urlparams.httpex.json +5 -0
- edq/testing/testdata/http/exchanges/specialcase_listparams_explicit.httpex.json +8 -0
- edq/testing/testdata/http/exchanges/specialcase_listparams_url.httpex.json +5 -0
- edq/testing/testdata/http/files/a.txt +1 -0
- edq/testing/testdata/http/files/tiny.png +0 -0
- edq/testing/unittest.py +88 -0
- edq/util/__init__.py +3 -0
- edq/util/dirent.py +340 -0
- edq/util/dirent_test.py +979 -0
- edq/util/encoding.py +18 -0
- edq/util/hash.py +41 -0
- edq/util/hash_test.py +89 -0
- edq/util/json.py +180 -0
- edq/util/json_test.py +228 -0
- edq/util/net.py +1008 -0
- edq/util/parse.py +33 -0
- edq/util/pyimport.py +94 -0
- edq/util/pyimport_test.py +119 -0
- edq/util/reflection.py +32 -0
- edq/util/time.py +75 -0
- edq/util/time_test.py +107 -0
- edq_utils-0.1.9.dist-info/METADATA +164 -0
- edq_utils-0.1.9.dist-info/RECORD +83 -0
- edq_utils-0.1.9.dist-info/WHEEL +5 -0
- edq_utils-0.1.9.dist-info/licenses/LICENSE +21 -0
- edq_utils-0.1.9.dist-info/top_level.txt +1 -0
edq/util/dirent_test.py
ADDED
|
@@ -0,0 +1,979 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import edq.testing.unittest
|
|
4
|
+
import edq.util.dirent
|
|
5
|
+
|
|
6
|
+
DIRENT_TYPE_DIR = 'dir'
|
|
7
|
+
DIRENT_TYPE_FILE = 'file'
|
|
8
|
+
DIRENT_TYPE_BROKEN_SYMLINK = 'broken_symlink'
|
|
9
|
+
|
|
10
|
+
def create_test_dir(temp_dir_prefix: str) -> str:
|
|
11
|
+
"""
|
|
12
|
+
Create a temp dir and populate it with dirents for testing.
|
|
13
|
+
|
|
14
|
+
This test data directory is laid out as:
|
|
15
|
+
.
|
|
16
|
+
├── a.txt
|
|
17
|
+
├── dir_1
|
|
18
|
+
│ ├── b.txt
|
|
19
|
+
│ └── dir_2
|
|
20
|
+
│ └── c.txt
|
|
21
|
+
├── dir_empty
|
|
22
|
+
├── file_empty
|
|
23
|
+
├── symlink_a.txt -> a.txt
|
|
24
|
+
├── symlink_dir_1 -> dir_1
|
|
25
|
+
├── symlink_dir_empty -> dir_empty
|
|
26
|
+
└── symlink_file_empty -> file_empty
|
|
27
|
+
|
|
28
|
+
Where non-empty files are filled with their filename (without the extension).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
temp_dir = edq.util.dirent.get_temp_dir(prefix = temp_dir_prefix)
|
|
32
|
+
|
|
33
|
+
# Dirs
|
|
34
|
+
edq.util.dirent.mkdir(os.path.join(temp_dir, 'dir_1', 'dir_2'))
|
|
35
|
+
edq.util.dirent.mkdir(os.path.join(temp_dir, 'dir_empty'))
|
|
36
|
+
|
|
37
|
+
# Files
|
|
38
|
+
edq.util.dirent.write_file(os.path.join(temp_dir, 'a.txt'), 'a')
|
|
39
|
+
edq.util.dirent.write_file(os.path.join(temp_dir, 'file_empty'), '')
|
|
40
|
+
edq.util.dirent.write_file(os.path.join(temp_dir, 'dir_1', 'b.txt'), 'b')
|
|
41
|
+
edq.util.dirent.write_file(os.path.join(temp_dir, 'dir_1', 'dir_2', 'c.txt'), 'c')
|
|
42
|
+
|
|
43
|
+
# Links
|
|
44
|
+
os.symlink('a.txt', os.path.join(temp_dir, 'symlink_a.txt'))
|
|
45
|
+
os.symlink('dir_1', os.path.join(temp_dir, 'symlink_dir_1'))
|
|
46
|
+
os.symlink('dir_empty', os.path.join(temp_dir, 'symlink_dir_empty'))
|
|
47
|
+
os.symlink('file_empty', os.path.join(temp_dir, 'symlink_file_empty'))
|
|
48
|
+
|
|
49
|
+
return temp_dir
|
|
50
|
+
|
|
51
|
+
class TestDirent(edq.testing.unittest.BaseTest):
|
|
52
|
+
""" Test basic operations on dirents. """
|
|
53
|
+
|
|
54
|
+
def test_setup(self):
|
|
55
|
+
""" Test that the base temp directory is properly setup. """
|
|
56
|
+
|
|
57
|
+
temp_dir = self._prep_temp_dir()
|
|
58
|
+
|
|
59
|
+
expected_paths = [
|
|
60
|
+
('a.txt', DIRENT_TYPE_FILE),
|
|
61
|
+
('dir_1', DIRENT_TYPE_DIR),
|
|
62
|
+
(os.path.join('dir_1', 'b.txt'), DIRENT_TYPE_FILE),
|
|
63
|
+
(os.path.join('dir_1', 'dir_2'), DIRENT_TYPE_DIR),
|
|
64
|
+
(os.path.join('dir_1', 'dir_2', 'c.txt'), DIRENT_TYPE_FILE),
|
|
65
|
+
('dir_empty', DIRENT_TYPE_DIR),
|
|
66
|
+
('file_empty', DIRENT_TYPE_FILE),
|
|
67
|
+
('symlink_a.txt', DIRENT_TYPE_FILE, True),
|
|
68
|
+
('symlink_dir_1', DIRENT_TYPE_DIR, True),
|
|
69
|
+
('symlink_dir_empty', DIRENT_TYPE_DIR, True),
|
|
70
|
+
('symlink_file_empty', DIRENT_TYPE_FILE, True),
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
self._check_existing_paths(temp_dir, expected_paths)
|
|
74
|
+
|
|
75
|
+
def test_contains_path_base(self):
|
|
76
|
+
""" Test checking path containment. """
|
|
77
|
+
|
|
78
|
+
temp_dir = self._prep_temp_dir()
|
|
79
|
+
|
|
80
|
+
# [(parent, child, contains?), ...]
|
|
81
|
+
test_cases = [
|
|
82
|
+
# Containment
|
|
83
|
+
('a', os.path.join('a', 'b', 'c'), True),
|
|
84
|
+
(os.path.join('a', 'b'), os.path.join('a', 'b', 'c'), True),
|
|
85
|
+
('.', os.path.join('a', 'b', 'c'), True),
|
|
86
|
+
('..', '.', True),
|
|
87
|
+
|
|
88
|
+
# Self No Containment
|
|
89
|
+
('a', 'a', False),
|
|
90
|
+
(os.path.join('a', 'b', 'c'), os.path.join('a', 'b', 'c'), False),
|
|
91
|
+
('.', '.', False),
|
|
92
|
+
|
|
93
|
+
# Trivial No Containment
|
|
94
|
+
('a', 'b', False),
|
|
95
|
+
('z', os.path.join('a', 'b', 'c'), False),
|
|
96
|
+
('aa', os.path.join('a', 'b', 'c'), False),
|
|
97
|
+
('a', os.path.join('aa', 'b', 'c'), False),
|
|
98
|
+
|
|
99
|
+
# Child Contains Parent
|
|
100
|
+
(os.path.join('a', 'b', 'c'), 'a', False),
|
|
101
|
+
(os.path.join('a', 'b', 'c'), os.path.join('a', 'b'), False),
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
for (i, test_case) in enumerate(test_cases):
|
|
105
|
+
(parent, child, expected) = test_case
|
|
106
|
+
|
|
107
|
+
with self.subTest(msg = f"Case {i} ('{parent}' ⊂ '{child}'):"):
|
|
108
|
+
parent = os.path.join(temp_dir, parent)
|
|
109
|
+
child = os.path.join(temp_dir, child)
|
|
110
|
+
|
|
111
|
+
actual = edq.util.dirent.contains_path(parent, child)
|
|
112
|
+
self.assertEqual(expected, actual)
|
|
113
|
+
|
|
114
|
+
def test_read_write_file_bytes_base(self):
|
|
115
|
+
""" Test reading and writing a file as bytes. """
|
|
116
|
+
|
|
117
|
+
# [(path, write kwargs, read kwargs, write contents, expected contents, error substring), ...]
|
|
118
|
+
# All conent should be strings that will be encoded.
|
|
119
|
+
test_cases = [
|
|
120
|
+
# Base
|
|
121
|
+
(
|
|
122
|
+
"test.txt",
|
|
123
|
+
{},
|
|
124
|
+
{},
|
|
125
|
+
"test",
|
|
126
|
+
"test",
|
|
127
|
+
None,
|
|
128
|
+
),
|
|
129
|
+
|
|
130
|
+
# Empty Write
|
|
131
|
+
(
|
|
132
|
+
"test.txt",
|
|
133
|
+
{},
|
|
134
|
+
{},
|
|
135
|
+
"",
|
|
136
|
+
"",
|
|
137
|
+
None,
|
|
138
|
+
),
|
|
139
|
+
|
|
140
|
+
# None Write
|
|
141
|
+
(
|
|
142
|
+
"test.txt",
|
|
143
|
+
{},
|
|
144
|
+
{},
|
|
145
|
+
None,
|
|
146
|
+
"",
|
|
147
|
+
None,
|
|
148
|
+
),
|
|
149
|
+
|
|
150
|
+
# Clobber
|
|
151
|
+
(
|
|
152
|
+
"a.txt",
|
|
153
|
+
{},
|
|
154
|
+
{},
|
|
155
|
+
"test",
|
|
156
|
+
"test",
|
|
157
|
+
None,
|
|
158
|
+
),
|
|
159
|
+
(
|
|
160
|
+
"dir_1",
|
|
161
|
+
{},
|
|
162
|
+
{},
|
|
163
|
+
"test",
|
|
164
|
+
"test",
|
|
165
|
+
None,
|
|
166
|
+
),
|
|
167
|
+
(
|
|
168
|
+
"symlink_a.txt",
|
|
169
|
+
{},
|
|
170
|
+
{},
|
|
171
|
+
"test",
|
|
172
|
+
"test",
|
|
173
|
+
None,
|
|
174
|
+
),
|
|
175
|
+
|
|
176
|
+
# No Clobber
|
|
177
|
+
(
|
|
178
|
+
"a.txt",
|
|
179
|
+
{'no_clobber': True},
|
|
180
|
+
{},
|
|
181
|
+
"test",
|
|
182
|
+
"test",
|
|
183
|
+
'already exists',
|
|
184
|
+
),
|
|
185
|
+
(
|
|
186
|
+
"dir_1",
|
|
187
|
+
{'no_clobber': True},
|
|
188
|
+
{},
|
|
189
|
+
"test",
|
|
190
|
+
"test",
|
|
191
|
+
'already exists',
|
|
192
|
+
),
|
|
193
|
+
(
|
|
194
|
+
"symlink_a.txt",
|
|
195
|
+
{'no_clobber': True},
|
|
196
|
+
{},
|
|
197
|
+
"test",
|
|
198
|
+
"test",
|
|
199
|
+
'already exists',
|
|
200
|
+
),
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
for (i, test_case) in enumerate(test_cases):
|
|
204
|
+
(path, write_options, read_options, write_contents, expected_contents, error_substring) = test_case
|
|
205
|
+
|
|
206
|
+
with self.subTest(msg = f"Case {i} ('{path}'):"):
|
|
207
|
+
temp_dir = self._prep_temp_dir()
|
|
208
|
+
path = os.path.join(temp_dir, path)
|
|
209
|
+
|
|
210
|
+
if (write_contents is not None):
|
|
211
|
+
write_contents = bytes(write_contents, edq.util.dirent.DEFAULT_ENCODING)
|
|
212
|
+
|
|
213
|
+
expected_contents = bytes(expected_contents, edq.util.dirent.DEFAULT_ENCODING)
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
edq.util.dirent.write_file_bytes(path, write_contents, **write_options)
|
|
217
|
+
actual_contents = edq.util.dirent.read_file_bytes(path, **read_options)
|
|
218
|
+
except Exception as ex:
|
|
219
|
+
error_string = self.format_error_string(ex)
|
|
220
|
+
if (error_substring is None):
|
|
221
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
222
|
+
|
|
223
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
224
|
+
|
|
225
|
+
continue
|
|
226
|
+
|
|
227
|
+
if (error_substring is not None):
|
|
228
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
229
|
+
|
|
230
|
+
self.assertEqual(expected_contents, actual_contents)
|
|
231
|
+
|
|
232
|
+
def test_read_write_file_base(self):
|
|
233
|
+
""" Test reading and writing a file. """
|
|
234
|
+
|
|
235
|
+
# [(path, write kwargs, read kwargs, write contents, expected contents, error substring), ...]
|
|
236
|
+
test_cases = [
|
|
237
|
+
# Base
|
|
238
|
+
(
|
|
239
|
+
"test.txt",
|
|
240
|
+
{},
|
|
241
|
+
{},
|
|
242
|
+
"test",
|
|
243
|
+
"test",
|
|
244
|
+
None,
|
|
245
|
+
),
|
|
246
|
+
|
|
247
|
+
# Defaults
|
|
248
|
+
(
|
|
249
|
+
"test.txt",
|
|
250
|
+
{},
|
|
251
|
+
{},
|
|
252
|
+
" test ",
|
|
253
|
+
"test",
|
|
254
|
+
None,
|
|
255
|
+
),
|
|
256
|
+
|
|
257
|
+
# No Modifications
|
|
258
|
+
(
|
|
259
|
+
"test.txt",
|
|
260
|
+
{'strip': False, 'newline': False},
|
|
261
|
+
{'strip': False},
|
|
262
|
+
" test ",
|
|
263
|
+
" test ",
|
|
264
|
+
None,
|
|
265
|
+
),
|
|
266
|
+
|
|
267
|
+
# No Strip
|
|
268
|
+
(
|
|
269
|
+
"test.txt",
|
|
270
|
+
{'strip': False, 'newline': True},
|
|
271
|
+
{'strip': False},
|
|
272
|
+
" test ",
|
|
273
|
+
" test \n",
|
|
274
|
+
None,
|
|
275
|
+
),
|
|
276
|
+
|
|
277
|
+
# No Read Strip
|
|
278
|
+
(
|
|
279
|
+
"test.txt",
|
|
280
|
+
{},
|
|
281
|
+
{'strip': False},
|
|
282
|
+
"test",
|
|
283
|
+
"test\n",
|
|
284
|
+
None,
|
|
285
|
+
),
|
|
286
|
+
|
|
287
|
+
# Empty Write
|
|
288
|
+
(
|
|
289
|
+
"test.txt",
|
|
290
|
+
{'newline': False},
|
|
291
|
+
{},
|
|
292
|
+
"",
|
|
293
|
+
"",
|
|
294
|
+
None,
|
|
295
|
+
),
|
|
296
|
+
|
|
297
|
+
# None Write
|
|
298
|
+
(
|
|
299
|
+
"test.txt",
|
|
300
|
+
{'newline': False},
|
|
301
|
+
{},
|
|
302
|
+
None,
|
|
303
|
+
"",
|
|
304
|
+
None,
|
|
305
|
+
),
|
|
306
|
+
|
|
307
|
+
# Clobber
|
|
308
|
+
(
|
|
309
|
+
"a.txt",
|
|
310
|
+
{},
|
|
311
|
+
{},
|
|
312
|
+
"test",
|
|
313
|
+
"test",
|
|
314
|
+
None,
|
|
315
|
+
),
|
|
316
|
+
(
|
|
317
|
+
"dir_1",
|
|
318
|
+
{},
|
|
319
|
+
{},
|
|
320
|
+
"test",
|
|
321
|
+
"test",
|
|
322
|
+
None,
|
|
323
|
+
),
|
|
324
|
+
(
|
|
325
|
+
"symlink_a.txt",
|
|
326
|
+
{},
|
|
327
|
+
{},
|
|
328
|
+
"test",
|
|
329
|
+
"test",
|
|
330
|
+
None,
|
|
331
|
+
),
|
|
332
|
+
|
|
333
|
+
# No Clobber
|
|
334
|
+
(
|
|
335
|
+
"a.txt",
|
|
336
|
+
{'no_clobber': True},
|
|
337
|
+
{},
|
|
338
|
+
"test",
|
|
339
|
+
"test",
|
|
340
|
+
'Destination of write already exists',
|
|
341
|
+
),
|
|
342
|
+
(
|
|
343
|
+
"dir_1",
|
|
344
|
+
{'no_clobber': True},
|
|
345
|
+
{},
|
|
346
|
+
"test",
|
|
347
|
+
"test",
|
|
348
|
+
'Destination of write already exists',
|
|
349
|
+
),
|
|
350
|
+
(
|
|
351
|
+
"symlink_a.txt",
|
|
352
|
+
{'no_clobber': True},
|
|
353
|
+
{},
|
|
354
|
+
"test",
|
|
355
|
+
"test",
|
|
356
|
+
'Destination of write already exists',
|
|
357
|
+
),
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
for (i, test_case) in enumerate(test_cases):
|
|
361
|
+
(path, write_options, read_options, write_contents, expected_contents, error_substring) = test_case
|
|
362
|
+
|
|
363
|
+
with self.subTest(msg = f"Case {i} ('{path}'):"):
|
|
364
|
+
temp_dir = self._prep_temp_dir()
|
|
365
|
+
path = os.path.join(temp_dir, path)
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
edq.util.dirent.write_file(path, write_contents, **write_options)
|
|
369
|
+
actual_contents = edq.util.dirent.read_file(path, **read_options)
|
|
370
|
+
except Exception as ex:
|
|
371
|
+
error_string = self.format_error_string(ex)
|
|
372
|
+
if (error_substring is None):
|
|
373
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
374
|
+
|
|
375
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
376
|
+
|
|
377
|
+
continue
|
|
378
|
+
|
|
379
|
+
if (error_substring is not None):
|
|
380
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
381
|
+
|
|
382
|
+
self.assertEqual(expected_contents, actual_contents)
|
|
383
|
+
|
|
384
|
+
def test_copy_contents_base(self):
|
|
385
|
+
""" Test copying the contents of a dirent. """
|
|
386
|
+
|
|
387
|
+
# [(source, dest, no clobber?, error substring), ...]
|
|
388
|
+
test_cases = [
|
|
389
|
+
('a.txt', 'dir_1', False, None),
|
|
390
|
+
('a.txt', 'ZZZ', False, None),
|
|
391
|
+
('dir_empty', 'dir_1', False, None),
|
|
392
|
+
|
|
393
|
+
('dir_1', 'dir_1', False, 'Source and destination of contents copy cannot be the same'),
|
|
394
|
+
('dir_empty', 'symlink_dir_empty', False, 'Source and destination of contents copy cannot be the same'),
|
|
395
|
+
|
|
396
|
+
('a.txt', 'file_empty', False, 'Destination of contents copy exists and is not a dir'),
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
for (i, test_case) in enumerate(test_cases):
|
|
400
|
+
(source, dest, no_clobber, error_substring) = test_case
|
|
401
|
+
|
|
402
|
+
with self.subTest(msg = f"Case {i} ('{source}' -> '{dest}'):"):
|
|
403
|
+
temp_dir = self._prep_temp_dir()
|
|
404
|
+
|
|
405
|
+
source = os.path.join(temp_dir, source)
|
|
406
|
+
dest = os.path.join(temp_dir, dest)
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
edq.util.dirent.copy_contents(source, dest, no_clobber = no_clobber)
|
|
410
|
+
except Exception as ex:
|
|
411
|
+
error_string = self.format_error_string(ex)
|
|
412
|
+
if (error_substring is None):
|
|
413
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
414
|
+
|
|
415
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
416
|
+
|
|
417
|
+
continue
|
|
418
|
+
|
|
419
|
+
if (error_substring is not None):
|
|
420
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
421
|
+
|
|
422
|
+
def test_copy_base(self):
|
|
423
|
+
""" Test copying dirents. """
|
|
424
|
+
|
|
425
|
+
# [(source, dest, no_clobber?, error substring), ...]
|
|
426
|
+
test_cases = [
|
|
427
|
+
# File
|
|
428
|
+
('a.txt', 'test.txt', False, None),
|
|
429
|
+
('a.txt', 'test.txt', True, None),
|
|
430
|
+
('a.txt', os.path.join('dir_1', 'test.txt'), False, None),
|
|
431
|
+
('a.txt', os.path.join('dir_1', 'test.txt'), True, None),
|
|
432
|
+
|
|
433
|
+
# File - Clobber
|
|
434
|
+
('a.txt', 'file_empty', False, None),
|
|
435
|
+
('a.txt', os.path.join('dir_1', 'b.txt'), False, None),
|
|
436
|
+
('a.txt', 'dir_1', False, None),
|
|
437
|
+
('a.txt', os.path.join('dir_1', 'dir_2'), False, None),
|
|
438
|
+
|
|
439
|
+
# File - No Clobber
|
|
440
|
+
('a.txt', 'file_empty', True, 'Destination of copy already exists'),
|
|
441
|
+
('a.txt', os.path.join('dir_1', 'b.txt'), True, 'Destination of copy already exists'),
|
|
442
|
+
('a.txt', 'dir_1', True, 'Destination of copy already exists'),
|
|
443
|
+
('a.txt', os.path.join('dir_1', 'dir_2'), True, 'Destination of copy already exists'),
|
|
444
|
+
|
|
445
|
+
# Dir
|
|
446
|
+
('dir_empty', 'test', False, None),
|
|
447
|
+
('dir_empty', 'test', True, None),
|
|
448
|
+
('dir_empty', os.path.join('dir_1', 'test'), False, None),
|
|
449
|
+
('dir_empty', os.path.join('dir_1', 'test'), True, None),
|
|
450
|
+
|
|
451
|
+
# Dir - Clobber
|
|
452
|
+
('dir_empty', 'file_empty', False, None),
|
|
453
|
+
('dir_empty', os.path.join('dir_1', 'b.txt'), False, None),
|
|
454
|
+
('dir_empty', 'dir_1', False, None),
|
|
455
|
+
('dir_empty', os.path.join('dir_1', 'dir_2'), False, None),
|
|
456
|
+
|
|
457
|
+
# Dir - No Clobber
|
|
458
|
+
('dir_empty', 'file_empty', True, 'Destination of copy already exists'),
|
|
459
|
+
('dir_empty', os.path.join('dir_1', 'b.txt'), True, 'Destination of copy already exists'),
|
|
460
|
+
('dir_empty', 'dir_1', True, 'Destination of copy already exists'),
|
|
461
|
+
('dir_empty', os.path.join('dir_1', 'dir_2'), True, 'Destination of copy already exists'),
|
|
462
|
+
|
|
463
|
+
# Link
|
|
464
|
+
('symlink_a.txt', 'test.txt', False, None),
|
|
465
|
+
('symlink_dir_1', 'test', False, None),
|
|
466
|
+
('symlink_dir_empty', 'test', False, None),
|
|
467
|
+
('symlink_file_empty', 'test.txt', False, None),
|
|
468
|
+
|
|
469
|
+
# Link - Clobber
|
|
470
|
+
('symlink_a.txt', 'file_empty', False, None),
|
|
471
|
+
('symlink_a.txt', 'symlink_dir_1', False, None),
|
|
472
|
+
|
|
473
|
+
# Link - No Clobber
|
|
474
|
+
('symlink_a.txt', 'file_empty', True, 'Destination of copy already exists'),
|
|
475
|
+
('symlink_a.txt', 'symlink_dir_1', True, 'Destination of copy already exists'),
|
|
476
|
+
|
|
477
|
+
# Clobber Parent
|
|
478
|
+
(os.path.join('dir_1', 'b.txt'), 'dir_1', False, 'Destination of copy cannot contain the source.'),
|
|
479
|
+
|
|
480
|
+
# Same
|
|
481
|
+
('a.txt', 'a.txt', False, None),
|
|
482
|
+
('symlink_a.txt', 'a.txt', False, None),
|
|
483
|
+
('a.txt', 'a.txt', True, None),
|
|
484
|
+
('symlink_a.txt', 'a.txt', True, None),
|
|
485
|
+
|
|
486
|
+
# Missing Source
|
|
487
|
+
('ZZZ', 'test.txt', False, 'Source of copy does not exist'),
|
|
488
|
+
('ZZZ', 'test.txt', True, 'Source of copy does not exist'),
|
|
489
|
+
]
|
|
490
|
+
|
|
491
|
+
for (i, test_case) in enumerate(test_cases):
|
|
492
|
+
(source, dest, no_clobber, error_substring) = test_case
|
|
493
|
+
|
|
494
|
+
with self.subTest(msg = f"Case {i} ('{source}' -> '{dest}'):"):
|
|
495
|
+
temp_dir = self._prep_temp_dir()
|
|
496
|
+
|
|
497
|
+
source = os.path.join(temp_dir, source)
|
|
498
|
+
dest = os.path.join(temp_dir, dest)
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
edq.util.dirent.copy(source, dest, no_clobber = no_clobber)
|
|
502
|
+
except Exception as ex:
|
|
503
|
+
error_string = self.format_error_string(ex)
|
|
504
|
+
if (error_substring is None):
|
|
505
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
506
|
+
|
|
507
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
508
|
+
|
|
509
|
+
continue
|
|
510
|
+
|
|
511
|
+
if (error_substring is not None):
|
|
512
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
513
|
+
|
|
514
|
+
dirent_type, is_link = self._get_dirent_type(source)
|
|
515
|
+
|
|
516
|
+
checks = [
|
|
517
|
+
(source, dirent_type, is_link),
|
|
518
|
+
]
|
|
519
|
+
|
|
520
|
+
if (not edq.util.dirent.same(source, dest)):
|
|
521
|
+
checks += [
|
|
522
|
+
(dest, dirent_type, is_link),
|
|
523
|
+
]
|
|
524
|
+
|
|
525
|
+
self._check_existing_paths(temp_dir, checks)
|
|
526
|
+
|
|
527
|
+
def test_same_base(self):
|
|
528
|
+
""" Test checking for two paths pointing to the same dirent. """
|
|
529
|
+
|
|
530
|
+
temp_dir = self._prep_temp_dir()
|
|
531
|
+
|
|
532
|
+
# [(path, path, same?), ...]
|
|
533
|
+
test_cases = [
|
|
534
|
+
# Same
|
|
535
|
+
('a.txt', 'a.txt', True),
|
|
536
|
+
('dir_1', 'dir_1', True),
|
|
537
|
+
(os.path.join('dir_1', 'b.txt'), os.path.join('dir_1', 'b.txt'), True),
|
|
538
|
+
(os.path.join('dir_1', 'b.txt'), os.path.join('dir_1', '..', 'dir_1', 'b.txt'), True),
|
|
539
|
+
|
|
540
|
+
# Not Same
|
|
541
|
+
('a.txt', 'dir_1', False),
|
|
542
|
+
('a.txt', os.path.join('dir_1', 'b.txt'), False),
|
|
543
|
+
('a.txt', 'file_empty', False),
|
|
544
|
+
('a.txt', 'dir_empty', False),
|
|
545
|
+
|
|
546
|
+
# Not Exists
|
|
547
|
+
('a.txt', 'ZZZ', False),
|
|
548
|
+
(os.path.join('dir_1', 'b.txt'), os.path.join('dir_1', 'ZZZ'), False),
|
|
549
|
+
(os.path.join('dir_1', 'b.txt'), os.path.join('ZZZ', 'b.txt'), False),
|
|
550
|
+
|
|
551
|
+
# Links
|
|
552
|
+
('a.txt', 'symlink_a.txt', True),
|
|
553
|
+
('a.txt', 'symlink_file_empty', False),
|
|
554
|
+
('dir_1', 'symlink_dir_1', True),
|
|
555
|
+
('dir_1', 'symlink_dir_empty', False),
|
|
556
|
+
]
|
|
557
|
+
|
|
558
|
+
for (i, test_case) in enumerate(test_cases):
|
|
559
|
+
(a, b, expected) = test_case
|
|
560
|
+
|
|
561
|
+
with self.subTest(msg = f"Case {i} ('{a}' vs '{b}'):"):
|
|
562
|
+
a = os.path.join(temp_dir, a)
|
|
563
|
+
b = os.path.join(temp_dir, b)
|
|
564
|
+
|
|
565
|
+
actual = edq.util.dirent.same(a, b)
|
|
566
|
+
self.assertEqual(expected, actual)
|
|
567
|
+
|
|
568
|
+
def test_mkdir_base(self):
|
|
569
|
+
""" Test creating directories. """
|
|
570
|
+
|
|
571
|
+
temp_dir = self._prep_temp_dir()
|
|
572
|
+
|
|
573
|
+
# [(path, error substring), ...]
|
|
574
|
+
test_cases = [
|
|
575
|
+
# Base
|
|
576
|
+
('new_dir_1', None),
|
|
577
|
+
(os.path.join('dir_1', 'new_dir_2'), None),
|
|
578
|
+
|
|
579
|
+
# Missing Parents
|
|
580
|
+
(os.path.join('ZZZ', 'new_dir_ZZZ'), None),
|
|
581
|
+
(os.path.join('ZZZ', 'YYY', 'XXX', 'new_dir_XXX'), None),
|
|
582
|
+
|
|
583
|
+
# Existing Dir
|
|
584
|
+
('dir_1', None),
|
|
585
|
+
('dir_empty', None),
|
|
586
|
+
('symlink_dir_1', None),
|
|
587
|
+
|
|
588
|
+
# Existing Non-Dir
|
|
589
|
+
('a.txt', 'Target of mkdir already exists'),
|
|
590
|
+
('symlink_a.txt', 'Target of mkdir already exists'),
|
|
591
|
+
|
|
592
|
+
# Existing Non-Dir Parent
|
|
593
|
+
(os.path.join('dir_1', 'b.txt', 'BBB'), 'Target of mkdir contains parent'),
|
|
594
|
+
]
|
|
595
|
+
|
|
596
|
+
for (i, test_case) in enumerate(test_cases):
|
|
597
|
+
(path, error_substring) = test_case
|
|
598
|
+
|
|
599
|
+
with self.subTest(msg = f"Case {i} ('{path}'):"):
|
|
600
|
+
path = os.path.join(temp_dir, path)
|
|
601
|
+
|
|
602
|
+
try:
|
|
603
|
+
edq.util.dirent.mkdir(path)
|
|
604
|
+
except Exception as ex:
|
|
605
|
+
error_string = self.format_error_string(ex)
|
|
606
|
+
if (error_substring is None):
|
|
607
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
608
|
+
|
|
609
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
610
|
+
|
|
611
|
+
continue
|
|
612
|
+
|
|
613
|
+
if (error_substring is not None):
|
|
614
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
615
|
+
|
|
616
|
+
self.assertTrue(edq.util.dirent.exists(path), 'Dir does not exist post mkdir.')
|
|
617
|
+
|
|
618
|
+
def test_get_temp_path_base(self):
|
|
619
|
+
""" Ensure that temp paths are not the same. """
|
|
620
|
+
|
|
621
|
+
a = edq.util.dirent.get_temp_path()
|
|
622
|
+
b = edq.util.dirent.get_temp_path()
|
|
623
|
+
|
|
624
|
+
self.assertNotEqual(a, b)
|
|
625
|
+
|
|
626
|
+
def test_get_temp_dir_base(self):
|
|
627
|
+
""" Ensure that the temp dir exists. """
|
|
628
|
+
|
|
629
|
+
path = edq.util.dirent.get_temp_dir()
|
|
630
|
+
self.assertTrue(edq.util.dirent.exists(path))
|
|
631
|
+
|
|
632
|
+
def test_exists_base(self):
|
|
633
|
+
"""
|
|
634
|
+
Test checking for existence.
|
|
635
|
+
|
|
636
|
+
./dir_empty and ./file_empty will be removed to check for broken links.
|
|
637
|
+
"""
|
|
638
|
+
|
|
639
|
+
temp_dir = self._prep_temp_dir()
|
|
640
|
+
|
|
641
|
+
# Remove some dirents to break links.
|
|
642
|
+
edq.util.dirent.remove(os.path.join(temp_dir, 'dir_empty'))
|
|
643
|
+
edq.util.dirent.remove(os.path.join(temp_dir, 'file_empty'))
|
|
644
|
+
|
|
645
|
+
# [(path, exists?), ...]
|
|
646
|
+
test_cases = [
|
|
647
|
+
# File
|
|
648
|
+
('a.txt', True),
|
|
649
|
+
(os.path.join('dir_1', 'b.txt'), True),
|
|
650
|
+
|
|
651
|
+
# Dir
|
|
652
|
+
('dir_1', True),
|
|
653
|
+
(os.path.join('dir_1', 'dir_2'), True),
|
|
654
|
+
|
|
655
|
+
# Links
|
|
656
|
+
('symlink_a.txt', True),
|
|
657
|
+
('symlink_dir_1', True),
|
|
658
|
+
('symlink_dir_empty', True), # Broken Link
|
|
659
|
+
('symlink_file_empty', True), # Broken Link
|
|
660
|
+
|
|
661
|
+
# Not Exists
|
|
662
|
+
('dir_empty', False),
|
|
663
|
+
('file_empty', False),
|
|
664
|
+
(os.path.join('dir_1', 'ZZZ'), False),
|
|
665
|
+
]
|
|
666
|
+
|
|
667
|
+
for (i, test_case) in enumerate(test_cases):
|
|
668
|
+
(path, expected) = test_case
|
|
669
|
+
|
|
670
|
+
with self.subTest(msg = f"Case {i} ('{path}'):"):
|
|
671
|
+
path = os.path.join(temp_dir, path)
|
|
672
|
+
actual = edq.util.dirent.exists(path)
|
|
673
|
+
self.assertEqual(expected, actual)
|
|
674
|
+
|
|
675
|
+
def test_move_base(self):
|
|
676
|
+
"""
|
|
677
|
+
Test moving dirents.
|
|
678
|
+
|
|
679
|
+
This test will create some additional dirents:
|
|
680
|
+
├── dir_1
|
|
681
|
+
│ └── dir_2
|
|
682
|
+
│ ├── a.txt
|
|
683
|
+
│ └── dir_empty
|
|
684
|
+
"""
|
|
685
|
+
|
|
686
|
+
# [(source, dest, no_clobber?, error substring), ...]
|
|
687
|
+
# The dest can be a single string, or a tuple of (operation input, expected output).
|
|
688
|
+
test_cases = [
|
|
689
|
+
# File
|
|
690
|
+
('a.txt', 'test.txt', False, None),
|
|
691
|
+
|
|
692
|
+
# Move into Dir - Explicit
|
|
693
|
+
('a.txt', os.path.join('dir_1', 'a.txt'), False, None),
|
|
694
|
+
|
|
695
|
+
# Move into Dir - Implicit
|
|
696
|
+
('a.txt', ('dir_1', os.path.join('dir_1', 'a.txt')), False, None),
|
|
697
|
+
|
|
698
|
+
# Move out of Dir
|
|
699
|
+
(os.path.join('dir_1', 'b.txt'), 'b.txt', False, None),
|
|
700
|
+
|
|
701
|
+
# Missing Parents
|
|
702
|
+
('a.txt', os.path.join('dir_1', 'a', 'b', 'a.txt'), False, None),
|
|
703
|
+
|
|
704
|
+
# Same File
|
|
705
|
+
('a.txt', 'a.txt', False, None),
|
|
706
|
+
|
|
707
|
+
# Clobber File with File
|
|
708
|
+
('a.txt', os.path.join('dir_1', 'b.txt'), False, None),
|
|
709
|
+
|
|
710
|
+
# No Clobber File with File
|
|
711
|
+
('a.txt', os.path.join('dir_1', 'b.txt'), True, 'Destination of move already exists'),
|
|
712
|
+
|
|
713
|
+
# Clobber File with File - Implicit
|
|
714
|
+
('a.txt', (os.path.join('dir_1', 'dir_2'), os.path.join('dir_1', 'dir_2', 'a.txt')), False, None),
|
|
715
|
+
|
|
716
|
+
# No Clobber File with File - Implicit
|
|
717
|
+
('a.txt', os.path.join('dir_1', 'dir_2'), True, 'Destination of move already exists'),
|
|
718
|
+
|
|
719
|
+
# Clobber Dir with Dir
|
|
720
|
+
('dir_empty', 'dir_1', False, None),
|
|
721
|
+
|
|
722
|
+
# Clobber Dir with Dir - Implicit
|
|
723
|
+
('dir_empty', (os.path.join('dir_1', 'dir_2'), os.path.join('dir_1', 'dir_2', 'dir_empty')), False, None),
|
|
724
|
+
|
|
725
|
+
# No Clobber Dir with Dir - Implicit
|
|
726
|
+
('dir_empty', os.path.join('dir_1', 'dir_2'), True, 'Destination of move already exists'),
|
|
727
|
+
]
|
|
728
|
+
|
|
729
|
+
for (i, test_case) in enumerate(test_cases):
|
|
730
|
+
(source, raw_dest, no_clobber, error_substring) = test_case
|
|
731
|
+
|
|
732
|
+
with self.subTest(msg = f"Case {i} ('{source}' -> '{raw_dest}'):"):
|
|
733
|
+
temp_dir = self._prep_temp_dir()
|
|
734
|
+
|
|
735
|
+
# Create the additional dirents for this test.
|
|
736
|
+
edq.util.dirent.copy(os.path.join(temp_dir, 'a.txt'), os.path.join(temp_dir, 'dir_1', 'dir_2', 'a.txt'))
|
|
737
|
+
edq.util.dirent.copy(os.path.join(temp_dir, 'dir_empty'), os.path.join(temp_dir, 'dir_1', 'dir_2', 'dir_empty'))
|
|
738
|
+
|
|
739
|
+
if (isinstance(raw_dest, tuple)):
|
|
740
|
+
(input_dest, expected_dest) = raw_dest
|
|
741
|
+
else:
|
|
742
|
+
input_dest = raw_dest
|
|
743
|
+
expected_dest = raw_dest
|
|
744
|
+
|
|
745
|
+
source = os.path.join(temp_dir, source)
|
|
746
|
+
input_dest = os.path.join(temp_dir, input_dest)
|
|
747
|
+
expected_dest = os.path.join(temp_dir, expected_dest)
|
|
748
|
+
|
|
749
|
+
try:
|
|
750
|
+
edq.util.dirent.move(source, input_dest, no_clobber = no_clobber)
|
|
751
|
+
except Exception as ex:
|
|
752
|
+
error_string = self.format_error_string(ex)
|
|
753
|
+
if (error_substring is None):
|
|
754
|
+
self.fail(f"Unexpected error: '{error_string}'.")
|
|
755
|
+
|
|
756
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
757
|
+
|
|
758
|
+
continue
|
|
759
|
+
|
|
760
|
+
if (error_substring is not None):
|
|
761
|
+
self.fail(f"Did not get expected error: '{error_substring}'.")
|
|
762
|
+
|
|
763
|
+
self._check_existing_paths(temp_dir, [expected_dest])
|
|
764
|
+
|
|
765
|
+
if (not edq.util.dirent.same(os.path.join(temp_dir, source), os.path.join(temp_dir, expected_dest))):
|
|
766
|
+
self._check_nonexisting_paths(temp_dir, [source])
|
|
767
|
+
|
|
768
|
+
def test_move_rename(self):
|
|
769
|
+
""" Test renaming dirents (via move()). """
|
|
770
|
+
|
|
771
|
+
temp_dir = self._prep_temp_dir()
|
|
772
|
+
|
|
773
|
+
# [(source, dest, expected error), ...]
|
|
774
|
+
rename_relpaths = [
|
|
775
|
+
# Symlink - File
|
|
776
|
+
('symlink_a.txt', 'rename_symlink_a.txt', None),
|
|
777
|
+
|
|
778
|
+
# Symlink - Dir
|
|
779
|
+
('symlink_dir_1', 'rename_symlink_dir_1', None),
|
|
780
|
+
|
|
781
|
+
# File in Directory
|
|
782
|
+
(os.path.join('dir_1', 'dir_2', 'c.txt'), os.path.join('dir_1', 'dir_2', 'rename_c.txt'), None),
|
|
783
|
+
|
|
784
|
+
# File
|
|
785
|
+
('a.txt', 'rename_a.txt', None),
|
|
786
|
+
|
|
787
|
+
# Empty File
|
|
788
|
+
('file_empty', 'rename_file_empty', None),
|
|
789
|
+
|
|
790
|
+
# Directory
|
|
791
|
+
('dir_1', 'rename_dir_1', None),
|
|
792
|
+
|
|
793
|
+
# Empty Directory
|
|
794
|
+
('dir_empty', 'rename_dir_empty', None),
|
|
795
|
+
|
|
796
|
+
# Non-Existent
|
|
797
|
+
('ZZZ', 'rename_ZZZ', 'Source of move does not exist'),
|
|
798
|
+
]
|
|
799
|
+
|
|
800
|
+
expected_paths = [
|
|
801
|
+
('rename_a.txt', DIRENT_TYPE_FILE),
|
|
802
|
+
('rename_dir_1', DIRENT_TYPE_DIR),
|
|
803
|
+
(os.path.join('rename_dir_1', 'b.txt'), DIRENT_TYPE_FILE),
|
|
804
|
+
(os.path.join('rename_dir_1', 'dir_2'), DIRENT_TYPE_DIR),
|
|
805
|
+
(os.path.join('rename_dir_1', 'dir_2', 'rename_c.txt'), DIRENT_TYPE_FILE),
|
|
806
|
+
('rename_dir_empty', DIRENT_TYPE_DIR),
|
|
807
|
+
('rename_file_empty', DIRENT_TYPE_FILE),
|
|
808
|
+
('rename_symlink_a.txt', DIRENT_TYPE_BROKEN_SYMLINK, True),
|
|
809
|
+
('rename_symlink_dir_1', DIRENT_TYPE_BROKEN_SYMLINK, True),
|
|
810
|
+
('symlink_dir_empty', DIRENT_TYPE_BROKEN_SYMLINK, True),
|
|
811
|
+
('symlink_file_empty', DIRENT_TYPE_BROKEN_SYMLINK, True),
|
|
812
|
+
]
|
|
813
|
+
|
|
814
|
+
unexpected_paths = [
|
|
815
|
+
'symlink_a.txt',
|
|
816
|
+
'symlink_dir_1',
|
|
817
|
+
os.path.join('dir_1', 'dir_2', 'c.txt'),
|
|
818
|
+
'a.txt',
|
|
819
|
+
'file_empty',
|
|
820
|
+
'dir_1',
|
|
821
|
+
'dir_empty',
|
|
822
|
+
'ZZZ',
|
|
823
|
+
'rename_ZZZ',
|
|
824
|
+
]
|
|
825
|
+
|
|
826
|
+
for (i, test_case) in enumerate(rename_relpaths):
|
|
827
|
+
(source, dest, error_substring) = test_case
|
|
828
|
+
|
|
829
|
+
source = os.path.join(temp_dir, source)
|
|
830
|
+
dest = os.path.join(temp_dir, dest)
|
|
831
|
+
|
|
832
|
+
try:
|
|
833
|
+
edq.util.dirent.move(source, dest)
|
|
834
|
+
except Exception as ex:
|
|
835
|
+
error_string = self.format_error_string(ex)
|
|
836
|
+
if (error_substring is None):
|
|
837
|
+
self.fail(f"Case {i}: Unexpected error: '{error_string}'.")
|
|
838
|
+
|
|
839
|
+
self.assertIn(error_substring, error_string, 'Error is not as expected.')
|
|
840
|
+
|
|
841
|
+
continue
|
|
842
|
+
|
|
843
|
+
if (error_substring is not None):
|
|
844
|
+
self.fail(f"Case {i}: Did not get expected error: '{error_substring}'.")
|
|
845
|
+
|
|
846
|
+
self._check_nonexisting_paths(temp_dir, unexpected_paths)
|
|
847
|
+
self._check_existing_paths(temp_dir, expected_paths)
|
|
848
|
+
|
|
849
|
+
def test_remove_base(self):
|
|
850
|
+
""" Test removing dirents. """
|
|
851
|
+
|
|
852
|
+
temp_dir = self._prep_temp_dir()
|
|
853
|
+
|
|
854
|
+
# Remove these paths in this order.
|
|
855
|
+
remove_relpaths = [
|
|
856
|
+
# Symlink - File
|
|
857
|
+
'symlink_a.txt',
|
|
858
|
+
|
|
859
|
+
# Symlink - Dir
|
|
860
|
+
'symlink_dir_1',
|
|
861
|
+
|
|
862
|
+
# File in Directory
|
|
863
|
+
os.path.join('dir_1', 'dir_2', 'c.txt'),
|
|
864
|
+
|
|
865
|
+
# File
|
|
866
|
+
'a.txt',
|
|
867
|
+
|
|
868
|
+
# Empty File
|
|
869
|
+
'file_empty'
|
|
870
|
+
|
|
871
|
+
# Directory
|
|
872
|
+
'dir_1',
|
|
873
|
+
|
|
874
|
+
# Empty Directory
|
|
875
|
+
'dir_empty',
|
|
876
|
+
|
|
877
|
+
# Non-Existent
|
|
878
|
+
'ZZZ',
|
|
879
|
+
]
|
|
880
|
+
|
|
881
|
+
expected_paths = [
|
|
882
|
+
(os.path.join('dir_1', 'dir_2'), DIRENT_TYPE_DIR),
|
|
883
|
+
('file_empty', DIRENT_TYPE_FILE),
|
|
884
|
+
# Windows has some symlink issues, so we will not check for this file.
|
|
885
|
+
# ('symlink_dir_empty', DIRENT_TYPE_DIR, True),
|
|
886
|
+
]
|
|
887
|
+
|
|
888
|
+
for relpath in remove_relpaths:
|
|
889
|
+
path = os.path.join(temp_dir, relpath)
|
|
890
|
+
edq.util.dirent.remove(path)
|
|
891
|
+
|
|
892
|
+
self._check_nonexisting_paths(temp_dir, remove_relpaths)
|
|
893
|
+
self._check_existing_paths(temp_dir, expected_paths)
|
|
894
|
+
|
|
895
|
+
def _prep_temp_dir(self):
|
|
896
|
+
return create_test_dir('edq_test_dirent_')
|
|
897
|
+
|
|
898
|
+
def _check_existing_paths(self, base_dir, raw_paths):
|
|
899
|
+
"""
|
|
900
|
+
Ensure that specific paths exists, and fail the test if they do not.
|
|
901
|
+
All paths should be relative to the base dir.
|
|
902
|
+
Paths can be:
|
|
903
|
+
- A string.
|
|
904
|
+
- A two-item tuple (path, dirent type).
|
|
905
|
+
- A three-item tuple (path, dirent type, is link?).
|
|
906
|
+
Missing components are not defaulted, they are just not checked.
|
|
907
|
+
"""
|
|
908
|
+
|
|
909
|
+
for raw_path in raw_paths:
|
|
910
|
+
relpath = ''
|
|
911
|
+
dirent_type = None
|
|
912
|
+
is_link = False
|
|
913
|
+
|
|
914
|
+
if (isinstance(raw_path, str)):
|
|
915
|
+
relpath = raw_path
|
|
916
|
+
elif (isinstance(raw_path, tuple)):
|
|
917
|
+
if (len(raw_path) not in [2, 3]):
|
|
918
|
+
raise ValueError(f"Expected exactly two or three items for path check, found {len(raw_path)} items: '{raw_path}'.")
|
|
919
|
+
|
|
920
|
+
relpath = raw_path[0]
|
|
921
|
+
dirent_type = raw_path[1]
|
|
922
|
+
|
|
923
|
+
if (len(raw_path) == 3):
|
|
924
|
+
is_link = raw_path[2]
|
|
925
|
+
else:
|
|
926
|
+
raise ValueError(f"Could not parse expected path ({type(raw_path)}): '{raw_path}'.")
|
|
927
|
+
|
|
928
|
+
path = os.path.join(base_dir, relpath)
|
|
929
|
+
|
|
930
|
+
# Check the path exists.
|
|
931
|
+
if (not edq.util.dirent.exists(path)):
|
|
932
|
+
self.fail(f"Expected path does not exist: '{relpath}'.")
|
|
933
|
+
|
|
934
|
+
# Check the link status.
|
|
935
|
+
if (is_link is not None):
|
|
936
|
+
if (is_link != os.path.islink(path)):
|
|
937
|
+
self.fail(f"Expected path does not have a matching link status. Expected {is_link}, but is {not is_link}: '{relpath}'.")
|
|
938
|
+
|
|
939
|
+
# Check the type of the dirent.
|
|
940
|
+
if (dirent_type is not None):
|
|
941
|
+
if (dirent_type == DIRENT_TYPE_DIR):
|
|
942
|
+
if (not os.path.isdir(path)):
|
|
943
|
+
self.fail(f"Expected path to be a directory, but it is not: '{relpath}'.")
|
|
944
|
+
elif (dirent_type == DIRENT_TYPE_FILE):
|
|
945
|
+
if (not os.path.isfile(path)):
|
|
946
|
+
self.fail(f"Expected path to be a file, but it is not: '{relpath}'.")
|
|
947
|
+
elif (dirent_type == DIRENT_TYPE_BROKEN_SYMLINK):
|
|
948
|
+
if ((not os.path.islink(path)) or os.path.isfile(path) or os.path.isdir(path)):
|
|
949
|
+
self.fail(f"Expected path to be a broken link, but it is not: '{relpath}'.")
|
|
950
|
+
else:
|
|
951
|
+
raise ValueError(f"Unknown dirent type '{dirent_type}' for path: '{relpath}'.")
|
|
952
|
+
|
|
953
|
+
def _check_nonexisting_paths(self, base_dir, raw_paths):
|
|
954
|
+
"""
|
|
955
|
+
Ensure that specific paths do not exists, and fail the test if they do exist.
|
|
956
|
+
All paths should be relative to the base dir.
|
|
957
|
+
Unlike _check_existing_paths(), paths should only be strings.
|
|
958
|
+
"""
|
|
959
|
+
|
|
960
|
+
for relpath in raw_paths:
|
|
961
|
+
path = os.path.join(base_dir, relpath)
|
|
962
|
+
|
|
963
|
+
if (edq.util.dirent.exists(path)):
|
|
964
|
+
self.fail(f"Path exists when it should not: '{relpath}'.")
|
|
965
|
+
|
|
966
|
+
def _get_dirent_type(self, path):
|
|
967
|
+
is_link = os.path.islink(path)
|
|
968
|
+
dirent_type = None
|
|
969
|
+
|
|
970
|
+
if (os.path.isdir(path)):
|
|
971
|
+
dirent_type = DIRENT_TYPE_DIR
|
|
972
|
+
elif (os.path.isfile(path)):
|
|
973
|
+
dirent_type = DIRENT_TYPE_FILE
|
|
974
|
+
elif (os.path.islink(path)):
|
|
975
|
+
dirent_type = DIRENT_TYPE_BROKEN_SYMLINK
|
|
976
|
+
else:
|
|
977
|
+
raise ValueError(f"Unknown dirent type: '{path}'.")
|
|
978
|
+
|
|
979
|
+
return dirent_type, is_link
|