github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/jsoni/misc_tests/jsoniter_int_test.go (about)

     1  //go:build go1.8
     2  // +build go1.8
     3  
     4  package misc_tests
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"encoding/json"
    10  	"io"
    11  	"io/ioutil"
    12  	"math/rand"
    13  	"strconv"
    14  	"testing"
    15  
    16  	"github.com/bingoohuang/gg/pkg/jsoni"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func Test_read_uint64_invalid(t *testing.T) {
    21  	should := require.New(t)
    22  	iter := jsoni.ParseString(jsoni.ConfigDefault, ",")
    23  	iter.ReadUint64()
    24  	should.NotNil(iter.Error)
    25  }
    26  
    27  func Test_read_int32_array(t *testing.T) {
    28  	should := require.New(t)
    29  	input := `[123,456,789]`
    30  	val := make([]int32, 0)
    31  	jsoni.UnmarshalFromString(input, &val)
    32  	should.Equal(3, len(val))
    33  }
    34  
    35  func Test_read_int64_array(t *testing.T) {
    36  	should := require.New(t)
    37  	input := `[123,456,789]`
    38  	val := make([]int64, 0)
    39  	jsoni.UnmarshalFromString(input, &val)
    40  	should.Equal(3, len(val))
    41  }
    42  
    43  func Test_wrap_int(t *testing.T) {
    44  	should := require.New(t)
    45  	str, err := jsoni.MarshalToString(jsoni.WrapInt64(100))
    46  	should.Nil(err)
    47  	should.Equal("100", str)
    48  }
    49  
    50  func Test_write_val_int(t *testing.T) {
    51  	should := require.New(t)
    52  	buf := &bytes.Buffer{}
    53  	stream := jsoni.NewStream(jsoni.ConfigDefault, buf, 4096)
    54  	stream.WriteVal(context.Background(), 1001)
    55  	stream.Flush()
    56  	should.Nil(stream.Error)
    57  	should.Equal("1001", buf.String())
    58  }
    59  
    60  func Test_write_val_int_ptr(t *testing.T) {
    61  	should := require.New(t)
    62  	buf := &bytes.Buffer{}
    63  	stream := jsoni.NewStream(jsoni.ConfigDefault, buf, 4096)
    64  	val := 1001
    65  	stream.WriteVal(context.Background(), &val)
    66  	stream.Flush()
    67  	should.Nil(stream.Error)
    68  	should.Equal("1001", buf.String())
    69  }
    70  
    71  func Test_float_as_int(t *testing.T) {
    72  	should := require.New(t)
    73  	var i int
    74  	should.NotNil(jsoni.Unmarshal([]byte(`1.1`), &i))
    75  }
    76  
    77  // chunkedData is io.Reader which returns random amount of data in range [1, chunkedData.chunkSize].
    78  // It simulates chunked data on from HTTP server, which is commonly used by net/http package.
    79  type chunkedData struct {
    80  	chunkSize int
    81  	data      []byte
    82  	head      int
    83  }
    84  
    85  // Read is implementation of the io.Reader which returns random amount of data in range [1, chunkedData.chunkSize].
    86  func (c *chunkedData) Read(p []byte) (n int, err error) {
    87  	to := c.head + int(rand.Int31n(int32(c.chunkSize))+1)
    88  
    89  	// copy does not copy more data then p can consume
    90  	n = copy(p, c.data[c.head:to])
    91  	c.head = c.head + n
    92  	if c.head >= len(c.data) {
    93  		err = io.EOF
    94  	}
    95  	return n, err
    96  }
    97  
    98  // TestIterator_ReadInt_chunkedInput validates the behaviour of Iterator.ReadInt() method in where:
    99  // - it reads data from io.Reader,
   100  // - expected value is 0 (zero)
   101  // - Iterator.tail == Iterator.head
   102  // - Iterator.tail < len(Iterator.buf)
   103  // - value in buffer after Iterator.tail is presented from previous read and has '.' character.
   104  func TestIterator_ReadInt_chunkedInput(t *testing.T) {
   105  	should := require.New(t)
   106  
   107  	data := &chunkedData{
   108  		data: jsonFloatIntArray(t, 10),
   109  	}
   110  
   111  	// because this test is rely on randomness of chunkedData, we are doing multiple iterations to
   112  	// be sure, that we can hit a required case.
   113  	for data.chunkSize = 3; data.chunkSize <= len(data.data); data.chunkSize++ {
   114  		data.head = 0
   115  
   116  		iter := jsoni.Parse(jsoni.ConfigDefault, data, data.chunkSize)
   117  		i := 0
   118  		for iter.ReadArray() {
   119  			// every even item is float, let's just skip it.
   120  			if i%2 == 0 {
   121  				iter.Skip()
   122  				i++
   123  				continue
   124  			}
   125  
   126  			should.Zero(iter.ReadInt())
   127  			should.NoError(iter.Error)
   128  
   129  			i++
   130  		}
   131  	}
   132  }
   133  
   134  // jsonFloatIntArray generates JSON array where every
   135  //
   136  //   - even item is float 0.1
   137  //
   138  //   - odd item is integer 0
   139  //
   140  //     [0.1, 0, 0.1, 0]
   141  func jsonFloatIntArray(t *testing.T, numberOfItems int) []byte {
   142  	t.Helper()
   143  	numbers := make([]jsoni.Any, numberOfItems)
   144  	for i := range numbers {
   145  		switch i % 2 {
   146  		case 0:
   147  			numbers[i] = jsoni.WrapFloat64(0.1)
   148  		default:
   149  			numbers[i] = jsoni.WrapInt64(0)
   150  		}
   151  	}
   152  
   153  	fixture, err := jsoni.ConfigFastest.Marshal(context.Background(), numbers)
   154  	if err != nil {
   155  		panic(err)
   156  	}
   157  
   158  	b := &bytes.Buffer{}
   159  
   160  	require.NoError(
   161  		t,
   162  		json.Compact(b, fixture),
   163  		"json should be compactable",
   164  	)
   165  	return b.Bytes()
   166  }
   167  
   168  func Benchmark_jsoniter_encode_int(b *testing.B) {
   169  	stream := jsoni.NewStream(jsoni.ConfigDefault, ioutil.Discard, 64)
   170  	for n := 0; n < b.N; n++ {
   171  		stream.Reset(nil)
   172  		stream.WriteUint64(0xffffffff)
   173  	}
   174  }
   175  
   176  func Benchmark_itoa(b *testing.B) {
   177  	for n := 0; n < b.N; n++ {
   178  		strconv.FormatInt(0xffffffff, 10)
   179  	}
   180  }
   181  
   182  func Benchmark_jsoniter_int(b *testing.B) {
   183  	iter := jsoni.NewIterator(jsoni.ConfigDefault)
   184  	input := []byte(`100`)
   185  	for n := 0; n < b.N; n++ {
   186  		iter.ResetBytes(input)
   187  		iter.ReadInt64()
   188  	}
   189  }
   190  
   191  func Benchmark_json_int(b *testing.B) {
   192  	for n := 0; n < b.N; n++ {
   193  		result := int64(0)
   194  		json.Unmarshal([]byte(`-100`), &result)
   195  	}
   196  }