package handlers import ( "net/http" "net/http/httptest" "strings" "testing" ) // TestPlainText tests the PlainText handler // NOTE: This test requires running from project root due to template path resolution // Run with: go test ./internal/handlers/ -run TestPlainText -v // Or skip in CI: go test ./internal/handlers/ -run TestPlainText -short func TestPlainText(t *testing.T) { // Skip if running in short mode (CI) - requires project root if testing.Short() { t.Skip("Skipping PlainText test - requires running from project root") } handler := newTestCVHandler(t, "localhost:8080", nil) tests := []struct { name string lang string icons string download string expectStatus int expectHeader string expectContains string }{ { name: "Default language (English)", lang: "", expectStatus: http.StatusOK, expectContains: "Juan", }, { name: "English language", lang: "en", expectStatus: http.StatusOK, expectContains: "Juan", }, { name: "Spanish language", lang: "es", expectStatus: http.StatusOK, expectContains: "Juan", }, { name: "Invalid language", lang: "fr", expectStatus: http.StatusBadRequest, }, { name: "With icons disabled", lang: "en", icons: "false", expectStatus: http.StatusOK, expectContains: "Juan", }, { name: "Download mode", lang: "en", download: "true", expectStatus: http.StatusOK, expectHeader: "attachment", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Build query string query := "/text" params := []string{} if tt.lang != "" { params = append(params, "lang="+tt.lang) } if tt.icons != "" { params = append(params, "icons="+tt.icons) } if tt.download != "" { params = append(params, "download="+tt.download) } if len(params) > 0 { query += "?" + strings.Join(params, "&") } req := httptest.NewRequest(http.MethodGet, query, nil) w := httptest.NewRecorder() handler.PlainText(w, req) if w.Code != tt.expectStatus { t.Errorf("Expected status %d, got %d", tt.expectStatus, w.Code) } // Check Content-Type for successful requests if tt.expectStatus == http.StatusOK { contentType := w.Header().Get("Content-Type") if !strings.HasPrefix(contentType, "text/plain") { t.Errorf("Expected text/plain content type, got %s", contentType) } } // Check Content-Disposition header for download mode if tt.expectHeader != "" { disposition := w.Header().Get("Content-Disposition") if !strings.Contains(disposition, tt.expectHeader) { t.Errorf("Expected Content-Disposition containing '%s', got '%s'", tt.expectHeader, disposition) } } // Check response body contains expected content (if success) if tt.expectStatus == http.StatusOK && tt.expectContains != "" { body := w.Body.String() if !strings.Contains(body, tt.expectContains) { t.Errorf("Expected body to contain '%s'", tt.expectContains) } } }) } } // TestPlainTextDownloadFilename tests that download filename is correctly formatted // NOTE: This test requires running from project root due to template path resolution func TestPlainTextDownloadFilename(t *testing.T) { // Skip if running in short mode (CI) - requires project root if testing.Short() { t.Skip("Skipping PlainTextDownloadFilename test - requires running from project root") } handler := newTestCVHandler(t, "localhost:8080", nil) tests := []struct { name string lang string expectPrefix string }{ { name: "English download filename", lang: "en", expectPrefix: "cv-jamr-", }, { name: "Spanish download filename", lang: "es", expectPrefix: "cv-jamr-", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/text?lang="+tt.lang+"&download=true", nil) w := httptest.NewRecorder() handler.PlainText(w, req) if w.Code != http.StatusOK { t.Fatalf("Expected status OK, got %d", w.Code) } disposition := w.Header().Get("Content-Disposition") if !strings.Contains(disposition, tt.expectPrefix) { t.Errorf("Expected filename to contain '%s', got '%s'", tt.expectPrefix, disposition) } // Verify language suffix is in filename if !strings.Contains(disposition, "-"+tt.lang+".txt") { t.Errorf("Expected filename to end with '-%s.txt', got '%s'", tt.lang, disposition) } }) } } // TestIsTextBrowser tests the text browser detection func TestIsTextBrowser(t *testing.T) { tests := []struct { name string userAgent string accept string expect bool }{ { name: "Regular browser", userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", expect: false, }, { name: "curl", userAgent: "curl/7.79.1", expect: true, }, { name: "wget", userAgent: "Wget/1.21", expect: true, }, { name: "httpie", userAgent: "HTTPie/2.6.0", expect: true, }, { name: "lynx", userAgent: "Lynx/2.9.0dev.10", expect: true, }, { name: "w3m", userAgent: "w3m/0.5.3", expect: true, }, { name: "Accept text/plain", userAgent: "Mozilla/5.0", accept: "text/plain", expect: true, }, { name: "Accept text/html", userAgent: "Mozilla/5.0", accept: "text/html", expect: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) if tt.userAgent != "" { req.Header.Set("User-Agent", tt.userAgent) } if tt.accept != "" { req.Header.Set("Accept", tt.accept) } result := isTextBrowser(req) if result != tt.expect { t.Errorf("isTextBrowser() = %v, expected %v for User-Agent: %s", result, tt.expect, tt.userAgent) } }) } }