diff options
Diffstat (limited to 'internal/schedule/stats_test.go')
| -rw-r--r-- | internal/schedule/stats_test.go | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/internal/schedule/stats_test.go b/internal/schedule/stats_test.go new file mode 100644 index 0000000..af71222 --- /dev/null +++ b/internal/schedule/stats_test.go @@ -0,0 +1,319 @@ +package schedule + +import ( + "os" + "path/filepath" + "testing" + "time" + + "codeberg.org/snonux/gos/internal/config" + "codeberg.org/snonux/gos/internal/timestamp" +) + +func TestGatherPostedStats(t *testing.T) { + // Create a temporary directory for test files + tmpDir, err := os.MkdirTemp("", "gos_stats_test_*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + // Create test posted files with different timestamps + now := time.Now() + testFiles := []struct { + filename string + content string + timestamp time.Time + }{ + { + // Posted entry from 5 days ago + filename: "post1.txt." + now.AddDate(0, 0, -5).Format(timestamp.Format) + ".posted", + content: "Test post 1", + timestamp: now.AddDate(0, 0, -5), + }, + { + // Posted entry from 3 days ago + filename: "post2.txt." + now.AddDate(0, 0, -3).Format(timestamp.Format) + ".posted", + content: "Test post 2", + timestamp: now.AddDate(0, 0, -3), + }, + { + // Posted entry from 1 day ago + filename: "post3.txt." + now.AddDate(0, 0, -1).Format(timestamp.Format) + ".posted", + content: "Test post 3", + timestamp: now.AddDate(0, 0, -1), + }, + { + // Posted entry from 10 days ago (outside lookback period) + filename: "old_post.txt." + now.AddDate(0, 0, -10).Format(timestamp.Format) + ".posted", + content: "Old test post", + timestamp: now.AddDate(0, 0, -10), + }, + { + // Queued entry (should be ignored) + filename: "queued_post.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".queued", + content: "Queued post", + timestamp: now.AddDate(0, 0, -2), + }, + { + // Posted entry with .now. tag (should be ignored) + filename: "now_post.now.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".posted", + content: "Now post", + timestamp: now.AddDate(0, 0, -2), + }, + } + + // Create test files + for _, tf := range testFiles { + filePath := filepath.Join(tmpDir, tf.filename) + if err := os.WriteFile(filePath, []byte(tf.content), 0644); err != nil { + t.Fatalf("Failed to create test file %s: %v", tf.filename, err) + } + } + + // Initialize stats and run gatherPostedStats + s := &stats{} + lookbackTime := now.AddDate(0, 0, -7) // 7 days lookback + cfg := config.Config{} // Empty config (no pause) + + err = s.gatherPostedStats(tmpDir, lookbackTime, cfg) + if err != nil { + t.Fatalf("gatherPostedStats failed: %v", err) + } + + // Verify results + expectedPosted := 3 // post1, post2, post3 (excludes old_post, queued_post, now_post) + if s.posted != expectedPosted { + t.Errorf("Expected posted=%d, got posted=%d", expectedPosted, s.posted) + } + + expectedTotalPosted := 5 // post1, post2, post3, old_post, now_post (excludes only queued_post) + if s.totalPosted != expectedTotalPosted { + t.Errorf("Expected totalPosted=%d, got totalPosted=%d", expectedTotalPosted, s.totalPosted) + } + + // Check sinceDays calculation (should be approximately 5 days from oldest to now) + expectedSinceDays := 5.0 + if s.sinceDays < expectedSinceDays-0.1 || s.sinceDays > expectedSinceDays+0.1 { + t.Errorf("Expected sinceDays≈%.1f, got sinceDays=%.1f", expectedSinceDays, s.sinceDays) + } + + // Check postsPerDay calculation + expectedPostsPerDay := float64(expectedPosted) / s.sinceDays + if s.postsPerDay < expectedPostsPerDay-0.01 || s.postsPerDay > expectedPostsPerDay+0.01 { + t.Errorf("Expected postsPerDay≈%.2f, got postsPerDay=%.2f", expectedPostsPerDay, s.postsPerDay) + } + + // Check lastPostDaysAgo (should be approximately 1 day) + expectedLastPostDaysAgo := 1.0 + if s.lastPostDaysAgo < expectedLastPostDaysAgo-0.1 || s.lastPostDaysAgo > expectedLastPostDaysAgo+0.1 { + t.Errorf("Expected lastPostDaysAgo≈%.1f, got lastPostDaysAgo=%.1f", expectedLastPostDaysAgo, s.lastPostDaysAgo) + } + + // Check totalSinceDays (should be approximately 10 days from oldest to now) + expectedTotalSinceDays := 10.0 + if s.totalSinceDays < expectedTotalSinceDays-0.1 || s.totalSinceDays > expectedTotalSinceDays+0.1 { + t.Errorf("Expected totalSinceDays≈%.1f, got totalSinceDays=%.1f", expectedTotalSinceDays, s.totalSinceDays) + } + + // Check totalPostsPerDay calculation + expectedTotalPostsPerDay := float64(expectedTotalPosted) / s.totalSinceDays + if s.totalPostsPerDay < expectedTotalPostsPerDay-0.01 || s.totalPostsPerDay > expectedTotalPostsPerDay+0.01 { + t.Errorf("Expected totalPostsPerDay≈%.2f, got totalPostsPerDay=%.2f", expectedTotalPostsPerDay, s.totalPostsPerDay) + } +} + +func TestGatherPostedStatsEmptyDir(t *testing.T) { + // Create a temporary directory with no files + tmpDir, err := os.MkdirTemp("", "gos_stats_empty_test_*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + s := &stats{} + lookbackTime := time.Now().AddDate(0, 0, -7) + cfg := config.Config{} // Empty config (no pause) + + err = s.gatherPostedStats(tmpDir, lookbackTime, cfg) + if err != nil { + t.Fatalf("gatherPostedStats failed: %v", err) + } + + // All stats should be zero or NaN for division by zero + if s.posted != 0 { + t.Errorf("Expected posted=0, got posted=%d", s.posted) + } + if s.totalPosted != 0 { + t.Errorf("Expected totalPosted=0, got totalPosted=%d", s.totalPosted) + } + // postsPerDay and totalPostsPerDay will be NaN due to division by zero when no posts exist + // This is the current behavior of the code +} + +func TestGatherPostedStatsWithPause(t *testing.T) { + // Create a temporary directory for test files + tmpDir, err := os.MkdirTemp("", "gos_stats_pause_test_*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + // Create test scenario: + // - Analysis period: 10 days ago to now + // - Pause period: 6 days ago to 2 days ago (4 days pause) + // - Posts: 8 days ago, 7 days ago, 1 day ago (3 posts) + // - Expected: 3 posts over 6 active days (10 - 4 pause days) = 0.5 posts/day + + now := time.Now() + testFiles := []struct { + filename string + content string + }{ + { + // Posted entry from 8 days ago (before pause) + filename: "post1.txt." + now.AddDate(0, 0, -8).Format(timestamp.Format) + ".posted", + content: "Test post 1", + }, + { + // Posted entry from 7 days ago (before pause) + filename: "post2.txt." + now.AddDate(0, 0, -7).Format(timestamp.Format) + ".posted", + content: "Test post 2", + }, + { + // Posted entry from 1 day ago (after pause) + filename: "post3.txt." + now.AddDate(0, 0, -1).Format(timestamp.Format) + ".posted", + content: "Test post 3", + }, + } + + // Create test files + for _, tf := range testFiles { + filePath := filepath.Join(tmpDir, tf.filename) + if err := os.WriteFile(filePath, []byte(tf.content), 0644); err != nil { + t.Fatalf("Failed to create test file %s: %v", tf.filename, err) + } + } + + // Configure pause period (6 days ago to 2 days ago) + pauseStart := now.AddDate(0, 0, -6).Format("2006-01-02") + pauseEnd := now.AddDate(0, 0, -2).Format("2006-01-02") + cfg := config.Config{ + PauseStart: pauseStart, + PauseEnd: pauseEnd, + } + + // Initialize stats and run gatherPostedStats + s := &stats{} + lookbackTime := now.AddDate(0, 0, -10) // 10 days lookback + + err = s.gatherPostedStats(tmpDir, lookbackTime, cfg) + if err != nil { + t.Fatalf("gatherPostedStats failed: %v", err) + } + + // Verify results + expectedPosted := 3 // All 3 posts are within lookback period + if s.posted != expectedPosted { + t.Errorf("Expected posted=%d, got posted=%d", expectedPosted, s.posted) + } + + // Check sinceDays should be around 8 days (oldest post to now) + expectedSinceDays := 8.0 + if s.sinceDays < expectedSinceDays-0.1 || s.sinceDays > expectedSinceDays+0.1 { + t.Errorf("Expected sinceDays≈%.1f, got sinceDays=%.1f", expectedSinceDays, s.sinceDays) + } + + // Key test: postsPerDay should exclude the pause period + // Let's calculate this step by step: + + // 1. Find the actual time range of our posts + oldestPost := now.AddDate(0, 0, -8) + + // 2. Calculate paused days using our helper function + actualPausedDays := calculatePausedDays(oldestPost, now, cfg) + + // 3. Calculate expected values + expectedActiveDays := s.sinceDays - actualPausedDays + expectedPostsPerDay := float64(expectedPosted) / expectedActiveDays + + // Debug info for understanding the calculation + // t.Logf("Debug: sinceDays=%.1f, actualPausedDays=%.1f, expectedActiveDays=%.1f", + // s.sinceDays, actualPausedDays, expectedActiveDays) + + if s.postsPerDay < expectedPostsPerDay-0.01 || s.postsPerDay > expectedPostsPerDay+0.01 { + t.Errorf("Expected postsPerDay≈%.2f (%.0f posts / %.1f active days), got postsPerDay=%.2f", + expectedPostsPerDay, float64(expectedPosted), expectedActiveDays, s.postsPerDay) + } +} + +func TestCalculatePausedDays(t *testing.T) { + cfg := config.Config{ + PauseStart: "2024-07-01", + PauseEnd: "2024-07-10", + } + + tests := []struct { + name string + startTime string + endTime string + expected float64 + description string + }{ + { + name: "No overlap - before pause", + startTime: "2024-06-20", + endTime: "2024-06-30", + expected: 0, + description: "Period entirely before pause", + }, + { + name: "No overlap - after pause", + startTime: "2024-07-15", + endTime: "2024-07-20", + expected: 0, + description: "Period entirely after pause", + }, + { + name: "Full pause period overlap", + startTime: "2024-06-25", + endTime: "2024-07-15", + expected: 10, + description: "Period encompasses entire pause", + }, + { + name: "Partial overlap - start during pause", + startTime: "2024-07-05", + endTime: "2024-07-15", + expected: 6, // 2024-07-05 to 2024-07-10 inclusive = 6 days + description: "Period starts during pause", + }, + { + name: "Partial overlap - end during pause", + startTime: "2024-06-25", + endTime: "2024-07-05", + expected: 5, + description: "Period ends during pause", + }, + { + name: "Exact pause period", + startTime: "2024-07-01", + endTime: "2024-07-10", + expected: 10, + description: "Period exactly matches pause", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + startTime, _ := time.Parse("2006-01-02", tt.startTime) + endTime, _ := time.Parse("2006-01-02", tt.endTime) + endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second) // End of day + + result := calculatePausedDays(startTime, endTime, cfg) + if result < tt.expected-0.1 || result > tt.expected+0.1 { + t.Errorf("Expected %.1f paused days, got %.1f", tt.expected, result) + } + }) + } +}
\ No newline at end of file |
