cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
29
fork

Configure Feed

Select the types of activity you want to include in your feed.

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}