cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
at main 271 lines 7.0 kB view raw
1// shared test utilities & helpers 2package shared 3 4import ( 5 "encoding/json" 6 "net" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "strings" 11 "testing" 12 "time" 13) 14 15func NewHTTPTestServer(t testing.TB, handler http.Handler) *httptest.Server { 16 t.Helper() 17 server, err := startHTTPTestServer(handler) 18 if err != nil { 19 t.Fatalf("failed to start HTTP test server: %v", err) 20 } 21 return server 22} 23 24func startHTTPTestServer(handler http.Handler) (*httptest.Server, error) { 25 ln, err := net.Listen("tcp4", "127.0.0.1:0") 26 if err != nil { 27 return nil, err 28 } 29 server := &httptest.Server{ 30 Listener: ln, 31 Config: &http.Server{Handler: handler}, 32 } 33 server.Start() 34 return server, nil 35} 36 37func CreateTempDir(p string, t *testing.T) (string, func()) { 38 t.Helper() 39 tempDir, err := os.MkdirTemp("", p) 40 if err != nil { 41 t.Fatalf("Failed to create temp directory: %v", err) 42 } 43 return tempDir, func() { os.RemoveAll(tempDir) } 44} 45 46func AssertNoError(t *testing.T, err error, msg string) { 47 t.Helper() 48 if err != nil { 49 t.Fatalf("%s: %v", msg, err) 50 } 51} 52 53func AssertError(t *testing.T, err error, msg string) { 54 t.Helper() 55 if err == nil { 56 t.Fatalf("%s: expected error but got none", msg) 57 } 58} 59 60// AssertErrorContains checks that an error occurred and optionally contains expected text 61func AssertErrorContains(t *testing.T, err error, expected, msg string) { 62 t.Helper() 63 if err == nil { 64 t.Errorf("%s: expected error but got none", msg) 65 return 66 } 67 68 if !ContainsString(err.Error(), expected) { 69 if msg == "" { 70 t.Errorf("expected error containing %q, got: %v", expected, err) 71 } else if expected != "" { 72 t.Errorf("%s: expected error containing %q, got: %v", msg, expected, err) 73 } 74 } 75} 76 77func AssertTrue(t *testing.T, condition bool, msg string) { 78 t.Helper() 79 if !condition { 80 t.Fatalf("%s: expected true", msg) 81 } 82} 83 84func AssertFalse(t *testing.T, condition bool, msg string) { 85 t.Helper() 86 if condition { 87 t.Fatalf("%s: expected false", msg) 88 } 89} 90 91func AssertContains(t *testing.T, str, substr, msg string) { 92 t.Helper() 93 if !strings.Contains(str, substr) { 94 t.Fatalf("%s: expected string '%s' to contain '%s'", msg, str, substr) 95 } 96} 97 98func AssertEqual[T comparable](t *testing.T, expected, actual T, msg string) { 99 t.Helper() 100 if expected != actual { 101 t.Fatalf("%s: expected %v, got %v", msg, expected, actual) 102 } 103} 104 105func AssertNotEqual[T comparable](t *testing.T, not, actual T, msg string) { 106 t.Helper() 107 if not == actual { 108 t.Fatalf("%s: expected value to not equal %v", msg, not) 109 } 110} 111 112func AssertNil(t *testing.T, value any, msg string) { 113 t.Helper() 114 if value != nil { 115 t.Fatalf("%s: expected nil, got %v", msg, value) 116 } 117} 118 119func AssertNotNil(t *testing.T, value any, msg string) { 120 t.Helper() 121 if value == nil { 122 t.Fatalf("%s: expected non-nil value", msg) 123 } 124} 125 126func AssertGreaterThan[T interface{ int | int64 | float64 }](t *testing.T, actual, threshold T, msg string) { 127 t.Helper() 128 if actual <= threshold { 129 t.Fatalf("%s: expected %v > %v", msg, actual, threshold) 130 } 131} 132 133func AssertLessThan[T interface{ int | int64 | float64 }](t *testing.T, actual, threshold T, msg string) { 134 t.Helper() 135 if actual >= threshold { 136 t.Fatalf("%s: expected %v < %v", msg, actual, threshold) 137 } 138} 139 140// Helper function to check if string contains substring (case-insensitive) 141func ContainsString(haystack, needle string) bool { 142 if needle == "" { 143 return true 144 } 145 return len(haystack) >= len(needle) && 146 haystack[len(haystack)-len(needle):] == needle || 147 haystack[:len(needle)] == needle || 148 (len(haystack) > len(needle) && 149 func() bool { 150 for i := 1; i <= len(haystack)-len(needle); i++ { 151 if haystack[i:i+len(needle)] == needle { 152 return true 153 } 154 } 155 return false 156 }()) 157} 158 159// HTTPMockServer provides utilities for mocking HTTP services in tests 160type HTTPMockServer struct { 161 server *httptest.Server 162 requests []*http.Request 163} 164 165// NewMockServer creates a new mock HTTP server 166func NewMockServer() *HTTPMockServer { 167 mock := &HTTPMockServer{ 168 requests: make([]*http.Request, 0), 169 } 170 return mock 171} 172 173// WithHandler sets up the mock server with a custom handler 174func (m *HTTPMockServer) WithHandler(handler http.HandlerFunc) *HTTPMockServer { 175 server, err := startHTTPTestServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 176 m.requests = append(m.requests, r) 177 handler(w, r) 178 })) 179 if err != nil { 180 panic(err) 181 } 182 183 m.server = server 184 return m 185} 186 187// URL returns the mock server URL 188func (m *HTTPMockServer) URL() string { 189 if m.server == nil { 190 panic("mock server not initialized - call WithHandler first") 191 } 192 return m.server.URL 193} 194 195// Close closes the mock server 196func (m *HTTPMockServer) Close() { 197 if m.server != nil { 198 m.server.Close() 199 } 200} 201 202// GetRequests returns all recorded HTTP requests 203func (m *HTTPMockServer) GetRequests() []*http.Request { 204 return m.requests 205} 206 207// GetLastRequest returns the last recorded HTTP request 208func (m *HTTPMockServer) GetLastRequest() *http.Request { 209 if len(m.requests) == 0 { 210 return nil 211 } 212 return m.requests[len(m.requests)-1] 213} 214 215func (m HTTPMockServer) Requests() []*http.Request { 216 return m.requests 217} 218 219// HTTPErrorMockServer creates a mock server that returns HTTP errors 220func HTTPErrorMockServer(statusCode int, message string) *HTTPMockServer { 221 return NewMockServer().WithHandler(func(w http.ResponseWriter, r *http.Request) { 222 http.Error(w, message, statusCode) 223 }) 224} 225 226// JSONMockServer creates a mock server that returns JSON responses 227func JSONMockServer(response any) *HTTPMockServer { 228 return NewMockServer().WithHandler(func(w http.ResponseWriter, r *http.Request) { 229 w.Header().Set("Content-Type", "application/json") 230 if err := json.NewEncoder(w).Encode(response); err != nil { 231 http.Error(w, "Failed to encode response", http.StatusInternalServerError) 232 } 233 }) 234} 235 236// TimeoutMockServer creates a mock server that simulates timeouts 237func TimeoutMockServer(delay time.Duration) *HTTPMockServer { 238 return NewMockServer().WithHandler(func(w http.ResponseWriter, r *http.Request) { 239 time.Sleep(delay) 240 w.WriteHeader(http.StatusOK) 241 }) 242} 243 244// InvalidJSONMockServer creates a mock server that returns malformed JSON 245func InvalidJSONMockServer() *HTTPMockServer { 246 return NewMockServer().WithHandler(func(w http.ResponseWriter, r *http.Request) { 247 w.Header().Set("Content-Type", "application/json") 248 w.Write([]byte(`{"invalid": json`)) 249 }) 250} 251 252// EmptyResponseMockServer creates a mock server that returns empty responses 253func EmptyResponseMockServer() *HTTPMockServer { 254 return NewMockServer().WithHandler(func(w http.ResponseWriter, r *http.Request) { 255 w.WriteHeader(http.StatusOK) 256 }) 257} 258 259// AssertRequestMade verifies that a request was made to the mock server 260func AssertRequestMade(t *testing.T, server *HTTPMockServer, expected string) { 261 t.Helper() 262 if len(server.requests) == 0 { 263 t.Error("Expected HTTP request to be made but none were recorded") 264 return 265 } 266 267 lastReq := server.GetLastRequest() 268 if lastReq.URL.Path != expected { 269 t.Errorf("Expected request to path %s, got %s", expected, lastReq.URL.Path) 270 } 271}