import json import tempfile from pathlib import Path import pytest from lintunes.storage.conflict_resolver import resolve_conflicts def _write_json(path: Path, data: dict): with open(path, "w") as f: json.dump(data, f) def _read_json(path: Path) -> dict: with open(path) as f: return json.load(f) class TestConflictResolver: def test_no_conflicts(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() _write_json(data_dir / "library.json", {"1": {"track_id": 1, "name": "Song"}}) resolve_conflicts(data_dir) # Should not crash, data should be unchanged result = _read_json(data_dir / "library.json") assert result["1"]["name"] == "Song" def test_nonexistent_dir(self, tmp_path): # Should not crash resolve_conflicts(tmp_path / "nonexistent") def test_merge_play_counts(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() original = { "1": {"track_id": 1, "name": "Song", "play_count": 5, "skip_count": 2} } conflict = { "1": {"track_id": 1, "name": "Song", "play_count": 8, "skip_count": 1} } _write_json(data_dir / "library.json", original) _write_json( data_dir / "library.sync-conflict-20240101-120000-ABCDEFG.json", conflict, ) resolve_conflicts(data_dir) result = _read_json(data_dir / "library.json") assert result["1"]["play_count"] == 8 # max(5, 8) assert result["1"]["skip_count"] == 2 # max(2, 1) def test_merge_loved_or(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() original = {"1": {"track_id": 1, "loved": False}} conflict = {"1": {"track_id": 1, "loved": True}} _write_json(data_dir / "library.json", original) _write_json( data_dir / "library.sync-conflict-20240101-120000-ABCDEFG.json", conflict, ) resolve_conflicts(data_dir) result = _read_json(data_dir / "library.json") assert result["1"]["loved"] is True def test_merge_date_added_earliest(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() original = {"1": {"track_id": 1, "date_added": "2022-06-01T00:00:00"}} conflict = {"1": {"track_id": 1, "date_added": "2020-01-15T00:00:00"}} _write_json(data_dir / "library.json", original) _write_json( data_dir / "library.sync-conflict-20240101-120000-ABCDEFG.json", conflict, ) resolve_conflicts(data_dir) result = _read_json(data_dir / "library.json") assert result["1"]["date_added"] == "2020-01-15T00:00:00" def test_merge_new_track_from_conflict(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() original = {"1": {"track_id": 1, "name": "Song A"}} conflict = { "1": {"track_id": 1, "name": "Song A"}, "2": {"track_id": 2, "name": "Song B"}, } _write_json(data_dir / "library.json", original) _write_json( data_dir / "library.sync-conflict-20240101-120000-ABCDEFG.json", conflict, ) resolve_conflicts(data_dir) result = _read_json(data_dir / "library.json") assert "2" in result assert result["2"]["name"] == "Song B" def test_playlist_merge_union(self, tmp_path): data_dir = tmp_path / ".lintunes" playlists_dir = data_dir / "playlists" playlists_dir.mkdir(parents=True) original = {"name": "My Playlist", "track_ids": [1, 2, 3], "settings": {}} conflict = {"name": "My Playlist", "track_ids": [2, 3, 4, 5], "settings": {}} orig_path = playlists_dir / "PL1.json" conf_path = playlists_dir / "PL1.sync-conflict-20240101-120000-ABCDEFG.json" _write_json(orig_path, original) _write_json(conf_path, conflict) resolve_conflicts(data_dir) result = _read_json(orig_path) # All track IDs should be present (union) assert set(result["track_ids"]) == {1, 2, 3, 4, 5} def test_conflicts_archived(self, tmp_path): data_dir = tmp_path / ".lintunes" data_dir.mkdir() _write_json(data_dir / "library.json", {"1": {"track_id": 1}}) conf_path = data_dir / "library.sync-conflict-20240101-120000-ABCDEFG.json" _write_json(conf_path, {"1": {"track_id": 1}}) resolve_conflicts(data_dir) assert not conf_path.exists() resolved_dir = data_dir / ".resolved" assert resolved_dir.exists() archived = list(resolved_dir.iterdir()) assert len(archived) == 1