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 d2c4ecc217c2c1655026bba3b364c124b3a95a8a 324 lines 9.2 kB view raw
1package services 2 3import ( 4 "errors" 5 "strings" 6 "testing" 7) 8 9type validationTC struct { 10 name string 11 value string 12 err bool 13} 14 15func TestValidation(t *testing.T) { 16 t.Run("ValidationError", func(t *testing.T) { 17 err := ValidationError{Field: "testField", Message: "test message"} 18 expected := "validation error for field 'testField': test message" 19 if err.Error() != expected { 20 t.Errorf("Expected %q, got %q", expected, err.Error()) 21 } 22 }) 23 24 t.Run("ValidationErrors", func(t *testing.T) { 25 t.Run("empty errors", func(t *testing.T) { 26 var errs ValidationErrors 27 expected := "no validation errors" 28 if errs.Error() != expected { 29 t.Errorf("Expected %q, got %q", expected, errs.Error()) 30 } 31 }) 32 33 t.Run("single error", func(t *testing.T) { 34 errs := ValidationErrors{{Field: "field1", Message: "message1"}} 35 expected := "validation error for field 'field1': message1" 36 if errs.Error() != expected { 37 t.Errorf("Expected %q, got %q", expected, errs.Error()) 38 } 39 }) 40 41 t.Run("multiple errors", func(t *testing.T) { 42 errs := ValidationErrors{{Field: "field1", Message: "message1"}, {Field: "field2", Message: "message2"}} 43 result := errs.Error() 44 if !strings.Contains(result, "multiple validation errors") { 45 t.Error("Expected 'multiple validation errors' in result") 46 } 47 if !strings.Contains(result, "field1") || !strings.Contains(result, "field2") { 48 t.Error("Expected both field names in result") 49 } 50 }) 51 }) 52 53 t.Run("RequiredString", func(t *testing.T) { 54 tests := []validationTC{ 55 {"empty string", "", true}, 56 {"whitespace only", " ", true}, 57 {"valid string", "test", false}, 58 {"string with spaces", "test value", false}, 59 } 60 61 for _, tt := range tests { 62 t.Run(tt.name, func(t *testing.T) { 63 err := RequiredString("testField", tt.value) 64 if (err != nil) != tt.err { 65 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 66 } 67 if err != nil { 68 if !strings.Contains(err.Error(), "testField") { 69 t.Error("Expected field name in error message") 70 } 71 } 72 }) 73 } 74 }) 75 76 t.Run("ValidURL", func(t *testing.T) { 77 tests := []validationTC{ 78 {"empty string", "", false}, 79 {"valid http URL", "http://example.com", false}, 80 {"valid https URL", "https://example.com", false}, 81 {"invalid URL", "not-a-url", true}, 82 {"ftp scheme", "ftp://example.com", true}, 83 {"URL with path", "https://example.com/path", false}, 84 {"URL with query", "https://example.com?param=value", false}, 85 } 86 87 for _, tt := range tests { 88 t.Run(tt.name, func(t *testing.T) { 89 err := ValidURL("testField", tt.value) 90 if (err != nil) != tt.err { 91 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 92 } 93 }) 94 } 95 }) 96 97 t.Run("ValidEmail", func(t *testing.T) { 98 tests := []validationTC{ 99 {"empty string", "", false}, 100 {"valid email", "test@example.com", false}, 101 {"valid email with subdomain", "test@mail.example.com", false}, 102 {"invalid email no @", "testexample.com", true}, 103 {"invalid email no domain", "test@", true}, 104 {"invalid email no local part", "@example.com", true}, 105 {"invalid email spaces", "test @example.com", true}, 106 } 107 108 for _, tt := range tests { 109 t.Run(tt.name, func(t *testing.T) { 110 err := ValidEmail("testField", tt.value) 111 if (err != nil) != tt.err { 112 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 113 } 114 }) 115 } 116 }) 117 118 t.Run("StringLength", func(t *testing.T) { 119 tests := []struct { 120 name string 121 value string 122 min int 123 max int 124 shouldErr bool 125 }{ 126 {"within range", "test", 2, 10, false}, 127 {"too short", "a", 2, 10, true}, 128 {"too long", "verylongstring", 2, 10, true}, 129 {"exact min", "ab", 2, 10, false}, 130 {"exact max", "1234567890", 2, 10, false}, 131 {"no min constraint", "a", 0, 10, false}, 132 {"no max constraint", "verylongstring", 2, 0, false}, 133 {"whitespace trimmed", " test ", 3, 10, false}, 134 } 135 136 for _, tt := range tests { 137 t.Run(tt.name, func(t *testing.T) { 138 err := StringLength("testField", tt.value, tt.min, tt.max) 139 if (err != nil) != tt.shouldErr { 140 t.Errorf("Expected error: %v, got error: %v", tt.shouldErr, err != nil) 141 } 142 }) 143 } 144 }) 145 146 t.Run("ValidDate", func(t *testing.T) { 147 tests := []validationTC{ 148 {"empty string", "", false}, 149 {"YYYY-MM-DD format", "2024-01-01", false}, 150 {"ISO format with time", "2024-01-01T15:04:05Z", false}, 151 {"ISO format with timezone", "2024-01-01T15:04:05-07:00", false}, 152 {"datetime format", "2024-01-01 15:04:05", false}, 153 {"invalid date", "not-a-date", true}, 154 {"invalid format", "01/01/2024", true}, 155 {"incomplete date", "2024-01", true}, 156 } 157 158 for _, tt := range tests { 159 t.Run(tt.name, func(t *testing.T) { 160 err := ValidDate("testField", tt.value) 161 if (err != nil) != tt.err { 162 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 163 } 164 }) 165 } 166 }) 167 168 t.Run("PositiveID", func(t *testing.T) { 169 tests := []struct { 170 name string 171 value int64 172 shouldErr bool 173 }{ 174 {"positive ID", 1, false}, 175 {"zero ID", 0, true}, 176 {"negative ID", -1, true}, 177 {"large positive ID", 999999, false}, 178 } 179 180 for _, tt := range tests { 181 t.Run(tt.name, func(t *testing.T) { 182 err := PositiveID("testField", tt.value) 183 if (err != nil) != tt.shouldErr { 184 t.Errorf("Expected error: %v, got error: %v", tt.shouldErr, err != nil) 185 } 186 }) 187 } 188 }) 189 190 t.Run("ValidEnum", func(t *testing.T) { 191 allowed := []string{"option1", "option2", "option3"} 192 193 tests := []validationTC{ 194 {"empty string", "", false}, 195 {"valid option1", "option1", false}, 196 {"valid option2", "option2", false}, 197 {"valid option3", "option3", false}, 198 {"invalid option", "option4", true}, 199 {"case sensitive", "Option1", true}, 200 } 201 202 for _, tt := range tests { 203 t.Run(tt.name, func(t *testing.T) { 204 err := ValidEnum("testField", tt.value, allowed) 205 if (err != nil) != tt.err { 206 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 207 } 208 }) 209 } 210 }) 211 212 t.Run("ValidFilePath", func(t *testing.T) { 213 tests := []validationTC{ 214 {"empty string", "", false}, 215 {"valid path", "/path/to/file.txt", false}, 216 {"relative path", "path/to/file.txt", false}, 217 {"path traversal", "../../../etc/passwd", true}, 218 {"path with .. in middle", "/path/../to/file.txt", true}, 219 {"invalid characters", "/path/to/file<>.txt", true}, 220 {"pipe character", "/path/to/file|.txt", true}, 221 {"question mark", "/path/to/file?.txt", true}, 222 {"asterisk", "/path/to/file*.txt", true}, 223 {"colon", "/path/to/file:.txt", true}, 224 {"quotes", "/path/to/\"file\".txt", true}, 225 {"windows path", "C:\\path\\to\\file.txt", true}, 226 } 227 228 for _, tt := range tests { 229 t.Run(tt.name, func(t *testing.T) { 230 err := ValidFilePath("testField", tt.value) 231 if (err != nil) != tt.err { 232 t.Errorf("Expected error: %v, got error: %v", tt.err, err != nil) 233 } 234 }) 235 } 236 }) 237 238 t.Run("Validator", func(t *testing.T) { 239 t.Run("empty validator", func(t *testing.T) { 240 v := NewValidator() 241 if !v.IsValid() { 242 t.Error("Expected new validator to be valid") 243 } 244 if v.Errors() != nil { 245 t.Error("Expected new validator to have no errors") 246 } 247 }) 248 249 t.Run("single validation error", func(t *testing.T) { 250 v := NewValidator() 251 v.Check(RequiredString("testField", "")) 252 253 if v.IsValid() { 254 t.Error("Expected validator to be invalid after failed check") 255 } 256 if v.Errors() == nil { 257 t.Error("Expected validator to have errors") 258 } 259 }) 260 261 t.Run("multiple validation errors", func(t *testing.T) { 262 v := NewValidator() 263 v.Check(RequiredString("field1", "")) 264 v.Check(RequiredString("field2", "")) 265 266 if v.IsValid() { 267 t.Error("Expected validator to be invalid") 268 } 269 err := v.Errors() 270 if err == nil { 271 t.Error("Expected validator to have errors") 272 } 273 if !strings.Contains(err.Error(), "field1") || !strings.Contains(err.Error(), "field2") { 274 t.Error("Expected both field names in error message") 275 } 276 }) 277 278 t.Run("mixed valid and invalid checks", func(t *testing.T) { 279 v := NewValidator() 280 v.Check(RequiredString("validField", "valid")) 281 v.Check(RequiredString("invalidField", "")) 282 283 if v.IsValid() { 284 t.Error("Expected validator to be invalid") 285 } 286 err := v.Errors() 287 if err == nil { 288 t.Error("Expected validator to have errors") 289 } 290 if !strings.Contains(err.Error(), "invalidField") { 291 t.Error("Expected invalid field name in error message") 292 } 293 }) 294 295 t.Run("fluent interface", func(t *testing.T) { 296 v := NewValidator() 297 result := v.Check(RequiredString("field1", "valid")).Check(RequiredString("field2", "valid")) 298 299 if result != v { 300 t.Error("Expected Check to return the same validator instance") 301 } 302 if !v.IsValid() { 303 t.Error("Expected validator to be valid after valid checks") 304 } 305 }) 306 307 t.Run("non-validation error handling", func(t *testing.T) { 308 v := NewValidator() 309 v.Check(errors.New("generic error")) 310 311 if v.IsValid() { 312 t.Error("Expected validator to be invalid") 313 } 314 err := v.Errors() 315 if err == nil { 316 t.Error("Expected validator to have errors") 317 } 318 319 if !strings.Contains(err.Error(), "unknown") { 320 t.Error("Expected 'unknown' field in converted error") 321 } 322 }) 323 }) 324}