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  }