feat(handlers): integrate ProgressService into media, koreader, kobo, and queue
All four progress write paths now delegate to ProgressService.SaveProgress: - MediaHandler: UpdateMediaReadingProgress uses ProgressService for web saves with richer request body (reading_mode, zoom_level, scroll). GET now uses GetUniversalProgress query that JOINs media_items for format_group, total_characters, chapter_count. - KOReaderHandler: updateProgressForBook delegates to ProgressService. Fixed device ID bug (was using userID, now uses deviceID). Removed duplicate UpdateDeviceLastSync with zero UUID. Added pgtype helper functions (textPtrToPgText, intPtrToPgInt4, int64PtrToPgInt8). - KoboHandler: all four progress write points (Markup ReadingSync, Markup last-read-place, AnalyticsGettests, SyncFromServer) delegate to ProgressService. Fixed empty epubcfi string now correctly set to Valid: false. SyncFromServer preserves last_sync_source=bookhoard and Broadcast: false. - QueueProcessor: syncProgress delegates to ProgressService. - main.go: creates ProgressService after ConnectionManager, injects via SetProgressService() on all handlers and queue processor. Handler tests cover pgtype conversion helpers (textPtrToPgText, etc.) and device icon mapping.
This commit is contained in:
@@ -3,6 +3,7 @@ package handlers
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -28,3 +29,124 @@ func TestGetDeviceIcon_Unknown(t *testing.T) {
|
||||
result = getDeviceIcon("")
|
||||
assert.Equal(t, "📚", result)
|
||||
}
|
||||
|
||||
func TestTextPtrToPgText(t *testing.T) {
|
||||
t.Run("nil returns invalid", func(t *testing.T) {
|
||||
result := textPtrToPgText(nil)
|
||||
assert.False(t, result.Valid)
|
||||
})
|
||||
t.Run("non-nil returns valid", func(t *testing.T) {
|
||||
s := "epubcfi(/6/4/2:10)"
|
||||
result := textPtrToPgText(&s)
|
||||
assert.True(t, result.Valid)
|
||||
assert.Equal(t, s, result.String)
|
||||
})
|
||||
t.Run("empty string returns valid", func(t *testing.T) {
|
||||
s := ""
|
||||
result := textPtrToPgText(&s)
|
||||
assert.True(t, result.Valid)
|
||||
assert.Equal(t, "", result.String)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntPtrToPgInt4(t *testing.T) {
|
||||
t.Run("nil returns invalid", func(t *testing.T) {
|
||||
result := intPtrToPgInt4(nil)
|
||||
assert.False(t, result.Valid)
|
||||
})
|
||||
t.Run("non-nil returns valid", func(t *testing.T) {
|
||||
v := 5
|
||||
result := intPtrToPgInt4(&v)
|
||||
assert.True(t, result.Valid)
|
||||
assert.Equal(t, int32(5), result.Int32)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInt64PtrToPgInt8(t *testing.T) {
|
||||
t.Run("nil returns invalid", func(t *testing.T) {
|
||||
result := int64PtrToPgInt8(nil)
|
||||
assert.False(t, result.Valid)
|
||||
})
|
||||
t.Run("non-nil returns valid", func(t *testing.T) {
|
||||
v := int64(10000)
|
||||
result := int64PtrToPgInt8(&v)
|
||||
assert.True(t, result.Valid)
|
||||
assert.Equal(t, int64(10000), result.Int64)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFloat64PtrHelpers(t *testing.T) {
|
||||
t.Run("pgtype float64 valid", func(t *testing.T) {
|
||||
v := pgtype.Float8{Float64: 0.5, Valid: true}
|
||||
result := float64PtrVal(v)
|
||||
assert.NotNil(t, result)
|
||||
assert.InDelta(t, 0.5, *result, 0.001)
|
||||
})
|
||||
t.Run("pgtype float64 invalid", func(t *testing.T) {
|
||||
v := pgtype.Float8{Valid: false}
|
||||
result := float64PtrVal(v)
|
||||
assert.Nil(t, result)
|
||||
})
|
||||
t.Run("pgtype text valid", func(t *testing.T) {
|
||||
v := pgtype.Text{String: "hello", Valid: true}
|
||||
result := textPtrVal(v)
|
||||
assert.NotNil(t, result)
|
||||
assert.Equal(t, "hello", *result)
|
||||
})
|
||||
t.Run("pgtype text invalid", func(t *testing.T) {
|
||||
v := pgtype.Text{Valid: false}
|
||||
result := textPtrVal(v)
|
||||
assert.Nil(t, result)
|
||||
})
|
||||
t.Run("pgtype int4 valid", func(t *testing.T) {
|
||||
v := pgtype.Int4{Int32: 42, Valid: true}
|
||||
result := int32PtrVal(v)
|
||||
assert.NotNil(t, result)
|
||||
assert.Equal(t, 42, *result)
|
||||
})
|
||||
t.Run("pgtype int4 invalid", func(t *testing.T) {
|
||||
v := pgtype.Int4{Valid: false}
|
||||
result := int32PtrVal(v)
|
||||
assert.Nil(t, result)
|
||||
})
|
||||
t.Run("pgtype int8 valid", func(t *testing.T) {
|
||||
v := pgtype.Int8{Int64: 10000, Valid: true}
|
||||
result := int64PtrVal(v)
|
||||
assert.NotNil(t, result)
|
||||
assert.Equal(t, int64(10000), *result)
|
||||
})
|
||||
t.Run("pgtype int8 invalid", func(t *testing.T) {
|
||||
v := pgtype.Int8{Valid: false}
|
||||
result := int64PtrVal(v)
|
||||
assert.Nil(t, result)
|
||||
})
|
||||
}
|
||||
|
||||
func float64PtrVal(v pgtype.Float8) *float64 {
|
||||
if v.Valid {
|
||||
return &v.Float64
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func textPtrVal(v pgtype.Text) *string {
|
||||
if v.Valid {
|
||||
return &v.String
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func int32PtrVal(v pgtype.Int4) *int {
|
||||
if v.Valid {
|
||||
val := int(v.Int32)
|
||||
return &val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func int64PtrVal(v pgtype.Int8) *int64 {
|
||||
if v.Valid {
|
||||
return &v.Int64
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user