Add remaining test files: test_merge, test_sync, test_validate
This commit is contained in:
209
confsync/tests/test_merge.py
Normal file
209
confsync/tests/test_merge.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""Tests for merge strategies."""
|
||||
|
||||
import pytest
|
||||
from confsync.core.merger import (
|
||||
Merger,
|
||||
KeepLocalStrategy,
|
||||
KeepRemoteStrategy,
|
||||
KeepCommonStrategy,
|
||||
ThreeWayMergeStrategy,
|
||||
UnionMergeStrategy,
|
||||
MergeConflict,
|
||||
)
|
||||
|
||||
|
||||
class TestMergeStrategies:
|
||||
"""Tests for individual merge strategies."""
|
||||
|
||||
def test_keep_local_strategy(self):
|
||||
"""Test keep local strategy."""
|
||||
strategy = KeepLocalStrategy()
|
||||
|
||||
local = "local content"
|
||||
remote = "remote content"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote)
|
||||
|
||||
assert success
|
||||
assert merged == local
|
||||
assert conflict is None
|
||||
|
||||
def test_keep_remote_strategy(self):
|
||||
"""Test keep remote strategy."""
|
||||
strategy = KeepRemoteStrategy()
|
||||
|
||||
local = "local content"
|
||||
remote = "remote content"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote)
|
||||
|
||||
assert success
|
||||
assert merged == remote
|
||||
assert conflict is None
|
||||
|
||||
def test_keep_common_strategy(self):
|
||||
"""Test keep common strategy."""
|
||||
strategy = KeepCommonStrategy()
|
||||
|
||||
local = "line1\nline2\nline3"
|
||||
remote = "line2\nline3\nline4"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote)
|
||||
|
||||
assert success
|
||||
assert "line2" in merged
|
||||
assert "line3" in merged
|
||||
assert "line1" not in merged
|
||||
assert "line4" not in merged
|
||||
|
||||
def test_three_way_merge_identical(self):
|
||||
"""Test three-way merge with identical content."""
|
||||
strategy = ThreeWayMergeStrategy()
|
||||
|
||||
content = "same content"
|
||||
success, merged, conflict = strategy.merge(content, content, content)
|
||||
|
||||
assert success
|
||||
assert merged == content
|
||||
assert conflict is None
|
||||
|
||||
def test_three_way_merge_no_conflicts(self):
|
||||
"""Test three-way merge without conflicts."""
|
||||
strategy = ThreeWayMergeStrategy()
|
||||
|
||||
base = "same content"
|
||||
local = "same content"
|
||||
remote = "same content"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote, base)
|
||||
|
||||
assert success
|
||||
assert conflict is None
|
||||
|
||||
def test_union_merge_strategy(self):
|
||||
"""Test union merge strategy."""
|
||||
strategy = UnionMergeStrategy()
|
||||
|
||||
local = "line1\nline2\nline3"
|
||||
remote = "line3\nline4\nline5"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote)
|
||||
|
||||
assert success
|
||||
assert "line1" in merged
|
||||
assert "line2" in merged
|
||||
assert "line3" in merged
|
||||
assert "line4" in merged
|
||||
assert "line5" in merged
|
||||
|
||||
def test_union_merge_removes_duplicates(self):
|
||||
"""Test union merge removes duplicate lines."""
|
||||
strategy = UnionMergeStrategy()
|
||||
|
||||
local = "line1\nline2\nline2"
|
||||
remote = "line2\nline3"
|
||||
|
||||
success, merged, conflict = strategy.merge(local, remote)
|
||||
|
||||
assert success
|
||||
lines = merged.split('\n')
|
||||
assert lines.count("line2") == 1
|
||||
|
||||
|
||||
class TestMergeConflict:
|
||||
"""Tests for merge conflict handling."""
|
||||
|
||||
def test_format_conflict(self):
|
||||
"""Test conflict formatting."""
|
||||
conflict = MergeConflict(
|
||||
file_path="/test/file.txt",
|
||||
local_lines=["local line 1", "local line 2"],
|
||||
remote_lines=["remote line 1", "remote line 2"],
|
||||
base_lines=["base line 1"],
|
||||
)
|
||||
|
||||
formatted = conflict.format_conflict()
|
||||
|
||||
assert "<<<<<<< LOCAL" in formatted
|
||||
assert "=======" in formatted
|
||||
assert ">>>>>>> REMOTE" in formatted
|
||||
assert "local line 1" in formatted
|
||||
assert "remote line 1" in formatted
|
||||
|
||||
|
||||
class TestMerger:
|
||||
"""Tests for the main Merger class."""
|
||||
|
||||
def test_get_strategy(self):
|
||||
"""Test getting strategy by name."""
|
||||
merger = Merger()
|
||||
|
||||
strategy = merger.get_strategy("keep_local")
|
||||
assert isinstance(strategy, KeepLocalStrategy)
|
||||
|
||||
strategy = merger.get_strategy("three_way")
|
||||
assert isinstance(strategy, ThreeWayMergeStrategy)
|
||||
|
||||
def test_merge_file_with_strategy(self):
|
||||
"""Test merging a single file with strategy."""
|
||||
merger = Merger()
|
||||
|
||||
local = "local config"
|
||||
remote = "remote config"
|
||||
|
||||
success, merged, conflict = merger.merge_file(
|
||||
local, remote, strategy_name="keep_local"
|
||||
)
|
||||
|
||||
assert success
|
||||
assert merged == "local config"
|
||||
|
||||
def test_merge_multiple_files(self):
|
||||
"""Test merging multiple files at once."""
|
||||
merger = Merger()
|
||||
|
||||
files = [
|
||||
{
|
||||
"path": "/test/file1.txt",
|
||||
"local": "local1",
|
||||
"remote": "remote1",
|
||||
"strategy": "keep_local",
|
||||
},
|
||||
{
|
||||
"path": "/test/file2.txt",
|
||||
"local": "local2",
|
||||
"remote": "remote2",
|
||||
"strategy": "keep_remote",
|
||||
},
|
||||
]
|
||||
|
||||
results = merger.merge_multiple(files)
|
||||
|
||||
assert "/test/file1.txt" in results
|
||||
assert "/test/file2.txt" in results
|
||||
|
||||
|
||||
class TestMergeResult:
|
||||
"""Tests for merge result model."""
|
||||
|
||||
def test_merge_result_serialization(self):
|
||||
"""Test MergeResult serialization."""
|
||||
from confsync.models.config_models import MergeResult
|
||||
|
||||
result = MergeResult(
|
||||
success=True,
|
||||
merged_files={"file1": "merged content"},
|
||||
conflicts={},
|
||||
unresolved=[],
|
||||
strategy_used="three_way",
|
||||
message="Merge successful",
|
||||
)
|
||||
|
||||
data = result.to_dict()
|
||||
|
||||
assert data["success"] is True
|
||||
assert data["strategy_used"] == "three_way"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user