github.com/cloudwego/hertz@v0.9.3/pkg/app/server/render/render_test.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *  http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * The MIT License (MIT)
    17   *
    18   * Copyright (c) 2014 Manuel Martínez-Almeida
    19   *
    20   * Permission is hereby granted, free of charge, to any person obtaining a copy
    21   * of this software and associated documentation files (the "Software"), to deal
    22   * in the Software without restriction, including without limitation the rights
    23   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    24   * copies of the Software, and to permit persons to whom the Software is
    25   * furnished to do so, subject to the following conditions:
    26   *
    27   * The above copyright notice and this permission notice shall be included in
    28   * all copies or substantial portions of the Software.
    29   *
    30   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    31   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    32   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    33   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    34   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    35   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    36   * THE SOFTWARE.
    37  
    38   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    39   * Modifications are Copyright 2022 CloudWeGo Authors.
    40   */
    41  
    42  package render
    43  
    44  import (
    45  	"encoding/xml"
    46  	"testing"
    47  
    48  	"github.com/bytedance/sonic"
    49  	"github.com/cloudwego/hertz/pkg/common/test/assert"
    50  	"github.com/cloudwego/hertz/pkg/common/testdata/proto"
    51  	"github.com/cloudwego/hertz/pkg/protocol"
    52  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    53  )
    54  
    55  type xmlmap map[string]interface{}
    56  
    57  // Allows type H to be used with xml.Marshal
    58  func (h xmlmap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    59  	start.Name = xml.Name{
    60  		Space: "",
    61  		Local: "map",
    62  	}
    63  	if err := e.EncodeToken(start); err != nil {
    64  		return err
    65  	}
    66  	for key, value := range h {
    67  		elem := xml.StartElement{
    68  			Name: xml.Name{Space: "", Local: key},
    69  			Attr: []xml.Attr{},
    70  		}
    71  		if err := e.EncodeElement(value, elem); err != nil {
    72  			return err
    73  		}
    74  	}
    75  
    76  	return e.EncodeToken(xml.EndElement{Name: start.Name})
    77  }
    78  
    79  func TestRenderJSON(t *testing.T) {
    80  	resp := &protocol.Response{}
    81  	data := map[string]interface{}{
    82  		"foo":  "bar",
    83  		"html": "<b>",
    84  	}
    85  
    86  	(JSONRender{data}).WriteContentType(resp)
    87  	assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
    88  
    89  	err := (JSONRender{data}).Render(resp)
    90  
    91  	assert.Nil(t, err)
    92  	assert.DeepEqual(t, []byte("{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}"), resp.Body())
    93  	assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
    94  }
    95  
    96  func TestRenderJSONError(t *testing.T) {
    97  	resp := &protocol.Response{}
    98  	data := make(chan int)
    99  
   100  	err := (JSONRender{data}).Render(resp)
   101  	// json: unsupported type: chan int
   102  	assert.NotNil(t, err)
   103  }
   104  
   105  func TestRenderPureJSON(t *testing.T) {
   106  	resp := &protocol.Response{}
   107  	data := map[string]interface{}{
   108  		"foo":  "bar",
   109  		"html": "<b>",
   110  	}
   111  
   112  	(PureJSON{data}).WriteContentType(resp)
   113  	assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
   114  
   115  	err := (PureJSON{data}).Render(resp)
   116  
   117  	assert.Nil(t, err)
   118  
   119  	assert.DeepEqual(t, []byte("{\"foo\":\"bar\",\"html\":\"<b>\"}\n"), resp.Body())
   120  	assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
   121  }
   122  
   123  func TestRenderPureJSONError(t *testing.T) {
   124  	resp := &protocol.Response{}
   125  	data := make(chan int)
   126  
   127  	err := (PureJSON{data}).Render(resp)
   128  	// json: unsupported type: chan int
   129  	assert.NotNil(t, err)
   130  }
   131  
   132  func TestRenderProtobuf(t *testing.T) {
   133  	resp := &protocol.Response{}
   134  	data := proto.TestStruct{Body: []byte("Hello World")}
   135  
   136  	(ProtoBuf{&data}).WriteContentType(resp)
   137  	assert.DeepEqual(t, []byte("application/x-protobuf"), resp.Header.Peek("Content-Type"))
   138  
   139  	err := (ProtoBuf{&data}).Render(resp)
   140  
   141  	assert.Nil(t, err)
   142  	assert.DeepEqual(t, []byte("\n\vHello World"), resp.Body())
   143  	assert.DeepEqual(t, []byte("application/x-protobuf"), resp.Header.Peek("Content-Type"))
   144  }
   145  
   146  func TestRenderProtobufError(t *testing.T) {
   147  	resp := &protocol.Response{}
   148  	data := proto.Test{}
   149  
   150  	err := (ProtoBuf{&data}).Render(resp)
   151  
   152  	assert.NotNil(t, err)
   153  }
   154  
   155  func TestRenderString(t *testing.T) {
   156  	resp := &protocol.Response{}
   157  
   158  	(String{
   159  		Format: "hello %s %d",
   160  		Data:   []interface{}{},
   161  	}).WriteContentType(resp)
   162  	assert.DeepEqual(t, []byte(consts.MIMETextPlainUTF8), resp.Header.Peek("Content-Type"))
   163  
   164  	err := (String{
   165  		Format: "hola %s %d",
   166  		Data:   []interface{}{"manu", 2},
   167  	}).Render(resp)
   168  
   169  	assert.Nil(t, err)
   170  	assert.DeepEqual(t, []byte("hola manu 2"), resp.Body())
   171  	assert.DeepEqual(t, []byte(consts.MIMETextPlainUTF8), resp.Header.Peek("Content-Type"))
   172  }
   173  
   174  func TestRenderStringLenZero(t *testing.T) {
   175  	resp := &protocol.Response{}
   176  
   177  	err := (String{
   178  		Format: "hola %s %d",
   179  		Data:   []interface{}{},
   180  	}).Render(resp)
   181  
   182  	assert.Nil(t, err)
   183  	assert.DeepEqual(t, []byte("hola %s %d"), resp.Body())
   184  	assert.DeepEqual(t, []byte(consts.MIMETextPlainUTF8), resp.Header.Peek("Content-Type"))
   185  }
   186  
   187  func TestRenderData(t *testing.T) {
   188  	resp := &protocol.Response{}
   189  	data := []byte("#!PNG some raw data")
   190  
   191  	err := (Data{
   192  		ContentType: "image/png",
   193  		Data:        data,
   194  	}).Render(resp)
   195  
   196  	assert.Nil(t, err)
   197  	assert.DeepEqual(t, []byte("#!PNG some raw data"), resp.Body())
   198  	assert.DeepEqual(t, []byte(consts.MIMEImagePNG), resp.Header.Peek("Content-Type"))
   199  }
   200  
   201  func TestRenderXML(t *testing.T) {
   202  	resp := &protocol.Response{}
   203  	data := xmlmap{
   204  		"foo": "bar",
   205  	}
   206  
   207  	(XML{data}).WriteContentType(resp)
   208  	assert.DeepEqual(t, []byte(consts.MIMEApplicationXMLUTF8), resp.Header.Peek("Content-Type"))
   209  
   210  	err := (XML{data}).Render(resp)
   211  
   212  	assert.Nil(t, err)
   213  	assert.DeepEqual(t, []byte("<map><foo>bar</foo></map>"), resp.Body())
   214  	assert.DeepEqual(t, []byte(consts.MIMEApplicationXMLUTF8), resp.Header.Peek("Content-Type"))
   215  }
   216  
   217  func TestRenderXMLError(t *testing.T) {
   218  	resp := &protocol.Response{}
   219  	data := make(chan int)
   220  
   221  	err := (XML{data}).Render(resp)
   222  
   223  	assert.NotNil(t, err)
   224  }
   225  
   226  func TestRenderIndentedJSON(t *testing.T) {
   227  	data := map[string]interface{}{
   228  		"foo":  "bar",
   229  		"html": "h1",
   230  	}
   231  	t.Run("TestHeader", func(t *testing.T) {
   232  		resp := &protocol.Response{}
   233  		(IndentedJSON{data}).WriteContentType(resp)
   234  		assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
   235  	})
   236  	t.Run("TestBody", func(t *testing.T) {
   237  		ResetStdJSONMarshal()
   238  		resp := &protocol.Response{}
   239  		err := (IndentedJSON{data}).Render(resp)
   240  		assert.Nil(t, err)
   241  		assert.DeepEqual(t, []byte("{\n    \"foo\": \"bar\",\n    \"html\": \"h1\"\n}"), resp.Body())
   242  		assert.DeepEqual(t, []byte(consts.MIMEApplicationJSONUTF8), resp.Header.Peek("Content-Type"))
   243  		ResetJSONMarshal(sonic.Marshal)
   244  	})
   245  	t.Run("TestError", func(t *testing.T) {
   246  		resp := &protocol.Response{}
   247  		ch := make(chan int)
   248  		err := (IndentedJSON{ch}).Render(resp)
   249  		assert.NotNil(t, err)
   250  	})
   251  }