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  }