blob: 3ad93b19f59d9f4d16bd53e2d52d23967a91d50b [file] [log] [blame]
Diana Picus3b2ef822016-10-13 16:53:18 +03001import os
2import unittest
3import uuid
4
5from sh import git
6
7from linaropy.cd import cd
8from linaropy.proj import Proj
9from linaropy.git.clone import Clone
10from linaropy.git.worktree import Worktree
11
12from modules.llvm import LLVMSourceConfig, LLVMSubproject
13
14
15class TestLLVMSourceConfig(unittest.TestCase):
16 testdirprefix = "SourceConfigUT"
17
18 def __create_dummy_commit(self):
19 filename = "file" + str(uuid.uuid4())
20 open(filename, "a").close()
21 git("add", filename)
22 git("commit", "-m", "Branches without commits confuse git")
23
24 def __create_dummy_repo(self, path):
25 if not os.path.exists(path):
26 os.makedirs(path)
27
28 with cd(path):
29 git("init")
30 self.__create_dummy_commit()
31
32 def __get_subproj_repo_path(self, subproj):
33 return os.path.join(self.originalLLVM.repodir, "..", subproj + "-repo")
34
35 def __get_subproj_repo(self, subproj):
36 return Clone(self.proj, self.__get_subproj_repo_path(subproj))
37
38 def setUp(self):
39 # We're going to create a hierarchy with [llvm|clang|whatever]-repo
40 # containing dummy repos, and llvm-copy containing a worktree of
41 # llvm-repo
42 self.proj = Proj(prefix=TestLLVMSourceConfig.testdirprefix)
43 path = os.path.join(self.proj.projdir, "llvm-repo")
44 self.__create_dummy_repo(path)
45 self.originalLLVM = Clone(self.proj, path)
46
47 subprojs = LLVMSubproject.get_all_subprojects()
Diana Picusb4307602017-04-05 19:48:39 +020048 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +030049 repo = self.__get_subproj_repo_path(subproj)
50 self.__create_dummy_repo(repo)
51
52 self.temporaryLLVMbranch = "a-branch"
53 self.temporaryLLVM = Worktree.create(
54 self.proj, self.originalLLVM, os.path.join(
55 self.proj.projdir, "llvm-copy"), self.temporaryLLVMbranch)
56
57 def tearDown(self):
58 self.proj.cleanup()
59
60 def test_detect_enabled_all(self):
61 subprojs = LLVMSubproject.get_all_subprojects()
62 sourcePath = self.temporaryLLVM.repodir
63
64 for subproj in subprojs:
65 path = subprojs[subproj].get_cmake_path(sourcePath)
66 worktree = Worktree.create(
67 self.proj,
68 self.__get_subproj_repo(subproj),
69 path,
70 self.temporaryLLVMbranch)
71 self.assertTrue(os.path.isdir(path), "Failed to create worktree")
72
73 config = LLVMSourceConfig(self.proj, sourcePath)
74 enabled = config.get_enabled_subprojects()
75
76 self.assertEqual(set(subprojs), set(enabled),
77 "Expected %s but detected only %s" %
78 (str(set(subprojs)), str(enabled)))
79
80 def test_detect_enabled_none(self):
81 sourcePath = self.temporaryLLVM.repodir
82
83 path = os.path.join(sourcePath, "unrelated")
84 os.makedirs(path)
85
86 path = os.path.join(sourcePath, "wrong", "place", "for", "lld")
87 os.makedirs(path)
88
89 path = os.path.join(sourcePath, "projects", "clang")
90 os.makedirs(path)
91
92 path = os.path.join(sourcePath, "tools", "libcxx")
93 os.makedirs(path)
94
95 config = LLVMSourceConfig(self.proj, sourcePath)
96 enabled = config.get_enabled_subprojects()
97
98 self.assertEqual(
99 enabled,
100 [],
101 "Detected unexpected projects %s" % str(enabled)
102 )
103
104 def test_detect_enabled_some(self):
105 sourcePath = self.temporaryLLVM.repodir
106 subprojs = LLVMSubproject.get_all_subprojects()
107
108 for subproj in ["lld", "libcxxabi", "clang"]:
109 path = subprojs[subproj].get_cmake_path(sourcePath)
110 worktree = Worktree.create(
111 self.proj,
112 self.__get_subproj_repo(subproj),
113 path,
114 self.temporaryLLVMbranch)
115 self.assertTrue(os.path.isdir(path), "Failed to create worktree")
116
117 config = LLVMSourceConfig(self.proj, sourcePath)
118 enabled = config.get_enabled_subprojects()
119
120 self.assertTrue("lld" in enabled, "Failed to detect lld")
121 self.assertTrue("clang" in enabled, "Failed to detect clang")
122 self.assertTrue("libcxxabi" in enabled,
123 "Failed to detect libcxxabi")
124
125 def test_detect_enabled_not_worktree(self):
126 sourcePath = self.temporaryLLVM.repodir
127 subprojs = LLVMSubproject.get_all_subprojects()
128
129 path = subprojs["compiler-rt"].get_cmake_path(sourcePath)
130 os.makedirs(path)
131
132 config = LLVMSourceConfig(self.proj, sourcePath)
133 enabled = config.get_enabled_subprojects()
134
135 # Check that if it's not a worktree, it's not enabled.
136 self.assertEqual(
137 enabled,
138 [],
139 "Detected unexpected projects %s" % str(enabled)
140 )
141
142 def test_detect_enabled_wrong_branch(self):
143 sourcePath = self.temporaryLLVM.repodir
144 subprojs = LLVMSubproject.get_all_subprojects()
145
146 path = subprojs["compiler-rt"].get_cmake_path(sourcePath)
147 branch = "different-than-" + self.temporaryLLVMbranch
148 worktree = Worktree.create(
149 self.proj,
150 self.__get_subproj_repo("compiler-rt"),
151 path,
152 branch)
153 self.assertTrue(os.path.isdir(path), "Failed to create worktree")
154
155 config = LLVMSourceConfig(self.proj, sourcePath)
156 enabled = config.get_enabled_subprojects()
157
158 # Check that if it's a worktree on the wrong branch, it's not enabled.
159 self.assertEqual(
160 enabled,
161 [],
162 "Detected unexpected projects %s" % str(enabled)
163 )
164
165 def test_add_invalid_subproject(self):
166 config = LLVMSourceConfig(self.proj, self.temporaryLLVM.repodir)
167 subproj = "not-an-llvm-subproject"
168 subprojPath = self.originalLLVM.repodir # Dummy path
169
170 with self.assertRaises(ValueError) as context:
171 config.update({subproj : Clone(self.proj, subprojPath)})
172
Diana Picusb4307602017-04-05 19:48:39 +0200173 self.assertRegex(str(context.exception),
174 "Unknown llvm subproject %s" % subproj)
Diana Picus3b2ef822016-10-13 16:53:18 +0300175
176 def test_add_each_subproject(self):
177 sourcePath = self.temporaryLLVM.repodir
178
179 config = LLVMSourceConfig(self.proj, sourcePath)
180
181 subprojs = LLVMSubproject.get_all_subprojects()
182 for subproj in subprojs:
183 expectedPath = subprojs[subproj].get_cmake_path(sourcePath)
184 config.update({subproj : self.__get_subproj_repo(subproj)})
185 self.assertTrue(os.path.isdir(expectedPath),
186 "Failed to add subproject %s" % subproj)
187
188 def test_add_all_subprojects(self):
189 sourcePath = self.temporaryLLVM.repodir
190
191 config = LLVMSourceConfig(self.proj, sourcePath)
192
193 to_add = {}
194 subprojs = LLVMSubproject.get_all_subprojects()
195
196 for subproj in subprojs:
197 to_add[subproj] = self.__get_subproj_repo(subproj)
198
199 config.update(to_add)
200
201 for subproj in subprojs:
202 expectedPath = subprojs[subproj].get_cmake_path(sourcePath)
203 self.assertTrue(os.path.isdir(expectedPath),
204 "Failed to add subproject %s" % subproj)
205
206 def test_add_some_subprojects(self):
207 sourcePath = self.temporaryLLVM.repodir
208
209 config = LLVMSourceConfig(self.proj, sourcePath)
210
211 to_add = {}
212 to_add["clang"] = self.__get_subproj_repo("clang")
213 to_add["compiler-rt"] = self.__get_subproj_repo("compiler-rt")
214
215 config.update(to_add)
216
217 subprojs = LLVMSubproject.get_all_subprojects()
218 self.assertTrue(
219 os.path.isdir(subprojs["clang"].get_cmake_path(sourcePath)),
220 "Failed to add subproject clang")
221 self.assertTrue(
222 os.path.isdir(subprojs["compiler-rt"].get_cmake_path(sourcePath)),
223 "Failed to add subproject compiler-rt")
224
225 def test_add_existing_subprojects(self):
226 sourcePath = self.temporaryLLVM.repodir
227
228 config = LLVMSourceConfig(self.proj, sourcePath)
229
230 subprojs = LLVMSubproject.get_all_subprojects()
231 existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
232 Worktree.create(
233 self.proj,
234 self.__get_subproj_repo("lldb"),
235 existingPath,
236 self.temporaryLLVMbranch)
237
238 config.update({ "lldb" : self.__get_subproj_repo("lldb")})
239
240 # If we got this far, we're probably ok, but let's be pedantic and check
241 # that the subproject is still there
242 self.assertTrue(os.path.isdir(existingPath),
243 "Existing subproject vanished")
244
245 def test_add_subproject_existing_branch(self):
246 """
247 Test that we can add a subproject that already has the branch that LLVM
248 is on. This can happen for instance if we have added and then removed
249 the subproject and now we're trying to add it again.
250 """
251 sourcePath = self.temporaryLLVM.repodir
252
253 config = LLVMSourceConfig(self.proj, sourcePath)
254
255 clangRepo = self.__get_subproj_repo("clang")
256 with cd(clangRepo.repodir):
257 # Make sure that the branch that LLVM is on already exists in the
258 # clang repo as well.
259 git("checkout", "-b", self.temporaryLLVMbranch)
260 self.__create_dummy_commit()
261 git("checkout", "master")
262
263 config.update( { "clang" : clangRepo })
264
265 subprojs = LLVMSubproject.get_all_subprojects()
266 path = subprojs["clang"].get_cmake_path(sourcePath)
267 self.assertTrue(os.path.isdir(path), "Failed to add subproject")
268
269 def test_add_subproject_not_a_worktree(self):
270 """
271 Test that we can't update a config to include a subproject that exists
272 but is not a worktree.
273 """
274 sourcePath = self.temporaryLLVM.repodir
275 branch = "different-than-" + self.temporaryLLVMbranch
276
277 config = LLVMSourceConfig(self.proj, sourcePath)
278
279 subprojs = LLVMSubproject.get_all_subprojects()
280 existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
281 os.makedirs(existingPath)
282
283 with self.assertRaises(EnvironmentError) as context:
284 config.update({ "lldb" : self.__get_subproj_repo("lldb")})
285
Diana Picusb4307602017-04-05 19:48:39 +0200286 self.assertRegex(str(context.exception),
287 "{} already exists but is not a valid subproject directory.*"
288 .format(existingPath))
Diana Picus3b2ef822016-10-13 16:53:18 +0300289
290 # If we got this far, we're probably ok, but let's be pedantic and check
291 # that the subproject is still there
292 self.assertTrue(os.path.isdir(existingPath),
293 "Existing subproject vanished")
294
295 def test_add_subproject_wrong_branch(self):
296 """
297 Test that we can't update a config to include a subproject that exists
298 but is on the wrong branch.
299 """
300 sourcePath = self.temporaryLLVM.repodir
301 branch = "different-than-" + self.temporaryLLVMbranch
302
303 config = LLVMSourceConfig(self.proj, sourcePath)
304
305 subprojs = LLVMSubproject.get_all_subprojects()
306 existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
307 Worktree.create(
308 self.proj,
309 self.__get_subproj_repo("lldb"),
310 existingPath,
311 branch)
312
313 with self.assertRaises(EnvironmentError) as context:
314 config.update({ "lldb" : self.__get_subproj_repo("lldb")})
315
Diana Picusb4307602017-04-05 19:48:39 +0200316 self.assertRegex(str(context.exception),
317 "{} already exists but is not a valid subproject directory.*"
318 .format(existingPath))
Diana Picus3b2ef822016-10-13 16:53:18 +0300319
320 # If we got this far, we're probably ok, but let's be pedantic and check
321 # that the subproject is still there
322 self.assertTrue(os.path.isdir(existingPath),
323 "Existing subproject vanished")
324
325 def test_remove_subproject(self):
326 sourcePath = self.temporaryLLVM.repodir
327
328 subprojs = LLVMSubproject.get_all_subprojects()
329
330 lldPath = subprojs["lld"].get_cmake_path(sourcePath)
331 lldWorktree = Worktree.create(
332 self.proj,
333 self.__get_subproj_repo("lld"),
334 lldPath,
335 self.temporaryLLVMbranch)
336
337 clangPath = subprojs["clang"].get_cmake_path(sourcePath)
338 clangWorktree = Worktree.create(
339 self.proj,
340 self.__get_subproj_repo("clang"),
341 clangPath,
342 self.temporaryLLVMbranch)
343
344 config = LLVMSourceConfig(self.proj, sourcePath)
345 config.update(remove=["lld"])
346
347 self.assertFalse(os.path.isdir(lldPath), "Failed to remove subproject")
348 self.assertTrue(os.path.isdir(clangPath), "Removed sibling subproject")
349
350 def test_remove_some_subprojects(self):
351 sourcePath = self.temporaryLLVM.repodir
352
353 subprojs = LLVMSubproject.get_all_subprojects()
354
355 for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
356 path = subprojs[subproj].get_cmake_path(sourcePath)
357 worktree = Worktree.create(
358 self.proj,
359 self.__get_subproj_repo(subproj),
360 path,
361 self.temporaryLLVMbranch)
362
363 config = LLVMSourceConfig(self.proj, sourcePath)
364 config.update(remove=["compiler-rt", "lld"])
365
366 for subproj in ["compiler-rt", "lld"]:
367 path = subprojs[subproj].get_cmake_path(sourcePath)
368 self.assertFalse(
369 os.path.isdir(path),
370 "Failed to remove subproject")
371
372 for subproj in ["clang", "lldb", "libunwind"]:
373 path = subprojs[subproj].get_cmake_path(sourcePath)
374 self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
375
376 def test_remove_all_subprojects(self):
377 sourcePath = self.temporaryLLVM.repodir
378
379 subprojs = LLVMSubproject.get_all_subprojects()
380
Diana Picusb4307602017-04-05 19:48:39 +0200381 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +0300382 path = subprojs[subproj].get_cmake_path(sourcePath)
383 worktree = Worktree.create(
384 self.proj,
385 self.__get_subproj_repo(subproj),
386 path,
387 self.temporaryLLVMbranch)
388 self.assertTrue(os.path.isdir(path), "Failed to create worktree")
389
390 config = LLVMSourceConfig(self.proj, sourcePath)
Diana Picusb4307602017-04-05 19:48:39 +0200391 config.update(remove=list(subprojs.keys()))
Diana Picus3b2ef822016-10-13 16:53:18 +0300392
Diana Picusb4307602017-04-05 19:48:39 +0200393 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +0300394 path = subprojs[subproj].get_cmake_path(sourcePath)
395 self.assertFalse(
396 os.path.isdir(path),
397 "Failed to remove subproject")
398
399 def test_remove_each_subproject(self):
400 sourcePath = self.temporaryLLVM.repodir
401
402 subprojs = LLVMSubproject.get_all_subprojects()
403
Diana Picusb4307602017-04-05 19:48:39 +0200404 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +0300405 path = subprojs[subproj].get_cmake_path(sourcePath)
406 worktree = Worktree.create(
407 self.proj,
408 self.__get_subproj_repo(subproj),
409 path,
410 self.temporaryLLVMbranch)
411 self.assertTrue(os.path.isdir(path), "Failed to create worktree")
412
413 config = LLVMSourceConfig(self.proj, sourcePath)
414
Diana Picusb4307602017-04-05 19:48:39 +0200415 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +0300416 config.update(remove=[subproj])
417
Diana Picusb4307602017-04-05 19:48:39 +0200418 for subproj in list(subprojs.keys()):
Diana Picus3b2ef822016-10-13 16:53:18 +0300419 path = subprojs[subproj].get_cmake_path(sourcePath)
420 self.assertFalse(
421 os.path.isdir(path),
422 "Failed to remove subproject")
423
424 def test_remove_duplicates(self):
425 sourcePath = self.temporaryLLVM.repodir
426
427 subprojs = LLVMSubproject.get_all_subprojects()
428
429 for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
430 path = subprojs[subproj].get_cmake_path(sourcePath)
431 worktree = Worktree.create(
432 self.proj,
433 self.__get_subproj_repo(subproj),
434 path,
435 self.temporaryLLVMbranch)
436
437 config = LLVMSourceConfig(self.proj, sourcePath)
438 config.update(remove=["compiler-rt", "lld", "lld", "compiler-rt"])
439
440 for subproj in ["compiler-rt", "lld"]:
441 path = subprojs[subproj].get_cmake_path(sourcePath)
442 self.assertFalse(
443 os.path.isdir(path),
444 "Failed to remove subproject")
445
446 for subproj in ["clang", "lldb", "libunwind"]:
447 path = subprojs[subproj].get_cmake_path(sourcePath)
448 self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
449
450 def test_remove_invalid_subproject(self):
451 sourcePath = self.temporaryLLVM.repodir
452 config = LLVMSourceConfig(self.proj, sourcePath)
453
454 subproj = "not-an-llvm-subproject"
455
456 with self.assertRaises(ValueError) as context:
457 config.update(remove=[subproj])
458
Diana Picusb4307602017-04-05 19:48:39 +0200459 self.assertRegex(str(context.exception),
460 "Unknown llvm subproject %s" % subproj)
Diana Picus3b2ef822016-10-13 16:53:18 +0300461
462 def test_remove_inexistent_subproject(self):
463 sourcePath = self.temporaryLLVM.repodir
464
465 subprojs = LLVMSubproject.get_all_subprojects()
466
467 lldPath = subprojs["lld"].get_cmake_path(sourcePath)
468 lldWorktree = Worktree.create(
469 self.proj,
470 self.__get_subproj_repo("lld"),
471 lldPath,
472 self.temporaryLLVMbranch)
473
474 clangPath = subprojs["clang"].get_cmake_path(sourcePath)
475
476 config = LLVMSourceConfig(self.proj, sourcePath)
477 config.update(remove=["clang"])
478
479 self.assertFalse(
480 os.path.isdir(clangPath),
481 "Failed to remove subproject")
482 self.assertTrue(os.path.isdir(lldPath), "Removed sibling subproject")
483
484 def test_add_after_remove(self):
485 sourcePath = self.temporaryLLVM.repodir
486
487 subprojs = LLVMSubproject.get_all_subprojects()
488 lldbRepo = self.__get_subproj_repo("lldb")
489
490 config = LLVMSourceConfig(self.proj, sourcePath)
491
492 config.update({"lldb" : lldbRepo})
493 self.assertTrue(
494 os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
495 "Failed to add lldb")
496
497 config.update(remove=["lldb"])
498 self.assertFalse(
499 os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
500 "Failed to remove lldb")
501
502 config.update({"lldb" : lldbRepo })
503 self.assertTrue(
504 os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
505 "Failed to add lldb")
506
507 def test_mixed_adds_removes(self):
508 sourcePath = self.temporaryLLVM.repodir
509
510 subprojs = LLVMSubproject.get_all_subprojects()
511
512 for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
513 path = subprojs[subproj].get_cmake_path(sourcePath)
514 worktree = Worktree.create(
515 self.proj,
516 self.__get_subproj_repo(subproj),
517 path,
518 self.temporaryLLVMbranch)
519
520 config = LLVMSourceConfig(self.proj, sourcePath)
521 config.update({
522 "libcxx" : self.__get_subproj_repo("libcxx"),
523 "libcxxabi" : self.__get_subproj_repo("libcxxabi")},
524 ["compiler-rt", "lld"])
525
526 for subproj in ["libcxx", "libcxxabi"]:
527 path = subprojs[subproj].get_cmake_path(sourcePath)
528 self.assertTrue(os.path.isdir(path), "Failed to add subproject")
529
530 for subproj in ["compiler-rt", "lld"]:
531 path = subprojs[subproj].get_cmake_path(sourcePath)
532 self.assertFalse(
533 os.path.isdir(path),
534 "Failed to remove subproject")
535
536 for subproj in ["clang", "lldb", "libunwind"]:
537 path = subprojs[subproj].get_cmake_path(sourcePath)
538 self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
539
540 def test_simultaneous_add_remove(self):
541 sourcePath = self.temporaryLLVM.repodir
542 subprojs = LLVMSubproject.get_all_subprojects()
543
544 clangRepo = self.__get_subproj_repo("clang")
545 lldRepo = self.__get_subproj_repo("lld")
546 libunwindRepo = self.__get_subproj_repo("libunwind")
547
548 config = LLVMSourceConfig(self.proj, sourcePath)
549 with self.assertRaises(ValueError) as context:
550 config.update(
551 { "clang" : clangRepo, "lld" : lldRepo, "libunwind" :
552 libunwindRepo}, ["libcxx", "lld", "libcxxabi"])
553
554 self.assertEqual(str(context.exception),
555 "Can't add and remove lld at the same time")
556
557 # Make sure we didn't add any of the others either
558 for subproj in ["clang", "libunwind"]:
559 path = subprojs[subproj].get_cmake_path(sourcePath)
560 self.assertFalse(
561 os.path.isdir(path),
562 "Incorrectly added subproject")
563
564 # TODO: test with a different dictionary than the default one (not
565 # necessarily containing subprojects - it can contain "potato", "banana" and
566 # "gazpacho" for all we care); in fact, it would probably be best to move the
567 # existing tests to that...
568
569 # TODO: test that CMake gets our layout
570
571if __name__ == "__main__":
572 unittest.main()