[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/QuantStack/git2cpp/main/test/test_rebase.py [Back]  [Original]

import subprocess


def test_rebase_basic(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test basic rebase operation with fast-forward"""
    assert (tmp_path / "initial.txt").exists()

    # Create a feature branch
    checkout_cmd = [git2cpp_path, "checkout", "-b", "feature"]
    p_checkout = subprocess.run(checkout_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_checkout.returncode == 0

    # Create a commit on feature branch
    file_path = tmp_path / "feature_file.txt"
    file_path.write_text("feature content")

    add_cmd = [git2cpp_path, "add", "feature_file.txt"]
    p_add = subprocess.run(add_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_add.returncode == 0

    commit_cmd = [git2cpp_path, "commit", "-m", "feature commit"]
    p_commit = subprocess.run(commit_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_commit.returncode == 0

    # Go back to master and create another commit
    checkout_master_cmd = [git2cpp_path, "checkout", "main"]
    p_checkout_master = subprocess.run(
        checkout_master_cmd, capture_output=True, cwd=tmp_path, text=True
    )
    assert p_checkout_master.returncode == 0

    file_path_2 = tmp_path / "master_file.txt"
    file_path_2.write_text("master content")

    add_cmd_2 = [git2cpp_path, "add", "master_file.txt"]
    p_add_2 = subprocess.run(add_cmd_2, capture_output=True, cwd=tmp_path, text=True)
    assert p_add_2.returncode == 0

    commit_cmd_2 = [git2cpp_path, "commit", "-m", "master commit"]
    p_commit_2 = subprocess.run(commit_cmd_2, capture_output=True, cwd=tmp_path, text=True)
    assert p_commit_2.returncode == 0

    # Switch to feature and rebase onto master
    checkout_feature_cmd = [git2cpp_path, "checkout", "feature"]
    p_checkout_feature = subprocess.run(
        checkout_feature_cmd, capture_output=True, cwd=tmp_path, text=True
    )
    assert p_checkout_feature.returncode == 0

    rebase_cmd = [git2cpp_path, "rebase", "main"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode == 0
    assert "Successfully rebased" in p_rebase.stdout
    assert "Rebasing 1 commit(s)" in p_rebase.stdout

    # Verify both files exist
    assert (tmp_path / "feature_file.txt").exists()
    assert (tmp_path / "master_file.txt").exists()


def test_rebase_multiple_commits(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase with multiple commits"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch with multiple commits
    checkout_cmd = [git2cpp_path, "checkout", "-b", "feature"]
    p_checkout = subprocess.run(checkout_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_checkout.returncode == 0

    # First commit
    file_1 = tmp_path / "file_1.txt"
    file_1.write_text("content 1")
    add_cmd_1 = [git2cpp_path, "add", "file_1.txt"]
    subprocess.run(add_cmd_1, cwd=tmp_path, text=True)
    commit_cmd_1 = [git2cpp_path, "commit", "-m", "commit 1"]
    subprocess.run(commit_cmd_1, cwd=tmp_path, text=True)

    # Second commit
    file_2 = tmp_path / "file_2.txt"
    file_2.write_text("content 2")
    add_cmd_2 = [git2cpp_path, "add", "file_2.txt"]
    subprocess.run(add_cmd_2, cwd=tmp_path, text=True)
    commit_cmd_2 = [git2cpp_path, "commit", "-m", "commit 2"]
    subprocess.run(commit_cmd_2, cwd=tmp_path, text=True)

    # Third commit
    file_3 = tmp_path / "file_3.txt"
    file_3.write_text("content 3")
    add_cmd_3 = [git2cpp_path, "add", "file_3.txt"]
    subprocess.run(add_cmd_3, cwd=tmp_path, text=True)
    commit_cmd_3 = [git2cpp_path, "commit", "-m", "commit 3"]
    subprocess.run(commit_cmd_3, cwd=tmp_path, text=True)

    # Go to master and add a commit
    checkout_master_cmd = [git2cpp_path, "checkout", "main"]
    subprocess.run(checkout_master_cmd, cwd=tmp_path)

    master_file = tmp_path / "master_file.txt"
    master_file.write_text("master")
    subprocess.run([git2cpp_path, "add", "master_file.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Rebase feature onto master
    checkout_feature_cmd = [git2cpp_path, "checkout", "feature"]
    subprocess.run(checkout_feature_cmd, cwd=tmp_path)

    rebase_cmd = [git2cpp_path, "rebase", "main"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode == 0
    assert "Rebasing 3 commit(s)" in p_rebase.stdout
    assert "Successfully rebased" in p_rebase.stdout

    # Verify all files exist
    assert (tmp_path / "file_1.txt").exists()
    assert (tmp_path / "file_2.txt").exists()
    assert (tmp_path / "file_3.txt").exists()
    assert (tmp_path / "master_file.txt").exists()


def test_rebase_with_conflicts(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase with conflicts"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch
    checkout_cmd = [git2cpp_path, "checkout", "-b", "feature"]
    subprocess.run(checkout_cmd, capture_output=True, cwd=tmp_path, text=True)

    # Create conflicting file on feature
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature commit"], cwd=tmp_path)

    # Go to master and create conflicting commit
    checkout_master_cmd = [git2cpp_path, "checkout", "main"]
    subprocess.run(checkout_master_cmd, cwd=tmp_path)

    conflict_file.write_text("master content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Try to rebase feature onto master
    checkout_feature_cmd = [git2cpp_path, "checkout", "feature"]
    subprocess.run(checkout_feature_cmd, cwd=tmp_path)

    rebase_cmd = [git2cpp_path, "rebase", "main"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode == 0
    assert "Conflicts detected" in p_rebase.stdout
    assert "rebase --continue" in p_rebase.stdout
    assert "rebase --skip" in p_rebase.stdout
    assert "rebase --abort" in p_rebase.stdout


def test_rebase_abort(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase abort after conflicts"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch
    checkout_cmd = [git2cpp_path, "checkout", "-b", "feature"]
    subprocess.run(checkout_cmd, cwd=tmp_path)

    # Create conflicting file on feature
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature commit"], cwd=tmp_path)

    # Go to master and create conflicting commit
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("master content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Rebase and get conflict
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Abort the rebase
    abort_cmd = [git2cpp_path, "rebase", "--abort"]
    p_abort = subprocess.run(abort_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_abort.returncode == 0
    assert "Rebase aborted" in p_abort.stdout

    # Verify we're back to original state
    assert conflict_file.read_text() == "feature content"


def test_rebase_continue(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase continue after resolving conflicts"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch
    subprocess.run([git2cpp_path, "checkout", "-b", "feature"], cwd=tmp_path)

    # Create conflicting file on feature
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature commit"], cwd=tmp_path)

    # Go to master and create conflicting commit
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("master content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Rebase and get conflict
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Resolve conflict
    conflict_file.write_text("resolved content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)

    # Continue rebase
    continue_cmd = [git2cpp_path, "rebase", "--continue"]
    p_continue = subprocess.run(continue_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_continue.returncode == 0
    assert "Successfully rebased" in p_continue.stdout

    # Verify resolution
    assert conflict_file.read_text() == "resolved content"


def test_rebase_skip(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase skip to skip current commit"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch
    subprocess.run([git2cpp_path, "checkout", "-b", "feature"], cwd=tmp_path)

    # Create conflicting file on feature
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature commit"], cwd=tmp_path)

    # Go to master and create conflicting commit
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("master content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Rebase and get conflict
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Skip the conflicting commit
    skip_cmd = [git2cpp_path, "rebase", "--skip"]
    p_skip = subprocess.run(skip_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_skip.returncode == 0
    assert "Skipping" in p_skip.stdout


def test_rebase_quit(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase quit to cleanup state without resetting HEAD"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch
    subprocess.run([git2cpp_path, "checkout", "-b", "feature"], cwd=tmp_path)

    # Create conflicting file
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature commit"], cwd=tmp_path)

    # Create conflict on master
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("master content")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "master commit"], cwd=tmp_path)

    # Start rebase
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Quit rebase
    quit_cmd = [git2cpp_path, "rebase", "--quit"]
    p_quit = subprocess.run(quit_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_quit.returncode == 0
    assert "Rebase state cleaned up" in p_quit.stdout
    assert "HEAD not reset" in p_quit.stdout


def test_rebase_onto(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test rebase with --onto option"""
    assert (tmp_path / "initial.txt").exists()

    # Create first branch
    subprocess.run([git2cpp_path, "checkout", "-b", "branch1"], cwd=tmp_path)
    file1 = tmp_path / "file1.txt"
    file1.write_text("branch1")
    subprocess.run([git2cpp_path, "add", "file1.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "branch1 commit"], cwd=tmp_path)

    # Create second branch from branch1
    subprocess.run([git2cpp_path, "checkout", "-b", "branch2"], cwd=tmp_path)
    file2 = tmp_path / "file2.txt"
    file2.write_text("branch2")
    subprocess.run([git2cpp_path, "add", "file2.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "branch2 commit"], cwd=tmp_path)

    # Create target branch from master
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "checkout", "-b", "target"], cwd=tmp_path)
    target_file = tmp_path / "target.txt"
    target_file.write_text("target")
    subprocess.run([git2cpp_path, "add", "target.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "target commit"], cwd=tmp_path)

    # Rebase branch2 onto target, upstream is branch1
    rebase_cmd = [git2cpp_path, "rebase", "branch1", "branch2", "--onto", "target"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode == 0

    # Verify target file exists and branch2 file exists, but not branch1 file
    assert not (tmp_path / "target.txt").exists()
    assert (tmp_path / "file2.txt").exists()


def test_rebase_no_upstream_error(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path):
    """Test that rebase without upstream argument fails"""
    assert (tmp_path / "initial.txt").exists()

    rebase_cmd = [git2cpp_path, "rebase"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode != 0
    assert "upstream is required for rebase" in p_rebase.stderr


def test_rebase_invalid_upstream_error(
    repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path
):
    """Test that rebase with invalid upstream fails"""
    assert (tmp_path / "initial.txt").exists()

    rebase_cmd = [git2cpp_path, "rebase", "nonexistent-branch"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode != 0
    assert (
        "could not resolve upstream" in p_rebase.stderr
        or "could not resolve upstream" in p_rebase.stdout
    )


def test_rebase_already_in_progress_error(
    repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path
):
    """Test that starting rebase when one is in progress fails"""
    assert (tmp_path / "initial.txt").exists()

    # Create feature branch with conflict
    subprocess.run([git2cpp_path, "checkout", "-b", "feature"], cwd=tmp_path)
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature"], cwd=tmp_path)

    # Create conflict on master
    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("main")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "main"], cwd=tmp_path)

    # Start rebase with conflict
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Try to start another rebase
    rebase_cmd = [git2cpp_path, "rebase", "main"]
    p_rebase = subprocess.run(rebase_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_rebase.returncode != 0
    assert (
        "rebase is already in progress" in p_rebase.stderr
        or "rebase is already in progress" in p_rebase.stdout
    )


def test_rebase_continue_without_rebase_error(
    repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path
):
    """Test that --continue without rebase in progress fails"""
    assert (tmp_path / "initial.txt").exists()

    continue_cmd = [git2cpp_path, "rebase", "--continue"]
    p_continue = subprocess.run(continue_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_continue.returncode != 0
    assert (
        "No rebase in progress" in p_continue.stderr or "No rebase in progress" in p_continue.stdout
    )


def test_rebase_continue_with_unresolved_conflicts(
    repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path
):
    """Test that --continue with unresolved conflicts fails"""
    assert (tmp_path / "initial.txt").exists()

    # Create conflict scenario
    subprocess.run([git2cpp_path, "checkout", "-b", "feature"], cwd=tmp_path)
    conflict_file = tmp_path / "conflict.txt"
    conflict_file.write_text("feature")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "feature"], cwd=tmp_path)

    subprocess.run([git2cpp_path, "checkout", "main"], cwd=tmp_path)
    conflict_file.write_text("main")
    subprocess.run([git2cpp_path, "add", "conflict.txt"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "commit", "-m", "main"], cwd=tmp_path)

    # Start rebase
    subprocess.run([git2cpp_path, "checkout", "feature"], cwd=tmp_path)
    subprocess.run([git2cpp_path, "rebase", "main"], cwd=tmp_path)

    # Try to continue without resolving
    continue_cmd = [git2cpp_path, "rebase", "--continue"]
    p_continue = subprocess.run(continue_cmd, capture_output=True, cwd=tmp_path, text=True)
    assert p_continue.returncode != 0
    assert "resolve conflicts" in p_continue.stderr or "resolve conflicts" in p_continue.stdout

Web Proxy Viewer  |  New URL  |  Original Page