github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/util/json_writer_test.go (about) 1 // Copyright 2024 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package util 15 16 import ( 17 "bytes" 18 "testing" 19 20 "github.com/stretchr/testify/suite" 21 "github.com/thanhpk/randstr" 22 ) 23 24 type JSONWriterTestSuite struct { 25 suite.Suite 26 useInternalBuffer bool 27 } 28 29 func (suite *JSONWriterTestSuite) writeJSON(fn func(*JSONWriter)) string { 30 if suite.useInternalBuffer { 31 w := BorrowJSONWriter(nil) 32 fn(w) 33 ret := string(w.Buffer()) 34 ReturnJSONWriter(w) 35 return ret 36 } 37 38 out := &bytes.Buffer{} 39 w := BorrowJSONWriter(out) 40 fn(w) 41 ReturnJSONWriter(w) 42 return out.String() 43 } 44 45 func (suite *JSONWriterTestSuite) TestObject() { 46 var s string 47 48 s = suite.writeJSON(func(w *JSONWriter) { 49 w.WriteObject(func() {}) 50 }) 51 suite.Require().Equal(`{}`, s) 52 53 s = suite.writeJSON(func(w *JSONWriter) { 54 w.WriteObject(func() { 55 w.WriteAnyField("foo", 1) 56 }) 57 }) 58 suite.Require().Equal(`{"foo":1}`, s) 59 60 s = suite.writeJSON(func(w *JSONWriter) { 61 w.WriteObject(func() { 62 w.WriteAnyField("foo", 1) 63 w.WriteAnyField("bar", 2) 64 }) 65 }) 66 suite.Require().Equal(`{"foo":1,"bar":2}`, s) 67 68 s = suite.writeJSON(func(w *JSONWriter) { 69 w.WriteObject(func() { 70 w.WriteObjectField("foo", func() {}) 71 }) 72 }) 73 suite.Require().Equal(`{"foo":{}}`, s) 74 75 s = suite.writeJSON(func(w *JSONWriter) { 76 w.WriteObject(func() { 77 w.WriteObjectField("foo", func() {}) 78 w.WriteObjectField("bar", func() {}) 79 }) 80 }) 81 suite.Require().Equal(`{"foo":{},"bar":{}}`, s) 82 83 s = suite.writeJSON(func(w *JSONWriter) { 84 w.WriteObject(func() { 85 w.WriteObjectField("foo", func() { 86 w.WriteObjectField("foo1", func() {}) 87 }) 88 w.WriteObjectField("bar", func() { 89 w.WriteObjectField("foo2", func() {}) 90 }) 91 }) 92 }) 93 suite.Require().Equal(`{"foo":{"foo1":{}},"bar":{"foo2":{}}}`, s) 94 95 s = suite.writeJSON(func(w *JSONWriter) { 96 w.WriteObject(func() { 97 w.WriteObjectField("foo", func() { 98 w.WriteObjectField("foo1", func() {}) 99 w.WriteObjectField("bar1", func() {}) 100 }) 101 w.WriteObjectField("bar", func() { 102 w.WriteObjectField("foo2", func() {}) 103 }) 104 }) 105 }) 106 suite.Require().Equal(`{"foo":{"foo1":{},"bar1":{}},"bar":{"foo2":{}}}`, s) 107 108 s = suite.writeJSON(func(w *JSONWriter) { 109 w.WriteObject(func() { 110 w.WriteObjectField("foo", func() { 111 w.WriteObjectField("foo1", func() {}) 112 w.WriteObjectField("bar1", func() {}) 113 }) 114 w.WriteObjectField("bar", func() { 115 w.WriteObjectField("foo2", func() {}) 116 w.WriteObjectField("bar2", func() {}) 117 }) 118 }) 119 }) 120 suite.Require().Equal(`{"foo":{"foo1":{},"bar1":{}},"bar":{"foo2":{},"bar2":{}}}`, s) 121 122 s = suite.writeJSON(func(w *JSONWriter) { 123 w.WriteObject(func() { 124 w.WriteObjectField("foo", func() { 125 w.WriteObjectField("foo1", func() { 126 w.WriteNullField("abc") 127 }) 128 w.WriteObjectField("bar1", func() {}) 129 }) 130 w.WriteObjectField("bar", func() { 131 w.WriteObjectField("foo2", func() {}) 132 w.WriteObjectField("bar2", func() {}) 133 }) 134 }) 135 }) 136 suite.Require().Equal(`{"foo":{"foo1":{"abc":null},"bar1":{}},"bar":{"foo2":{},"bar2":{}}}`, s) 137 } 138 139 func (suite *JSONWriterTestSuite) TestArray() { 140 var s string 141 142 s = suite.writeJSON(func(w *JSONWriter) { 143 w.WriteArray(func() {}) 144 }) 145 suite.Require().Equal(`[]`, s) 146 147 s = suite.writeJSON(func(w *JSONWriter) { 148 w.WriteArray(func() { 149 w.WriteUint64Element(1) 150 }) 151 }) 152 suite.Require().Equal(`[1]`, s) 153 154 s = suite.writeJSON(func(w *JSONWriter) { 155 w.WriteArray(func() { 156 w.WriteUint64Element(1) 157 w.WriteUint64Element(2) 158 }) 159 }) 160 suite.Require().Equal(`[1,2]`, s) 161 162 s = suite.writeJSON(func(w *JSONWriter) { 163 w.WriteArray(func() { 164 w.WriteArrayElement(func() {}) 165 }) 166 }) 167 suite.Require().Equal(`[[]]`, s) 168 169 s = suite.writeJSON(func(w *JSONWriter) { 170 w.WriteArray(func() { 171 w.WriteArrayElement(func() {}) 172 w.WriteArrayElement(func() {}) 173 }) 174 }) 175 suite.Require().Equal(`[[],[]]`, s) 176 177 s = suite.writeJSON(func(w *JSONWriter) { 178 w.WriteArray(func() { 179 w.WriteArrayElement(func() { 180 w.WriteArrayElement(func() {}) 181 }) 182 w.WriteArrayElement(func() { 183 w.WriteArrayElement(func() {}) 184 }) 185 }) 186 }) 187 suite.Require().Equal(`[[[]],[[]]]`, s) 188 189 s = suite.writeJSON(func(w *JSONWriter) { 190 w.WriteArray(func() { 191 w.WriteArrayElement(func() { 192 w.WriteArrayElement(func() {}) 193 w.WriteArrayElement(func() {}) 194 }) 195 w.WriteArrayElement(func() { 196 w.WriteArrayElement(func() {}) 197 }) 198 }) 199 }) 200 suite.Require().Equal(`[[[],[]],[[]]]`, s) 201 202 s = suite.writeJSON(func(w *JSONWriter) { 203 w.WriteArray(func() { 204 w.WriteArrayElement(func() { 205 w.WriteArrayElement(func() {}) 206 w.WriteArrayElement(func() {}) 207 }) 208 w.WriteArrayElement(func() { 209 w.WriteArrayElement(func() {}) 210 w.WriteArrayElement(func() {}) 211 }) 212 }) 213 }) 214 suite.Require().Equal(`[[[],[]],[[],[]]]`, s) 215 216 s = suite.writeJSON(func(w *JSONWriter) { 217 w.WriteArray(func() { 218 w.WriteArrayElement(func() { 219 w.WriteArrayElement(func() { 220 w.WriteNullElement() 221 }) 222 w.WriteArrayElement(func() {}) 223 }) 224 w.WriteArrayElement(func() { 225 w.WriteArrayElement(func() {}) 226 w.WriteArrayElement(func() {}) 227 }) 228 }) 229 }) 230 suite.Require().Equal(`[[[null],[]],[[],[]]]`, s) 231 232 s = suite.writeJSON(func(w *JSONWriter) { 233 w.WriteArray(func() { 234 w.WriteObjectElement(func() {}) 235 }) 236 }) 237 suite.Require().Equal(`[{}]`, s) 238 239 s = suite.writeJSON(func(w *JSONWriter) { 240 w.WriteArray(func() { 241 w.WriteObjectElement(func() { 242 w.WriteUint64Field("foo", 1) 243 }) 244 }) 245 }) 246 suite.Require().Equal(`[{"foo":1}]`, s) 247 248 s = suite.writeJSON(func(w *JSONWriter) { 249 w.WriteArray(func() { 250 w.WriteObjectElement(func() { 251 w.WriteUint64Field("foo", 1) 252 w.WriteUint64Field("bar", 2) 253 }) 254 }) 255 }) 256 suite.Require().Equal(`[{"foo":1,"bar":2}]`, s) 257 258 s = suite.writeJSON(func(w *JSONWriter) { 259 w.WriteArray(func() { 260 w.WriteObjectElement(func() { 261 w.WriteUint64Field("foo", 1) 262 w.WriteUint64Field("bar", 2) 263 }) 264 w.WriteObjectElement(func() { 265 w.WriteUint64Field("The world is just a stage", 1) 266 w.WriteUint64Field("It's better to laugh than to cry", 2) 267 }) 268 }) 269 }) 270 suite.Require().Equal(`[{"foo":1,"bar":2},{"The world is just a stage":1,"It's better to laugh than to cry":2}]`, s) 271 272 s = suite.writeJSON(func(w *JSONWriter) { 273 w.WriteObject(func() { 274 w.WriteArrayField("values", func() { 275 w.WriteUint64Element(1) 276 w.WriteUint64Element(2) 277 }) 278 }) 279 }) 280 suite.Require().Equal(`{"values":[1,2]}`, s) 281 282 s = suite.writeJSON(func(w *JSONWriter) { 283 w.WriteObject(func() { 284 w.WriteArrayField("values", func() { 285 w.WriteUint64Element(1) 286 w.WriteUint64Element(2) 287 }) 288 w.WriteUint64Field("foo", 1) 289 }) 290 }) 291 suite.Require().Equal(`{"values":[1,2],"foo":1}`, s) 292 293 s = suite.writeJSON(func(w *JSONWriter) { 294 w.WriteObject(func() { 295 w.WriteUint64Field("foo", 1) 296 w.WriteArrayField("values", func() { 297 w.WriteUint64Element(1) 298 w.WriteUint64Element(2) 299 }) 300 }) 301 }) 302 suite.Require().Equal(`{"foo":1,"values":[1,2]}`, s) 303 } 304 305 func (suite *JSONWriterTestSuite) TestBase64() { 306 var s string 307 308 s = suite.writeJSON(func(w *JSONWriter) { 309 w.WriteBase64String([]byte("foo")) 310 }) 311 suite.Require().Equal(`"Zm9v"`, s) 312 313 s = suite.writeJSON(func(w *JSONWriter) { 314 w.WriteObject(func() { 315 w.WriteBase64StringField("foo", []byte("bar")) 316 }) 317 }) 318 suite.Require().Equal(`{"foo":"YmFy"}`, s) 319 } 320 321 func (suite *JSONWriterTestSuite) TestField() { 322 var s string 323 324 s = suite.writeJSON(func(w *JSONWriter) { 325 w.WriteObject(func() { 326 w.WriteStringField("foo", "bar") 327 }) 328 }) 329 suite.Require().Equal(`{"foo":"bar"}`, s) 330 331 s = suite.writeJSON(func(w *JSONWriter) { 332 w.WriteObject(func() { 333 w.WriteUint64Field("foo", 1) 334 }) 335 }) 336 suite.Require().Equal(`{"foo":1}`, s) 337 338 s = suite.writeJSON(func(w *JSONWriter) { 339 w.WriteObject(func() { 340 w.WriteFloat64Field("foo", 1.1) 341 }) 342 }) 343 suite.Require().Equal(`{"foo":1.1}`, s) 344 345 s = suite.writeJSON(func(w *JSONWriter) { 346 w.WriteObject(func() { 347 w.WriteNullField("foo") 348 }) 349 }) 350 suite.Require().Equal(`{"foo":null}`, s) 351 352 s = suite.writeJSON(func(w *JSONWriter) { 353 w.WriteObject(func() { 354 w.WriteAnyField("foo", nil) 355 }) 356 }) 357 suite.Require().Equal(`{"foo":null}`, s) 358 359 s = suite.writeJSON(func(w *JSONWriter) { 360 w.WriteObject(func() { 361 w.WriteAnyField("foo", 1) 362 }) 363 }) 364 suite.Require().Equal(`{"foo":1}`, s) 365 366 s = suite.writeJSON(func(w *JSONWriter) { 367 w.WriteObject(func() { 368 w.WriteBoolField("foo", true) 369 }) 370 }) 371 suite.Require().Equal(`{"foo":true}`, s) 372 373 s = suite.writeJSON(func(w *JSONWriter) { 374 w.WriteObject(func() { 375 w.WriteBoolField("foo", false) 376 }) 377 }) 378 suite.Require().Equal(`{"foo":false}`, s) 379 380 s = suite.writeJSON(func(w *JSONWriter) { 381 w.WriteObject(func() { 382 w.WriteObjectField("foo", func() {}) 383 }) 384 }) 385 suite.Require().Equal(`{"foo":{}}`, s) 386 387 s = suite.writeJSON(func(w *JSONWriter) { 388 w.WriteObject(func() { 389 w.WriteObjectField("foo", func() { 390 w.WriteUint64Field("bar", 1) 391 }) 392 }) 393 }) 394 suite.Require().Equal(`{"foo":{"bar":1}}`, s) 395 396 s = suite.writeJSON(func(w *JSONWriter) { 397 w.WriteObject(func() { 398 w.WriteObjectField("foo", func() { 399 w.WriteUint64Field("bar", 1) 400 w.WriteStringField("abc", "def") 401 }) 402 }) 403 }) 404 suite.Require().Equal(`{"foo":{"bar":1,"abc":"def"}}`, s) 405 406 s = suite.writeJSON(func(w *JSONWriter) { 407 w.WriteObject(func() { 408 w.WriteUint64Field("bar", 1) 409 w.WriteStringField("abc", "def") 410 w.WriteNullField("xyz") 411 }) 412 }) 413 suite.Require().Equal(`{"bar":1,"abc":"def","xyz":null}`, s) 414 415 s = suite.writeJSON(func(w *JSONWriter) { 416 w.WriteObject(func() { 417 w.WriteUint64Field("bar", 1) 418 w.WriteStringField("abc", "def") 419 w.WriteNullField("xyz") 420 w.WriteObjectField("foo", func() {}) 421 }) 422 }) 423 suite.Require().Equal(`{"bar":1,"abc":"def","xyz":null,"foo":{}}`, s) 424 } 425 426 func TestExternalBuffer(t *testing.T) { 427 suite.Run(t, &JSONWriterTestSuite{useInternalBuffer: false}) 428 } 429 430 func TestInternalBuffer(t *testing.T) { 431 suite.Run(t, &JSONWriterTestSuite{useInternalBuffer: true}) 432 } 433 434 func BenchmarkExternalBufferWriteBase64(b *testing.B) { 435 out := &bytes.Buffer{} 436 str := randstr.Bytes(1024) 437 for i := 0; i < b.N; i++ { 438 out.Reset() 439 w := BorrowJSONWriter(out) 440 w.WriteObject(func() { 441 w.WriteBase64StringField("foo", str) 442 }) 443 _ = out.Bytes() 444 ReturnJSONWriter(w) 445 } 446 } 447 448 func BenchmarkInternalBufferWriteBase64(b *testing.B) { 449 str := randstr.Bytes(1024) 450 for i := 0; i < b.N; i++ { 451 w := BorrowJSONWriter(nil) 452 w.WriteObject(func() { 453 w.WriteBase64StringField("foo", str) 454 }) 455 _ = w.Buffer() 456 ReturnJSONWriter(w) 457 } 458 } 459 460 func BenchmarkExternalBufferWriteString(b *testing.B) { 461 out := &bytes.Buffer{} 462 str := randstr.String(1024) 463 for i := 0; i < b.N; i++ { 464 out.Reset() 465 w := BorrowJSONWriter(out) 466 w.WriteObject(func() { 467 w.WriteStringField("foo", str) 468 }) 469 _ = out.Bytes() 470 ReturnJSONWriter(w) 471 } 472 } 473 474 func BenchmarkInternalBufferWriteString(b *testing.B) { 475 str := randstr.String(1024) 476 for i := 0; i < b.N; i++ { 477 w := BorrowJSONWriter(nil) 478 w.WriteObject(func() { 479 w.WriteStringField("foo", str) 480 }) 481 _ = w.Buffer() 482 ReturnJSONWriter(w) 483 } 484 }