blob: 1add13af7bcbc6c511519334569b31f2937c0e36 [file] [log] [blame]
import os
import unittest
import uuid
from sh import git
from linaropy.cd import cd
from linaropy.proj import Proj
from linaropy.git.clone import Clone
from linaropy.git.worktree import Worktree
from modules.llvm import LLVMSourceConfig, LLVMSubproject
class TestLLVMSourceConfig(unittest.TestCase):
testdirprefix = "SourceConfigUT"
def __create_dummy_commit(self):
filename = "file" + str(uuid.uuid4())
open(filename, "a").close()
git("add", filename)
git("commit", "-m", "Branches without commits confuse git")
def __create_dummy_repo(self, path):
if not os.path.exists(path):
os.makedirs(path)
with cd(path):
git("init")
self.__create_dummy_commit()
def __get_subproj_repo_path(self, subproj):
return os.path.join(self.originalLLVM.repodir, "..", subproj + "-repo")
def __get_subproj_repo(self, subproj):
return Clone(self.proj, self.__get_subproj_repo_path(subproj))
def setUp(self):
# We're going to create a hierarchy with [llvm|clang|whatever]-repo
# containing dummy repos, and llvm-copy containing a worktree of
# llvm-repo
self.proj = Proj(prefix=TestLLVMSourceConfig.testdirprefix)
path = os.path.join(self.proj.projdir, "llvm-repo")
self.__create_dummy_repo(path)
self.originalLLVM = Clone(self.proj, path)
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in subprojs.keys():
repo = self.__get_subproj_repo_path(subproj)
self.__create_dummy_repo(repo)
self.temporaryLLVMbranch = "a-branch"
self.temporaryLLVM = Worktree.create(
self.proj, self.originalLLVM, os.path.join(
self.proj.projdir, "llvm-copy"), self.temporaryLLVMbranch)
def tearDown(self):
self.proj.cleanup()
def test_detect_enabled_all(self):
subprojs = LLVMSubproject.get_all_subprojects()
sourcePath = self.temporaryLLVM.repodir
for subproj in subprojs:
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
enabled = config.get_enabled_subprojects()
self.assertEqual(set(subprojs), set(enabled),
"Expected %s but detected only %s" %
(str(set(subprojs)), str(enabled)))
def test_detect_enabled_none(self):
sourcePath = self.temporaryLLVM.repodir
path = os.path.join(sourcePath, "unrelated")
os.makedirs(path)
path = os.path.join(sourcePath, "wrong", "place", "for", "lld")
os.makedirs(path)
path = os.path.join(sourcePath, "projects", "clang")
os.makedirs(path)
path = os.path.join(sourcePath, "tools", "libcxx")
os.makedirs(path)
config = LLVMSourceConfig(self.proj, sourcePath)
enabled = config.get_enabled_subprojects()
self.assertEqual(
enabled,
[],
"Detected unexpected projects %s" % str(enabled)
)
def test_detect_enabled_some(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in ["lld", "libcxxabi", "clang"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
enabled = config.get_enabled_subprojects()
self.assertTrue("lld" in enabled, "Failed to detect lld")
self.assertTrue("clang" in enabled, "Failed to detect clang")
self.assertTrue("libcxxabi" in enabled,
"Failed to detect libcxxabi")
def test_detect_enabled_not_worktree(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
path = subprojs["compiler-rt"].get_cmake_path(sourcePath)
os.makedirs(path)
config = LLVMSourceConfig(self.proj, sourcePath)
enabled = config.get_enabled_subprojects()
# Check that if it's not a worktree, it's not enabled.
self.assertEqual(
enabled,
[],
"Detected unexpected projects %s" % str(enabled)
)
def test_detect_enabled_wrong_branch(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
path = subprojs["compiler-rt"].get_cmake_path(sourcePath)
branch = "different-than-" + self.temporaryLLVMbranch
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo("compiler-rt"),
path,
branch)
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
enabled = config.get_enabled_subprojects()
# Check that if it's a worktree on the wrong branch, it's not enabled.
self.assertEqual(
enabled,
[],
"Detected unexpected projects %s" % str(enabled)
)
def test_add_invalid_subproject(self):
config = LLVMSourceConfig(self.proj, self.temporaryLLVM.repodir)
subproj = "not-an-llvm-subproject"
subprojPath = self.originalLLVM.repodir # Dummy path
with self.assertRaises(ValueError) as context:
config.update({subproj : Clone(self.proj, subprojPath)})
self.assertRegexpMatches(str(context.exception),
"Unknown llvm subproject %s" % subproj)
def test_add_each_subproject(self):
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in subprojs:
expectedPath = subprojs[subproj].get_cmake_path(sourcePath)
config.update({subproj : self.__get_subproj_repo(subproj)})
self.assertTrue(os.path.isdir(expectedPath),
"Failed to add subproject %s" % subproj)
def test_add_all_subprojects(self):
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
to_add = {}
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in subprojs:
to_add[subproj] = self.__get_subproj_repo(subproj)
config.update(to_add)
for subproj in subprojs:
expectedPath = subprojs[subproj].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(expectedPath),
"Failed to add subproject %s" % subproj)
def test_add_some_subprojects(self):
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
to_add = {}
to_add["clang"] = self.__get_subproj_repo("clang")
to_add["compiler-rt"] = self.__get_subproj_repo("compiler-rt")
config.update(to_add)
subprojs = LLVMSubproject.get_all_subprojects()
self.assertTrue(
os.path.isdir(subprojs["clang"].get_cmake_path(sourcePath)),
"Failed to add subproject clang")
self.assertTrue(
os.path.isdir(subprojs["compiler-rt"].get_cmake_path(sourcePath)),
"Failed to add subproject compiler-rt")
def test_add_existing_subprojects(self):
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
subprojs = LLVMSubproject.get_all_subprojects()
existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
Worktree.create(
self.proj,
self.__get_subproj_repo("lldb"),
existingPath,
self.temporaryLLVMbranch)
config.update({ "lldb" : self.__get_subproj_repo("lldb")})
# If we got this far, we're probably ok, but let's be pedantic and check
# that the subproject is still there
self.assertTrue(os.path.isdir(existingPath),
"Existing subproject vanished")
def test_add_subproject_existing_branch(self):
"""
Test that we can add a subproject that already has the branch that LLVM
is on. This can happen for instance if we have added and then removed
the subproject and now we're trying to add it again.
"""
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
clangRepo = self.__get_subproj_repo("clang")
with cd(clangRepo.repodir):
# Make sure that the branch that LLVM is on already exists in the
# clang repo as well.
git("checkout", "-b", self.temporaryLLVMbranch)
self.__create_dummy_commit()
git("checkout", "master")
config.update( { "clang" : clangRepo })
subprojs = LLVMSubproject.get_all_subprojects()
path = subprojs["clang"].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(path), "Failed to add subproject")
def test_add_subproject_not_a_worktree(self):
"""
Test that we can't update a config to include a subproject that exists
but is not a worktree.
"""
sourcePath = self.temporaryLLVM.repodir
branch = "different-than-" + self.temporaryLLVMbranch
config = LLVMSourceConfig(self.proj, sourcePath)
subprojs = LLVMSubproject.get_all_subprojects()
existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
os.makedirs(existingPath)
with self.assertRaises(EnvironmentError) as context:
config.update({ "lldb" : self.__get_subproj_repo("lldb")})
self.assertRegexpMatches(str(context.exception),
"{} already exists but is not a valid subproject directory.*"
.format(existingPath))
# If we got this far, we're probably ok, but let's be pedantic and check
# that the subproject is still there
self.assertTrue(os.path.isdir(existingPath),
"Existing subproject vanished")
def test_add_subproject_wrong_branch(self):
"""
Test that we can't update a config to include a subproject that exists
but is on the wrong branch.
"""
sourcePath = self.temporaryLLVM.repodir
branch = "different-than-" + self.temporaryLLVMbranch
config = LLVMSourceConfig(self.proj, sourcePath)
subprojs = LLVMSubproject.get_all_subprojects()
existingPath = subprojs["lldb"].get_cmake_path(sourcePath)
Worktree.create(
self.proj,
self.__get_subproj_repo("lldb"),
existingPath,
branch)
with self.assertRaises(EnvironmentError) as context:
config.update({ "lldb" : self.__get_subproj_repo("lldb")})
self.assertRegexpMatches(str(context.exception),
"{} already exists but is not a valid subproject directory.*"
.format(existingPath))
# If we got this far, we're probably ok, but let's be pedantic and check
# that the subproject is still there
self.assertTrue(os.path.isdir(existingPath),
"Existing subproject vanished")
def test_remove_subproject(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
lldPath = subprojs["lld"].get_cmake_path(sourcePath)
lldWorktree = Worktree.create(
self.proj,
self.__get_subproj_repo("lld"),
lldPath,
self.temporaryLLVMbranch)
clangPath = subprojs["clang"].get_cmake_path(sourcePath)
clangWorktree = Worktree.create(
self.proj,
self.__get_subproj_repo("clang"),
clangPath,
self.temporaryLLVMbranch)
config = LLVMSourceConfig(self.proj, sourcePath)
config.update(remove=["lld"])
self.assertFalse(os.path.isdir(lldPath), "Failed to remove subproject")
self.assertTrue(os.path.isdir(clangPath), "Removed sibling subproject")
def test_remove_some_subprojects(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
config = LLVMSourceConfig(self.proj, sourcePath)
config.update(remove=["compiler-rt", "lld"])
for subproj in ["compiler-rt", "lld"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Failed to remove subproject")
for subproj in ["clang", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
def test_remove_all_subprojects(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in subprojs.keys():
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
config.update(remove=subprojs.keys())
for subproj in subprojs.keys():
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Failed to remove subproject")
def test_remove_each_subproject(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in subprojs.keys():
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
for subproj in subprojs.keys():
config.update(remove=[subproj])
for subproj in subprojs.keys():
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Failed to remove subproject")
def test_remove_duplicates(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
config = LLVMSourceConfig(self.proj, sourcePath)
config.update(remove=["compiler-rt", "lld", "lld", "compiler-rt"])
for subproj in ["compiler-rt", "lld"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Failed to remove subproject")
for subproj in ["clang", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
def test_remove_invalid_subproject(self):
sourcePath = self.temporaryLLVM.repodir
config = LLVMSourceConfig(self.proj, sourcePath)
subproj = "not-an-llvm-subproject"
with self.assertRaises(ValueError) as context:
config.update(remove=[subproj])
self.assertRegexpMatches(str(context.exception),
"Unknown llvm subproject %s" % subproj)
def test_remove_inexistent_subproject(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
lldPath = subprojs["lld"].get_cmake_path(sourcePath)
lldWorktree = Worktree.create(
self.proj,
self.__get_subproj_repo("lld"),
lldPath,
self.temporaryLLVMbranch)
clangPath = subprojs["clang"].get_cmake_path(sourcePath)
config = LLVMSourceConfig(self.proj, sourcePath)
config.update(remove=["clang"])
self.assertFalse(
os.path.isdir(clangPath),
"Failed to remove subproject")
self.assertTrue(os.path.isdir(lldPath), "Removed sibling subproject")
def test_add_after_remove(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
lldbRepo = self.__get_subproj_repo("lldb")
config = LLVMSourceConfig(self.proj, sourcePath)
config.update({"lldb" : lldbRepo})
self.assertTrue(
os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
"Failed to add lldb")
config.update(remove=["lldb"])
self.assertFalse(
os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
"Failed to remove lldb")
config.update({"lldb" : lldbRepo })
self.assertTrue(
os.path.isdir(subprojs["lldb"].get_cmake_path(sourcePath)),
"Failed to add lldb")
def test_mixed_adds_removes(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
for subproj in ["clang", "compiler-rt", "lld", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
worktree = Worktree.create(
self.proj,
self.__get_subproj_repo(subproj),
path,
self.temporaryLLVMbranch)
config = LLVMSourceConfig(self.proj, sourcePath)
config.update({
"libcxx" : self.__get_subproj_repo("libcxx"),
"libcxxabi" : self.__get_subproj_repo("libcxxabi")},
["compiler-rt", "lld"])
for subproj in ["libcxx", "libcxxabi"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(path), "Failed to add subproject")
for subproj in ["compiler-rt", "lld"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Failed to remove subproject")
for subproj in ["clang", "lldb", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertTrue(os.path.isdir(path), "Removed sibling subproject")
def test_simultaneous_add_remove(self):
sourcePath = self.temporaryLLVM.repodir
subprojs = LLVMSubproject.get_all_subprojects()
clangRepo = self.__get_subproj_repo("clang")
lldRepo = self.__get_subproj_repo("lld")
libunwindRepo = self.__get_subproj_repo("libunwind")
config = LLVMSourceConfig(self.proj, sourcePath)
with self.assertRaises(ValueError) as context:
config.update(
{ "clang" : clangRepo, "lld" : lldRepo, "libunwind" :
libunwindRepo}, ["libcxx", "lld", "libcxxabi"])
self.assertEqual(str(context.exception),
"Can't add and remove lld at the same time")
# Make sure we didn't add any of the others either
for subproj in ["clang", "libunwind"]:
path = subprojs[subproj].get_cmake_path(sourcePath)
self.assertFalse(
os.path.isdir(path),
"Incorrectly added subproject")
# TODO: test with a different dictionary than the default one (not
# necessarily containing subprojects - it can contain "potato", "banana" and
# "gazpacho" for all we care); in fact, it would probably be best to move the
# existing tests to that...
# TODO: test that CMake gets our layout
if __name__ == "__main__":
unittest.main()