blob: 2f9f0cd3424499a7768aaf35608b003da4e49e9e [file]
# Copyright 2026 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import unittest
from unittest.mock import patch, MagicMock, mock_open
from pathlib import Path
import sys
import os
# Mocking sys.exit to avoid test runner exit
# Importing worktree
import worktree
class TestWorktree(unittest.TestCase):
@patch("worktree.subprocess.run")
def test_run_cmd(self, mock_run):
worktree.run_cmd(["echo", "hi"])
mock_run.assert_called_once_with(["echo", "hi"],
cwd=None,
check=True,
text=True,
capture_output=False)
@patch("worktree.subprocess.run")
def test_run_cmd_no_check_failure(self, mock_run):
import subprocess
mock_run.side_effect = subprocess.CalledProcessError(1, ["false"])
result = worktree.run_cmd(["false"], check=False)
self.assertIsNone(result)
@patch("pathlib.Path.is_dir", return_value=True)
@patch("pathlib.Path.exists", side_effect=[True, True, True])
@patch("pathlib.Path.resolve")
def test_validate_parent_repo_success(self, mock_resolve, mock_exists,
mock_is_dir):
mock_resolve.return_value = Path("/fake/repo")
parent_dir, g_config, s_dir = worktree.validate_parent_repo("/fake/repo")
self.assertEqual(parent_dir, Path("/fake/repo"))
self.assertEqual(g_config, Path("/fake/repo/.gclient"))
self.assertEqual(s_dir, Path("/fake/repo/src"))
@patch("pathlib.Path.is_dir", return_value=True)
@patch("pathlib.Path.exists", side_effect=[True, True, True])
@patch("pathlib.Path.resolve")
def test_validate_parent_repo_from_src(self, mock_resolve, mock_exists,
mock_is_dir):
# Simulate being called from /fake/repo/src
mock_resolve.return_value = Path("/fake/repo/src")
parent_dir, g_config, s_dir = worktree.validate_parent_repo(
"/fake/repo/src")
self.assertEqual(parent_dir, Path("/fake/repo"))
self.assertEqual(g_config, Path("/fake/repo/.gclient"))
self.assertEqual(s_dir, Path("/fake/repo/src"))
@patch("pathlib.Path.read_text",
return_value='solutions = []\ncache_dir = "/tmp/cache"')
def test_check_cache_dir_present(self, mock_read):
with patch("builtins.print") as mock_print:
worktree.check_cache_dir(Path("fake/.gclient"))
# Should not print warning
self.assertFalse(
any("WARNING" in str(call) for call in mock_print.call_args_list))
@patch("pathlib.Path.read_text", return_value='solutions = []')
def test_check_cache_dir_missing(self, mock_read):
with patch("builtins.print") as mock_print:
worktree.check_cache_dir(Path("fake/.gclient"))
# Should print warning
mock_print.assert_any_call(
"\nWARNING: 'cache_dir' not found in your .gclient file.")
@patch("worktree.run_cmd")
def test_create_worktree(self, mock_run):
worktree.create_worktree("parent/src", "variant/src", "my_branch")
mock_run.assert_called_with(
["git", "worktree", "add", "variant/src", "-b", "my_branch"],
cwd="parent/src")
@patch("worktree.run_cmd")
def test_create_worktree_with_base(self, mock_run):
worktree.create_worktree("parent/src", "variant/src", "my_branch",
"base_branch")
# Should call git worktree add AND git branch --set-upstream-to
self.assertEqual(mock_run.call_count, 2)
mock_run.assert_any_call([
"git", "worktree", "add", "variant/src", "-b", "my_branch",
"base_branch"
],
cwd="parent/src")
mock_run.assert_any_call(
["git", "branch", "--set-upstream-to", "base_branch", "my_branch"],
cwd="variant/src")
def test_setup_vscode_color(self):
with patch("pathlib.Path.mkdir"), \
patch("pathlib.Path.exists", return_value=False), \
patch("pathlib.Path.write_text") as mock_write:
variant_src = Path("/tmp/src")
worktree.setup_vscode_color(variant_src, "red")
# Check if it writes valid JSON with titleBar colors
args, _ = mock_write.call_args
content = json.loads(args[0])
self.assertEqual(
content["workbench.colorCustomizations"]["titleBar.activeBackground"],
"#3a1414")
@patch("worktree.Path.exists")
def test_get_next_variant_name(self, mock_exists):
# Simulate 'bling_1' exists (True), but 'bling_2' does not (False)
mock_exists.side_effect = [True, False]
parent_dir = Path("/Users/vincb/bling")
name = worktree.get_next_variant_name(parent_dir)
self.assertEqual(name, "bling_2")
@patch("worktree.validate_parent_repo")
@patch("worktree.check_cache_dir")
@patch("worktree.Path.mkdir")
@patch("worktree.create_worktree")
@patch("shutil.copy2")
@patch("worktree.run_cmd")
@patch("worktree.Path.exists")
def test_main_internal_base(self, mock_exists, mock_run, mock_copy,
mock_create, mock_mkdir, mock_check,
mock_validate):
# Mocking validate_parent_repo
parent_dir = Path("/fake/repo")
gclient_config = parent_dir / ".gclient"
parent_src = parent_dir / "src"
mock_validate.return_value = (parent_dir, gclient_config, parent_src)
mock_check.return_value = True
# Mocking variant setup
# 1. get_next_variant_name (will be called in main)
# 3. internal_src.exists() (will be True)
mock_exists.side_effect = [False, False, True]
# Mocking args
with patch("sys.argv", [
"worktree.py", "/fake/repo", "--internal-base", "internal_base_branch"
]):
worktree.main()
# Verify internal logic
# run_cmd should be called for:
# 1. gclient sync
# 2. git checkout -b ... (internal)
# 3. git branch --set-upstream-to ... (internal)
# Find the index of internal commands in mock_run.call_args_list
calls = [call.args[0] for call in mock_run.call_args_list]
self.assertIn(["git", "checkout", "-b", "repo_1", "internal_base_branch"],
calls)
self.assertIn([
"git", "branch", "--set-upstream-to", "internal_base_branch", "repo_1"
], calls)
@patch("worktree.validate_parent_repo")
@patch("worktree.check_cache_dir")
@patch("worktree.Path.mkdir")
@patch("worktree.create_worktree")
@patch("shutil.copy2")
@patch("worktree.run_cmd")
@patch("worktree.Path.exists")
def test_main_internal_base_fetch_from_parent(self, mock_exists, mock_run,
mock_copy, mock_create,
mock_mkdir, mock_check,
mock_validate):
# Mocking validate_parent_repo
parent_dir = Path("/fake/repo")
gclient_config = parent_dir / ".gclient"
parent_src = parent_dir / "src"
mock_validate.return_value = (parent_dir, gclient_config, parent_src)
mock_check.return_value = True
# Mocking variant setup
# 1. get_next_variant_name (will be called in main)
# 2. variant_root.exists() (will be False)
# 3. internal_src.exists() (will be True)
mock_exists.side_effect = [False, False, True]
# Mocking run_cmd:
# 1. validate_parent_repo might call run_cmd (it doesn't in our mocks)
# 2. git show-ref --verify refs/heads/internal_base_branch (return None to simulate missing)
# 3. git remote add parent ...
# 4. git fetch parent ...
# 5. git checkout -b ...
# 6. git branch --set-upstream-to ...
mock_run.side_effect = [
None, # git show-ref returns None (captured=True)
None, # git remote add
None, # git fetch
None, # git checkout
None # git branch --set-upstream-to
]
# Mocking args
with patch("sys.argv", [
"worktree.py", "/fake/repo", "--internal-base", "internal_base_branch"
]):
worktree.main()
# Verify ios_internal logic
calls = [call.args[0] for call in mock_run.call_args_list]
self.assertIn(
["git", "remote", "add", "parent",
str(parent_src / "internal")], calls)
self.assertIn(["git", "fetch", "parent", "internal_base_branch"], calls)
self.assertIn(["git", "checkout", "-b", "repo_1", "FETCH_HEAD"], calls)
self.assertIn([
"git", "branch", "--set-upstream-to", "parent/internal_base_branch",
"repo_1"
], calls)
if __name__ == "__main__":
unittest.main()