github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/render/render_test.go (about) 1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package render 6 7 import ( 8 "encoding/xml" 9 "errors" 10 "github.com/hellobchain/newcryptosm/http" 11 "github.com/hellobchain/newcryptosm/http/httptest" 12 "html/template" 13 "strconv" 14 "strings" 15 "testing" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/stretchr/testify/assert" 19 20 testdata "github.com/hellobchain/third_party/gin/testdata/protoexample" 21 ) 22 23 // TODO unit tests 24 // test errors 25 26 func TestRenderJSON(t *testing.T) { 27 w := httptest.NewRecorder() 28 data := map[string]interface{}{ 29 "foo": "bar", 30 "html": "<b>", 31 } 32 33 (JSON{data}).WriteContentType(w) 34 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 35 36 err := (JSON{data}).Render(w) 37 38 assert.NoError(t, err) 39 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) 40 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 41 } 42 43 func TestRenderJSONPanics(t *testing.T) { 44 w := httptest.NewRecorder() 45 data := make(chan int) 46 47 // json: unsupported type: chan int 48 assert.Panics(t, func() { assert.NoError(t, (JSON{data}).Render(w)) }) 49 } 50 51 func TestRenderIndentedJSON(t *testing.T) { 52 w := httptest.NewRecorder() 53 data := map[string]interface{}{ 54 "foo": "bar", 55 "bar": "foo", 56 } 57 58 err := (IndentedJSON{data}).Render(w) 59 60 assert.NoError(t, err) 61 assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String()) 62 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 63 } 64 65 func TestRenderIndentedJSONPanics(t *testing.T) { 66 w := httptest.NewRecorder() 67 data := make(chan int) 68 69 // json: unsupported type: chan int 70 err := (IndentedJSON{data}).Render(w) 71 assert.Error(t, err) 72 } 73 74 func TestRenderSecureJSON(t *testing.T) { 75 w1 := httptest.NewRecorder() 76 data := map[string]interface{}{ 77 "foo": "bar", 78 } 79 80 (SecureJSON{"while(1);", data}).WriteContentType(w1) 81 assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type")) 82 83 err1 := (SecureJSON{"while(1);", data}).Render(w1) 84 85 assert.NoError(t, err1) 86 assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String()) 87 assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type")) 88 89 w2 := httptest.NewRecorder() 90 datas := []map[string]interface{}{{ 91 "foo": "bar", 92 }, { 93 "bar": "foo", 94 }} 95 96 err2 := (SecureJSON{"while(1);", datas}).Render(w2) 97 assert.NoError(t, err2) 98 assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String()) 99 assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type")) 100 } 101 102 func TestRenderSecureJSONFail(t *testing.T) { 103 w := httptest.NewRecorder() 104 data := make(chan int) 105 106 // json: unsupported type: chan int 107 err := (SecureJSON{"while(1);", data}).Render(w) 108 assert.Error(t, err) 109 } 110 111 func TestRenderJsonpJSON(t *testing.T) { 112 w1 := httptest.NewRecorder() 113 data := map[string]interface{}{ 114 "foo": "bar", 115 } 116 117 (JsonpJSON{"x", data}).WriteContentType(w1) 118 assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type")) 119 120 err1 := (JsonpJSON{"x", data}).Render(w1) 121 122 assert.NoError(t, err1) 123 assert.Equal(t, "x({\"foo\":\"bar\"});", w1.Body.String()) 124 assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type")) 125 126 w2 := httptest.NewRecorder() 127 datas := []map[string]interface{}{{ 128 "foo": "bar", 129 }, { 130 "bar": "foo", 131 }} 132 133 err2 := (JsonpJSON{"x", datas}).Render(w2) 134 assert.NoError(t, err2) 135 assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}]);", w2.Body.String()) 136 assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type")) 137 } 138 139 func TestRenderJsonpJSONError2(t *testing.T) { 140 w := httptest.NewRecorder() 141 data := map[string]interface{}{ 142 "foo": "bar", 143 } 144 (JsonpJSON{"", data}).WriteContentType(w) 145 assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) 146 147 e := (JsonpJSON{"", data}).Render(w) 148 assert.NoError(t, e) 149 150 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) 151 assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) 152 } 153 154 func TestRenderJsonpJSONFail(t *testing.T) { 155 w := httptest.NewRecorder() 156 data := make(chan int) 157 158 // json: unsupported type: chan int 159 err := (JsonpJSON{"x", data}).Render(w) 160 assert.Error(t, err) 161 } 162 163 func TestRenderAsciiJSON(t *testing.T) { 164 w1 := httptest.NewRecorder() 165 data1 := map[string]interface{}{ 166 "lang": "GO语言", 167 "tag": "<br>", 168 } 169 170 err := (AsciiJSON{data1}).Render(w1) 171 172 assert.NoError(t, err) 173 assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String()) 174 assert.Equal(t, "application/json", w1.Header().Get("Content-Type")) 175 176 w2 := httptest.NewRecorder() 177 data2 := float64(3.1415926) 178 179 err = (AsciiJSON{data2}).Render(w2) 180 assert.NoError(t, err) 181 assert.Equal(t, "3.1415926", w2.Body.String()) 182 } 183 184 func TestRenderAsciiJSONFail(t *testing.T) { 185 w := httptest.NewRecorder() 186 data := make(chan int) 187 188 // json: unsupported type: chan int 189 assert.Error(t, (AsciiJSON{data}).Render(w)) 190 } 191 192 func TestRenderPureJSON(t *testing.T) { 193 w := httptest.NewRecorder() 194 data := map[string]interface{}{ 195 "foo": "bar", 196 "html": "<b>", 197 } 198 err := (PureJSON{data}).Render(w) 199 assert.NoError(t, err) 200 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String()) 201 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 202 } 203 204 type xmlmap map[string]interface{} 205 206 // Allows type H to be used with xml.Marshal 207 func (h xmlmap) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 208 start.Name = xml.Name{ 209 Space: "", 210 Local: "map", 211 } 212 if err := e.EncodeToken(start); err != nil { 213 return err 214 } 215 for key, value := range h { 216 elem := xml.StartElement{ 217 Name: xml.Name{Space: "", Local: key}, 218 Attr: []xml.Attr{}, 219 } 220 if err := e.EncodeElement(value, elem); err != nil { 221 return err 222 } 223 } 224 225 return e.EncodeToken(xml.EndElement{Name: start.Name}) 226 } 227 228 func TestRenderYAML(t *testing.T) { 229 w := httptest.NewRecorder() 230 data := ` 231 a : Easy! 232 b: 233 c: 2 234 d: [3, 4] 235 ` 236 (YAML{data}).WriteContentType(w) 237 assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) 238 239 err := (YAML{data}).Render(w) 240 assert.NoError(t, err) 241 assert.Equal(t, "\"\\na : Easy!\\nb:\\n\\tc: 2\\n\\td: [3, 4]\\n\\t\"\n", w.Body.String()) 242 assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) 243 } 244 245 type fail struct{} 246 247 // Hook MarshalYAML 248 func (ft *fail) MarshalYAML() (interface{}, error) { 249 return nil, errors.New("fail") 250 } 251 252 func TestRenderYAMLFail(t *testing.T) { 253 w := httptest.NewRecorder() 254 err := (YAML{&fail{}}).Render(w) 255 assert.Error(t, err) 256 } 257 258 // test Protobuf rendering 259 func TestRenderProtoBuf(t *testing.T) { 260 w := httptest.NewRecorder() 261 reps := []int64{int64(1), int64(2)} 262 label := "test" 263 data := &testdata.Test{ 264 Label: &label, 265 Reps: reps, 266 } 267 268 (ProtoBuf{data}).WriteContentType(w) 269 protoData, err := proto.Marshal(data) 270 assert.NoError(t, err) 271 assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type")) 272 273 err = (ProtoBuf{data}).Render(w) 274 275 assert.NoError(t, err) 276 assert.Equal(t, string(protoData), w.Body.String()) 277 assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type")) 278 } 279 280 func TestRenderProtoBufFail(t *testing.T) { 281 w := httptest.NewRecorder() 282 data := &testdata.Test{} 283 err := (ProtoBuf{data}).Render(w) 284 assert.Error(t, err) 285 } 286 287 func TestRenderXML(t *testing.T) { 288 w := httptest.NewRecorder() 289 data := xmlmap{ 290 "foo": "bar", 291 } 292 293 (XML{data}).WriteContentType(w) 294 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) 295 296 err := (XML{data}).Render(w) 297 298 assert.NoError(t, err) 299 assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String()) 300 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) 301 } 302 303 func TestRenderRedirect(t *testing.T) { 304 req, err := http.NewRequest("GET", "/test-redirect", nil) 305 assert.NoError(t, err) 306 307 data1 := Redirect{ 308 Code: http.StatusMovedPermanently, 309 Request: req, 310 Location: "/new/location", 311 } 312 313 w := httptest.NewRecorder() 314 err = data1.Render(w) 315 assert.NoError(t, err) 316 317 data2 := Redirect{ 318 Code: http.StatusOK, 319 Request: req, 320 Location: "/new/location", 321 } 322 323 w = httptest.NewRecorder() 324 assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() { 325 err := data2.Render(w) 326 assert.NoError(t, err) 327 }) 328 329 data3 := Redirect{ 330 Code: http.StatusCreated, 331 Request: req, 332 Location: "/new/location", 333 } 334 335 w = httptest.NewRecorder() 336 err = data3.Render(w) 337 assert.NoError(t, err) 338 339 // only improve coverage 340 data2.WriteContentType(w) 341 } 342 343 func TestRenderData(t *testing.T) { 344 w := httptest.NewRecorder() 345 data := []byte("#!PNG some raw data") 346 347 err := (Data{ 348 ContentType: "image/png", 349 Data: data, 350 }).Render(w) 351 352 assert.NoError(t, err) 353 assert.Equal(t, "#!PNG some raw data", w.Body.String()) 354 assert.Equal(t, "image/png", w.Header().Get("Content-Type")) 355 } 356 357 func TestRenderString(t *testing.T) { 358 w := httptest.NewRecorder() 359 360 (String{ 361 Format: "hello %s %d", 362 Data: []interface{}{}, 363 }).WriteContentType(w) 364 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 365 366 err := (String{ 367 Format: "hola %s %d", 368 Data: []interface{}{"manu", 2}, 369 }).Render(w) 370 371 assert.NoError(t, err) 372 assert.Equal(t, "hola manu 2", w.Body.String()) 373 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 374 } 375 376 func TestRenderStringLenZero(t *testing.T) { 377 w := httptest.NewRecorder() 378 379 err := (String{ 380 Format: "hola %s %d", 381 Data: []interface{}{}, 382 }).Render(w) 383 384 assert.NoError(t, err) 385 assert.Equal(t, "hola %s %d", w.Body.String()) 386 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 387 } 388 389 func TestRenderHTMLTemplate(t *testing.T) { 390 w := httptest.NewRecorder() 391 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) 392 393 htmlRender := HTMLProduction{Template: templ} 394 instance := htmlRender.Instance("t", map[string]interface{}{ 395 "name": "alexandernyquist", 396 }) 397 398 err := instance.Render(w) 399 400 assert.NoError(t, err) 401 assert.Equal(t, "Hello alexandernyquist", w.Body.String()) 402 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 403 } 404 405 func TestRenderHTMLTemplateEmptyName(t *testing.T) { 406 w := httptest.NewRecorder() 407 templ := template.Must(template.New("").Parse(`Hello {{.name}}`)) 408 409 htmlRender := HTMLProduction{Template: templ} 410 instance := htmlRender.Instance("", map[string]interface{}{ 411 "name": "alexandernyquist", 412 }) 413 414 err := instance.Render(w) 415 416 assert.NoError(t, err) 417 assert.Equal(t, "Hello alexandernyquist", w.Body.String()) 418 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 419 } 420 421 func TestRenderHTMLDebugFiles(t *testing.T) { 422 w := httptest.NewRecorder() 423 htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"}, 424 Glob: "", 425 Delims: Delims{Left: "{[{", Right: "}]}"}, 426 FuncMap: nil, 427 } 428 instance := htmlRender.Instance("hello.tmpl", map[string]interface{}{ 429 "name": "thinkerou", 430 }) 431 432 err := instance.Render(w) 433 434 assert.NoError(t, err) 435 assert.Equal(t, "<h1>Hello thinkerou</h1>", w.Body.String()) 436 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 437 } 438 439 func TestRenderHTMLDebugGlob(t *testing.T) { 440 w := httptest.NewRecorder() 441 htmlRender := HTMLDebug{Files: nil, 442 Glob: "../testdata/template/hello*", 443 Delims: Delims{Left: "{[{", Right: "}]}"}, 444 FuncMap: nil, 445 } 446 instance := htmlRender.Instance("hello.tmpl", map[string]interface{}{ 447 "name": "thinkerou", 448 }) 449 450 err := instance.Render(w) 451 452 assert.NoError(t, err) 453 assert.Equal(t, "<h1>Hello thinkerou</h1>", w.Body.String()) 454 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 455 } 456 457 func TestRenderHTMLDebugPanics(t *testing.T) { 458 htmlRender := HTMLDebug{Files: nil, 459 Glob: "", 460 Delims: Delims{"{{", "}}"}, 461 FuncMap: nil, 462 } 463 assert.Panics(t, func() { htmlRender.Instance("", nil) }) 464 } 465 466 func TestRenderReader(t *testing.T) { 467 w := httptest.NewRecorder() 468 469 body := "#!PNG some raw data" 470 headers := make(map[string]string) 471 headers["Content-Disposition"] = `attachment; filename="filename.png"` 472 headers["x-request-id"] = "requestId" 473 474 err := (Reader{ 475 ContentLength: int64(len(body)), 476 ContentType: "image/png", 477 Reader: strings.NewReader(body), 478 Headers: headers, 479 }).Render(w) 480 481 assert.NoError(t, err) 482 assert.Equal(t, body, w.Body.String()) 483 assert.Equal(t, "image/png", w.Header().Get("Content-Type")) 484 assert.Equal(t, strconv.Itoa(len(body)), w.Header().Get("Content-Length")) 485 assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) 486 assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) 487 } 488 489 func TestRenderReaderNoContentLength(t *testing.T) { 490 w := httptest.NewRecorder() 491 492 body := "#!PNG some raw data" 493 headers := make(map[string]string) 494 headers["Content-Disposition"] = `attachment; filename="filename.png"` 495 headers["x-request-id"] = "requestId" 496 497 err := (Reader{ 498 ContentLength: -1, 499 ContentType: "image/png", 500 Reader: strings.NewReader(body), 501 Headers: headers, 502 }).Render(w) 503 504 assert.NoError(t, err) 505 assert.Equal(t, body, w.Body.String()) 506 assert.Equal(t, "image/png", w.Header().Get("Content-Type")) 507 assert.NotContains(t, "Content-Length", w.Header()) 508 assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) 509 assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) 510 }