diff options
Diffstat (limited to 'tests/test_manifest_xml.py')
-rw-r--r-- | tests/test_manifest_xml.py | 230 |
1 files changed, 159 insertions, 71 deletions
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py index 4b545140..f69e9cf8 100644 --- a/tests/test_manifest_xml.py +++ b/tests/test_manifest_xml.py | |||
@@ -24,6 +24,40 @@ import error | |||
24 | import manifest_xml | 24 | import manifest_xml |
25 | 25 | ||
26 | 26 | ||
27 | # Invalid paths that we don't want in the filesystem. | ||
28 | INVALID_FS_PATHS = ( | ||
29 | '', | ||
30 | '.', | ||
31 | '..', | ||
32 | '../', | ||
33 | './', | ||
34 | 'foo/', | ||
35 | './foo', | ||
36 | '../foo', | ||
37 | 'foo/./bar', | ||
38 | 'foo/../../bar', | ||
39 | '/foo', | ||
40 | './../foo', | ||
41 | '.git/foo', | ||
42 | # Check case folding. | ||
43 | '.GIT/foo', | ||
44 | 'blah/.git/foo', | ||
45 | '.repo/foo', | ||
46 | '.repoconfig', | ||
47 | # Block ~ due to 8.3 filenames on Windows filesystems. | ||
48 | '~', | ||
49 | 'foo~', | ||
50 | 'blah/foo~', | ||
51 | # Block Unicode characters that get normalized out by filesystems. | ||
52 | u'foo\u200Cbar', | ||
53 | ) | ||
54 | |||
55 | # Make sure platforms that use path separators (e.g. Windows) are also | ||
56 | # rejected properly. | ||
57 | if os.path.sep != '/': | ||
58 | INVALID_FS_PATHS += tuple(x.replace('/', os.path.sep) for x in INVALID_FS_PATHS) | ||
59 | |||
60 | |||
27 | class ManifestParseTestCase(unittest.TestCase): | 61 | class ManifestParseTestCase(unittest.TestCase): |
28 | """TestCase for parsing manifests.""" | 62 | """TestCase for parsing manifests.""" |
29 | 63 | ||
@@ -86,38 +120,7 @@ class ManifestValidateFilePaths(unittest.TestCase): | |||
86 | 120 | ||
87 | def test_bad_paths(self): | 121 | def test_bad_paths(self): |
88 | """Make sure bad paths (src & dest) are rejected.""" | 122 | """Make sure bad paths (src & dest) are rejected.""" |
89 | PATHS = ( | 123 | for path in INVALID_FS_PATHS: |
90 | '', | ||
91 | '.', | ||
92 | '..', | ||
93 | '../', | ||
94 | './', | ||
95 | 'foo/', | ||
96 | './foo', | ||
97 | '../foo', | ||
98 | 'foo/./bar', | ||
99 | 'foo/../../bar', | ||
100 | '/foo', | ||
101 | './../foo', | ||
102 | '.git/foo', | ||
103 | # Check case folding. | ||
104 | '.GIT/foo', | ||
105 | 'blah/.git/foo', | ||
106 | '.repo/foo', | ||
107 | '.repoconfig', | ||
108 | # Block ~ due to 8.3 filenames on Windows filesystems. | ||
109 | '~', | ||
110 | 'foo~', | ||
111 | 'blah/foo~', | ||
112 | # Block Unicode characters that get normalized out by filesystems. | ||
113 | u'foo\u200Cbar', | ||
114 | ) | ||
115 | # Make sure platforms that use path separators (e.g. Windows) are also | ||
116 | # rejected properly. | ||
117 | if os.path.sep != '/': | ||
118 | PATHS += tuple(x.replace('/', os.path.sep) for x in PATHS) | ||
119 | |||
120 | for path in PATHS: | ||
121 | self.assertRaises( | 124 | self.assertRaises( |
122 | error.ManifestInvalidPathError, self.check_both, path, 'a') | 125 | error.ManifestInvalidPathError, self.check_both, path, 'a') |
123 | self.assertRaises( | 126 | self.assertRaises( |
@@ -248,7 +251,82 @@ class XmlManifestTests(ManifestParseTestCase): | |||
248 | '<superproject name="superproject"/>' + | 251 | '<superproject name="superproject"/>' + |
249 | '</manifest>') | 252 | '</manifest>') |
250 | 253 | ||
251 | def test_project_group(self): | 254 | |
255 | class IncludeElementTests(ManifestParseTestCase): | ||
256 | """Tests for <include>.""" | ||
257 | |||
258 | def test_group_levels(self): | ||
259 | root_m = os.path.join(self.manifest_dir, 'root.xml') | ||
260 | with open(root_m, 'w') as fp: | ||
261 | fp.write(""" | ||
262 | <manifest> | ||
263 | <remote name="test-remote" fetch="http://localhost" /> | ||
264 | <default remote="test-remote" revision="refs/heads/main" /> | ||
265 | <include name="level1.xml" groups="level1-group" /> | ||
266 | <project name="root-name1" path="root-path1" /> | ||
267 | <project name="root-name2" path="root-path2" groups="r2g1,r2g2" /> | ||
268 | </manifest> | ||
269 | """) | ||
270 | with open(os.path.join(self.manifest_dir, 'level1.xml'), 'w') as fp: | ||
271 | fp.write(""" | ||
272 | <manifest> | ||
273 | <include name="level2.xml" groups="level2-group" /> | ||
274 | <project name="level1-name1" path="level1-path1" /> | ||
275 | </manifest> | ||
276 | """) | ||
277 | with open(os.path.join(self.manifest_dir, 'level2.xml'), 'w') as fp: | ||
278 | fp.write(""" | ||
279 | <manifest> | ||
280 | <project name="level2-name1" path="level2-path1" groups="l2g1,l2g2" /> | ||
281 | </manifest> | ||
282 | """) | ||
283 | include_m = manifest_xml.XmlManifest(self.repodir, root_m) | ||
284 | for proj in include_m.projects: | ||
285 | if proj.name == 'root-name1': | ||
286 | # Check include group not set on root level proj. | ||
287 | self.assertNotIn('level1-group', proj.groups) | ||
288 | if proj.name == 'root-name2': | ||
289 | # Check root proj group not removed. | ||
290 | self.assertIn('r2g1', proj.groups) | ||
291 | if proj.name == 'level1-name1': | ||
292 | # Check level1 proj has inherited group level 1. | ||
293 | self.assertIn('level1-group', proj.groups) | ||
294 | if proj.name == 'level2-name1': | ||
295 | # Check level2 proj has inherited group levels 1 and 2. | ||
296 | self.assertIn('level1-group', proj.groups) | ||
297 | self.assertIn('level2-group', proj.groups) | ||
298 | # Check level2 proj group not removed. | ||
299 | self.assertIn('l2g1', proj.groups) | ||
300 | |||
301 | def test_bad_name_checks(self): | ||
302 | """Check handling of bad name attribute.""" | ||
303 | def parse(name): | ||
304 | manifest = self.getXmlManifest(f""" | ||
305 | <manifest> | ||
306 | <remote name="default-remote" fetch="http://localhost" /> | ||
307 | <default remote="default-remote" revision="refs/heads/main" /> | ||
308 | <include name="{name}" /> | ||
309 | </manifest> | ||
310 | """) | ||
311 | # Force the manifest to be parsed. | ||
312 | manifest.ToXml() | ||
313 | |||
314 | # Handle empty name explicitly because a different codepath rejects it. | ||
315 | with self.assertRaises(error.ManifestParseError): | ||
316 | parse('') | ||
317 | |||
318 | for path in INVALID_FS_PATHS: | ||
319 | if not path: | ||
320 | continue | ||
321 | |||
322 | with self.assertRaises(error.ManifestInvalidPathError): | ||
323 | parse(path) | ||
324 | |||
325 | |||
326 | class ProjectElementTests(ManifestParseTestCase): | ||
327 | """Tests for <project>.""" | ||
328 | |||
329 | def test_group(self): | ||
252 | """Check project group settings.""" | 330 | """Check project group settings.""" |
253 | manifest = self.getXmlManifest(""" | 331 | manifest = self.getXmlManifest(""" |
254 | <manifest> | 332 | <manifest> |
@@ -272,7 +350,7 @@ class XmlManifestTests(ManifestParseTestCase): | |||
272 | result['extras'], | 350 | result['extras'], |
273 | ['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path']) | 351 | ['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path']) |
274 | 352 | ||
275 | def test_project_set_revision_id(self): | 353 | def test_set_revision_id(self): |
276 | """Check setting of project's revisionId.""" | 354 | """Check setting of project's revisionId.""" |
277 | manifest = self.getXmlManifest(""" | 355 | manifest = self.getXmlManifest(""" |
278 | <manifest> | 356 | <manifest> |
@@ -292,51 +370,61 @@ class XmlManifestTests(ManifestParseTestCase): | |||
292 | '<project name="test-name" revision="ABCDEF"/>' + | 370 | '<project name="test-name" revision="ABCDEF"/>' + |
293 | '</manifest>') | 371 | '</manifest>') |
294 | 372 | ||
295 | def test_include_levels(self): | 373 | def test_trailing_slash(self): |
296 | root_m = os.path.join(self.manifest_dir, 'root.xml') | 374 | """Check handling of trailing slashes in attributes.""" |
297 | with open(root_m, 'w') as fp: | 375 | def parse(name, path): |
298 | fp.write(""" | 376 | return self.getXmlManifest(f""" |
299 | <manifest> | ||
300 | <remote name="test-remote" fetch="http://localhost" /> | ||
301 | <default remote="test-remote" revision="refs/heads/main" /> | ||
302 | <include name="level1.xml" groups="level1-group" /> | ||
303 | <project name="root-name1" path="root-path1" /> | ||
304 | <project name="root-name2" path="root-path2" groups="r2g1,r2g2" /> | ||
305 | </manifest> | ||
306 | """) | ||
307 | with open(os.path.join(self.manifest_dir, 'level1.xml'), 'w') as fp: | ||
308 | fp.write(""" | ||
309 | <manifest> | 377 | <manifest> |
310 | <include name="level2.xml" groups="level2-group" /> | 378 | <remote name="default-remote" fetch="http://localhost" /> |
311 | <project name="level1-name1" path="level1-path1" /> | 379 | <default remote="default-remote" revision="refs/heads/main" /> |
380 | <project name="{name}" path="{path}" /> | ||
312 | </manifest> | 381 | </manifest> |
313 | """) | 382 | """) |
314 | with open(os.path.join(self.manifest_dir, 'level2.xml'), 'w') as fp: | 383 | |
315 | fp.write(""" | 384 | manifest = parse('a/path/', 'foo') |
385 | self.assertEqual(manifest.projects[0].gitdir, | ||
386 | os.path.join(self.tempdir, '.repo/projects/foo.git')) | ||
387 | self.assertEqual(manifest.projects[0].objdir, | ||
388 | os.path.join(self.tempdir, '.repo/project-objects/a/path.git')) | ||
389 | |||
390 | manifest = parse('a/path', 'foo/') | ||
391 | self.assertEqual(manifest.projects[0].gitdir, | ||
392 | os.path.join(self.tempdir, '.repo/projects/foo.git')) | ||
393 | self.assertEqual(manifest.projects[0].objdir, | ||
394 | os.path.join(self.tempdir, '.repo/project-objects/a/path.git')) | ||
395 | |||
396 | def test_bad_path_name_checks(self): | ||
397 | """Check handling of bad path & name attributes.""" | ||
398 | def parse(name, path): | ||
399 | manifest = self.getXmlManifest(f""" | ||
316 | <manifest> | 400 | <manifest> |
317 | <project name="level2-name1" path="level2-path1" groups="l2g1,l2g2" /> | 401 | <remote name="default-remote" fetch="http://localhost" /> |
402 | <default remote="default-remote" revision="refs/heads/main" /> | ||
403 | <project name="{name}" path="{path}" /> | ||
318 | </manifest> | 404 | </manifest> |
319 | """) | 405 | """) |
320 | include_m = manifest_xml.XmlManifest(self.repodir, root_m) | 406 | # Force the manifest to be parsed. |
321 | for proj in include_m.projects: | 407 | manifest.ToXml() |
322 | if proj.name == 'root-name1': | 408 | |
323 | # Check include group not set on root level proj. | 409 | # Verify the parser is valid by default to avoid buggy tests below. |
324 | self.assertNotIn('level1-group', proj.groups) | 410 | parse('ok', 'ok') |
325 | if proj.name == 'root-name2': | 411 | |
326 | # Check root proj group not removed. | 412 | # Handle empty name explicitly because a different codepath rejects it. |
327 | self.assertIn('r2g1', proj.groups) | 413 | # Empty path is OK because it defaults to the name field. |
328 | if proj.name == 'level1-name1': | 414 | with self.assertRaises(error.ManifestParseError): |
329 | # Check level1 proj has inherited group level 1. | 415 | parse('', 'ok') |
330 | self.assertIn('level1-group', proj.groups) | 416 | |
331 | if proj.name == 'level2-name1': | 417 | for path in INVALID_FS_PATHS: |
332 | # Check level2 proj has inherited group levels 1 and 2. | 418 | if not path or path.endswith('/'): |
333 | self.assertIn('level1-group', proj.groups) | 419 | continue |
334 | self.assertIn('level2-group', proj.groups) | 420 | |
335 | # Check level2 proj group not removed. | 421 | with self.assertRaises(error.ManifestInvalidPathError): |
336 | self.assertIn('l2g1', proj.groups) | 422 | parse(path, 'ok') |
423 | with self.assertRaises(error.ManifestInvalidPathError): | ||
424 | parse('ok', path) | ||
337 | 425 | ||
338 | 426 | ||
339 | class SuperProjectTests(ManifestParseTestCase): | 427 | class SuperProjectElementTests(ManifestParseTestCase): |
340 | """Tests for <superproject>.""" | 428 | """Tests for <superproject>.""" |
341 | 429 | ||
342 | def test_superproject(self): | 430 | def test_superproject(self): |