summaryrefslogtreecommitdiffstats
path: root/tests/test_manifest_xml.py
diff options
context:
space:
mode:
authorGavin Mak <gavinmak@google.com>2023-03-11 06:46:20 +0000
committerLUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-22 17:46:28 +0000
commitea2e330e43c182dc16b0111ebc69ee5a71ee4ce1 (patch)
treedc33ba0e56825b3e007d0589891756724725a465 /tests/test_manifest_xml.py
parent1604cf255f8c1786a23388db6d5277ac7949a24a (diff)
downloadgit-repo-ea2e330e43c182dc16b0111ebc69ee5a71ee4ce1.tar.gz
Format codebase with black and check formatting in CQ
Apply rules set by https://gerrit-review.googlesource.com/c/git-repo/+/362954/ across the codebase and fix any lingering errors caught by flake8. Also check black formatting in run_tests (and CQ). Bug: b/267675342 Change-Id: I972d77649dac351150dcfeb1cd1ad0ea2efc1956 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/363474 Reviewed-by: Mike Frysinger <vapier@google.com> Tested-by: Gavin Mak <gavinmak@google.com> Commit-Queue: Gavin Mak <gavinmak@google.com>
Diffstat (limited to 'tests/test_manifest_xml.py')
-rw-r--r--tests/test_manifest_xml.py1414
1 files changed, 776 insertions, 638 deletions
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index 3634701f..648acde8 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -27,291 +27,318 @@ import manifest_xml
27 27
28# Invalid paths that we don't want in the filesystem. 28# Invalid paths that we don't want in the filesystem.
29INVALID_FS_PATHS = ( 29INVALID_FS_PATHS = (
30 '', 30 "",
31 '.', 31 ".",
32 '..', 32 "..",
33 '../', 33 "../",
34 './', 34 "./",
35 './/', 35 ".//",
36 'foo/', 36 "foo/",
37 './foo', 37 "./foo",
38 '../foo', 38 "../foo",
39 'foo/./bar', 39 "foo/./bar",
40 'foo/../../bar', 40 "foo/../../bar",
41 '/foo', 41 "/foo",
42 './../foo', 42 "./../foo",
43 '.git/foo', 43 ".git/foo",
44 # Check case folding. 44 # Check case folding.
45 '.GIT/foo', 45 ".GIT/foo",
46 'blah/.git/foo', 46 "blah/.git/foo",
47 '.repo/foo', 47 ".repo/foo",
48 '.repoconfig', 48 ".repoconfig",
49 # Block ~ due to 8.3 filenames on Windows filesystems. 49 # Block ~ due to 8.3 filenames on Windows filesystems.
50 '~', 50 "~",
51 'foo~', 51 "foo~",
52 'blah/foo~', 52 "blah/foo~",
53 # Block Unicode characters that get normalized out by filesystems. 53 # Block Unicode characters that get normalized out by filesystems.
54 u'foo\u200Cbar', 54 "foo\u200Cbar",
55 # Block newlines. 55 # Block newlines.
56 'f\n/bar', 56 "f\n/bar",
57 'f\r/bar', 57 "f\r/bar",
58) 58)
59 59
60# Make sure platforms that use path separators (e.g. Windows) are also 60# Make sure platforms that use path separators (e.g. Windows) are also
61# rejected properly. 61# rejected properly.
62if os.path.sep != '/': 62if os.path.sep != "/":
63 INVALID_FS_PATHS += tuple(x.replace('/', os.path.sep) for x in INVALID_FS_PATHS) 63 INVALID_FS_PATHS += tuple(
64 x.replace("/", os.path.sep) for x in INVALID_FS_PATHS
65 )
64 66
65 67
66def sort_attributes(manifest): 68def sort_attributes(manifest):
67 """Sort the attributes of all elements alphabetically. 69 """Sort the attributes of all elements alphabetically.
68 70
69 This is needed because different versions of the toxml() function from 71 This is needed because different versions of the toxml() function from
70 xml.dom.minidom outputs the attributes of elements in different orders. 72 xml.dom.minidom outputs the attributes of elements in different orders.
71 Before Python 3.8 they were output alphabetically, later versions preserve 73 Before Python 3.8 they were output alphabetically, later versions preserve
72 the order specified by the user. 74 the order specified by the user.
73 75
74 Args: 76 Args:
75 manifest: String containing an XML manifest. 77 manifest: String containing an XML manifest.
76 78
77 Returns: 79 Returns:
78 The XML manifest with the attributes of all elements sorted alphabetically. 80 The XML manifest with the attributes of all elements sorted
79 """ 81 alphabetically.
80 new_manifest = '' 82 """
81 # This will find every element in the XML manifest, whether they have 83 new_manifest = ""
82 # attributes or not. This simplifies recreating the manifest below. 84 # This will find every element in the XML manifest, whether they have
83 matches = re.findall(r'(<[/?]?[a-z-]+\s*)((?:\S+?="[^"]+"\s*?)*)(\s*[/?]?>)', manifest) 85 # attributes or not. This simplifies recreating the manifest below.
84 for head, attrs, tail in matches: 86 matches = re.findall(
85 m = re.findall(r'\S+?="[^"]+"', attrs) 87 r'(<[/?]?[a-z-]+\s*)((?:\S+?="[^"]+"\s*?)*)(\s*[/?]?>)', manifest
86 new_manifest += head + ' '.join(sorted(m)) + tail 88 )
87 return new_manifest 89 for head, attrs, tail in matches:
90 m = re.findall(r'\S+?="[^"]+"', attrs)
91 new_manifest += head + " ".join(sorted(m)) + tail
92 return new_manifest
88 93
89 94
90class ManifestParseTestCase(unittest.TestCase): 95class ManifestParseTestCase(unittest.TestCase):
91 """TestCase for parsing manifests.""" 96 """TestCase for parsing manifests."""
92 97
93 def setUp(self): 98 def setUp(self):
94 self.tempdirobj = tempfile.TemporaryDirectory(prefix='repo_tests') 99 self.tempdirobj = tempfile.TemporaryDirectory(prefix="repo_tests")
95 self.tempdir = self.tempdirobj.name 100 self.tempdir = self.tempdirobj.name
96 self.repodir = os.path.join(self.tempdir, '.repo') 101 self.repodir = os.path.join(self.tempdir, ".repo")
97 self.manifest_dir = os.path.join(self.repodir, 'manifests') 102 self.manifest_dir = os.path.join(self.repodir, "manifests")
98 self.manifest_file = os.path.join( 103 self.manifest_file = os.path.join(
99 self.repodir, manifest_xml.MANIFEST_FILE_NAME) 104 self.repodir, manifest_xml.MANIFEST_FILE_NAME
100 self.local_manifest_dir = os.path.join( 105 )
101 self.repodir, manifest_xml.LOCAL_MANIFESTS_DIR_NAME) 106 self.local_manifest_dir = os.path.join(
102 os.mkdir(self.repodir) 107 self.repodir, manifest_xml.LOCAL_MANIFESTS_DIR_NAME
103 os.mkdir(self.manifest_dir) 108 )
104 109 os.mkdir(self.repodir)
105 # The manifest parsing really wants a git repo currently. 110 os.mkdir(self.manifest_dir)
106 gitdir = os.path.join(self.repodir, 'manifests.git') 111
107 os.mkdir(gitdir) 112 # The manifest parsing really wants a git repo currently.
108 with open(os.path.join(gitdir, 'config'), 'w') as fp: 113 gitdir = os.path.join(self.repodir, "manifests.git")
109 fp.write("""[remote "origin"] 114 os.mkdir(gitdir)
115 with open(os.path.join(gitdir, "config"), "w") as fp:
116 fp.write(
117 """[remote "origin"]
110 url = https://localhost:0/manifest 118 url = https://localhost:0/manifest
111""") 119"""
120 )
112 121
113 def tearDown(self): 122 def tearDown(self):
114 self.tempdirobj.cleanup() 123 self.tempdirobj.cleanup()
115 124
116 def getXmlManifest(self, data): 125 def getXmlManifest(self, data):
117 """Helper to initialize a manifest for testing.""" 126 """Helper to initialize a manifest for testing."""
118 with open(self.manifest_file, 'w', encoding="utf-8") as fp: 127 with open(self.manifest_file, "w", encoding="utf-8") as fp:
119 fp.write(data) 128 fp.write(data)
120 return manifest_xml.XmlManifest(self.repodir, self.manifest_file) 129 return manifest_xml.XmlManifest(self.repodir, self.manifest_file)
121 130
122 @staticmethod 131 @staticmethod
123 def encodeXmlAttr(attr): 132 def encodeXmlAttr(attr):
124 """Encode |attr| using XML escape rules.""" 133 """Encode |attr| using XML escape rules."""
125 return attr.replace('\r', '&#x000d;').replace('\n', '&#x000a;') 134 return attr.replace("\r", "&#x000d;").replace("\n", "&#x000a;")
126 135
127 136
128class ManifestValidateFilePaths(unittest.TestCase): 137class ManifestValidateFilePaths(unittest.TestCase):
129 """Check _ValidateFilePaths helper. 138 """Check _ValidateFilePaths helper.
130 139
131 This doesn't access a real filesystem. 140 This doesn't access a real filesystem.
132 """ 141 """
133 142
134 def check_both(self, *args): 143 def check_both(self, *args):
135 manifest_xml.XmlManifest._ValidateFilePaths('copyfile', *args) 144 manifest_xml.XmlManifest._ValidateFilePaths("copyfile", *args)
136 manifest_xml.XmlManifest._ValidateFilePaths('linkfile', *args) 145 manifest_xml.XmlManifest._ValidateFilePaths("linkfile", *args)
137 146
138 def test_normal_path(self): 147 def test_normal_path(self):
139 """Make sure good paths are accepted.""" 148 """Make sure good paths are accepted."""
140 self.check_both('foo', 'bar') 149 self.check_both("foo", "bar")
141 self.check_both('foo/bar', 'bar') 150 self.check_both("foo/bar", "bar")
142 self.check_both('foo', 'bar/bar') 151 self.check_both("foo", "bar/bar")
143 self.check_both('foo/bar', 'bar/bar') 152 self.check_both("foo/bar", "bar/bar")
144 153
145 def test_symlink_targets(self): 154 def test_symlink_targets(self):
146 """Some extra checks for symlinks.""" 155 """Some extra checks for symlinks."""
147 def check(*args): 156
148 manifest_xml.XmlManifest._ValidateFilePaths('linkfile', *args) 157 def check(*args):
149 158 manifest_xml.XmlManifest._ValidateFilePaths("linkfile", *args)
150 # We allow symlinks to end in a slash since we allow them to point to dirs 159
151 # in general. Technically the slash isn't necessary. 160 # We allow symlinks to end in a slash since we allow them to point to
152 check('foo/', 'bar') 161 # dirs in general. Technically the slash isn't necessary.
153 # We allow a single '.' to get a reference to the project itself. 162 check("foo/", "bar")
154 check('.', 'bar') 163 # We allow a single '.' to get a reference to the project itself.
155 164 check(".", "bar")
156 def test_bad_paths(self): 165
157 """Make sure bad paths (src & dest) are rejected.""" 166 def test_bad_paths(self):
158 for path in INVALID_FS_PATHS: 167 """Make sure bad paths (src & dest) are rejected."""
159 self.assertRaises( 168 for path in INVALID_FS_PATHS:
160 error.ManifestInvalidPathError, self.check_both, path, 'a') 169 self.assertRaises(
161 self.assertRaises( 170 error.ManifestInvalidPathError, self.check_both, path, "a"
162 error.ManifestInvalidPathError, self.check_both, 'a', path) 171 )
172 self.assertRaises(
173 error.ManifestInvalidPathError, self.check_both, "a", path
174 )
163 175
164 176
165class ValueTests(unittest.TestCase): 177class ValueTests(unittest.TestCase):
166 """Check utility parsing code.""" 178 """Check utility parsing code."""
167 179
168 def _get_node(self, text): 180 def _get_node(self, text):
169 return xml.dom.minidom.parseString(text).firstChild 181 return xml.dom.minidom.parseString(text).firstChild
170 182
171 def test_bool_default(self): 183 def test_bool_default(self):
172 """Check XmlBool default handling.""" 184 """Check XmlBool default handling."""
173 node = self._get_node('<node/>') 185 node = self._get_node("<node/>")
174 self.assertIsNone(manifest_xml.XmlBool(node, 'a')) 186 self.assertIsNone(manifest_xml.XmlBool(node, "a"))
175 self.assertIsNone(manifest_xml.XmlBool(node, 'a', None)) 187 self.assertIsNone(manifest_xml.XmlBool(node, "a", None))
176 self.assertEqual(123, manifest_xml.XmlBool(node, 'a', 123)) 188 self.assertEqual(123, manifest_xml.XmlBool(node, "a", 123))
177 189
178 node = self._get_node('<node a=""/>') 190 node = self._get_node('<node a=""/>')
179 self.assertIsNone(manifest_xml.XmlBool(node, 'a')) 191 self.assertIsNone(manifest_xml.XmlBool(node, "a"))
180 192
181 def test_bool_invalid(self): 193 def test_bool_invalid(self):
182 """Check XmlBool invalid handling.""" 194 """Check XmlBool invalid handling."""
183 node = self._get_node('<node a="moo"/>') 195 node = self._get_node('<node a="moo"/>')
184 self.assertEqual(123, manifest_xml.XmlBool(node, 'a', 123)) 196 self.assertEqual(123, manifest_xml.XmlBool(node, "a", 123))
185 197
186 def test_bool_true(self): 198 def test_bool_true(self):
187 """Check XmlBool true values.""" 199 """Check XmlBool true values."""
188 for value in ('yes', 'true', '1'): 200 for value in ("yes", "true", "1"):
189 node = self._get_node('<node a="%s"/>' % (value,)) 201 node = self._get_node('<node a="%s"/>' % (value,))
190 self.assertTrue(manifest_xml.XmlBool(node, 'a')) 202 self.assertTrue(manifest_xml.XmlBool(node, "a"))
191 203
192 def test_bool_false(self): 204 def test_bool_false(self):
193 """Check XmlBool false values.""" 205 """Check XmlBool false values."""
194 for value in ('no', 'false', '0'): 206 for value in ("no", "false", "0"):
195 node = self._get_node('<node a="%s"/>' % (value,)) 207 node = self._get_node('<node a="%s"/>' % (value,))
196 self.assertFalse(manifest_xml.XmlBool(node, 'a')) 208 self.assertFalse(manifest_xml.XmlBool(node, "a"))
197 209
198 def test_int_default(self): 210 def test_int_default(self):
199 """Check XmlInt default handling.""" 211 """Check XmlInt default handling."""
200 node = self._get_node('<node/>') 212 node = self._get_node("<node/>")
201 self.assertIsNone(manifest_xml.XmlInt(node, 'a')) 213 self.assertIsNone(manifest_xml.XmlInt(node, "a"))
202 self.assertIsNone(manifest_xml.XmlInt(node, 'a', None)) 214 self.assertIsNone(manifest_xml.XmlInt(node, "a", None))
203 self.assertEqual(123, manifest_xml.XmlInt(node, 'a', 123)) 215 self.assertEqual(123, manifest_xml.XmlInt(node, "a", 123))
204 216
205 node = self._get_node('<node a=""/>') 217 node = self._get_node('<node a=""/>')
206 self.assertIsNone(manifest_xml.XmlInt(node, 'a')) 218 self.assertIsNone(manifest_xml.XmlInt(node, "a"))
207 219
208 def test_int_good(self): 220 def test_int_good(self):
209 """Check XmlInt numeric handling.""" 221 """Check XmlInt numeric handling."""
210 for value in (-1, 0, 1, 50000): 222 for value in (-1, 0, 1, 50000):
211 node = self._get_node('<node a="%s"/>' % (value,)) 223 node = self._get_node('<node a="%s"/>' % (value,))
212 self.assertEqual(value, manifest_xml.XmlInt(node, 'a')) 224 self.assertEqual(value, manifest_xml.XmlInt(node, "a"))
213 225
214 def test_int_invalid(self): 226 def test_int_invalid(self):
215 """Check XmlInt invalid handling.""" 227 """Check XmlInt invalid handling."""
216 with self.assertRaises(error.ManifestParseError): 228 with self.assertRaises(error.ManifestParseError):
217 node = self._get_node('<node a="xx"/>') 229 node = self._get_node('<node a="xx"/>')
218 manifest_xml.XmlInt(node, 'a') 230 manifest_xml.XmlInt(node, "a")
219 231
220 232
221class XmlManifestTests(ManifestParseTestCase): 233class XmlManifestTests(ManifestParseTestCase):
222 """Check manifest processing.""" 234 """Check manifest processing."""
223 235
224 def test_empty(self): 236 def test_empty(self):
225 """Parse an 'empty' manifest file.""" 237 """Parse an 'empty' manifest file."""
226 manifest = self.getXmlManifest( 238 manifest = self.getXmlManifest(
227 '<?xml version="1.0" encoding="UTF-8"?>' 239 '<?xml version="1.0" encoding="UTF-8"?>' "<manifest></manifest>"
228 '<manifest></manifest>') 240 )
229 self.assertEqual(manifest.remotes, {}) 241 self.assertEqual(manifest.remotes, {})
230 self.assertEqual(manifest.projects, []) 242 self.assertEqual(manifest.projects, [])
231 243
232 def test_link(self): 244 def test_link(self):
233 """Verify Link handling with new names.""" 245 """Verify Link handling with new names."""
234 manifest = manifest_xml.XmlManifest(self.repodir, self.manifest_file) 246 manifest = manifest_xml.XmlManifest(self.repodir, self.manifest_file)
235 with open(os.path.join(self.manifest_dir, 'foo.xml'), 'w') as fp: 247 with open(os.path.join(self.manifest_dir, "foo.xml"), "w") as fp:
236 fp.write('<manifest></manifest>') 248 fp.write("<manifest></manifest>")
237 manifest.Link('foo.xml') 249 manifest.Link("foo.xml")
238 with open(self.manifest_file) as fp: 250 with open(self.manifest_file) as fp:
239 self.assertIn('<include name="foo.xml" />', fp.read()) 251 self.assertIn('<include name="foo.xml" />', fp.read())
240 252
241 def test_toxml_empty(self): 253 def test_toxml_empty(self):
242 """Verify the ToXml() helper.""" 254 """Verify the ToXml() helper."""
243 manifest = self.getXmlManifest( 255 manifest = self.getXmlManifest(
244 '<?xml version="1.0" encoding="UTF-8"?>' 256 '<?xml version="1.0" encoding="UTF-8"?>' "<manifest></manifest>"
245 '<manifest></manifest>') 257 )
246 self.assertEqual(manifest.ToXml().toxml(), '<?xml version="1.0" ?><manifest/>') 258 self.assertEqual(
247 259 manifest.ToXml().toxml(), '<?xml version="1.0" ?><manifest/>'
248 def test_todict_empty(self): 260 )
249 """Verify the ToDict() helper.""" 261
250 manifest = self.getXmlManifest( 262 def test_todict_empty(self):
251 '<?xml version="1.0" encoding="UTF-8"?>' 263 """Verify the ToDict() helper."""
252 '<manifest></manifest>') 264 manifest = self.getXmlManifest(
253 self.assertEqual(manifest.ToDict(), {}) 265 '<?xml version="1.0" encoding="UTF-8"?>' "<manifest></manifest>"
254 266 )
255 def test_toxml_omit_local(self): 267 self.assertEqual(manifest.ToDict(), {})
256 """Does not include local_manifests projects when omit_local=True.""" 268
257 manifest = self.getXmlManifest( 269 def test_toxml_omit_local(self):
258 '<?xml version="1.0" encoding="UTF-8"?><manifest>' 270 """Does not include local_manifests projects when omit_local=True."""
259 '<remote name="a" fetch=".."/><default remote="a" revision="r"/>' 271 manifest = self.getXmlManifest(
260 '<project name="p" groups="local::me"/>' 272 '<?xml version="1.0" encoding="UTF-8"?><manifest>'
261 '<project name="q"/>' 273 '<remote name="a" fetch=".."/><default remote="a" revision="r"/>'
262 '<project name="r" groups="keep"/>' 274 '<project name="p" groups="local::me"/>'
263 '</manifest>') 275 '<project name="q"/>'
264 self.assertEqual( 276 '<project name="r" groups="keep"/>'
265 sort_attributes(manifest.ToXml(omit_local=True).toxml()), 277 "</manifest>"
266 '<?xml version="1.0" ?><manifest>' 278 )
267 '<remote fetch=".." name="a"/><default remote="a" revision="r"/>' 279 self.assertEqual(
268 '<project name="q"/><project groups="keep" name="r"/></manifest>') 280 sort_attributes(manifest.ToXml(omit_local=True).toxml()),
269 281 '<?xml version="1.0" ?><manifest>'
270 def test_toxml_with_local(self): 282 '<remote fetch=".." name="a"/><default remote="a" revision="r"/>'
271 """Does include local_manifests projects when omit_local=False.""" 283 '<project name="q"/><project groups="keep" name="r"/></manifest>',
272 manifest = self.getXmlManifest( 284 )
273 '<?xml version="1.0" encoding="UTF-8"?><manifest>' 285
274 '<remote name="a" fetch=".."/><default remote="a" revision="r"/>' 286 def test_toxml_with_local(self):
275 '<project name="p" groups="local::me"/>' 287 """Does include local_manifests projects when omit_local=False."""
276 '<project name="q"/>' 288 manifest = self.getXmlManifest(
277 '<project name="r" groups="keep"/>' 289 '<?xml version="1.0" encoding="UTF-8"?><manifest>'
278 '</manifest>') 290 '<remote name="a" fetch=".."/><default remote="a" revision="r"/>'
279 self.assertEqual( 291 '<project name="p" groups="local::me"/>'
280 sort_attributes(manifest.ToXml(omit_local=False).toxml()), 292 '<project name="q"/>'
281 '<?xml version="1.0" ?><manifest>' 293 '<project name="r" groups="keep"/>'
282 '<remote fetch=".." name="a"/><default remote="a" revision="r"/>' 294 "</manifest>"
283 '<project groups="local::me" name="p"/>' 295 )
284 '<project name="q"/><project groups="keep" name="r"/></manifest>') 296 self.assertEqual(
285 297 sort_attributes(manifest.ToXml(omit_local=False).toxml()),
286 def test_repo_hooks(self): 298 '<?xml version="1.0" ?><manifest>'
287 """Check repo-hooks settings.""" 299 '<remote fetch=".." name="a"/><default remote="a" revision="r"/>'
288 manifest = self.getXmlManifest(""" 300 '<project groups="local::me" name="p"/>'
301 '<project name="q"/><project groups="keep" name="r"/></manifest>',
302 )
303
304 def test_repo_hooks(self):
305 """Check repo-hooks settings."""
306 manifest = self.getXmlManifest(
307 """
289<manifest> 308<manifest>
290 <remote name="test-remote" fetch="http://localhost" /> 309 <remote name="test-remote" fetch="http://localhost" />
291 <default remote="test-remote" revision="refs/heads/main" /> 310 <default remote="test-remote" revision="refs/heads/main" />
292 <project name="repohooks" path="src/repohooks"/> 311 <project name="repohooks" path="src/repohooks"/>
293 <repo-hooks in-project="repohooks" enabled-list="a, b"/> 312 <repo-hooks in-project="repohooks" enabled-list="a, b"/>
294</manifest> 313</manifest>
295""") 314"""
296 self.assertEqual(manifest.repo_hooks_project.name, 'repohooks') 315 )
297 self.assertEqual(manifest.repo_hooks_project.enabled_repo_hooks, ['a', 'b']) 316 self.assertEqual(manifest.repo_hooks_project.name, "repohooks")
298 317 self.assertEqual(
299 def test_repo_hooks_unordered(self): 318 manifest.repo_hooks_project.enabled_repo_hooks, ["a", "b"]
300 """Check repo-hooks settings work even if the project def comes second.""" 319 )
301 manifest = self.getXmlManifest(""" 320
321 def test_repo_hooks_unordered(self):
322 """Check repo-hooks settings work even if the project def comes second.""" # noqa: E501
323 manifest = self.getXmlManifest(
324 """
302<manifest> 325<manifest>
303 <remote name="test-remote" fetch="http://localhost" /> 326 <remote name="test-remote" fetch="http://localhost" />
304 <default remote="test-remote" revision="refs/heads/main" /> 327 <default remote="test-remote" revision="refs/heads/main" />
305 <repo-hooks in-project="repohooks" enabled-list="a, b"/> 328 <repo-hooks in-project="repohooks" enabled-list="a, b"/>
306 <project name="repohooks" path="src/repohooks"/> 329 <project name="repohooks" path="src/repohooks"/>
307</manifest> 330</manifest>
308""") 331"""
309 self.assertEqual(manifest.repo_hooks_project.name, 'repohooks') 332 )
310 self.assertEqual(manifest.repo_hooks_project.enabled_repo_hooks, ['a', 'b']) 333 self.assertEqual(manifest.repo_hooks_project.name, "repohooks")
311 334 self.assertEqual(
312 def test_unknown_tags(self): 335 manifest.repo_hooks_project.enabled_repo_hooks, ["a", "b"]
313 """Check superproject settings.""" 336 )
314 manifest = self.getXmlManifest(""" 337
338 def test_unknown_tags(self):
339 """Check superproject settings."""
340 manifest = self.getXmlManifest(
341 """
315<manifest> 342<manifest>
316 <remote name="test-remote" fetch="http://localhost" /> 343 <remote name="test-remote" fetch="http://localhost" />
317 <default remote="test-remote" revision="refs/heads/main" /> 344 <default remote="test-remote" revision="refs/heads/main" />
@@ -319,44 +346,54 @@ class XmlManifestTests(ManifestParseTestCase):
319 <iankaz value="unknown (possible) future tags are ignored"/> 346 <iankaz value="unknown (possible) future tags are ignored"/>
320 <x-custom-tag>X tags are always ignored</x-custom-tag> 347 <x-custom-tag>X tags are always ignored</x-custom-tag>
321</manifest> 348</manifest>
322""") 349"""
323 self.assertEqual(manifest.superproject.name, 'superproject') 350 )
324 self.assertEqual(manifest.superproject.remote.name, 'test-remote') 351 self.assertEqual(manifest.superproject.name, "superproject")
325 self.assertEqual( 352 self.assertEqual(manifest.superproject.remote.name, "test-remote")
326 sort_attributes(manifest.ToXml().toxml()), 353 self.assertEqual(
327 '<?xml version="1.0" ?><manifest>' 354 sort_attributes(manifest.ToXml().toxml()),
328 '<remote fetch="http://localhost" name="test-remote"/>' 355 '<?xml version="1.0" ?><manifest>'
329 '<default remote="test-remote" revision="refs/heads/main"/>' 356 '<remote fetch="http://localhost" name="test-remote"/>'
330 '<superproject name="superproject"/>' 357 '<default remote="test-remote" revision="refs/heads/main"/>'
331 '</manifest>') 358 '<superproject name="superproject"/>'
332 359 "</manifest>",
333 def test_remote_annotations(self): 360 )
334 """Check remote settings.""" 361
335 manifest = self.getXmlManifest(""" 362 def test_remote_annotations(self):
363 """Check remote settings."""
364 manifest = self.getXmlManifest(
365 """
336<manifest> 366<manifest>
337 <remote name="test-remote" fetch="http://localhost"> 367 <remote name="test-remote" fetch="http://localhost">
338 <annotation name="foo" value="bar"/> 368 <annotation name="foo" value="bar"/>
339 </remote> 369 </remote>
340</manifest> 370</manifest>
341""") 371"""
342 self.assertEqual(manifest.remotes['test-remote'].annotations[0].name, 'foo') 372 )
343 self.assertEqual(manifest.remotes['test-remote'].annotations[0].value, 'bar') 373 self.assertEqual(
344 self.assertEqual( 374 manifest.remotes["test-remote"].annotations[0].name, "foo"
345 sort_attributes(manifest.ToXml().toxml()), 375 )
346 '<?xml version="1.0" ?><manifest>' 376 self.assertEqual(
347 '<remote fetch="http://localhost" name="test-remote">' 377 manifest.remotes["test-remote"].annotations[0].value, "bar"
348 '<annotation name="foo" value="bar"/>' 378 )
349 '</remote>' 379 self.assertEqual(
350 '</manifest>') 380 sort_attributes(manifest.ToXml().toxml()),
381 '<?xml version="1.0" ?><manifest>'
382 '<remote fetch="http://localhost" name="test-remote">'
383 '<annotation name="foo" value="bar"/>'
384 "</remote>"
385 "</manifest>",
386 )
351 387
352 388
353class IncludeElementTests(ManifestParseTestCase): 389class IncludeElementTests(ManifestParseTestCase):
354 """Tests for <include>.""" 390 """Tests for <include>."""
355 391
356 def test_group_levels(self): 392 def test_group_levels(self):
357 root_m = os.path.join(self.manifest_dir, 'root.xml') 393 root_m = os.path.join(self.manifest_dir, "root.xml")
358 with open(root_m, 'w') as fp: 394 with open(root_m, "w") as fp:
359 fp.write(""" 395 fp.write(
396 """
360<manifest> 397<manifest>
361 <remote name="test-remote" fetch="http://localhost" /> 398 <remote name="test-remote" fetch="http://localhost" />
362 <default remote="test-remote" revision="refs/heads/main" /> 399 <default remote="test-remote" revision="refs/heads/main" />
@@ -364,438 +401,524 @@ class IncludeElementTests(ManifestParseTestCase):
364 <project name="root-name1" path="root-path1" /> 401 <project name="root-name1" path="root-path1" />
365 <project name="root-name2" path="root-path2" groups="r2g1,r2g2" /> 402 <project name="root-name2" path="root-path2" groups="r2g1,r2g2" />
366</manifest> 403</manifest>
367""") 404"""
368 with open(os.path.join(self.manifest_dir, 'level1.xml'), 'w') as fp: 405 )
369 fp.write(""" 406 with open(os.path.join(self.manifest_dir, "level1.xml"), "w") as fp:
407 fp.write(
408 """
370<manifest> 409<manifest>
371 <include name="level2.xml" groups="level2-group" /> 410 <include name="level2.xml" groups="level2-group" />
372 <project name="level1-name1" path="level1-path1" /> 411 <project name="level1-name1" path="level1-path1" />
373</manifest> 412</manifest>
374""") 413"""
375 with open(os.path.join(self.manifest_dir, 'level2.xml'), 'w') as fp: 414 )
376 fp.write(""" 415 with open(os.path.join(self.manifest_dir, "level2.xml"), "w") as fp:
416 fp.write(
417 """
377<manifest> 418<manifest>
378 <project name="level2-name1" path="level2-path1" groups="l2g1,l2g2" /> 419 <project name="level2-name1" path="level2-path1" groups="l2g1,l2g2" />
379</manifest> 420</manifest>
380""") 421"""
381 include_m = manifest_xml.XmlManifest(self.repodir, root_m) 422 )
382 for proj in include_m.projects: 423 include_m = manifest_xml.XmlManifest(self.repodir, root_m)
383 if proj.name == 'root-name1': 424 for proj in include_m.projects:
384 # Check include group not set on root level proj. 425 if proj.name == "root-name1":
385 self.assertNotIn('level1-group', proj.groups) 426 # Check include group not set on root level proj.
386 if proj.name == 'root-name2': 427 self.assertNotIn("level1-group", proj.groups)
387 # Check root proj group not removed. 428 if proj.name == "root-name2":
388 self.assertIn('r2g1', proj.groups) 429 # Check root proj group not removed.
389 if proj.name == 'level1-name1': 430 self.assertIn("r2g1", proj.groups)
390 # Check level1 proj has inherited group level 1. 431 if proj.name == "level1-name1":
391 self.assertIn('level1-group', proj.groups) 432 # Check level1 proj has inherited group level 1.
392 if proj.name == 'level2-name1': 433 self.assertIn("level1-group", proj.groups)
393 # Check level2 proj has inherited group levels 1 and 2. 434 if proj.name == "level2-name1":
394 self.assertIn('level1-group', proj.groups) 435 # Check level2 proj has inherited group levels 1 and 2.
395 self.assertIn('level2-group', proj.groups) 436 self.assertIn("level1-group", proj.groups)
396 # Check level2 proj group not removed. 437 self.assertIn("level2-group", proj.groups)
397 self.assertIn('l2g1', proj.groups) 438 # Check level2 proj group not removed.
398 439 self.assertIn("l2g1", proj.groups)
399 def test_allow_bad_name_from_user(self): 440
400 """Check handling of bad name attribute from the user's input.""" 441 def test_allow_bad_name_from_user(self):
401 def parse(name): 442 """Check handling of bad name attribute from the user's input."""
402 name = self.encodeXmlAttr(name) 443
403 manifest = self.getXmlManifest(f""" 444 def parse(name):
445 name = self.encodeXmlAttr(name)
446 manifest = self.getXmlManifest(
447 f"""
404<manifest> 448<manifest>
405 <remote name="default-remote" fetch="http://localhost" /> 449 <remote name="default-remote" fetch="http://localhost" />
406 <default remote="default-remote" revision="refs/heads/main" /> 450 <default remote="default-remote" revision="refs/heads/main" />
407 <include name="{name}" /> 451 <include name="{name}" />
408</manifest> 452</manifest>
409""") 453"""
410 # Force the manifest to be parsed. 454 )
411 manifest.ToXml() 455 # Force the manifest to be parsed.
412 456 manifest.ToXml()
413 # Setup target of the include. 457
414 target = os.path.join(self.tempdir, 'target.xml') 458 # Setup target of the include.
415 with open(target, 'w') as fp: 459 target = os.path.join(self.tempdir, "target.xml")
416 fp.write('<manifest></manifest>') 460 with open(target, "w") as fp:
417 461 fp.write("<manifest></manifest>")
418 # Include with absolute path. 462
419 parse(os.path.abspath(target)) 463 # Include with absolute path.
420 464 parse(os.path.abspath(target))
421 # Include with relative path. 465
422 parse(os.path.relpath(target, self.manifest_dir)) 466 # Include with relative path.
423 467 parse(os.path.relpath(target, self.manifest_dir))
424 def test_bad_name_checks(self): 468
425 """Check handling of bad name attribute.""" 469 def test_bad_name_checks(self):
426 def parse(name): 470 """Check handling of bad name attribute."""
427 name = self.encodeXmlAttr(name) 471
428 # Setup target of the include. 472 def parse(name):
429 with open(os.path.join(self.manifest_dir, 'target.xml'), 'w', encoding="utf-8") as fp: 473 name = self.encodeXmlAttr(name)
430 fp.write(f'<manifest><include name="{name}"/></manifest>') 474 # Setup target of the include.
431 475 with open(
432 manifest = self.getXmlManifest(""" 476 os.path.join(self.manifest_dir, "target.xml"),
477 "w",
478 encoding="utf-8",
479 ) as fp:
480 fp.write(f'<manifest><include name="{name}"/></manifest>')
481
482 manifest = self.getXmlManifest(
483 """
433<manifest> 484<manifest>
434 <remote name="default-remote" fetch="http://localhost" /> 485 <remote name="default-remote" fetch="http://localhost" />
435 <default remote="default-remote" revision="refs/heads/main" /> 486 <default remote="default-remote" revision="refs/heads/main" />
436 <include name="target.xml" /> 487 <include name="target.xml" />
437</manifest> 488</manifest>
438""") 489"""
439 # Force the manifest to be parsed. 490 )
440 manifest.ToXml() 491 # Force the manifest to be parsed.
492 manifest.ToXml()
441 493
442 # Handle empty name explicitly because a different codepath rejects it. 494 # Handle empty name explicitly because a different codepath rejects it.
443 with self.assertRaises(error.ManifestParseError): 495 with self.assertRaises(error.ManifestParseError):
444 parse('') 496 parse("")
445 497
446 for path in INVALID_FS_PATHS: 498 for path in INVALID_FS_PATHS:
447 if not path: 499 if not path:
448 continue 500 continue
449 501
450 with self.assertRaises(error.ManifestInvalidPathError): 502 with self.assertRaises(error.ManifestInvalidPathError):
451 parse(path) 503 parse(path)
452 504
453 505
454class ProjectElementTests(ManifestParseTestCase): 506class ProjectElementTests(ManifestParseTestCase):
455 """Tests for <project>.""" 507 """Tests for <project>."""
456 508
457 def test_group(self): 509 def test_group(self):
458 """Check project group settings.""" 510 """Check project group settings."""
459 manifest = self.getXmlManifest(""" 511 manifest = self.getXmlManifest(
512 """
460<manifest> 513<manifest>
461 <remote name="test-remote" fetch="http://localhost" /> 514 <remote name="test-remote" fetch="http://localhost" />
462 <default remote="test-remote" revision="refs/heads/main" /> 515 <default remote="test-remote" revision="refs/heads/main" />
463 <project name="test-name" path="test-path"/> 516 <project name="test-name" path="test-path"/>
464 <project name="extras" path="path" groups="g1,g2,g1"/> 517 <project name="extras" path="path" groups="g1,g2,g1"/>
465</manifest> 518</manifest>
466""") 519"""
467 self.assertEqual(len(manifest.projects), 2) 520 )
468 # Ordering isn't guaranteed. 521 self.assertEqual(len(manifest.projects), 2)
469 result = { 522 # Ordering isn't guaranteed.
470 manifest.projects[0].name: manifest.projects[0].groups, 523 result = {
471 manifest.projects[1].name: manifest.projects[1].groups, 524 manifest.projects[0].name: manifest.projects[0].groups,
472 } 525 manifest.projects[1].name: manifest.projects[1].groups,
473 project = manifest.projects[0] 526 }
474 self.assertCountEqual( 527 self.assertCountEqual(
475 result['test-name'], 528 result["test-name"], ["name:test-name", "all", "path:test-path"]
476 ['name:test-name', 'all', 'path:test-path']) 529 )
477 self.assertCountEqual( 530 self.assertCountEqual(
478 result['extras'], 531 result["extras"],
479 ['g1', 'g2', 'g1', 'name:extras', 'all', 'path:path']) 532 ["g1", "g2", "g1", "name:extras", "all", "path:path"],
480 groupstr = 'default,platform-' + platform.system().lower() 533 )
481 self.assertEqual(groupstr, manifest.GetGroupsStr()) 534 groupstr = "default,platform-" + platform.system().lower()
482 groupstr = 'g1,g2,g1' 535 self.assertEqual(groupstr, manifest.GetGroupsStr())
483 manifest.manifestProject.config.SetString('manifest.groups', groupstr) 536 groupstr = "g1,g2,g1"
484 self.assertEqual(groupstr, manifest.GetGroupsStr()) 537 manifest.manifestProject.config.SetString("manifest.groups", groupstr)
485 538 self.assertEqual(groupstr, manifest.GetGroupsStr())
486 def test_set_revision_id(self): 539
487 """Check setting of project's revisionId.""" 540 def test_set_revision_id(self):
488 manifest = self.getXmlManifest(""" 541 """Check setting of project's revisionId."""
542 manifest = self.getXmlManifest(
543 """
489<manifest> 544<manifest>
490 <remote name="default-remote" fetch="http://localhost" /> 545 <remote name="default-remote" fetch="http://localhost" />
491 <default remote="default-remote" revision="refs/heads/main" /> 546 <default remote="default-remote" revision="refs/heads/main" />
492 <project name="test-name"/> 547 <project name="test-name"/>
493</manifest> 548</manifest>
494""") 549"""
495 self.assertEqual(len(manifest.projects), 1) 550 )
496 project = manifest.projects[0] 551 self.assertEqual(len(manifest.projects), 1)
497 project.SetRevisionId('ABCDEF') 552 project = manifest.projects[0]
498 self.assertEqual( 553 project.SetRevisionId("ABCDEF")
499 sort_attributes(manifest.ToXml().toxml()), 554 self.assertEqual(
500 '<?xml version="1.0" ?><manifest>' 555 sort_attributes(manifest.ToXml().toxml()),
501 '<remote fetch="http://localhost" name="default-remote"/>' 556 '<?xml version="1.0" ?><manifest>'
502 '<default remote="default-remote" revision="refs/heads/main"/>' 557 '<remote fetch="http://localhost" name="default-remote"/>'
503 '<project name="test-name" revision="ABCDEF" upstream="refs/heads/main"/>' 558 '<default remote="default-remote" revision="refs/heads/main"/>'
504 '</manifest>') 559 '<project name="test-name" revision="ABCDEF" upstream="refs/heads/main"/>' # noqa: E501
505 560 "</manifest>",
506 def test_trailing_slash(self): 561 )
507 """Check handling of trailing slashes in attributes.""" 562
508 def parse(name, path): 563 def test_trailing_slash(self):
509 name = self.encodeXmlAttr(name) 564 """Check handling of trailing slashes in attributes."""
510 path = self.encodeXmlAttr(path) 565
511 return self.getXmlManifest(f""" 566 def parse(name, path):
567 name = self.encodeXmlAttr(name)
568 path = self.encodeXmlAttr(path)
569 return self.getXmlManifest(
570 f"""
512<manifest> 571<manifest>
513 <remote name="default-remote" fetch="http://localhost" /> 572 <remote name="default-remote" fetch="http://localhost" />
514 <default remote="default-remote" revision="refs/heads/main" /> 573 <default remote="default-remote" revision="refs/heads/main" />
515 <project name="{name}" path="{path}" /> 574 <project name="{name}" path="{path}" />
516</manifest> 575</manifest>
517""") 576"""
518 577 )
519 manifest = parse('a/path/', 'foo') 578
520 self.assertEqual(os.path.normpath(manifest.projects[0].gitdir), 579 manifest = parse("a/path/", "foo")
521 os.path.join(self.tempdir, '.repo', 'projects', 'foo.git')) 580 self.assertEqual(
522 self.assertEqual(os.path.normpath(manifest.projects[0].objdir), 581 os.path.normpath(manifest.projects[0].gitdir),
523 os.path.join(self.tempdir, '.repo', 'project-objects', 'a', 'path.git')) 582 os.path.join(self.tempdir, ".repo", "projects", "foo.git"),
524 583 )
525 manifest = parse('a/path', 'foo/') 584 self.assertEqual(
526 self.assertEqual(os.path.normpath(manifest.projects[0].gitdir), 585 os.path.normpath(manifest.projects[0].objdir),
527 os.path.join(self.tempdir, '.repo', 'projects', 'foo.git')) 586 os.path.join(
528 self.assertEqual(os.path.normpath(manifest.projects[0].objdir), 587 self.tempdir, ".repo", "project-objects", "a", "path.git"
529 os.path.join(self.tempdir, '.repo', 'project-objects', 'a', 'path.git')) 588 ),
530 589 )
531 manifest = parse('a/path', 'foo//////') 590
532 self.assertEqual(os.path.normpath(manifest.projects[0].gitdir), 591 manifest = parse("a/path", "foo/")
533 os.path.join(self.tempdir, '.repo', 'projects', 'foo.git')) 592 self.assertEqual(
534 self.assertEqual(os.path.normpath(manifest.projects[0].objdir), 593 os.path.normpath(manifest.projects[0].gitdir),
535 os.path.join(self.tempdir, '.repo', 'project-objects', 'a', 'path.git')) 594 os.path.join(self.tempdir, ".repo", "projects", "foo.git"),
536 595 )
537 def test_toplevel_path(self): 596 self.assertEqual(
538 """Check handling of path=. specially.""" 597 os.path.normpath(manifest.projects[0].objdir),
539 def parse(name, path): 598 os.path.join(
540 name = self.encodeXmlAttr(name) 599 self.tempdir, ".repo", "project-objects", "a", "path.git"
541 path = self.encodeXmlAttr(path) 600 ),
542 return self.getXmlManifest(f""" 601 )
602
603 manifest = parse("a/path", "foo//////")
604 self.assertEqual(
605 os.path.normpath(manifest.projects[0].gitdir),
606 os.path.join(self.tempdir, ".repo", "projects", "foo.git"),
607 )
608 self.assertEqual(
609 os.path.normpath(manifest.projects[0].objdir),
610 os.path.join(
611 self.tempdir, ".repo", "project-objects", "a", "path.git"
612 ),
613 )
614
615 def test_toplevel_path(self):
616 """Check handling of path=. specially."""
617
618 def parse(name, path):
619 name = self.encodeXmlAttr(name)
620 path = self.encodeXmlAttr(path)
621 return self.getXmlManifest(
622 f"""
543<manifest> 623<manifest>
544 <remote name="default-remote" fetch="http://localhost" /> 624 <remote name="default-remote" fetch="http://localhost" />
545 <default remote="default-remote" revision="refs/heads/main" /> 625 <default remote="default-remote" revision="refs/heads/main" />
546 <project name="{name}" path="{path}" /> 626 <project name="{name}" path="{path}" />
547</manifest> 627</manifest>
548""") 628"""
549 629 )
550 for path in ('.', './', './/', './//'): 630
551 manifest = parse('server/path', path) 631 for path in (".", "./", ".//", ".///"):
552 self.assertEqual(os.path.normpath(manifest.projects[0].gitdir), 632 manifest = parse("server/path", path)
553 os.path.join(self.tempdir, '.repo', 'projects', '..git')) 633 self.assertEqual(
554 634 os.path.normpath(manifest.projects[0].gitdir),
555 def test_bad_path_name_checks(self): 635 os.path.join(self.tempdir, ".repo", "projects", "..git"),
556 """Check handling of bad path & name attributes.""" 636 )
557 def parse(name, path): 637
558 name = self.encodeXmlAttr(name) 638 def test_bad_path_name_checks(self):
559 path = self.encodeXmlAttr(path) 639 """Check handling of bad path & name attributes."""
560 manifest = self.getXmlManifest(f""" 640
641 def parse(name, path):
642 name = self.encodeXmlAttr(name)
643 path = self.encodeXmlAttr(path)
644 manifest = self.getXmlManifest(
645 f"""
561<manifest> 646<manifest>
562 <remote name="default-remote" fetch="http://localhost" /> 647 <remote name="default-remote" fetch="http://localhost" />
563 <default remote="default-remote" revision="refs/heads/main" /> 648 <default remote="default-remote" revision="refs/heads/main" />
564 <project name="{name}" path="{path}" /> 649 <project name="{name}" path="{path}" />
565</manifest> 650</manifest>
566""") 651"""
567 # Force the manifest to be parsed. 652 )
568 manifest.ToXml() 653 # Force the manifest to be parsed.
654 manifest.ToXml()
569 655
570 # Verify the parser is valid by default to avoid buggy tests below. 656 # Verify the parser is valid by default to avoid buggy tests below.
571 parse('ok', 'ok') 657 parse("ok", "ok")
572 658
573 # Handle empty name explicitly because a different codepath rejects it. 659 # Handle empty name explicitly because a different codepath rejects it.
574 # Empty path is OK because it defaults to the name field. 660 # Empty path is OK because it defaults to the name field.
575 with self.assertRaises(error.ManifestParseError): 661 with self.assertRaises(error.ManifestParseError):
576 parse('', 'ok') 662 parse("", "ok")
577 663
578 for path in INVALID_FS_PATHS: 664 for path in INVALID_FS_PATHS:
579 if not path or path.endswith('/') or path.endswith(os.path.sep): 665 if not path or path.endswith("/") or path.endswith(os.path.sep):
580 continue 666 continue
581 667
582 with self.assertRaises(error.ManifestInvalidPathError): 668 with self.assertRaises(error.ManifestInvalidPathError):
583 parse(path, 'ok') 669 parse(path, "ok")
584 670
585 # We have a dedicated test for path=".". 671 # We have a dedicated test for path=".".
586 if path not in {'.'}: 672 if path not in {"."}:
587 with self.assertRaises(error.ManifestInvalidPathError): 673 with self.assertRaises(error.ManifestInvalidPathError):
588 parse('ok', path) 674 parse("ok", path)
589 675
590 676
591class SuperProjectElementTests(ManifestParseTestCase): 677class SuperProjectElementTests(ManifestParseTestCase):
592 """Tests for <superproject>.""" 678 """Tests for <superproject>."""
593 679
594 def test_superproject(self): 680 def test_superproject(self):
595 """Check superproject settings.""" 681 """Check superproject settings."""
596 manifest = self.getXmlManifest(""" 682 manifest = self.getXmlManifest(
683 """
597<manifest> 684<manifest>
598 <remote name="test-remote" fetch="http://localhost" /> 685 <remote name="test-remote" fetch="http://localhost" />
599 <default remote="test-remote" revision="refs/heads/main" /> 686 <default remote="test-remote" revision="refs/heads/main" />
600 <superproject name="superproject"/> 687 <superproject name="superproject"/>
601</manifest> 688</manifest>
602""") 689"""
603 self.assertEqual(manifest.superproject.name, 'superproject') 690 )
604 self.assertEqual(manifest.superproject.remote.name, 'test-remote') 691 self.assertEqual(manifest.superproject.name, "superproject")
605 self.assertEqual(manifest.superproject.remote.url, 'http://localhost/superproject') 692 self.assertEqual(manifest.superproject.remote.name, "test-remote")
606 self.assertEqual(manifest.superproject.revision, 'refs/heads/main') 693 self.assertEqual(
607 self.assertEqual( 694 manifest.superproject.remote.url, "http://localhost/superproject"
608 sort_attributes(manifest.ToXml().toxml()), 695 )
609 '<?xml version="1.0" ?><manifest>' 696 self.assertEqual(manifest.superproject.revision, "refs/heads/main")
610 '<remote fetch="http://localhost" name="test-remote"/>' 697 self.assertEqual(
611 '<default remote="test-remote" revision="refs/heads/main"/>' 698 sort_attributes(manifest.ToXml().toxml()),
612 '<superproject name="superproject"/>' 699 '<?xml version="1.0" ?><manifest>'
613 '</manifest>') 700 '<remote fetch="http://localhost" name="test-remote"/>'
614 701 '<default remote="test-remote" revision="refs/heads/main"/>'
615 def test_superproject_revision(self): 702 '<superproject name="superproject"/>'
616 """Check superproject settings with a different revision attribute""" 703 "</manifest>",
617 self.maxDiff = None 704 )
618 manifest = self.getXmlManifest(""" 705
706 def test_superproject_revision(self):
707 """Check superproject settings with a different revision attribute"""
708 self.maxDiff = None
709 manifest = self.getXmlManifest(
710 """
619<manifest> 711<manifest>
620 <remote name="test-remote" fetch="http://localhost" /> 712 <remote name="test-remote" fetch="http://localhost" />
621 <default remote="test-remote" revision="refs/heads/main" /> 713 <default remote="test-remote" revision="refs/heads/main" />
622 <superproject name="superproject" revision="refs/heads/stable" /> 714 <superproject name="superproject" revision="refs/heads/stable" />
623</manifest> 715</manifest>
624""") 716"""
625 self.assertEqual(manifest.superproject.name, 'superproject') 717 )
626 self.assertEqual(manifest.superproject.remote.name, 'test-remote') 718 self.assertEqual(manifest.superproject.name, "superproject")
627 self.assertEqual(manifest.superproject.remote.url, 'http://localhost/superproject') 719 self.assertEqual(manifest.superproject.remote.name, "test-remote")
628 self.assertEqual(manifest.superproject.revision, 'refs/heads/stable') 720 self.assertEqual(
629 self.assertEqual( 721 manifest.superproject.remote.url, "http://localhost/superproject"
630 sort_attributes(manifest.ToXml().toxml()), 722 )
631 '<?xml version="1.0" ?><manifest>' 723 self.assertEqual(manifest.superproject.revision, "refs/heads/stable")
632 '<remote fetch="http://localhost" name="test-remote"/>' 724 self.assertEqual(
633 '<default remote="test-remote" revision="refs/heads/main"/>' 725 sort_attributes(manifest.ToXml().toxml()),
634 '<superproject name="superproject" revision="refs/heads/stable"/>' 726 '<?xml version="1.0" ?><manifest>'
635 '</manifest>') 727 '<remote fetch="http://localhost" name="test-remote"/>'
636 728 '<default remote="test-remote" revision="refs/heads/main"/>'
637 def test_superproject_revision_default_negative(self): 729 '<superproject name="superproject" revision="refs/heads/stable"/>'
638 """Check superproject settings with a same revision attribute""" 730 "</manifest>",
639 self.maxDiff = None 731 )
640 manifest = self.getXmlManifest(""" 732
733 def test_superproject_revision_default_negative(self):
734 """Check superproject settings with a same revision attribute"""
735 self.maxDiff = None
736 manifest = self.getXmlManifest(
737 """
641<manifest> 738<manifest>
642 <remote name="test-remote" fetch="http://localhost" /> 739 <remote name="test-remote" fetch="http://localhost" />
643 <default remote="test-remote" revision="refs/heads/stable" /> 740 <default remote="test-remote" revision="refs/heads/stable" />
644 <superproject name="superproject" revision="refs/heads/stable" /> 741 <superproject name="superproject" revision="refs/heads/stable" />
645</manifest> 742</manifest>
646""") 743"""
647 self.assertEqual(manifest.superproject.name, 'superproject') 744 )
648 self.assertEqual(manifest.superproject.remote.name, 'test-remote') 745 self.assertEqual(manifest.superproject.name, "superproject")
649 self.assertEqual(manifest.superproject.remote.url, 'http://localhost/superproject') 746 self.assertEqual(manifest.superproject.remote.name, "test-remote")
650 self.assertEqual(manifest.superproject.revision, 'refs/heads/stable') 747 self.assertEqual(
651 self.assertEqual( 748 manifest.superproject.remote.url, "http://localhost/superproject"
652 sort_attributes(manifest.ToXml().toxml()), 749 )
653 '<?xml version="1.0" ?><manifest>' 750 self.assertEqual(manifest.superproject.revision, "refs/heads/stable")
654 '<remote fetch="http://localhost" name="test-remote"/>' 751 self.assertEqual(
655 '<default remote="test-remote" revision="refs/heads/stable"/>' 752 sort_attributes(manifest.ToXml().toxml()),
656 '<superproject name="superproject"/>' 753 '<?xml version="1.0" ?><manifest>'
657 '</manifest>') 754 '<remote fetch="http://localhost" name="test-remote"/>'
658 755 '<default remote="test-remote" revision="refs/heads/stable"/>'
659 def test_superproject_revision_remote(self): 756 '<superproject name="superproject"/>'
660 """Check superproject settings with a same revision attribute""" 757 "</manifest>",
661 self.maxDiff = None 758 )
662 manifest = self.getXmlManifest(""" 759
760 def test_superproject_revision_remote(self):
761 """Check superproject settings with a same revision attribute"""
762 self.maxDiff = None
763 manifest = self.getXmlManifest(
764 """
663<manifest> 765<manifest>
664 <remote name="test-remote" fetch="http://localhost" revision="refs/heads/main" /> 766 <remote name="test-remote" fetch="http://localhost" revision="refs/heads/main" />
665 <default remote="test-remote" /> 767 <default remote="test-remote" />
666 <superproject name="superproject" revision="refs/heads/stable" /> 768 <superproject name="superproject" revision="refs/heads/stable" />
667</manifest> 769</manifest>
668""") 770""" # noqa: E501
669 self.assertEqual(manifest.superproject.name, 'superproject') 771 )
670 self.assertEqual(manifest.superproject.remote.name, 'test-remote') 772 self.assertEqual(manifest.superproject.name, "superproject")
671 self.assertEqual(manifest.superproject.remote.url, 'http://localhost/superproject') 773 self.assertEqual(manifest.superproject.remote.name, "test-remote")
672 self.assertEqual(manifest.superproject.revision, 'refs/heads/stable') 774 self.assertEqual(
673 self.assertEqual( 775 manifest.superproject.remote.url, "http://localhost/superproject"
674 sort_attributes(manifest.ToXml().toxml()), 776 )
675 '<?xml version="1.0" ?><manifest>' 777 self.assertEqual(manifest.superproject.revision, "refs/heads/stable")
676 '<remote fetch="http://localhost" name="test-remote" revision="refs/heads/main"/>' 778 self.assertEqual(
677 '<default remote="test-remote"/>' 779 sort_attributes(manifest.ToXml().toxml()),
678 '<superproject name="superproject" revision="refs/heads/stable"/>' 780 '<?xml version="1.0" ?><manifest>'
679 '</manifest>') 781 '<remote fetch="http://localhost" name="test-remote" revision="refs/heads/main"/>' # noqa: E501
680 782 '<default remote="test-remote"/>'
681 def test_remote(self): 783 '<superproject name="superproject" revision="refs/heads/stable"/>'
682 """Check superproject settings with a remote.""" 784 "</manifest>",
683 manifest = self.getXmlManifest(""" 785 )
786
787 def test_remote(self):
788 """Check superproject settings with a remote."""
789 manifest = self.getXmlManifest(
790 """
684<manifest> 791<manifest>
685 <remote name="default-remote" fetch="http://localhost" /> 792 <remote name="default-remote" fetch="http://localhost" />
686 <remote name="superproject-remote" fetch="http://localhost" /> 793 <remote name="superproject-remote" fetch="http://localhost" />
687 <default remote="default-remote" revision="refs/heads/main" /> 794 <default remote="default-remote" revision="refs/heads/main" />
688 <superproject name="platform/superproject" remote="superproject-remote"/> 795 <superproject name="platform/superproject" remote="superproject-remote"/>
689</manifest> 796</manifest>
690""") 797"""
691 self.assertEqual(manifest.superproject.name, 'platform/superproject') 798 )
692 self.assertEqual(manifest.superproject.remote.name, 'superproject-remote') 799 self.assertEqual(manifest.superproject.name, "platform/superproject")
693 self.assertEqual(manifest.superproject.remote.url, 'http://localhost/platform/superproject') 800 self.assertEqual(
694 self.assertEqual(manifest.superproject.revision, 'refs/heads/main') 801 manifest.superproject.remote.name, "superproject-remote"
695 self.assertEqual( 802 )
696 sort_attributes(manifest.ToXml().toxml()), 803 self.assertEqual(
697 '<?xml version="1.0" ?><manifest>' 804 manifest.superproject.remote.url,
698 '<remote fetch="http://localhost" name="default-remote"/>' 805 "http://localhost/platform/superproject",
699 '<remote fetch="http://localhost" name="superproject-remote"/>' 806 )
700 '<default remote="default-remote" revision="refs/heads/main"/>' 807 self.assertEqual(manifest.superproject.revision, "refs/heads/main")
701 '<superproject name="platform/superproject" remote="superproject-remote"/>' 808 self.assertEqual(
702 '</manifest>') 809 sort_attributes(manifest.ToXml().toxml()),
703 810 '<?xml version="1.0" ?><manifest>'
704 def test_defalut_remote(self): 811 '<remote fetch="http://localhost" name="default-remote"/>'
705 """Check superproject settings with a default remote.""" 812 '<remote fetch="http://localhost" name="superproject-remote"/>'
706 manifest = self.getXmlManifest(""" 813 '<default remote="default-remote" revision="refs/heads/main"/>'
814 '<superproject name="platform/superproject" remote="superproject-remote"/>' # noqa: E501
815 "</manifest>",
816 )
817
818 def test_defalut_remote(self):
819 """Check superproject settings with a default remote."""
820 manifest = self.getXmlManifest(
821 """
707<manifest> 822<manifest>
708 <remote name="default-remote" fetch="http://localhost" /> 823 <remote name="default-remote" fetch="http://localhost" />
709 <default remote="default-remote" revision="refs/heads/main" /> 824 <default remote="default-remote" revision="refs/heads/main" />
710 <superproject name="superproject" remote="default-remote"/> 825 <superproject name="superproject" remote="default-remote"/>
711</manifest> 826</manifest>
712""") 827"""
713 self.assertEqual(manifest.superproject.name, 'superproject') 828 )
714 self.assertEqual(manifest.superproject.remote.name, 'default-remote') 829 self.assertEqual(manifest.superproject.name, "superproject")
715 self.assertEqual(manifest.superproject.revision, 'refs/heads/main') 830 self.assertEqual(manifest.superproject.remote.name, "default-remote")
716 self.assertEqual( 831 self.assertEqual(manifest.superproject.revision, "refs/heads/main")
717 sort_attributes(manifest.ToXml().toxml()), 832 self.assertEqual(
718 '<?xml version="1.0" ?><manifest>' 833 sort_attributes(manifest.ToXml().toxml()),
719 '<remote fetch="http://localhost" name="default-remote"/>' 834 '<?xml version="1.0" ?><manifest>'
720 '<default remote="default-remote" revision="refs/heads/main"/>' 835 '<remote fetch="http://localhost" name="default-remote"/>'
721 '<superproject name="superproject"/>' 836 '<default remote="default-remote" revision="refs/heads/main"/>'
722 '</manifest>') 837 '<superproject name="superproject"/>'
838 "</manifest>",
839 )
723 840
724 841
725class ContactinfoElementTests(ManifestParseTestCase): 842class ContactinfoElementTests(ManifestParseTestCase):
726 """Tests for <contactinfo>.""" 843 """Tests for <contactinfo>."""
727 844
728 def test_contactinfo(self): 845 def test_contactinfo(self):
729 """Check contactinfo settings.""" 846 """Check contactinfo settings."""
730 bugurl = 'http://localhost/contactinfo' 847 bugurl = "http://localhost/contactinfo"
731 manifest = self.getXmlManifest(f""" 848 manifest = self.getXmlManifest(
849 f"""
732<manifest> 850<manifest>
733 <contactinfo bugurl="{bugurl}"/> 851 <contactinfo bugurl="{bugurl}"/>
734</manifest> 852</manifest>
735""") 853"""
736 self.assertEqual(manifest.contactinfo.bugurl, bugurl) 854 )
737 self.assertEqual( 855 self.assertEqual(manifest.contactinfo.bugurl, bugurl)
738 manifest.ToXml().toxml(), 856 self.assertEqual(
739 '<?xml version="1.0" ?><manifest>' 857 manifest.ToXml().toxml(),
740 f'<contactinfo bugurl="{bugurl}"/>' 858 '<?xml version="1.0" ?><manifest>'
741 '</manifest>') 859 f'<contactinfo bugurl="{bugurl}"/>'
860 "</manifest>",
861 )
742 862
743 863
744class DefaultElementTests(ManifestParseTestCase): 864class DefaultElementTests(ManifestParseTestCase):
745 """Tests for <default>.""" 865 """Tests for <default>."""
746 866
747 def test_default(self): 867 def test_default(self):
748 """Check default settings.""" 868 """Check default settings."""
749 a = manifest_xml._Default() 869 a = manifest_xml._Default()
750 a.revisionExpr = 'foo' 870 a.revisionExpr = "foo"
751 a.remote = manifest_xml._XmlRemote(name='remote') 871 a.remote = manifest_xml._XmlRemote(name="remote")
752 b = manifest_xml._Default() 872 b = manifest_xml._Default()
753 b.revisionExpr = 'bar' 873 b.revisionExpr = "bar"
754 self.assertEqual(a, a) 874 self.assertEqual(a, a)
755 self.assertNotEqual(a, b) 875 self.assertNotEqual(a, b)
756 self.assertNotEqual(b, a.remote) 876 self.assertNotEqual(b, a.remote)
757 self.assertNotEqual(a, 123) 877 self.assertNotEqual(a, 123)
758 self.assertNotEqual(a, None) 878 self.assertNotEqual(a, None)
759 879
760 880
761class RemoteElementTests(ManifestParseTestCase): 881class RemoteElementTests(ManifestParseTestCase):
762 """Tests for <remote>.""" 882 """Tests for <remote>."""
763 883
764 def test_remote(self): 884 def test_remote(self):
765 """Check remote settings.""" 885 """Check remote settings."""
766 a = manifest_xml._XmlRemote(name='foo') 886 a = manifest_xml._XmlRemote(name="foo")
767 a.AddAnnotation('key1', 'value1', 'true') 887 a.AddAnnotation("key1", "value1", "true")
768 b = manifest_xml._XmlRemote(name='foo') 888 b = manifest_xml._XmlRemote(name="foo")
769 b.AddAnnotation('key2', 'value1', 'true') 889 b.AddAnnotation("key2", "value1", "true")
770 c = manifest_xml._XmlRemote(name='foo') 890 c = manifest_xml._XmlRemote(name="foo")
771 c.AddAnnotation('key1', 'value2', 'true') 891 c.AddAnnotation("key1", "value2", "true")
772 d = manifest_xml._XmlRemote(name='foo') 892 d = manifest_xml._XmlRemote(name="foo")
773 d.AddAnnotation('key1', 'value1', 'false') 893 d.AddAnnotation("key1", "value1", "false")
774 self.assertEqual(a, a) 894 self.assertEqual(a, a)
775 self.assertNotEqual(a, b) 895 self.assertNotEqual(a, b)
776 self.assertNotEqual(a, c) 896 self.assertNotEqual(a, c)
777 self.assertNotEqual(a, d) 897 self.assertNotEqual(a, d)
778 self.assertNotEqual(a, manifest_xml._Default()) 898 self.assertNotEqual(a, manifest_xml._Default())
779 self.assertNotEqual(a, 123) 899 self.assertNotEqual(a, 123)
780 self.assertNotEqual(a, None) 900 self.assertNotEqual(a, None)
781 901
782 902
783class RemoveProjectElementTests(ManifestParseTestCase): 903class RemoveProjectElementTests(ManifestParseTestCase):
784 """Tests for <remove-project>.""" 904 """Tests for <remove-project>."""
785 905
786 def test_remove_one_project(self): 906 def test_remove_one_project(self):
787 manifest = self.getXmlManifest(""" 907 manifest = self.getXmlManifest(
908 """
788<manifest> 909<manifest>
789 <remote name="default-remote" fetch="http://localhost" /> 910 <remote name="default-remote" fetch="http://localhost" />
790 <default remote="default-remote" revision="refs/heads/main" /> 911 <default remote="default-remote" revision="refs/heads/main" />
791 <project name="myproject" /> 912 <project name="myproject" />
792 <remove-project name="myproject" /> 913 <remove-project name="myproject" />
793</manifest> 914</manifest>
794""") 915"""
795 self.assertEqual(manifest.projects, []) 916 )
917 self.assertEqual(manifest.projects, [])
796 918
797 def test_remove_one_project_one_remains(self): 919 def test_remove_one_project_one_remains(self):
798 manifest = self.getXmlManifest(""" 920 manifest = self.getXmlManifest(
921 """
799<manifest> 922<manifest>
800 <remote name="default-remote" fetch="http://localhost" /> 923 <remote name="default-remote" fetch="http://localhost" />
801 <default remote="default-remote" revision="refs/heads/main" /> 924 <default remote="default-remote" revision="refs/heads/main" />
@@ -803,51 +926,59 @@ class RemoveProjectElementTests(ManifestParseTestCase):
803 <project name="yourproject" /> 926 <project name="yourproject" />
804 <remove-project name="myproject" /> 927 <remove-project name="myproject" />
805</manifest> 928</manifest>
806""") 929"""
930 )
807 931
808 self.assertEqual(len(manifest.projects), 1) 932 self.assertEqual(len(manifest.projects), 1)
809 self.assertEqual(manifest.projects[0].name, 'yourproject') 933 self.assertEqual(manifest.projects[0].name, "yourproject")
810 934
811 def test_remove_one_project_doesnt_exist(self): 935 def test_remove_one_project_doesnt_exist(self):
812 with self.assertRaises(manifest_xml.ManifestParseError): 936 with self.assertRaises(manifest_xml.ManifestParseError):
813 manifest = self.getXmlManifest(""" 937 manifest = self.getXmlManifest(
938 """
814<manifest> 939<manifest>
815 <remote name="default-remote" fetch="http://localhost" /> 940 <remote name="default-remote" fetch="http://localhost" />
816 <default remote="default-remote" revision="refs/heads/main" /> 941 <default remote="default-remote" revision="refs/heads/main" />
817 <remove-project name="myproject" /> 942 <remove-project name="myproject" />
818</manifest> 943</manifest>
819""") 944"""
820 manifest.projects 945 )
946 manifest.projects
821 947
822 def test_remove_one_optional_project_doesnt_exist(self): 948 def test_remove_one_optional_project_doesnt_exist(self):
823 manifest = self.getXmlManifest(""" 949 manifest = self.getXmlManifest(
950 """
824<manifest> 951<manifest>
825 <remote name="default-remote" fetch="http://localhost" /> 952 <remote name="default-remote" fetch="http://localhost" />
826 <default remote="default-remote" revision="refs/heads/main" /> 953 <default remote="default-remote" revision="refs/heads/main" />
827 <remove-project name="myproject" optional="true" /> 954 <remove-project name="myproject" optional="true" />
828</manifest> 955</manifest>
829""") 956"""
830 self.assertEqual(manifest.projects, []) 957 )
958 self.assertEqual(manifest.projects, [])
831 959
832 960
833class ExtendProjectElementTests(ManifestParseTestCase): 961class ExtendProjectElementTests(ManifestParseTestCase):
834 """Tests for <extend-project>.""" 962 """Tests for <extend-project>."""
835 963
836 def test_extend_project_dest_path_single_match(self): 964 def test_extend_project_dest_path_single_match(self):
837 manifest = self.getXmlManifest(""" 965 manifest = self.getXmlManifest(
966 """
838<manifest> 967<manifest>
839 <remote name="default-remote" fetch="http://localhost" /> 968 <remote name="default-remote" fetch="http://localhost" />
840 <default remote="default-remote" revision="refs/heads/main" /> 969 <default remote="default-remote" revision="refs/heads/main" />
841 <project name="myproject" /> 970 <project name="myproject" />
842 <extend-project name="myproject" dest-path="bar" /> 971 <extend-project name="myproject" dest-path="bar" />
843</manifest> 972</manifest>
844""") 973"""
845 self.assertEqual(len(manifest.projects), 1) 974 )
846 self.assertEqual(manifest.projects[0].relpath, 'bar') 975 self.assertEqual(len(manifest.projects), 1)
847 976 self.assertEqual(manifest.projects[0].relpath, "bar")
848 def test_extend_project_dest_path_multi_match(self): 977
849 with self.assertRaises(manifest_xml.ManifestParseError): 978 def test_extend_project_dest_path_multi_match(self):
850 manifest = self.getXmlManifest(""" 979 with self.assertRaises(manifest_xml.ManifestParseError):
980 manifest = self.getXmlManifest(
981 """
851<manifest> 982<manifest>
852 <remote name="default-remote" fetch="http://localhost" /> 983 <remote name="default-remote" fetch="http://localhost" />
853 <default remote="default-remote" revision="refs/heads/main" /> 984 <default remote="default-remote" revision="refs/heads/main" />
@@ -855,11 +986,13 @@ class ExtendProjectElementTests(ManifestParseTestCase):
855 <project name="myproject" path="y" /> 986 <project name="myproject" path="y" />
856 <extend-project name="myproject" dest-path="bar" /> 987 <extend-project name="myproject" dest-path="bar" />
857</manifest> 988</manifest>
858""") 989"""
859 manifest.projects 990 )
991 manifest.projects
860 992
861 def test_extend_project_dest_path_multi_match_path_specified(self): 993 def test_extend_project_dest_path_multi_match_path_specified(self):
862 manifest = self.getXmlManifest(""" 994 manifest = self.getXmlManifest(
995 """
863<manifest> 996<manifest>
864 <remote name="default-remote" fetch="http://localhost" /> 997 <remote name="default-remote" fetch="http://localhost" />
865 <default remote="default-remote" revision="refs/heads/main" /> 998 <default remote="default-remote" revision="refs/heads/main" />
@@ -867,34 +1000,39 @@ class ExtendProjectElementTests(ManifestParseTestCase):
867 <project name="myproject" path="y" /> 1000 <project name="myproject" path="y" />
868 <extend-project name="myproject" path="x" dest-path="bar" /> 1001 <extend-project name="myproject" path="x" dest-path="bar" />
869</manifest> 1002</manifest>
870""") 1003"""
871 self.assertEqual(len(manifest.projects), 2) 1004 )
872 if manifest.projects[0].relpath == 'y': 1005 self.assertEqual(len(manifest.projects), 2)
873 self.assertEqual(manifest.projects[1].relpath, 'bar') 1006 if manifest.projects[0].relpath == "y":
874 else: 1007 self.assertEqual(manifest.projects[1].relpath, "bar")
875 self.assertEqual(manifest.projects[0].relpath, 'bar') 1008 else:
876 self.assertEqual(manifest.projects[1].relpath, 'y') 1009 self.assertEqual(manifest.projects[0].relpath, "bar")
877 1010 self.assertEqual(manifest.projects[1].relpath, "y")
878 def test_extend_project_dest_branch(self): 1011
879 manifest = self.getXmlManifest(""" 1012 def test_extend_project_dest_branch(self):
1013 manifest = self.getXmlManifest(
1014 """
880<manifest> 1015<manifest>
881 <remote name="default-remote" fetch="http://localhost" /> 1016 <remote name="default-remote" fetch="http://localhost" />
882 <default remote="default-remote" revision="refs/heads/main" dest-branch="foo" /> 1017 <default remote="default-remote" revision="refs/heads/main" dest-branch="foo" />
883 <project name="myproject" /> 1018 <project name="myproject" />
884 <extend-project name="myproject" dest-branch="bar" /> 1019 <extend-project name="myproject" dest-branch="bar" />
885</manifest> 1020</manifest>
886""") 1021""" # noqa: E501
887 self.assertEqual(len(manifest.projects), 1) 1022 )
888 self.assertEqual(manifest.projects[0].dest_branch, 'bar') 1023 self.assertEqual(len(manifest.projects), 1)
889 1024 self.assertEqual(manifest.projects[0].dest_branch, "bar")
890 def test_extend_project_upstream(self): 1025
891 manifest = self.getXmlManifest(""" 1026 def test_extend_project_upstream(self):
1027 manifest = self.getXmlManifest(
1028 """
892<manifest> 1029<manifest>
893 <remote name="default-remote" fetch="http://localhost" /> 1030 <remote name="default-remote" fetch="http://localhost" />
894 <default remote="default-remote" revision="refs/heads/main" /> 1031 <default remote="default-remote" revision="refs/heads/main" />
895 <project name="myproject" /> 1032 <project name="myproject" />
896 <extend-project name="myproject" upstream="bar" /> 1033 <extend-project name="myproject" upstream="bar" />
897</manifest> 1034</manifest>
898""") 1035"""
899 self.assertEqual(len(manifest.projects), 1) 1036 )
900 self.assertEqual(manifest.projects[0].upstream, 'bar') 1037 self.assertEqual(len(manifest.projects), 1)
1038 self.assertEqual(manifest.projects[0].upstream, "bar")