test: add comprehensive Go test suite with ~75% coverage
New test files: - config/config_test.go (100% coverage) - constants/constants_test.go (100% coverage) - httputil/response_test.go (100% coverage) - validation/rules_test.go (91.9% coverage) - middleware/logger_test.go, security_test.go, security_logger_test.go - handlers/errors_test.go Updated documentation: - doc/27-GO-TESTING.md: Complete testing guide - doc/00-GO-DOCUMENTATION-INDEX.md: Added testing section - doc/01-ARCHITECTURE.md: Updated package structure - doc/DECISIONS.md: Added ADR-004 caching decision - PROJECT-MEMORY.md: Added Go testing section
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResponseWriter_WriteHeader(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := &responseWriter{
|
||||
ResponseWriter: rec,
|
||||
status: http.StatusOK,
|
||||
}
|
||||
|
||||
// First call should set status
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
if rw.status != http.StatusNotFound {
|
||||
t.Errorf("status = %d, want %d", rw.status, http.StatusNotFound)
|
||||
}
|
||||
if !rw.wroteHeader {
|
||||
t.Error("wroteHeader should be true after WriteHeader")
|
||||
}
|
||||
|
||||
// Second call should be ignored
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
if rw.status != http.StatusNotFound {
|
||||
t.Errorf("status = %d, want %d (should not change)", rw.status, http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseWriter_Write(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := &responseWriter{
|
||||
ResponseWriter: rec,
|
||||
status: http.StatusOK,
|
||||
}
|
||||
|
||||
// Write should set default status if not set
|
||||
n, err := rw.Write([]byte("Hello"))
|
||||
if err != nil {
|
||||
t.Errorf("Write() error = %v", err)
|
||||
}
|
||||
if n != 5 {
|
||||
t.Errorf("Write() n = %d, want 5", n)
|
||||
}
|
||||
if rw.written != 5 {
|
||||
t.Errorf("written = %d, want 5", rw.written)
|
||||
}
|
||||
if !rw.wroteHeader {
|
||||
t.Error("wroteHeader should be true after Write")
|
||||
}
|
||||
if rw.status != http.StatusOK {
|
||||
t.Errorf("status = %d, want %d", rw.status, http.StatusOK)
|
||||
}
|
||||
|
||||
// Write more
|
||||
n, err = rw.Write([]byte(" World"))
|
||||
if err != nil {
|
||||
t.Errorf("Write() error = %v", err)
|
||||
}
|
||||
if n != 6 {
|
||||
t.Errorf("Write() n = %d, want 6", n)
|
||||
}
|
||||
if rw.written != 11 {
|
||||
t.Errorf("written = %d, want 11", rw.written)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseWriter_WriteWithExplicitStatus(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := &responseWriter{
|
||||
ResponseWriter: rec,
|
||||
status: http.StatusOK,
|
||||
}
|
||||
|
||||
// Set status first
|
||||
rw.WriteHeader(http.StatusCreated)
|
||||
|
||||
// Write should not change status
|
||||
_, _ = rw.Write([]byte("Created"))
|
||||
if rw.status != http.StatusCreated {
|
||||
t.Errorf("status = %d, want %d", rw.status, http.StatusCreated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
t.Run("Logs successful request", func(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("OK"))
|
||||
})
|
||||
|
||||
logged := Logger(handler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
logged.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Code = %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
if rec.Body.String() != "OK" {
|
||||
t.Errorf("Body = %q, want %q", rec.Body.String(), "OK")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Logs error response", func(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Not Found", http.StatusNotFound)
|
||||
})
|
||||
|
||||
logged := Logger(handler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/notfound", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
logged.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Errorf("Code = %d, want %d", rec.Code, http.StatusNotFound)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Handles POST request", func(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
})
|
||||
|
||||
logged := Logger(handler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/create", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
logged.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Errorf("Code = %d, want %d", rec.Code, http.StatusCreated)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Handles request with no explicit status", func(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Just write body without explicit status
|
||||
_, _ = w.Write([]byte("Implicit OK"))
|
||||
})
|
||||
|
||||
logged := Logger(handler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/implicit", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
logged.ServeHTTP(rec, req)
|
||||
|
||||
// Default status should be 200
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Code = %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user