import subprocess import pytest from .conftest import GIT2CPP_TEST_WASM def test_tag_list_empty(repo_init_with_commit, git2cpp_path, tmp_path): """Test listing tags when there are no tags.""" assert (tmp_path / "initial.txt").exists() cmd = [git2cpp_path, "tag"] p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True) assert p.returncode == 0 assert p.stdout == "" def test_tag_create_lightweight(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test creating a lightweight tag.""" assert (tmp_path / "initial.txt").exists() # Create a lightweight tag create_cmd = [git2cpp_path, "tag", "v1.0.0"] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True, check=True) # List tags to verify it was created list_cmd = [git2cpp_path, "tag"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout def test_tag_create_annotated(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test creating an annotated tag.""" assert (tmp_path / "initial.txt").exists() # Create an annotated tag create_cmd = [git2cpp_path, "tag", "-m", "Release version 1.0", "v1.0.0"] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True, check=True) # List tags to verify it was created list_cmd = [git2cpp_path, "tag", "-n", "1"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout assert "Release version 1.0" in p_list.stdout def test_tag_create_on_specific_commit( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path ): """Test creating a tag on a specific commit.""" assert (tmp_path / "initial.txt").exists() # Get the commit SHA before creating new commit old_head_cmd = [git2cpp_path, "rev-parse", "HEAD"] p_old_head = subprocess.run(old_head_cmd, capture_output=True, cwd=tmp_path, text=True) old_head_sha = p_old_head.stdout.strip() # Create a commit first file_path = tmp_path / "test_file.txt" file_path.write_text("test content") add_cmd = [git2cpp_path, "add", "test_file.txt"] subprocess.run(add_cmd, cwd=tmp_path, check=True) commit_cmd = [git2cpp_path, "commit", "-m", "test commit"] subprocess.run(commit_cmd, cwd=tmp_path, check=True) # Get new HEAD commit SHA new_head_cmd = [git2cpp_path, "rev-parse", "HEAD"] p_new_head = subprocess.run(new_head_cmd, capture_output=True, cwd=tmp_path, text=True) new_head_sha = p_new_head.stdout.strip() # Verify we actually created a new commit assert old_head_sha != new_head_sha # Create tag on HEAD tag_cmd = [git2cpp_path, "tag", "v1.0.0", "HEAD"] subprocess.run(tag_cmd, capture_output=True, cwd=tmp_path, check=True) # Verify tag exists list_cmd = [git2cpp_path, "tag"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout # Get commit SHA that the tag points to tag_sha_cmd = [git2cpp_path, "rev-parse", "v1.0.0^{commit}"] p_tag_sha = subprocess.run(tag_sha_cmd, capture_output=True, cwd=tmp_path, text=True) tag_sha = p_tag_sha.stdout.strip() # Verify tag points to new HEAD, not old HEAD assert tag_sha == new_head_sha assert tag_sha != old_head_sha def test_tag_delete(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test deleting a tag.""" assert (tmp_path / "initial.txt").exists() # Create a tag create_cmd = [git2cpp_path, "tag", "v1.0.0"] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True, check=True) # Delete the tag delete_cmd = [git2cpp_path, "tag", "-d", "v1.0.0"] p_delete = subprocess.run(delete_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_delete.returncode == 0 assert "Deleted tag 'v1.0.0'" in p_delete.stdout # Verify tag is gone list_cmd = [git2cpp_path, "tag"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" not in p_list.stdout def test_tag_delete_nonexistent(repo_init_with_commit, git2cpp_path, tmp_path): """Test deleting a tag that doesn't exist.""" assert (tmp_path / "initial.txt").exists() # Try to delete non-existent tag delete_cmd = [git2cpp_path, "tag", "-d", "nonexistent"] p_delete = subprocess.run(delete_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_delete.returncode != 0 assert "not found" in p_delete.stderr @pytest.mark.parametrize("list_flag", ["", "-l", "--list"]) def test_tag_list(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, list_flag): """Test listing tags with -l or --list flag.""" assert (tmp_path / "initial.txt").exists() # Create a tag tag_cmd = [git2cpp_path, "tag", "v1.0.0"] subprocess.run(tag_cmd, capture_output=True, cwd=tmp_path, text=True) # List tags list_cmd = [git2cpp_path, "tag", list_flag] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout def test_tag_list_with_pattern(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test listing tags with a pattern.""" assert (tmp_path / "initial.txt").exists() # Create tags with different prefixes tag_cmd_1 = [git2cpp_path, "tag", "v1.0.0"] subprocess.run(tag_cmd_1, capture_output=True, cwd=tmp_path, text=True) tag_cmd_2 = [git2cpp_path, "tag", "v1.0.1"] subprocess.run(tag_cmd_2, capture_output=True, cwd=tmp_path, text=True) tag_cmd_3 = [git2cpp_path, "tag", "release-1.0"] subprocess.run(tag_cmd_3, capture_output=True, cwd=tmp_path, text=True) # List only tags matching pattern list_cmd = [git2cpp_path, "tag", "-l", "v1.0*"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout assert "v1.0.1" in p_list.stdout assert "release-1.0" not in p_list.stdout def test_tag_list_with_message_lines( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path ): """Test listing tags with message lines (-n flag).""" assert (tmp_path / "initial.txt").exists() # Create an annotated tag with a message create_cmd = [ git2cpp_path, "tag", "-m", "First line\nSecond line\nThird line\nForth line", "v1.0.0", ] p_create = subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_create.returncode == 0 # List tags with message lines list_cmd = [git2cpp_path, "tag", "-n", "3", "-l"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout assert "First line" in p_list.stdout assert "Second line" in p_list.stdout assert "Third line" in p_list.stdout assert "Forth line" not in p_list.stdout @pytest.mark.parametrize("force_flag", ["-f", "--force"]) def test_tag_force_replace( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, force_flag ): """Test replacing an existing tag with -f or --force flag.""" assert (tmp_path / "initial.txt").exists() # Create initial tag create_cmd_1 = [git2cpp_path, "tag", "v1.0.0"] subprocess.run(create_cmd_1, capture_output=True, cwd=tmp_path, text=True, check=True) # Try to create same tag without force (should fail) create_cmd_2 = [git2cpp_path, "tag", "v1.0.0"] p_create_2 = subprocess.run(create_cmd_2, capture_output=True, cwd=tmp_path) assert p_create_2.returncode != 0 # Create same tag with force (should succeed) create_cmd_3 = [git2cpp_path, "tag", force_flag, "v1.0.0"] p_create_3 = subprocess.run(create_cmd_3, capture_output=True, cwd=tmp_path, text=True) assert p_create_3.returncode == 0 def test_tag_nogit(git2cpp_path, tmp_path): """Test tag command outside a git repository.""" cmd = [git2cpp_path, "tag"] p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True) assert p.returncode != 0 def test_tag_annotated_no_message(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test creating an annotated tag without a message should fail.""" assert (tmp_path / "initial.txt").exists() # Create a commit with a known message file_path = tmp_path / "test_file.txt" file_path.write_text("test content") add_cmd = [git2cpp_path, "add", "test_file.txt"] subprocess.run(add_cmd, cwd=tmp_path, check=True) commit_cmd = [git2cpp_path, "commit", "-m", "my specific commit message"] subprocess.run(commit_cmd, cwd=tmp_path, check=True) if GIT2CPP_TEST_WASM: pytest.skip("Not possible to pass empty argument to wasm") # Create tag with empty message (should create lightweight tag) create_cmd = [git2cpp_path, "tag", "-m", "", "v1.0.0"] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, check=True) # List tag with messages - lightweight tag shows commit message list_cmd = [git2cpp_path, "tag", "-n", "1"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout # Lightweight tag shows the commit message, not a tag message assert "my specific commit message" in p_list.stdout def test_tag_multiple_create_and_list( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path ): """Test creating multiple tags and listing them.""" assert (tmp_path / "initial.txt").exists() # Create multiple tags tags = ["v1.0.0", "v1.0.1", "v1.1.0", "v2.0.0"] for tag in tags: create_cmd = [git2cpp_path, "tag", tag] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, check=True) # List all tags list_cmd = [git2cpp_path, "tag"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 # Verify all tags are in the list for tag in tags: assert tag in p_list.stdout def test_tag_on_new_commit(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): """Test creating tags on new commits.""" assert (tmp_path / "initial.txt").exists() # Tag the current commit tag_cmd_1 = [git2cpp_path, "tag", "before-change"] subprocess.run(tag_cmd_1, cwd=tmp_path, check=True) # Make a new commit file_path = tmp_path / "new_file.txt" file_path.write_text("new content") add_cmd = [git2cpp_path, "add", "new_file.txt"] subprocess.run(add_cmd, cwd=tmp_path, check=True) commit_cmd = [git2cpp_path, "commit", "-m", "new commit"] subprocess.run(commit_cmd, cwd=tmp_path, check=True) # Tag the new commit tag_cmd_2 = [git2cpp_path, "tag", "after-change"] subprocess.run(tag_cmd_2, cwd=tmp_path, check=True) # List tags list_cmd = [git2cpp_path, "tag"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "before-change" in p_list.stdout assert "after-change" in p_list.stdout def test_tag_create_annotated_with_a_flag( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path ): """Test creating an annotated tag using -a flag.""" assert (tmp_path / "initial.txt").exists() # Create an annotated tag using -a and -m create_cmd = [git2cpp_path, "tag", "-a", "-m", "Release version 1.0", "v1.0.0"] subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True, check=True) # List tags with message lines to verify it was created as an annotated tag list_cmd = [git2cpp_path, "tag", "-n", "1"] p_list = subprocess.run(list_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_list.returncode == 0 assert "v1.0.0" in p_list.stdout assert "Release version 1.0" in p_list.stdout def test_tag_annotate_flag_requires_message( repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path ): """Test that -a/--annotate without -m fails.""" assert (tmp_path / "initial.txt").exists() create_cmd = [git2cpp_path, "tag", "-a", "v1.0.0"] p = subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True) assert p.returncode != 0 assert "requires -m" in p.stderr def test_tag_errors(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path): assert (tmp_path / "initial.txt").exists() # Test that -a/--annotate without -m fails. create_cmd = [git2cpp_path, "tag", "-a", "v1.0.0"] p_create = subprocess.run(create_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_create.returncode != 0 assert "requires -m" in p_create.stderr # Test that command fails when no message del_cmd = [git2cpp_path, "tag", "-d"] p_del = subprocess.run(del_cmd, capture_output=True, cwd=tmp_path, text=True) assert p_del.returncode != 0