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 //}