github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/streamer_test.go (about) 1 package jzon 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "reflect" 9 "strings" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 ) 14 15 type badWriter struct { 16 data string 17 } 18 19 func (w *badWriter) Write(data []byte) (int, error) { 20 n := len(data) 21 if n > 0 { 22 n-- 23 } 24 w.data = string(data) 25 return n, nil 26 } 27 28 func testStreamerWithEncoderConfig(t *testing.T, encCfg *EncoderConfig, exp string, cb func(s *Streamer)) { 29 streamer := encCfg.NewStreamer() 30 defer streamer.Release() 31 var b bytes.Buffer 32 streamer.Reset(&b) 33 34 cb(streamer) 35 err := streamer.Flush() 36 require.NoError(t, err) 37 38 s := b.String() 39 require.Equalf(t, exp, s, "expect %q but got %q", exp, s) 40 t.Logf("got %q", s) 41 } 42 43 func testStreamer(t *testing.T, exp string, cb func(s *Streamer)) { 44 testStreamerWithEncoderConfig(t, DefaultEncoderConfig, exp, cb) 45 } 46 47 func jsonMarshal(o interface{}, jsonOpt func(*json.Encoder)) (_ []byte, err error) { 48 defer func() { 49 if e := recover(); e != nil { 50 if err == nil { 51 err = fmt.Errorf("panic: %v", e) 52 } 53 } 54 }() 55 var buf bytes.Buffer 56 enc := json.NewEncoder(&buf) 57 if jsonOpt != nil { 58 jsonOpt(enc) 59 } 60 if err = enc.Encode(o); err != nil { 61 return 62 } 63 return buf.Bytes(), nil 64 } 65 66 func jsonEqual(s1, s2 []byte) (bool, error) { 67 var err error 68 69 s1 = bytes.TrimSpace(s1) 70 s2 = bytes.TrimSpace(s2) 71 72 switch s1[0] { 73 case 'n': 74 return "null" == localByteToString(s1) && 75 "null" == localByteToString(s2), nil 76 case 't': 77 return "true" == localByteToString(s1) && 78 "true" == localByteToString(s2), nil 79 case 'f': 80 return "false" == localByteToString(s1) && 81 "false" == localByteToString(s2), nil 82 case '[': 83 var arr1 []json.RawMessage 84 if err = json.Unmarshal(s1, &arr1); err != nil { 85 return false, err 86 } 87 var arr2 []json.RawMessage 88 if err = json.Unmarshal(s2, &arr2); err != nil { 89 return false, err 90 } 91 l := len(arr1) 92 if l != len(arr2) { 93 return false, nil 94 } 95 for i := 0; i < l; i++ { 96 b, err := jsonEqual(arr1[i], arr2[i]) 97 if err != nil || !b { 98 return b, err 99 } 100 } 101 return true, nil 102 case '{': 103 var m1 map[string]json.RawMessage 104 if err = json.Unmarshal(s1, &m1); err != nil { 105 return false, err 106 } 107 var m2 map[string]json.RawMessage 108 if err = json.Unmarshal(s2, &m2); err != nil { 109 return false, err 110 } 111 l := len(m1) 112 if l != len(m2) { 113 return false, nil 114 } 115 for k := range m1 { 116 b, err := jsonEqual(m1[k], m2[k]) 117 if err != nil || !b { 118 return b, err 119 } 120 } 121 return true, nil 122 case '"': 123 var str1 string 124 if err = json.Unmarshal(s1, &str1); err != nil { 125 return false, err 126 } 127 var str2 string 128 if err = json.Unmarshal(s2, &str2); err != nil { 129 return false, err 130 } 131 return str1 == str2, nil 132 default: 133 var f1 float64 134 if err = json.Unmarshal(s1, &f1); err != nil { 135 return false, err 136 } 137 var f2 float64 138 if err = json.Unmarshal(s2, &f2); err != nil { 139 return false, err 140 } 141 return f1 == f2, nil 142 } 143 } 144 145 var ( 146 testNoEscapeEncoderConfig = NewEncoderConfig(&EncoderOption{ 147 EscapeHTML: false, 148 }) 149 ) 150 151 func checkEncodeWithStandard(t *testing.T, obj interface{}, cb func(s *Streamer), 152 expErr interface{}) { 153 checkEncodeWithStandardInternal(t, nil, DefaultEncoderConfig, obj, cb, expErr) 154 checkEncodeWithStandardInternal(t, func(encoder *json.Encoder) { 155 encoder.SetEscapeHTML(false) 156 }, testNoEscapeEncoderConfig, obj, cb, expErr) 157 } 158 159 func checkEncodeWithStandardInternal(t *testing.T, jsonOpt func(*json.Encoder), encCfg *EncoderConfig, obj interface{}, 160 cb func(s *Streamer), expErr interface{}) { 161 buf, err := jsonMarshal(obj, jsonOpt) 162 require.Equal(t, expErr == nil, err == nil, "json.Marshal\nexp: %v\ngot: %v", 163 expErr, err) 164 165 streamer := encCfg.NewStreamer() 166 defer streamer.Release() 167 func() { 168 defer func() { 169 if e := recover(); e != nil { 170 if streamer.Error != nil { 171 panic(e) 172 } 173 ex, ok := e.(error) 174 if !ok { 175 panic(e) 176 } 177 streamer.Error = ex 178 } 179 }() 180 cb(streamer) 181 }() 182 183 if err != nil { 184 t.Logf("json err: %v", err) 185 t.Logf("jzon err: %v", streamer.Error) 186 switch x := expErr.(type) { 187 case reflect.Type: 188 gotErrType := reflect.TypeOf(streamer.Error) 189 if x.Kind() == reflect.Interface { 190 require.True(t, gotErrType.Implements(x), "exp err:%v\ngot err:%v", 191 x, streamer.Error) 192 } else { 193 require.Equal(t, x, gotErrType, "exp err:%v\ngot err:%v", 194 x, streamer.Error) 195 } 196 case error: 197 checkError(t, x, streamer.Error) 198 // if reflect.TypeOf(errors.New("")) == reflect.TypeOf(expErr) { 199 // require.Equalf(t, expErr, streamer.Error, "exp err:%v\ngot err:%v", 200 // expErr, streamer.Error) 201 // } else { 202 // require.IsTypef(t, expErr, streamer.Error, "exp err:%v\ngot err:%v", 203 // expErr, streamer.Error) 204 // } 205 } 206 require.Error(t, streamer.Error, "json.Marshal error: %v", err) 207 } else { 208 t.Logf("got %s", buf) 209 require.NoError(t, streamer.Error) 210 b, err := jsonEqual(buf, streamer.buffer) 211 require.NoErrorf(t, err, "final result\njson %s\njzon %s", 212 bytes.TrimSpace(buf), bytes.TrimSpace(streamer.buffer)) 213 require.Truef(t, b, "final result\njson %s\njzon %s", 214 bytes.TrimSpace(buf), bytes.TrimSpace(streamer.buffer)) 215 } 216 } 217 218 func checkEncodeValueWithStandard(t *testing.T, obj interface{}, expErr interface{}) { 219 checkEncodeWithStandard(t, obj, func(s *Streamer) { 220 s.Value(obj) 221 }, expErr) 222 } 223 224 func testStreamerChainError(t *testing.T, cb func(s *Streamer)) { 225 s := DefaultEncoderConfig.NewStreamer() 226 defer s.Release() 227 228 var b bytes.Buffer 229 s.Reset(&b) 230 231 e := errors.New("test") 232 s.Error = e 233 cb(s) 234 235 require.Equal(t, e, s.Error) 236 require.Equal(t, e, s.Flush()) 237 require.Len(t, s.buffer, 0) 238 require.Equal(t, 0, b.Len()) 239 } 240 241 func TestStreamer_Flush(t *testing.T) { 242 t.Run("no writer attached", func(t *testing.T) { 243 streamer := NewStreamer() 244 defer streamer.Release() 245 err := streamer.Flush() 246 require.Equal(t, ErrNoAttachedWriter, err) 247 }) 248 t.Run("bad writer implementation", func(t *testing.T) { 249 streamer := NewStreamer() 250 defer streamer.Release() 251 var ( 252 w badWriter 253 err error 254 ) 255 streamer.Reset(&w) 256 streamer.True() 257 258 err = streamer.Flush() 259 require.NoError(t, err) 260 require.Equal(t, "true", w.data) 261 262 err = streamer.Flush() 263 require.NoError(t, err) 264 require.Equal(t, "e", w.data) 265 }) 266 } 267 268 func TestStreamer(t *testing.T) { 269 t.Run("raw string", func(t *testing.T) { 270 testStreamer(t, "abc", func(s *Streamer) { 271 s.RawString("abc") 272 }) 273 }) 274 t.Run("raw", func(t *testing.T) { 275 testStreamer(t, "abc", func(s *Streamer) { 276 s.Raw([]byte("abc")) 277 }) 278 }) 279 t.Run("null", func(t *testing.T) { 280 testStreamer(t, "null", func(s *Streamer) { 281 s.Null() 282 }) 283 }) 284 t.Run("true", func(t *testing.T) { 285 testStreamer(t, "true", func(s *Streamer) { 286 s.True() 287 }) 288 testStreamer(t, "true", func(s *Streamer) { 289 s.Bool(true) 290 }) 291 }) 292 t.Run("false", func(t *testing.T) { 293 testStreamer(t, "false", func(s *Streamer) { 294 s.False() 295 }) 296 testStreamer(t, "false", func(s *Streamer) { 297 s.Bool(false) 298 }) 299 }) 300 t.Run("array", func(t *testing.T) { 301 t.Run("empty", func(t *testing.T) { 302 testStreamer(t, "[]", func(s *Streamer) { 303 s.ArrayStart().ArrayEnd() 304 }) 305 }) 306 t.Run("nested 1", func(t *testing.T) { 307 count := 10 308 s := strings.ReplaceAll(nestedArray1(count), " ", "") 309 testStreamer(t, s, func(s *Streamer) { 310 for i := 0; i < count; i++ { 311 s.ArrayStart() 312 } 313 s.ArrayStart().ArrayEnd() 314 for i := 0; i < count; i++ { 315 s.ArrayEnd() 316 } 317 }) 318 }) 319 t.Run("nested 2", func(t *testing.T) { 320 count := 10 321 s := strings.ReplaceAll(nestedArray2(count), " ", "") 322 testStreamer(t, s, func(s *Streamer) { 323 for i := 0; i < count; i++ { 324 s.ArrayStart(). 325 ArrayStart().ArrayEnd() 326 } 327 s.ArrayStart().ArrayEnd() 328 for i := 0; i < count; i++ { 329 s.ArrayEnd() 330 } 331 }) 332 }) 333 t.Run("nested with object", func(t *testing.T) { 334 count := 10 335 s := strings.ReplaceAll(nestedArrayWithObject(count), " ", "") 336 testStreamer(t, s, func(s *Streamer) { 337 for i := 0; i < count; i++ { 338 s.ArrayStart(). 339 ObjectStart().ObjectEnd() 340 } 341 s.ArrayStart().ArrayEnd() 342 for i := 0; i < count; i++ { 343 s.ArrayEnd() 344 } 345 }) 346 }) 347 }) 348 t.Run("object", func(t *testing.T) { 349 t.Run("empty", func(t *testing.T) { 350 testStreamer(t, "{}", func(s *Streamer) { 351 s.ObjectStart().ObjectEnd() 352 }) 353 }) 354 t.Run("nested", func(t *testing.T) { 355 count := 5 356 s := strings.ReplaceAll(nestedObject(count), " ", "") 357 testStreamer(t, s, func(s *Streamer) { 358 for i := 0; i < count; i++ { 359 s.ObjectStart(). 360 Field("a").ObjectStart().ObjectEnd(). 361 Field("b") 362 } 363 s.ObjectStart().ObjectEnd() 364 for i := 0; i < count; i++ { 365 s.ObjectEnd() 366 } 367 }) 368 }) 369 t.Run("nested with array", func(t *testing.T) { 370 count := 5 371 s := strings.ReplaceAll(nestedObjectWithArray(count), " ", "") 372 testStreamer(t, s, func(s *Streamer) { 373 for i := 0; i < count; i++ { 374 s.ObjectStart(). 375 Field("a").ArrayStart().ArrayEnd(). 376 Field("b") 377 } 378 s.ArrayStart().ArrayEnd() 379 for i := 0; i < count; i++ { 380 s.ObjectEnd() 381 } 382 }) 383 }) 384 }) 385 } 386 387 func TestStreamer_ChainError(t *testing.T) { 388 t.Run("raw string", func(t *testing.T) { 389 testStreamerChainError(t, func(s *Streamer) { 390 s.RawString(`"test"`) 391 }) 392 }) 393 t.Run("raw", func(t *testing.T) { 394 testStreamerChainError(t, func(s *Streamer) { 395 s.Raw([]byte(`"test"`)) 396 }) 397 }) 398 t.Run("null", func(t *testing.T) { 399 testStreamerChainError(t, func(s *Streamer) { 400 s.Null() 401 }) 402 }) 403 t.Run("true", func(t *testing.T) { 404 testStreamerChainError(t, func(s *Streamer) { 405 s.True() 406 }) 407 }) 408 t.Run("false", func(t *testing.T) { 409 testStreamerChainError(t, func(s *Streamer) { 410 s.False() 411 }) 412 }) 413 t.Run("object start", func(t *testing.T) { 414 testStreamerChainError(t, func(s *Streamer) { 415 s.ObjectStart() 416 }) 417 }) 418 t.Run("object end", func(t *testing.T) { 419 testStreamerChainError(t, func(s *Streamer) { 420 s.ObjectEnd() 421 }) 422 }) 423 t.Run("field", func(t *testing.T) { 424 testStreamerChainError(t, func(s *Streamer) { 425 s.Field("test") 426 }) 427 }) 428 t.Run("raw field", func(t *testing.T) { 429 testStreamerChainError(t, func(s *Streamer) { 430 s.RawField([]byte(`"test"`)) 431 }) 432 }) 433 t.Run("array start", func(t *testing.T) { 434 testStreamerChainError(t, func(s *Streamer) { 435 s.ArrayStart() 436 }) 437 }) 438 t.Run("array end", func(t *testing.T) { 439 testStreamerChainError(t, func(s *Streamer) { 440 s.ArrayEnd() 441 }) 442 }) 443 t.Run("value", func(t *testing.T) { 444 testStreamerChainError(t, func(s *Streamer) { 445 s.Value(nil) 446 }) 447 }) 448 }