github.com/cloudwego/hertz@v0.9.3/internal/bytesconv/bytesconv_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  
    17  package bytesconv
    18  
    19  import (
    20  	"net/url"
    21  	"strings"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/cloudwego/hertz/pkg/common/bytebufferpool"
    26  	"github.com/cloudwego/hertz/pkg/common/test/assert"
    27  	"github.com/cloudwego/hertz/pkg/common/test/mock"
    28  	"github.com/cloudwego/hertz/pkg/network"
    29  )
    30  
    31  func TestAppendDate(t *testing.T) {
    32  	t.Parallel()
    33  	// GMT+8
    34  	shanghaiTimeZone := time.FixedZone("Asia/Shanghai", 8*60*60)
    35  
    36  	for _, c := range []struct {
    37  		name    string
    38  		date    time.Time
    39  		dateStr string
    40  	}{
    41  		{
    42  			name:    "UTC",
    43  			date:    time.Date(2022, 6, 15, 11, 12, 13, 123, time.UTC),
    44  			dateStr: "Wed, 15 Jun 2022 11:12:13 GMT",
    45  		},
    46  		{
    47  			name:    "Asia/Shanghai",
    48  			date:    time.Date(2022, 6, 15, 3, 12, 45, 999, shanghaiTimeZone),
    49  			dateStr: "Tue, 14 Jun 2022 19:12:45 GMT",
    50  		},
    51  	} {
    52  		t.Run(c.name, func(t *testing.T) {
    53  			s := AppendHTTPDate(nil, c.date)
    54  			assert.DeepEqual(t, c.dateStr, B2s(s))
    55  		})
    56  	}
    57  }
    58  
    59  func TestLowercaseBytes(t *testing.T) {
    60  	t.Parallel()
    61  
    62  	for _, v := range []struct {
    63  		b1, b2 []byte
    64  	}{
    65  		{[]byte("CLOUDWEGO-HERTZ"), []byte("cloudwego-hertz")},
    66  		{[]byte("CLOUDWEGO"), []byte("cloudwego")},
    67  		{[]byte("HERTZ"), []byte("hertz")},
    68  	} {
    69  		LowercaseBytes(v.b1)
    70  		assert.DeepEqual(t, v.b2, v.b1)
    71  	}
    72  }
    73  
    74  // The test converts byte slice to a string without memory allocation.
    75  func TestB2s(t *testing.T) {
    76  	t.Parallel()
    77  
    78  	for _, v := range []struct {
    79  		s string
    80  		b []byte
    81  	}{
    82  		{"cloudwego-hertz", []byte("cloudwego-hertz")},
    83  		{"cloudwego", []byte("cloudwego")},
    84  		{"hertz", []byte("hertz")},
    85  	} {
    86  		assert.DeepEqual(t, v.s, B2s(v.b))
    87  	}
    88  }
    89  
    90  // The test converts string to a byte slice without memory allocation.
    91  func TestS2b(t *testing.T) {
    92  	t.Parallel()
    93  
    94  	for _, v := range []struct {
    95  		s string
    96  		b []byte
    97  	}{
    98  		{"cloudwego-hertz", []byte("cloudwego-hertz")},
    99  		{"cloudwego", []byte("cloudwego")},
   100  		{"hertz", []byte("hertz")},
   101  	} {
   102  		assert.DeepEqual(t, S2b(v.s), v.b)
   103  	}
   104  }
   105  
   106  // common test function for 32bit and 64bit
   107  func testWriteHexInt(t *testing.T, n int, expectedS string) {
   108  	w := bytebufferpool.Get()
   109  	zw := network.NewWriter(w)
   110  	if err := WriteHexInt(zw, n); err != nil {
   111  		t.Errorf("unexpected error when writing hex %x: %v", n, err)
   112  	}
   113  	if err := zw.Flush(); err != nil {
   114  		t.Fatalf("unexpected error when flushing hex %x: %v", n, err)
   115  	}
   116  	s := B2s(w.B)
   117  	assert.DeepEqual(t, s, expectedS)
   118  }
   119  
   120  // common test function for 32bit and 64bit
   121  func testReadHexInt(t *testing.T, s string, expectedN int) {
   122  	zr := mock.NewZeroCopyReader(s)
   123  	n, err := ReadHexInt(zr)
   124  	if err != nil {
   125  		t.Errorf("unexpected error: %v. s=%q", err, s)
   126  	}
   127  	assert.DeepEqual(t, n, expectedN)
   128  }
   129  
   130  func TestAppendQuotedPath(t *testing.T) {
   131  	t.Parallel()
   132  
   133  	// Test all characters
   134  	pathSegment := make([]byte, 256)
   135  	for i := 0; i < 256; i++ {
   136  		pathSegment[i] = byte(i)
   137  	}
   138  	for _, s := range []struct {
   139  		path string
   140  	}{
   141  		{"/"},
   142  		{"//"},
   143  		{"/foo/bar"},
   144  		{"*"},
   145  		{"/foo/" + B2s(pathSegment)},
   146  	} {
   147  		u := url.URL{Path: s.path}
   148  		expectedS := u.EscapedPath()
   149  		res := B2s(AppendQuotedPath(nil, S2b(s.path)))
   150  		assert.DeepEqual(t, expectedS, res)
   151  	}
   152  }
   153  
   154  func TestAppendQuotedArg(t *testing.T) {
   155  	t.Parallel()
   156  
   157  	// Sync with url.QueryEscape
   158  	allcases := make([]byte, 256)
   159  	for i := 0; i < 256; i++ {
   160  		allcases[i] = byte(i)
   161  	}
   162  	res := B2s(AppendQuotedArg(nil, allcases))
   163  	expect := url.QueryEscape(B2s(allcases))
   164  	assert.DeepEqual(t, expect, res)
   165  }
   166  
   167  func TestParseHTTPDate(t *testing.T) {
   168  	t.Parallel()
   169  
   170  	for _, v := range []struct {
   171  		t string
   172  	}{
   173  		{"Thu, 04 Feb 2010 21:00:57 PST"},
   174  		{"Mon, 02 Jan 2006 15:04:05 MST"},
   175  	} {
   176  		t1, err := time.Parse(time.RFC1123, v.t)
   177  		if err != nil {
   178  			t.Fatalf("unexpected error: %v. t=%q", err, v.t)
   179  		}
   180  		t2, err := ParseHTTPDate(S2b(t1.Format(time.RFC1123)))
   181  		if err != nil {
   182  			t.Fatalf("unexpected error: %v. t=%q", err, v.t)
   183  		}
   184  		assert.DeepEqual(t, t1, t2)
   185  	}
   186  }
   187  
   188  // For test only, but it will import golang.org/x/net/http.
   189  // So comment out all this code. Keep this for the full context.
   190  //func TestValidHeaderFieldValueTable(t *testing.T) {
   191  //	t.Parallel()
   192  //
   193  //	// Test all characters
   194  //	allBytes := make([]byte, 0)
   195  //	for i := 0; i < 256; i++ {
   196  //		allBytes = append(allBytes, byte(i))
   197  //	}
   198  //	for _, s := range allBytes {
   199  //		ss := []byte{s}
   200  //		expectedS := httpguts.ValidHeaderFieldValue(string(ss))
   201  //		res := func() bool {
   202  //			return ValidHeaderFieldValueTable[s] != 0
   203  //		}()
   204  //
   205  //		assert.DeepEqual(t, expectedS, res)
   206  //	}
   207  //}
   208  
   209  func TestNewlineToSpaceTable(t *testing.T) {
   210  	t.Parallel()
   211  	// Test all characters
   212  	allBytes := make([]byte, 0)
   213  	for i := 0; i < 256; i++ {
   214  		allBytes = append(allBytes, byte(i))
   215  	}
   216  
   217  	headerNewlineToSpace := strings.NewReplacer("\n", " ", "\r", " ")
   218  
   219  	expectedS := headerNewlineToSpace.Replace(string(allBytes))
   220  
   221  	res := make([]byte, len(allBytes))
   222  	copy(res, allBytes)
   223  	for i := 0; i < len(res); i++ {
   224  		res[i] = NewlineToSpaceTable[res[i]]
   225  	}
   226  
   227  	assert.DeepEqual(t, expectedS, string(res))
   228  }
   229  
   230  // For test only, but it will import golang.org/x/net/http.
   231  // So comment out all this code. Keep this for the full context.
   232  //func TestValidHeaderFieldNameTable(t *testing.T) {
   233  //	t.Parallel()
   234  //
   235  //	// Test all characters
   236  //	allBytes := make([]byte, 0)
   237  //	for i := 0; i < 256; i++ {
   238  //		allBytes = append(allBytes, byte(i))
   239  //	}
   240  //	for _, s := range allBytes {
   241  //		ss := []byte{s}
   242  //		expectedS := httpguts.ValidHeaderFieldName(string(ss))
   243  //		res := func() bool {
   244  //			return ValidHeaderFieldNameTable[s] != 0
   245  //		}()
   246  //
   247  //		assert.DeepEqual(t, expectedS, res)
   248  //	}
   249  //}