blob: 4ad2e1e0bd6a31885f0f5165abee23c8f1e6c49e [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for git_utils.py."""
import subprocess
import tempfile
import unittest
from pathlib import Path
from unittest import mock
from build.git import git_utils
class GitUtilsTest(unittest.TestCase):
def setUp(self) -> None:
self.temp_dir_obj = tempfile.TemporaryDirectory()
self.repo_dir = Path(self.temp_dir_obj.name)
def tearDown(self) -> None:
self.temp_dir_obj.cleanup()
@mock.patch.object(subprocess, "run")
def test_get_git_path_relative(self, mock_run: mock.Mock) -> None:
mock_run.return_value = mock.Mock(returncode=0, stdout=".git/HEAD\n")
result = git_utils.get_git_path(self.repo_dir, "HEAD")
self.assertEqual(result, (self.repo_dir / ".git/HEAD").resolve())
mock_run.assert_called_once_with(
[
"git",
"--no-optional-locks",
"-C",
str(self.repo_dir),
"rev-parse",
"--git-path",
"HEAD",
],
capture_output=True,
text=True,
check=True,
)
@mock.patch.object(subprocess, "run")
def test_get_git_path_absolute(self, mock_run: mock.Mock) -> None:
abs_path = (self.repo_dir / "custom" / "HEAD").resolve()
mock_run.return_value = mock.Mock(returncode=0, stdout=f"{abs_path}\n")
result = git_utils.get_git_path(self.repo_dir, "HEAD")
self.assertEqual(result, abs_path)
@mock.patch.object(subprocess, "run")
@mock.patch.object(git_utils, "get_git_path")
def test_get_git_ref_detached(
self, mock_get_git_path: mock.Mock, mock_run: mock.Mock
) -> None:
mock_run.return_value = mock.Mock(returncode=1, stdout="")
head_path = self.repo_dir / ".git" / "HEAD"
mock_get_git_path.return_value = head_path
result = git_utils.get_git_ref(self.repo_dir)
self.assertEqual(result, head_path)
mock_get_git_path.assert_called_once_with(self.repo_dir, "HEAD")
@mock.patch.object(subprocess, "run")
@mock.patch.object(git_utils, "get_git_path")
def test_get_git_ref_loose_exists(
self, mock_get_git_path: mock.Mock, mock_run: mock.Mock
) -> None:
mock_run.return_value = mock.Mock(
returncode=0, stdout="refs/heads/main\n"
)
ref_file = self.repo_dir / ".git" / "refs" / "heads" / "main"
ref_file.parent.mkdir(parents=True, exist_ok=True)
ref_file.write_text("1234567890abcdef1234567890abcdef12345678\n")
mock_get_git_path.return_value = ref_file
result = git_utils.get_git_ref(self.repo_dir)
self.assertEqual(result, ref_file)
@mock.patch.object(subprocess, "run")
@mock.patch.object(git_utils, "get_git_path")
def test_get_git_ref_packed_fallback(
self, mock_get_git_path: mock.Mock, mock_run: mock.Mock
) -> None:
mock_run.return_value = mock.Mock(
returncode=0, stdout="refs/heads/main\n"
)
loose_ref = self.repo_dir / ".git" / "refs" / "heads" / "nonexistent"
packed_refs = self.repo_dir / ".git" / "packed-refs"
packed_refs.parent.mkdir(parents=True, exist_ok=True)
packed_refs.write_text("# pack-refs with: peeled fully-peeled sorted\n")
def side_effect(repo_dir: Path, name: str) -> Path:
if name == "packed-refs":
return packed_refs
return loose_ref
mock_get_git_path.side_effect = side_effect
result = git_utils.get_git_ref(self.repo_dir)
self.assertEqual(result, packed_refs)
@mock.patch.object(git_utils, "get_git_ref")
@mock.patch.object(git_utils, "get_git_path")
def test_find_git_head_inputs(
self, mock_get_git_path: mock.Mock, mock_get_git_ref: mock.Mock
) -> None:
git_dir = self.repo_dir / ".git"
git_dir.mkdir(parents=True)
head_path = git_dir / "HEAD"
head_path.write_text("ref: refs/heads/main\n")
config_path = git_dir / "config"
config_path.write_text("[core]\n")
ref_path = git_dir / "refs" / "heads" / "main"
index_path = git_dir / "index"
index_path.write_text("index content")
def mock_path_lookup(repo_dir: Path, name: str) -> Path:
if name == "HEAD":
return head_path
if name == "config":
return config_path
if name == "packed-refs":
return git_dir / "packed-refs"
if name == "reftable":
return git_dir / "reftable"
if name == "index":
return index_path
return repo_dir / name
mock_get_git_path.side_effect = mock_path_lookup
mock_get_git_ref.return_value = ref_path
inputs = git_utils.find_git_head_inputs(self.repo_dir, track_index=True)
self.assertIn(head_path, inputs)
self.assertIn(config_path, inputs)
self.assertIn(ref_path, inputs)
self.assertIn(index_path, inputs)
@mock.patch.object(subprocess, "run")
def test_get_best_ref(self, mock_run: mock.Mock) -> None:
mock_run.side_effect = [
mock.Mock(returncode=1),
mock.Mock(returncode=0),
]
best_ref = git_utils._get_best_ref(self.repo_dir)
self.assertEqual(best_ref, "jiri/head")
@mock.patch.object(subprocess, "run")
@mock.patch.object(git_utils, "_get_best_ref", return_value="HEAD")
def test_get_git_revision(
self, mock_best_ref: mock.Mock, mock_run: mock.Mock
) -> None:
mock_run.return_value = mock.Mock(
returncode=0,
stdout="0123456789abcdef0123456789abcdef01234567\n",
)
rev = git_utils.get_git_revision(self.repo_dir)
self.assertEqual(rev, "0123456789abcdef0123456789abcdef01234567")
if __name__ == "__main__":
unittest.main()