diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..a0f110f08 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,20 @@ +# Repo Tests + +There is a mixture of [pytest] & [Python unittest] in here. We adopted [pytest] +later on but didn't migrate existing tests (since they still work). New tests +should be written using [pytest] only. + +## File layout + +* `test_xxx.py`: Unittests for the `xxx` module in the main repo codebase. + Modules that are in subdirs normalize the `/` into `_`. + For example, [test_error.py](./test_error.py) is for the + [error.py](../error.py) module, and + [test_subcmds_forall.py](./test_subcmds_forall.py) is for the + [subcmds/forall.py](../subcmds/forall.py) module. +* [conftest.py](./conftest.py): Custom pytest fixtures for sharing. +* [utils_for_test.py](./utils_for_test.py): Helpers for sharing in tests. + + +[pytest]: https://pytest.org/ +[Python unittest]: https://docs.python.org/3/library/unittest.html#unittest.TestCase diff --git a/tests/test_project.py b/tests/test_project.py index de26e91a1..e0a6dec07 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -21,33 +21,15 @@ import subprocess import tempfile import unittest +import utils_for_test + import error -import git_command import git_config import manifest_xml import platform_utils import project -@contextlib.contextmanager -def TempGitTree(): - """Create a new empty git checkout for testing.""" - with tempfile.TemporaryDirectory(prefix="repo-tests") as tempdir: - # Tests need to assume, that main is default branch at init, - # which is not supported in config until 2.28. - cmd = ["git", "init"] - if git_command.git_require((2, 28, 0)): - cmd += ["--initial-branch=main"] - else: - # Use template dir for init. - templatedir = tempfile.mkdtemp(prefix=".test-template") - with open(os.path.join(templatedir, "HEAD"), "w") as fp: - fp.write("ref: refs/heads/main\n") - cmd += ["--template", templatedir] - subprocess.check_call(cmd, cwd=tempdir) - yield tempdir - - class FakeProject: """A fake for Project for basic functionality.""" @@ -69,7 +51,7 @@ class ReviewableBranchTests(unittest.TestCase): def test_smoke(self): """A quick run through everything.""" - with TempGitTree() as tempdir: + with utils_for_test.TempGitTree() as tempdir: fakeproj = FakeProject(tempdir) # Generate some commits. @@ -467,7 +449,7 @@ class ManifestPropertiesFetchedCorrectly(unittest.TestCase): def test_manifest_config_properties(self): """Test we are fetching the manifest config properties correctly.""" - with TempGitTree() as tempdir: + with utils_for_test.TempGitTree() as tempdir: fakeproj = self.setUpManifest(tempdir) # Set property using the expected Set method, then ensure diff --git a/tests/test_subcmds_forall.py b/tests/test_subcmds_forall.py index 84744f893..e50b28d8a 100644 --- a/tests/test_subcmds_forall.py +++ b/tests/test_subcmds_forall.py @@ -17,12 +17,12 @@ from io import StringIO import os from shutil import rmtree -import subprocess import tempfile import unittest from unittest import mock -import git_command +import utils_for_test + import manifest_xml import project import subcmds @@ -50,24 +50,6 @@ class AllCommands(unittest.TestCase): """Common teardown.""" rmtree(self.tempdir, ignore_errors=True) - def initTempGitTree(self, git_dir): - """Create a new empty git checkout for testing.""" - - # Tests need to assume, that main is default branch at init, - # which is not supported in config until 2.28. - cmd = ["git", "init", "-q"] - if git_command.git_require((2, 28, 0)): - cmd += ["--initial-branch=main"] - else: - # Use template dir for init - templatedir = os.path.join(self.tempdirobj.name, ".test-template") - os.makedirs(templatedir) - with open(os.path.join(templatedir, "HEAD"), "w") as fp: - fp.write("ref: refs/heads/main\n") - cmd += ["--template", templatedir] - cmd += [git_dir] - subprocess.check_call(cmd) - def getXmlManifestWith8Projects(self): """Create and return a setup of 8 projects with enough dummy files and setup to execute forall.""" @@ -114,7 +96,7 @@ class AllCommands(unittest.TestCase): ) ) git_path = os.path.join(self.tempdir, "tests/path" + str(x)) - self.initTempGitTree(git_path) + utils_for_test.init_git_tree(git_path) return manifest_xml.XmlManifest(self.repodir, self.manifest_file) diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index 77ceda8f7..a38705675 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -23,7 +23,8 @@ import tempfile import unittest from unittest import mock -import git_command +import utils_for_test + import main import wrapper @@ -408,18 +409,7 @@ class GitCheckoutTestCase(RepoWrapperTestCase): remote = os.path.join(cls.GIT_DIR, "remote") os.mkdir(remote) - # Tests need to assume, that main is default branch at init, - # which is not supported in config until 2.28. - if git_command.git_require((2, 28, 0)): - initstr = "--initial-branch=main" - else: - # Use template dir for init. - templatedir = tempfile.mkdtemp(prefix=".test-template") - with open(os.path.join(templatedir, "HEAD"), "w") as fp: - fp.write("ref: refs/heads/main\n") - initstr = "--template=" + templatedir - - run_git("init", initstr, cwd=remote) + utils_for_test.init_git_tree(remote) run_git("commit", "--allow-empty", "-minit", cwd=remote) run_git("branch", "stable", cwd=remote) run_git("tag", "v1.0", cwd=remote) diff --git a/tests/utils_for_test.py b/tests/utils_for_test.py new file mode 100644 index 000000000..e162e8666 --- /dev/null +++ b/tests/utils_for_test.py @@ -0,0 +1,53 @@ +# Copyright (C) 2026 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Various utility code used by tests. + +If you want to write a per-test fixture, see conftest.py instead. +""" + +import contextlib +from pathlib import Path +import subprocess +import tempfile +from typing import Union + +import git_command + + +def init_git_tree(path: Union[str, Path]) -> None: + """Initialize `path` as a new git repo.""" + with contextlib.ExitStack() as stack: + # Tests need to assume, that main is default branch at init, + # which is not supported in config until 2.28. + cmd = ["git", "init"] + if git_command.git_require((2, 28, 0)): + cmd += ["--initial-branch=main"] + else: + # Use template dir for init. + templatedir = stack.enter_context( + tempfile.mkdtemp(prefix="git-template") + ) + (Path(templatedir) / "HEAD").write_text("ref: refs/heads/main\n") + cmd += ["--template", templatedir] + cmd += [path] + subprocess.run(cmd, check=True) + + +@contextlib.contextmanager +def TempGitTree(): + """Create a new empty git checkout for testing.""" + with tempfile.TemporaryDirectory(prefix="repo-tests") as tempdir: + init_git_tree(tempdir) + yield tempdir