package sync import ( "testing" "sub-cli/internal/model" ) func TestCalculateDuration(t *testing.T) { testCases := []struct { name string start model.Timestamp end model.Timestamp expected model.Timestamp }{ { name: "Simple duration", start: model.Timestamp{Minutes: 1, Seconds: 30}, end: model.Timestamp{Minutes: 3, Seconds: 10}, expected: model.Timestamp{Minutes: 1, Seconds: 40}, }, { name: "Duration with hours", start: model.Timestamp{Hours: 1, Minutes: 20}, end: model.Timestamp{Hours: 2, Minutes: 10}, expected: model.Timestamp{Hours: 0, Minutes: 50}, }, { name: "Duration with milliseconds", start: model.Timestamp{Seconds: 10, Milliseconds: 500}, end: model.Timestamp{Seconds: 20, Milliseconds: 800}, expected: model.Timestamp{Seconds: 10, Milliseconds: 300}, }, { name: "End before start (should return zero)", start: model.Timestamp{Minutes: 5}, end: model.Timestamp{Minutes: 3}, expected: model.Timestamp{Hours: 0, Minutes: 0, Seconds: 0, Milliseconds: 0}, }, { name: "Complex duration with carry", start: model.Timestamp{Hours: 1, Minutes: 45, Seconds: 30, Milliseconds: 500}, end: model.Timestamp{Hours: 3, Minutes: 20, Seconds: 15, Milliseconds: 800}, expected: model.Timestamp{Hours: 1, Minutes: 34, Seconds: 45, Milliseconds: 300}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := calculateDuration(tc.start, tc.end) if result.Hours != tc.expected.Hours || result.Minutes != tc.expected.Minutes || result.Seconds != tc.expected.Seconds || result.Milliseconds != tc.expected.Milliseconds { t.Errorf("Expected %+v, got %+v", tc.expected, result) } }) } } func TestAddDuration(t *testing.T) { testCases := []struct { name string start model.Timestamp duration model.Timestamp expected model.Timestamp }{ { name: "Simple addition", start: model.Timestamp{Minutes: 1, Seconds: 30}, duration: model.Timestamp{Minutes: 2, Seconds: 15}, expected: model.Timestamp{Minutes: 3, Seconds: 45}, }, { name: "Addition with carry", start: model.Timestamp{Minutes: 58, Seconds: 45}, duration: model.Timestamp{Minutes: 4, Seconds: 30}, expected: model.Timestamp{Hours: 1, Minutes: 3, Seconds: 15}, }, { name: "Addition with milliseconds", start: model.Timestamp{Seconds: 10, Milliseconds: 500}, duration: model.Timestamp{Seconds: 5, Milliseconds: 800}, expected: model.Timestamp{Seconds: 16, Milliseconds: 300}, }, { name: "Zero duration", start: model.Timestamp{Minutes: 5, Seconds: 30}, duration: model.Timestamp{}, expected: model.Timestamp{Minutes: 5, Seconds: 30}, }, { name: "Complex addition with multiple carries", start: model.Timestamp{Hours: 1, Minutes: 59, Seconds: 59, Milliseconds: 900}, duration: model.Timestamp{Hours: 2, Minutes: 10, Seconds: 15, Milliseconds: 200}, expected: model.Timestamp{Hours: 4, Minutes: 10, Seconds: 15, Milliseconds: 100}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := addDuration(tc.start, tc.duration) if result.Hours != tc.expected.Hours || result.Minutes != tc.expected.Minutes || result.Seconds != tc.expected.Seconds || result.Milliseconds != tc.expected.Milliseconds { t.Errorf("Expected %+v, got %+v", tc.expected, result) } }) } } func TestScaleTimeline(t *testing.T) { testCases := []struct { name string timeline []model.Timestamp targetCount int expected []model.Timestamp }{ { name: "Same length timeline", timeline: []model.Timestamp{ {Seconds: 1}, {Seconds: 2}, {Seconds: 3}, }, targetCount: 3, expected: []model.Timestamp{ {Seconds: 1}, {Seconds: 2}, {Seconds: 3}, }, }, { name: "Empty timeline", timeline: []model.Timestamp{}, targetCount: 3, expected: []model.Timestamp{}, }, { name: "Zero target count", timeline: []model.Timestamp{ {Seconds: 1}, {Seconds: 2}, }, targetCount: 0, expected: []model.Timestamp{}, }, { name: "Single item timeline", timeline: []model.Timestamp{ {Seconds: 5}, }, targetCount: 3, expected: []model.Timestamp{ {Seconds: 5}, {Seconds: 5}, {Seconds: 5}, }, }, { name: "Scale up timeline", timeline: []model.Timestamp{ {Seconds: 0}, {Seconds: 10}, }, targetCount: 5, expected: []model.Timestamp{ {Seconds: 0}, {Seconds: 2, Milliseconds: 500}, {Seconds: 5}, {Seconds: 7, Milliseconds: 500}, {Seconds: 10}, }, }, { name: "Scale down timeline", timeline: []model.Timestamp{ {Seconds: 0}, {Seconds: 5}, {Seconds: 10}, {Seconds: 15}, {Seconds: 20}, }, targetCount: 3, expected: []model.Timestamp{ {Seconds: 0}, {Seconds: 10}, {Seconds: 20}, }, }, { name: "Target count 1", timeline: []model.Timestamp{ {Seconds: 5}, {Seconds: 10}, {Seconds: 15}, }, targetCount: 1, expected: []model.Timestamp{ {Seconds: 5}, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := scaleTimeline(tc.timeline, tc.targetCount) if len(result) != len(tc.expected) { t.Errorf("Expected result length %d, got %d", len(tc.expected), len(result)) return } for i := range result { // Allow 1ms difference due to floating point calculations if abs(result[i].Hours - tc.expected[i].Hours) > 0 || abs(result[i].Minutes - tc.expected[i].Minutes) > 0 || abs(result[i].Seconds - tc.expected[i].Seconds) > 0 || abs(result[i].Milliseconds - tc.expected[i].Milliseconds) > 1 { t.Errorf("At index %d: expected %+v, got %+v", i, tc.expected[i], result[i]) } } }) } } // Helper function for timestamp comparison func abs(x int) int { if x < 0 { return -x } return x }