diff --git a/internal/handlers/conflicts_test.go b/internal/handlers/conflicts_test.go new file mode 100644 index 0000000..2c0b97c --- /dev/null +++ b/internal/handlers/conflicts_test.go @@ -0,0 +1,309 @@ +package handlers + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestGetMostRecentSource_KOReaderMoreRecent(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Timestamp: time.Date(2026, 1, 30, 20, 10, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.45, + "epubcfi": "epubcfi(/6/4/2:15)", + }, + }, + "kobo": { + Source: "kobo", + Timestamp: time.Date(2026, 1, 30, 20, 5, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.42, + "page": float64(89), + }, + }, + } + + source, data := handler.getMostRecentSource(conflictData) + assert.Equal(t, "koreader", source) + assert.Equal(t, 0.45, data["percentage"]) +} + +func TestGetMostRecentSource_KoboMoreRecent(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Timestamp: time.Date(2026, 1, 30, 20, 5, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.45, + }, + }, + "kobo": { + Source: "kobo", + Timestamp: time.Date(2026, 1, 30, 20, 15, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.42, + }, + }, + } + + source, data := handler.getMostRecentSource(conflictData) + assert.Equal(t, "kobo", source) + assert.Equal(t, 0.42, data["percentage"]) +} + +func TestGetMostRecentSource_SingleSource(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Timestamp: time.Date(2026, 1, 30, 20, 10, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.50, + }, + }, + } + + source, data := handler.getMostRecentSource(conflictData) + assert.Equal(t, "koreader", source) + assert.Equal(t, 0.50, data["percentage"]) +} + +func TestGetMostRecentSource_SameTimestamp(t *testing.T) { + handler := &ConflictHandler{} + + ts := time.Date(2026, 1, 30, 20, 10, 0, 0, time.UTC) + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Timestamp: ts, + Data: map[string]interface{}{ + "percentage": 0.45, + }, + }, + "kobo": { + Source: "kobo", + Timestamp: ts, + Data: map[string]interface{}{ + "percentage": 0.42, + }, + }, + } + + source, _ := handler.getMostRecentSource(conflictData) + assert.Contains(t, []string{"koreader", "kobo"}, source) +} + +func TestGetMostRecentSource_EmptyData(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{} + + source, data := handler.getMostRecentSource(conflictData) + assert.Equal(t, "", source) + assert.Nil(t, data) +} + +func TestGetHighestProgressSource_KOReaderHigher(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.75, + }, + }, + "kobo": { + Source: "kobo", + Data: map[string]interface{}{ + "percentage": 0.42, + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "koreader", source) + assert.Equal(t, 0.75, data["percentage"]) +} + +func TestGetHighestProgressSource_KoboHigher(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.30, + }, + }, + "kobo": { + Source: "kobo", + Data: map[string]interface{}{ + "percentage": 0.90, + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "kobo", source) + assert.Equal(t, 0.90, data["percentage"]) +} + +func TestGetHighestProgressSource_SingleSource(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.50, + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "koreader", source) + assert.Equal(t, 0.50, data["percentage"]) +} + +func TestGetHighestProgressSource_EmptyData(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{} + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "", source) + assert.Nil(t, data) +} + +func TestGetHighestProgressSource_NoPercentageField(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{}, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "", source) + assert.Nil(t, data) +} + +func TestGetHighestProgressSource_MixedPercentageTypes(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.60, + }, + }, + "kobo": { + Source: "kobo", + Data: map[string]interface{}{ + "percentage": float64(0.80), + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "kobo", source) + assert.Equal(t, float64(0.80), data["percentage"]) +} + +func TestGetHighestProgressSource_BothZero(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.0, + }, + }, + "kobo": { + Source: "kobo", + Data: map[string]interface{}{ + "percentage": 0.0, + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.NotEmpty(t, source) + assert.NotNil(t, data) + assert.Equal(t, 0.0, data["percentage"]) +} + +func TestGetHighestProgressSource_ThreeWayConflict(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Data: map[string]interface{}{ + "percentage": 0.45, + }, + }, + "kobo": { + Source: "kobo", + Data: map[string]interface{}{ + "percentage": 0.92, + }, + }, + "web": { + Source: "web", + Data: map[string]interface{}{ + "percentage": 0.70, + }, + }, + } + + source, data := handler.getHighestProgressSource(conflictData) + assert.Equal(t, "kobo", source) + assert.Equal(t, 0.92, data["percentage"]) +} + +func TestGetMostRecentSource_ThreeWayConflict(t *testing.T) { + handler := &ConflictHandler{} + + conflictData := map[string]ConflictSourceData{ + "koreader": { + Source: "koreader", + Timestamp: time.Date(2026, 1, 30, 20, 5, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.45, + }, + }, + "kobo": { + Source: "kobo", + Timestamp: time.Date(2026, 1, 30, 20, 20, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.92, + }, + }, + "web": { + Source: "web", + Timestamp: time.Date(2026, 1, 30, 20, 10, 0, 0, time.UTC), + Data: map[string]interface{}{ + "percentage": 0.70, + }, + }, + } + + source, data := handler.getMostRecentSource(conflictData) + assert.Equal(t, "kobo", source) + assert.Equal(t, 0.92, data["percentage"]) +}