From 0ca287cac2deeedc43fd5da2d2c3fc5b0b40a2a2 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Mon, 9 Mar 2026 05:51:36 +0000 Subject: [PATCH] test: extend test coverage for server, config, and utils --- config_test.go | 33 +++++++++++++ server_test.go | 127 +++++++++++++++++++++++++++++++++++++++++++++++++ utils_test.go | 14 ++++++ 3 files changed, 174 insertions(+) diff --git a/config_test.go b/config_test.go index ea6cd36..f8c27da 100644 --- a/config_test.go +++ b/config_test.go @@ -24,3 +24,36 @@ func TestConfig(t *testing.T) { assert.Equal(t, "https://localhost", cfg.FQDN) assert.Equal(t, "0.0.0.0:8000", cfg.Bind) } + +func TestConfigDefaults(t *testing.T) { + tests := []struct { + name string + config Config + expiry time.Duration + bind string + fqdn string + }{ + { + name: "short expiry", + config: Config{Expiry: 1 * time.Minute, Bind: ":8080", FQDN: "paste.example.com"}, + expiry: 1 * time.Minute, + bind: ":8080", + fqdn: "paste.example.com", + }, + { + name: "long expiry", + config: Config{Expiry: 24 * time.Hour, Bind: "127.0.0.1:3000", FQDN: "localhost"}, + expiry: 24 * time.Hour, + bind: "127.0.0.1:3000", + fqdn: "localhost", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expiry, tc.config.Expiry) + assert.Equal(t, tc.bind, tc.config.Bind) + assert.Equal(t, tc.fqdn, tc.config.FQDN) + }) + } +} diff --git a/server_test.go b/server_test.go index 7fc00da..e1223d2 100644 --- a/server_test.go +++ b/server_test.go @@ -226,6 +226,133 @@ func TestPasteOversized(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rec.Code) } +func TestViewHTMLRender(t *testing.T) { + server := newTestServer() + + server.store.Set("htmlview", "rendered content", 0) + + req := httptest.NewRequest(http.MethodGet, "/p/htmlview", nil) + req.Header.Set("Accept", "text/html") + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Header().Get("Content-Type"), "text/html") + assert.Contains(t, rec.Body.String(), "rendered content") + assert.Contains(t, rec.Body.String(), "htmlview") +} + +func TestStatsEmptyStore(t *testing.T) { + server := newTestServer() + + req := httptest.NewRequest(http.MethodGet, "/debug/stats", nil) + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), `"item_count":0`) +} + +func TestStatsMultipleItems(t *testing.T) { + server := newTestServer() + + server.store.Set("a", "1", 0) + server.store.Set("b", "2", 0) + server.store.Set("c", "3", 0) + + req := httptest.NewRequest(http.MethodGet, "/debug/stats", nil) + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), `"item_count":3`) +} + +func TestPasteNoFormField(t *testing.T) { + server := newTestServer() + + req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("")) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusBadRequest, rec.Code) +} + +func TestDeleteResponseBody(t *testing.T) { + server := newTestServer() + + server.store.Set("delresp", "content", 0) + + req := httptest.NewRequest(http.MethodDelete, "/p/delresp", nil) + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, "Deleted", rec.Body.String()) +} + +func TestDownloadContentHeaders(t *testing.T) { + server := newTestServer() + + server.store.Set("dlheader", "file content here", 0) + + req := httptest.NewRequest(http.MethodGet, "/download/dlheader", nil) + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, "attachment; filename=dlheader", rec.Header().Get("Content-Disposition")) +} + +func TestNegotiateContentTypeDefault(t *testing.T) { + server := newTestServer() + + // No Accept header defaults to plain text + req := httptest.NewRequest(http.MethodGet, "/", nil) + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), "pastebin service") +} + +func TestPasteRoundTripSpecialChars(t *testing.T) { + server := newTestServer() + + specialContent := "line1\nline2\n\n日本語テスト" + + formData := url.Values{} + formData.Set("blob", specialContent) + req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(formData.Encode())) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "text/plain") + rec := httptest.NewRecorder() + + server.mux.ServeHTTP(rec, req) + require.Equal(t, http.StatusOK, rec.Code) + + parts := strings.Split(rec.Body.String(), "/p/") + require.Len(t, parts, 2) + pasteID := parts[1] + + viewReq := httptest.NewRequest(http.MethodGet, "/p/"+pasteID, nil) + viewReq.Header.Set("Accept", "text/plain") + viewRec := httptest.NewRecorder() + + server.mux.ServeHTTP(viewRec, viewReq) + + assert.Equal(t, http.StatusOK, viewRec.Code) + assert.Equal(t, specialContent, viewRec.Body.String()) +} + func TestViewWithTabs(t *testing.T) { server := newTestServer() diff --git a/utils_test.go b/utils_test.go index f6607e6..fb40ef8 100644 --- a/utils_test.go +++ b/utils_test.go @@ -22,3 +22,17 @@ func TestRandomStringUniqueness(t *testing.T) { seen[result] = true } } + +func TestRandomStringURLSafe(t *testing.T) { + for range 50 { + result := RandomString(32) + // base64 URL encoding uses A-Z, a-z, 0-9, -, _ + for _, char := range result { + isValid := (char >= 'A' && char <= 'Z') || + (char >= 'a' && char <= 'z') || + (char >= '0' && char <= '9') || + char == '-' || char == '_' || char == '=' + assert.True(t, isValid, "RandomString contains invalid URL character: %c", char) + } + } +}