import re import subprocess import pytest from .conftest import strip_ansi_colours @pytest.mark.parametrize("format_flag", ["", "--format=full", "--format=fuller"]) def test_log(commit_env_config, git2cpp_path, tmp_path, format_flag): cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 p = tmp_path / "mook_file.txt" p.write_text("") cmd_add = [git2cpp_path, "add", "mook_file.txt"] p_add = subprocess.run(cmd_add, cwd=tmp_path, text=True) assert p_add.returncode == 0 cmd_commit = [git2cpp_path, "commit", "-m", "test commit"] p_commit = subprocess.run(cmd_commit, cwd=tmp_path, text=True) assert p_commit.returncode == 0 cmd_log = [git2cpp_path, "log"] if format_flag != "": cmd_log.append(format_flag) p_log = subprocess.run(cmd_log, capture_output=True, cwd=tmp_path, text=True) assert p_log.returncode == 0 assert "Jane Doe" in p_log.stdout assert "test commit" in p_log.stdout if format_flag == "": assert "Commit" not in p_log.stdout else: assert "Commit" in p_log.stdout if format_flag == "--format=full": assert "Date" not in p_log.stdout else: assert "CommitDate" in p_log.stdout def test_log_nogit(commit_env_config, git2cpp_path, tmp_path): cmd_log = [git2cpp_path, "log"] p_log = subprocess.run(cmd_log, capture_output=True, cwd=tmp_path, text=True) assert p_log.returncode != 0 assert "error: could not find repository at" in p_log.stderr @pytest.mark.parametrize("max_count_flag", ["", "-n", "--max-count"]) def test_max_count( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, max_count_flag ): assert (tmp_path / "initial.txt").exists() p2 = tmp_path / "second.txt" p2.write_text("second file") cmd_add2 = [git2cpp_path, "add", "second.txt"] subprocess.run(cmd_add2, capture_output=True, cwd=tmp_path, text=True, check=True) cmd_commit2 = [git2cpp_path, "commit", "-m", "Second commit"] subprocess.run(cmd_commit2, capture_output=True, cwd=tmp_path, text=True, check=True) p3 = tmp_path / "third.txt" p3.write_text("third file") cmd_add3 = [git2cpp_path, "add", "third.txt"] subprocess.run(cmd_add3, capture_output=True, cwd=tmp_path, text=True, check=True) cmd_commit3 = [git2cpp_path, "commit", "-m", "Third commit"] subprocess.run(cmd_commit3, capture_output=True, cwd=tmp_path, text=True, check=True) cmd_log = [git2cpp_path, "log"] if max_count_flag != "": cmd_log.append(max_count_flag) cmd_log.append("2") p_log = subprocess.run(cmd_log, capture_output=True, cwd=tmp_path, text=True) assert p_log.returncode == 0 if max_count_flag == "": assert p_log.stdout.count("Author") > 2 else: assert p_log.stdout.count("Author") == 2 def test_log_with_head_reference(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test that HEAD reference is shown on the latest commit.""" assert (tmp_path / "initial.txt").exists() # Create a new commit p = tmp_path / "test_file.txt" p.write_text("test content") subprocess.run([git2cpp_path, "add", "test_file.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", "test commit"], cwd=tmp_path, check=True) # Run log with max count 1 to get only the latest commit p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # Check that HEAD reference is shown assert "HEAD ->" in strip_ansi_colours(p_log.stdout) assert "master" in p_log.stdout or "main" in p_log.stdout def test_log_with_tag(commit_env_config, git2cpp_path, tmp_path): """Test that tags are shown in log output.""" cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 # Create a commit and tag it p = tmp_path / "tagged_file.txt" p.write_text("tagged content") subprocess.run([git2cpp_path, "add", "tagged_file.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", "tagged commit"], cwd=tmp_path, check=True) # Create a tag (using git command since git2cpp might not have tag creation yet) subprocess.run([git2cpp_path, "tag", "v1.0.0"], cwd=tmp_path, check=True) # Run log p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # Check that tag is shown assert "tag: v1.0.0" in p_log.stdout def test_log_with_multiple_tags(commit_env_config, git2cpp_path, tmp_path): """Test that multiple tags on the same commit are all shown.""" cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 # Create a commit p = tmp_path / "multi_tag_file.txt" p.write_text("content") subprocess.run([git2cpp_path, "add", "multi_tag_file.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", "multi tag commit"], cwd=tmp_path, check=True) # Create multiple tags subprocess.run([git2cpp_path, "tag", "v1.0.0"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "tag", "stable"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "tag", "latest"], cwd=tmp_path, check=True) # Run log p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # Check that all tags are shown assert "tag: v1.0.0" in p_log.stdout assert "tag: stable" in p_log.stdout assert "tag: latest" in p_log.stdout def test_log_with_annotated_tag(commit_env_config, git2cpp_path, tmp_path): """Test that annotated tags are shown in log output.""" cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 # Create a commit p = tmp_path / "annotated_tag_file.txt" p.write_text("content") subprocess.run([git2cpp_path, "add", "annotated_tag_file.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", "annotated tag commit"], cwd=tmp_path, check=True) # Create an annotated tag subprocess.run( [git2cpp_path, "tag", "-a", "v2.0.0", "-m", "Version 2.0.0"], cwd=tmp_path, check=True, ) # Run log p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # Check that annotated tag is shown assert "tag: v2.0.0" in p_log.stdout def test_log_with_branch(commit_env_config, git2cpp_path, tmp_path): """Test that branches are shown in log output.""" cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 # Create a commit p = tmp_path / "branch_file.txt" p.write_text("content") subprocess.run([git2cpp_path, "add", "branch_file.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", "branch commit"], cwd=tmp_path, check=True) # Create a new branch pointing to HEAD subprocess.run([git2cpp_path, "branch", "feature-branch"], cwd=tmp_path, check=True) # Run log p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # Check that both branches are shown (HEAD -> master/main and feature-branch) assert "feature-branch" in p_log.stdout def test_log_with_remote_branches(xtl_clone, commit_env_config, git2cpp_path, tmp_path): """Test that remote branches are shown in log output.""" assert (tmp_path / "xtl").exists() xtl_path = tmp_path / "xtl" # The xtl_clone fixture already has remote branches (origin/master, etc.) # Run log to check they appear p_log = subprocess.run( [git2cpp_path, "log", "-n", "1"], capture_output=True, cwd=xtl_path, text=True ) assert p_log.returncode == 0 # Check that origin remote branches are shown assert "origin/master" in p_log.stdout def test_log_commit_without_references(commit_env_config, git2cpp_path, tmp_path): """Test that commits without any references don't show empty parentheses.""" cmd_init = [git2cpp_path, "init", "."] p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path) assert p_init.returncode == 0 # Create two commits - the second one will have refs, the first won't for i in range(2): p = tmp_path / f"file_{i}.txt" p.write_text(f"content {i}") subprocess.run([git2cpp_path, "add", f"file_{i}.txt"], cwd=tmp_path, check=True) subprocess.run([git2cpp_path, "commit", "-m", f"commit {i}"], cwd=tmp_path, check=True) # Run log with 2 commits p_log = subprocess.run( [git2cpp_path, "log", "-n", "2"], capture_output=True, cwd=tmp_path, text=True ) assert p_log.returncode == 0 # First commit line should have references lines = strip_ansi_colours(p_log.stdout).split("\n") first_commit_line = [line for line in lines if line.startswith("commit")][0] assert "(" in first_commit_line # Has references # Second commit (older one) should not have empty parentheses second_commit_line = [line for line in lines if line.startswith("commit")][1] # Should either have no parentheses or have actual references if "(" in second_commit_line: # If it has parentheses, they shouldn't be empty assert "()" not in second_commit_line @pytest.mark.parametrize("abbrev_commit_flag", ["", "--abbrev-commit", "--no-abbrev-commit"]) @pytest.mark.parametrize("abbrev_flag", ["", "--abbrev=10"]) def test_log_abbrev_commit_flags( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, abbrev_commit_flag, abbrev_flag, ): """Test for --abbrev-commit, --abbrev= (only applies when --abbrev-commit is set) and --no-abbrev-commit""" assert (tmp_path / "initial.txt").exists() cmd = [git2cpp_path, "log", "-n", "1"] if abbrev_commit_flag != "": cmd.append(abbrev_commit_flag) if abbrev_flag != "": cmd.append(abbrev_flag) p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True) assert p.returncode == 0 m = re.search(r"^commit\s+([0-9a-fA-F]+)", strip_ansi_colours(p.stdout), flags=re.MULTILINE) if abbrev_commit_flag in ["", "--no-abbrev-commit"]: assert len(m.group(1)) == 40 else: if abbrev_flag == "--abbrev=10": assert len(m.group(1)) == 10 else: assert len(m.group(1)) == 7 def test_log_format_oneline(repo_init_with_commit, git2cpp_path, tmp_path): """Test --format=oneline prints the full sha""" assert (tmp_path / "initial.txt").exists() p = subprocess.run( [git2cpp_path, "rev-parse", "HEAD"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 full_sha = p.stdout.strip() p = subprocess.run( [git2cpp_path, "log", "--format=oneline", "-n", "1"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 # assert: should contain full 40-hex sha and subject assert full_sha in p.stdout assert "Initial commit" in p.stdout def test_log_oneline(repo_init_with_commit, git2cpp_path, tmp_path): """Test --oneline prints the default length sha (i.e 7)""" assert (tmp_path / "initial.txt").exists() p = subprocess.run( [git2cpp_path, "rev-parse", "HEAD"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 full_sha = str(p.stdout.strip()) abbrev7 = full_sha[:7] subprocess.run([git2cpp_path, "tag", "v1"], capture_output=True, cwd=tmp_path, check=True) p = subprocess.run( [git2cpp_path, "log", "--oneline", "-n", "1"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 assert abbrev7 in p.stdout assert full_sha not in p.stdout assert "tag: v1" in p.stdout assert "Initial commit" in p.stdout def test_log_oneline_no_abbrev_commit(repo_init_with_commit, git2cpp_path, tmp_path): """Test --oneline prints prints the full sha when using --no-abbrev-commit""" assert (tmp_path / "initial.txt").exists() p = subprocess.run( [git2cpp_path, "rev-parse", "HEAD"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 full_sha = str(p.stdout.strip()) p = subprocess.run( [git2cpp_path, "log", "--oneline", "--no-abbrev-commit", "-n", "1"], cwd=tmp_path, capture_output=True, text=True, ) assert p.returncode == 0 assert full_sha in p.stdout assert "Initial commit" in p.stdout