github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/encoding/decimal_test.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package encoding
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  	"math"
    17  	"math/rand"
    18  	"testing"
    19  
    20  	"github.com/cockroachdb/apd"
    21  	"github.com/cockroachdb/cockroach/pkg/util/randutil"
    22  )
    23  
    24  func TestDecimalMandE(t *testing.T) {
    25  	testCases := []struct {
    26  		Value string
    27  		E     int
    28  		M     []byte
    29  	}{
    30  		{"1.0", 1, []byte{0x02}},
    31  		{"10.0", 1, []byte{0x14}},
    32  		{"99.0", 1, []byte{0xc6}},
    33  		{"99.01", 1, []byte{0xc7, 0x02}},
    34  		{"99.0001", 1, []byte{0xc7, 0x01, 0x02}},
    35  		{"100.0", 2, []byte{0x02}},
    36  		{"100.01", 2, []byte{0x03, 0x01, 0x02}},
    37  		{"100.1", 2, []byte{0x03, 0x01, 0x14}},
    38  		{"1234", 2, []byte{0x19, 0x44}},
    39  		{"9999", 2, []byte{0xc7, 0xc6}},
    40  		{"9999.000001", 2, []byte{0xc7, 0xc7, 0x01, 0x01, 0x02}},
    41  		{"9999.000009", 2, []byte{0xc7, 0xc7, 0x01, 0x01, 0x12}},
    42  		{"9999.00001", 2, []byte{0xc7, 0xc7, 0x01, 0x01, 0x14}},
    43  		{"9999.00009", 2, []byte{0xc7, 0xc7, 0x01, 0x01, 0xb4}},
    44  		{"9999.000099", 2, []byte{0xc7, 0xc7, 0x01, 0x01, 0xc6}},
    45  		{"9999.0001", 2, []byte{0xc7, 0xc7, 0x01, 0x02}},
    46  		{"9999.001", 2, []byte{0xc7, 0xc7, 0x01, 0x14}},
    47  		{"9999.01", 2, []byte{0xc7, 0xc7, 0x02}},
    48  		{"9999.1", 2, []byte{0xc7, 0xc7, 0x14}},
    49  		{"10000", 3, []byte{0x02}},
    50  		{"10001", 3, []byte{0x03, 0x01, 0x02}},
    51  		{"12345", 3, []byte{0x03, 0x2f, 0x5a}},
    52  		{"123450", 3, []byte{0x19, 0x45, 0x64}},
    53  		{"1234.5", 2, []byte{0x19, 0x45, 0x64}},
    54  		{"12.345", 1, []byte{0x19, 0x45, 0x64}},
    55  		{"0.123", 0, []byte{0x19, 0x3c}},
    56  		{"0.0123", 0, []byte{0x03, 0x2e}},
    57  		{"0.00123", -1, []byte{0x19, 0x3c}},
    58  		{"1e-307", -153, []byte{0x14}},
    59  		{"1e308", 155, []byte{0x2}},
    60  		{"9223372036854775807", 10, []byte{0x13, 0x2d, 0x43, 0x91, 0x07, 0x89, 0x6d, 0x9b, 0x75, 0x0e}},
    61  	}
    62  	for _, c := range testCases {
    63  		d := new(apd.Decimal)
    64  		if _, _, err := d.SetString(c.Value); err != nil {
    65  			t.Fatalf("could not parse decimal from string %q", c.Value)
    66  		}
    67  
    68  		if e, m := decimalEandM(d, nil); e != c.E || !bytes.Equal(m, c.M) {
    69  			t.Errorf("unexpected mismatch in E/M for %v. expected E=%v | M=[% x], got E=%v | M=[% x]",
    70  				c.Value, c.E, c.M, e, m)
    71  		}
    72  	}
    73  }
    74  
    75  func mustDecimal(s string) *apd.Decimal {
    76  	d, _, err := new(apd.Decimal).SetString(s)
    77  	if err != nil {
    78  		panic(fmt.Sprintf("could not set string %q on decimal", s))
    79  	}
    80  	return d
    81  }
    82  
    83  func randBuf(rng *rand.Rand, maxLen int) []byte {
    84  	buf := make([]byte, rng.Intn(maxLen+1))
    85  	_, _ = rng.Read(buf)
    86  	return buf
    87  }
    88  
    89  func encodeDecimalWithDir(dir Direction, buf []byte, d *apd.Decimal) []byte {
    90  	if dir == Ascending {
    91  		return EncodeDecimalAscending(buf, d)
    92  	}
    93  	return EncodeDecimalDescending(buf, d)
    94  }
    95  
    96  func decodeDecimalWithDir(
    97  	t *testing.T, dir Direction, buf []byte, tmp []byte,
    98  ) ([]byte, apd.Decimal) {
    99  	var err error
   100  	var resBuf []byte
   101  	var res apd.Decimal
   102  	if dir == Ascending {
   103  		resBuf, res, err = DecodeDecimalAscending(buf, tmp)
   104  	} else {
   105  		resBuf, res, err = DecodeDecimalDescending(buf, tmp)
   106  	}
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	return resBuf, res
   111  }
   112  
   113  func mustDecimalFloat64(f float64) *apd.Decimal {
   114  	d, err := new(apd.Decimal).SetFloat64(f)
   115  	if err != nil {
   116  		panic(err)
   117  	}
   118  	return d
   119  }
   120  
   121  func mustDecimalString(s string) *apd.Decimal {
   122  	d, _, err := apd.NewFromString(s)
   123  	if err != nil {
   124  		panic(err)
   125  	}
   126  	return d
   127  }
   128  
   129  func TestEncodeDecimal(t *testing.T) {
   130  	testCases := []struct {
   131  		Value    *apd.Decimal
   132  		Encoding []byte
   133  	}{
   134  		{&apd.Decimal{Form: apd.NaN}, []byte{0x18}},
   135  		{&apd.Decimal{Form: apd.Infinite, Negative: true}, []byte{0x19}},
   136  		{apd.New(-99122, 99999), []byte{0x1a, 0x86, 0x3c, 0xad, 0x38, 0xe6, 0xd7, 0x00}},
   137  		// Three duplicates to make sure -13*10^1000 <= -130*10^999 <= -13*10^1000
   138  		{apd.New(-13, 1000), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}},
   139  		{apd.New(-130, 999), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}},
   140  		{apd.New(-13, 1000), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}},
   141  		{mustDecimalFloat64(-math.MaxFloat64), []byte{0x1a, 0x87, 0x64, 0xfc, 0x60, 0x66, 0x44, 0xe4, 0x9e, 0x82, 0xc0, 0x8d, 0x00}},
   142  		{apd.New(-130, 100), []byte{0x1a, 0x87, 0xcb, 0xfc, 0xc3, 0x00}},
   143  		{apd.New(-13, 0), []byte{0x24, 0xe5, 0x00}},
   144  		{apd.New(-11, 0), []byte{0x24, 0xe9, 0x00}},
   145  		{mustDecimal("-10.123456789"), []byte{0x24, 0xea, 0xe6, 0xba, 0x8e, 0x62, 0x4b, 0x00}},
   146  		{mustDecimal("-10"), []byte{0x24, 0xeb, 0x00}},
   147  		{mustDecimal("-9.123456789"), []byte{0x24, 0xec, 0xe6, 0xba, 0x8e, 0x62, 0x4b, 0x00}},
   148  		{mustDecimal("-9"), []byte{0x24, 0xed, 0x00}},
   149  		{mustDecimal("-1.1"), []byte{0x24, 0xfc, 0xeb, 0x00}},
   150  		{apd.New(-1, 0), []byte{0x24, 0xfd, 0x00}},
   151  		{apd.New(-8, -1), []byte{0x25, 0x5f, 0x00}},
   152  		{apd.New(-1, -1), []byte{0x25, 0xeb, 0x00}},
   153  		{mustDecimal("-.09"), []byte{0x25, 0xed, 0x00}},
   154  		{mustDecimal("-.054321"), []byte{0x25, 0xf4, 0xa8, 0xd5, 0x00}},
   155  		{mustDecimal("-.012"), []byte{0x25, 0xfc, 0xd7, 0x00}},
   156  		{apd.New(-11, -4), []byte{0x26, 0x89, 0xe9, 0x00}},
   157  		{apd.New(-11, -6), []byte{0x26, 0x8a, 0xe9, 0x00}},
   158  		{mustDecimalFloat64(-math.SmallestNonzeroFloat64), []byte{0x26, 0xf6, 0xa1, 0xf5, 0x00}},
   159  		{apd.New(-11, -66666), []byte{0x26, 0xf7, 0x82, 0x34, 0xe9, 0x00}},
   160  		{mustDecimal("-0"), []byte{0x27}},
   161  		{apd.New(0, 0), []byte{0x27}},
   162  		{mustDecimalFloat64(math.SmallestNonzeroFloat64), []byte{0x28, 0x87, 0x5e, 0x0a, 0x00}},
   163  		{apd.New(11, -6), []byte{0x28, 0x87, 0xfd, 0x16, 0x00}},
   164  		{apd.New(11, -4), []byte{0x28, 0x87, 0xfe, 0x16, 0x00}},
   165  		{apd.New(1, -1), []byte{0x29, 0x14, 0x00}},
   166  		{apd.New(8, -1), []byte{0x29, 0xa0, 0x00}},
   167  		{apd.New(1, 0), []byte{0x2a, 0x02, 0x00}},
   168  		{mustDecimal("1.1"), []byte{0x2a, 0x03, 0x14, 0x00}},
   169  		{apd.New(11, 0), []byte{0x2a, 0x16, 0x00}},
   170  		{apd.New(13, 0), []byte{0x2a, 0x1a, 0x00}},
   171  		{mustDecimalFloat64(math.MaxFloat64), []byte{0x34, 0xf6, 0x9b, 0x03, 0x9f, 0x99, 0xbb, 0x1b, 0x61, 0x7d, 0x3f, 0x72, 0x00}},
   172  		// Four duplicates to make sure 13*10^1000 <= 130*10^999 <= 1300*10^998 <= 13*10^1000
   173  		{apd.New(13, 1000), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}},
   174  		{apd.New(130, 999), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}},
   175  		{apd.New(1300, 998), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}},
   176  		{apd.New(13, 1000), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}},
   177  		{apd.New(99122, 99999), []byte{0x34, 0xf7, 0xc3, 0x52, 0xc7, 0x19, 0x28, 0x00}},
   178  		{apd.New(99122839898321208, 99999), []byte{0x34, 0xf7, 0xc3, 0x58, 0xc7, 0x19, 0x39, 0x4f, 0xb3, 0xa7, 0x2b, 0x29, 0xa0, 0x00}},
   179  		{&apd.Decimal{Form: apd.Infinite}, []byte{0x35}},
   180  	}
   181  
   182  	rng, _ := randutil.NewPseudoRand()
   183  
   184  	var lastEncoded []byte
   185  	for _, dir := range []Direction{Ascending, Descending} {
   186  		for _, tmp := range [][]byte{nil, make([]byte, 0, 100)} {
   187  			for i, c := range testCases {
   188  				t.Run(fmt.Sprintf("%v_%d_%d_%s", dir, cap(tmp), i, c.Value), func(t *testing.T) {
   189  					enc := encodeDecimalWithDir(dir, nil, c.Value)
   190  					_, dec := decodeDecimalWithDir(t, dir, enc, tmp)
   191  					if dir == Ascending && !bytes.Equal(enc, c.Encoding) {
   192  						t.Errorf("unexpected mismatch for %s. expected [% x], got [% x]",
   193  							c.Value, c.Encoding, enc)
   194  					}
   195  					if i > 0 {
   196  						if (bytes.Compare(lastEncoded, enc) > 0 && dir == Ascending) ||
   197  							(bytes.Compare(lastEncoded, enc) < 0 && dir == Descending) {
   198  							t.Errorf("%v: expected [% x] to be less than or equal to [% x]",
   199  								c.Value, testCases[i-1].Encoding, enc)
   200  						}
   201  					}
   202  					testPeekLength(t, enc)
   203  					if dec.Cmp(c.Value) != 0 {
   204  						t.Errorf("%d unexpected mismatch for %v. got %v", i, c.Value, dec)
   205  					}
   206  					lastEncoded = enc
   207  
   208  					// Test that appending the decimal to an existing buffer works. It
   209  					// is important to test with various values, slice lengths, and
   210  					// capacities because the various encoding paths try to use any
   211  					// spare capacity to avoid allocations.
   212  					for trials := 0; trials < 5; trials++ {
   213  						orig := randBuf(rng, 30)
   214  						origLen := len(orig)
   215  
   216  						bufCap := origLen + rng.Intn(30)
   217  						buf := make([]byte, origLen, bufCap)
   218  						copy(buf, orig)
   219  
   220  						enc := encodeDecimalWithDir(dir, buf, c.Value)
   221  						// Append some random bytes
   222  						enc = append(enc, randBuf(rng, 20)...)
   223  						_, dec := decodeDecimalWithDir(t, dir, enc[origLen:], tmp)
   224  
   225  						if dec.Cmp(c.Value) != 0 {
   226  							t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec)
   227  						}
   228  						// Verify the existing values weren't modified.
   229  						for i := range orig {
   230  							if enc[i] != orig[i] {
   231  								t.Errorf("existing byte %d changed after encoding (from %d to %d)",
   232  									i, orig[i], enc[i])
   233  							}
   234  						}
   235  					}
   236  				})
   237  			}
   238  		}
   239  	}
   240  }
   241  
   242  func TestEncodeDecimalRand(t *testing.T) {
   243  	rng, _ := randutil.NewPseudoRand()
   244  	// Test both directions.
   245  	for _, dir := range []Direction{Ascending, Descending} {
   246  		var prev *apd.Decimal
   247  		var prevEnc []byte
   248  		const randomTrials = 100000
   249  		for i := 0; i < randomTrials; i++ {
   250  			cur := randDecimal(rng, -20, 20)
   251  			var tmp, appendTo []byte
   252  			// Test with and without appending.
   253  			if rng.Intn(2) == 1 {
   254  				appendTo = randBuf(rng, 30)
   255  				appendTo = appendTo[:rng.Intn(len(appendTo)+1)]
   256  			}
   257  			// Test with and without tmp buffer.
   258  			if rng.Intn(2) == 1 {
   259  				tmp = randBuf(rng, 100)
   260  			}
   261  			var enc []byte
   262  			var res apd.Decimal
   263  			var err error
   264  			if dir == Ascending {
   265  				enc = EncodeDecimalAscending(appendTo, cur)
   266  				enc = enc[len(appendTo):]
   267  				_, res, err = DecodeDecimalAscending(enc, tmp)
   268  			} else {
   269  				enc = EncodeDecimalDescending(appendTo, cur)
   270  				enc = enc[len(appendTo):]
   271  				_, res, err = DecodeDecimalDescending(enc, tmp)
   272  			}
   273  			if err != nil {
   274  				t.Fatal(err)
   275  			}
   276  
   277  			testPeekLength(t, enc)
   278  
   279  			// Make sure we decode the same value we encoded.
   280  			if cur.Cmp(&res) != 0 {
   281  				t.Fatalf("unexpected mismatch for %v, got %v", cur, res)
   282  			}
   283  
   284  			// Make sure lexicographical sorting is consistent.
   285  			if prev != nil {
   286  				bytesCmp := bytes.Compare(prevEnc, enc)
   287  				cmpType := "same"
   288  				if dir == Descending {
   289  					bytesCmp *= -1
   290  					cmpType = "inverse"
   291  				}
   292  				if decCmp := prev.Cmp(cur); decCmp != bytesCmp {
   293  					t.Fatalf("expected [% x] to compare to [% x] the %s way that %v compares to %v",
   294  						prevEnc, enc, cmpType, prev, cur)
   295  				}
   296  			}
   297  			prev = cur
   298  			prevEnc = enc
   299  		}
   300  	}
   301  }
   302  
   303  func TestNonsortingEncodeDecimal(t *testing.T) {
   304  	testCases := []struct {
   305  		Value    *apd.Decimal
   306  		Encoding []byte
   307  	}{
   308  		{&apd.Decimal{Form: apd.NaN}, []byte{0x18}},
   309  		{&apd.Decimal{Form: apd.Infinite, Negative: true}, []byte{0x19}},
   310  		{apd.New(-99122, 99999), []byte{0x1a, 0xf8, 0x01, 0x86, 0xa4, 0x01, 0x83, 0x32}},
   311  		// Three duplicates to make sure -13*10^1000 <= -130*10^999 <= -13*10^1000
   312  		{apd.New(-13, 1000), []byte{0x1a, 0xf7, 0x03, 0xea, 0x0d}},
   313  		{apd.New(-130, 999), []byte{0x1a, 0xf7, 0x03, 0xea, 0x82}},
   314  		{apd.New(-13, 1000), []byte{0x1a, 0xf7, 0x03, 0xea, 0x0d}},
   315  		{mustDecimalFloat64(-math.MaxFloat64), []byte{0x1a, 0xf7, 0x01, 0x35, 0x3f, 0xdd, 0xec, 0x7f, 0x2f, 0xaf, 0x35}},
   316  		{apd.New(-130, 100), []byte{0x1a, 0xef, 0x82}},
   317  		{apd.New(-13, 0), []byte{0x1a, 0x8a, 0x0d}},
   318  		{apd.New(-11, 0), []byte{0x1a, 0x8a, 0x0b}},
   319  		{apd.New(-1, 0), []byte{0x1a, 0x89, 0x01}},
   320  		{apd.New(-8, -1), []byte{0x25, 0x08}},
   321  		{apd.New(-1, -1), []byte{0x25, 0x01}},
   322  		{apd.New(-11, -4), []byte{0x26, 0x8a, 0x0b}},
   323  		{apd.New(-11, -6), []byte{0x26, 0x8c, 0x0b}},
   324  		{mustDecimalFloat64(-math.SmallestNonzeroFloat64), []byte{0x26, 0xf7, 0x01, 0x43, 0x05}},
   325  		{apd.New(-11, -66666), []byte{0x26, 0xf8, 0x01, 0x04, 0x68, 0x0b}},
   326  		{mustDecimal("-0"), []byte{0x1a, 0x89}},
   327  		{apd.New(0, 0), []byte{0x27}},
   328  		{mustDecimalFloat64(math.SmallestNonzeroFloat64), []byte{0x28, 0xf7, 0x01, 0x43, 0x05}},
   329  		{apd.New(11, -6), []byte{0x28, 0x8c, 0x0b}},
   330  		{apd.New(11, -4), []byte{0x28, 0x8a, 0x0b}},
   331  		{apd.New(1, -1), []byte{0x29, 0x01}},
   332  		{apd.New(12345, -5), []byte{0x29, 0x30, 0x39}},
   333  		{apd.New(8, -1), []byte{0x29, 0x08}},
   334  		{apd.New(1, 0), []byte{0x34, 0x89, 0x01}},
   335  		{apd.New(11, 0), []byte{0x34, 0x8a, 0x0b}},
   336  		{apd.New(13, 0), []byte{0x34, 0x8a, 0x0d}},
   337  		// Note that this does not sort correctly!
   338  		{apd.New(255, 0), []byte{0x34, 0x8b, 0xff}},
   339  		{apd.New(256, 0), []byte{0x34, 0x8b, 0x01, 0x00}},
   340  		{mustDecimalFloat64(math.MaxFloat64), []byte{0x34, 0xf7, 0x01, 0x35, 0x3f, 0xdd, 0xec, 0x7f, 0x2f, 0xaf, 0x35}},
   341  		// Four duplicates to make sure 13*10^1000 <= 130*10^999 <= 1300*10^998 <= 13*10^1000
   342  		{apd.New(13, 1000), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}},
   343  		{apd.New(130, 999), []byte{0x34, 0xf7, 0x03, 0xea, 0x82}},
   344  		{apd.New(1300, 998), []byte{0x34, 0xf7, 0x03, 0xea, 0x05, 0x14}},
   345  		{apd.New(13, 1000), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}},
   346  		{apd.New(99122, 99999), []byte{0x34, 0xf8, 0x01, 0x86, 0xa4, 0x01, 0x83, 0x32}},
   347  		{apd.New(99122839898321208, 99999), []byte{0x34, 0xf8, 0x01, 0x86, 0xb0, 0x01, 0x60, 0x27, 0xb2, 0x9d, 0x44, 0x71, 0x38}},
   348  		{&apd.Decimal{Form: apd.Infinite}, []byte{0x35}},
   349  		{mustDecimalString("142378208485490985369999605144727062141206925976498256305323716858805588894693616552055968571135475510700810219028167653516982373238641332965927953273383572708760984694356069974208844865675206339235758647159337463780100273189720943242182911961627806424621091859596571173867825568394327041453823674373002756096"), []byte{0x34, 0xf7, 0x01, 0x35, 0xca, 0xc0, 0xd8, 0x34, 0x68, 0x5d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
   350  	}
   351  
   352  	rng, _ := randutil.NewPseudoRand()
   353  
   354  	for _, tmp := range [][]byte{nil, make([]byte, 0, 100)} {
   355  		for i, c := range testCases {
   356  			t.Run(fmt.Sprintf("%d_%d_%s", cap(tmp), i, c.Value), func(t *testing.T) {
   357  				enc := EncodeNonsortingDecimal(nil, c.Value)
   358  				dec, err := DecodeNonsortingDecimal(enc, tmp)
   359  				if err != nil {
   360  					t.Fatal(err)
   361  				}
   362  				if !bytes.Equal(enc, c.Encoding) {
   363  					t.Errorf("unexpected mismatch for %s. expected [% x], got [% x]",
   364  						c.Value, c.Encoding, enc)
   365  				}
   366  				if dec.CmpTotal(c.Value) != 0 {
   367  					t.Errorf("%d unexpected mismatch for %v. got %v", i, c.Value, dec)
   368  				}
   369  				// Test that appending the decimal to an existing buffer works. It
   370  				// is important to test with various values, slice lengths, and
   371  				// capacities because the various encoding paths try to use any
   372  				// spare capacity to avoid allocations.
   373  				for trials := 0; trials < 5; trials++ {
   374  					orig := randBuf(rng, 30)
   375  					origLen := len(orig)
   376  
   377  					bufCap := origLen + rng.Intn(30)
   378  					buf := make([]byte, origLen, bufCap)
   379  					copy(buf, orig)
   380  
   381  					enc := EncodeNonsortingDecimal(buf, c.Value)
   382  					dec, err := DecodeNonsortingDecimal(enc[origLen:], tmp)
   383  					if err != nil {
   384  						t.Fatal(err)
   385  					}
   386  
   387  					if dec.CmpTotal(c.Value) != 0 {
   388  						t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec)
   389  					}
   390  					// Verify the existing values weren't modified.
   391  					for i := range orig {
   392  						if enc[i] != orig[i] {
   393  							t.Errorf("existing byte %d changed after encoding (from %d to %d)",
   394  								i, orig[i], enc[i])
   395  						}
   396  					}
   397  				}
   398  			})
   399  		}
   400  	}
   401  }
   402  
   403  func TestNonsortingEncodeDecimalRand(t *testing.T) {
   404  	rng, _ := randutil.NewPseudoRand()
   405  	const randomTrials = 200000
   406  	for i := 0; i < randomTrials; i++ {
   407  		var tmp, appendTo []byte
   408  		// Test with and without appending.
   409  		if rng.Intn(2) == 1 {
   410  			appendTo = randBuf(rng, 30)
   411  			appendTo = appendTo[:rng.Intn(len(appendTo)+1)]
   412  		}
   413  		// Test with and without tmp buffer.
   414  		if rng.Intn(2) == 1 {
   415  			tmp = randBuf(rng, 100)
   416  		}
   417  		cur := randDecimal(rng, -20, 20)
   418  
   419  		enc := EncodeNonsortingDecimal(appendTo, cur)
   420  		enc = enc[len(appendTo):]
   421  		res, err := DecodeNonsortingDecimal(enc, tmp)
   422  		if err != nil {
   423  			t.Fatal(err)
   424  		}
   425  
   426  		// Make sure we decode the same value we encoded.
   427  		if cur.Cmp(&res) != 0 {
   428  			t.Fatalf("unexpected mismatch for %v, got %v", cur, res)
   429  		}
   430  
   431  		// Make sure we would have overestimated the value.
   432  		if est := UpperBoundNonsortingDecimalSize(cur); est < len(enc) {
   433  			t.Fatalf("expected estimate of %d for %v to be greater than or equal to the encoded length, found [% x]", est, cur, enc)
   434  		}
   435  	}
   436  }
   437  
   438  // TestNonsortingEncodeDecimalRoundtrip tests that decimals can round trip
   439  // through EncodeNonsortingDecimal and DecodeNonsortingDecimal with an expected
   440  // coefficient and exponent.
   441  func TestNonsortingEncodeDecimalRoundtrip(t *testing.T) {
   442  	tests := map[string]string{
   443  		"0":         "0E+0",
   444  		"0.0":       "0E-1",
   445  		"0.00":      "0E-2",
   446  		"0e-10":     "0E-10",
   447  		"0.00e-10":  "0E-12",
   448  		"00":        "0E+0",
   449  		"-0":        "-0E+0",
   450  		"-0.0":      "-0E-1",
   451  		"-0.00":     "-0E-2",
   452  		"-0e-10":    "-0E-10",
   453  		"-0.00e-10": "-0E-12",
   454  		"-00":       "-0E+0",
   455  	}
   456  	for tc, expect := range tests {
   457  		t.Run(tc, func(t *testing.T) {
   458  			d, _, err := apd.NewFromString(tc)
   459  			if err != nil {
   460  				t.Fatal(err)
   461  			}
   462  			enc := EncodeNonsortingDecimal(nil, d)
   463  			res, err := DecodeNonsortingDecimal(enc, nil)
   464  			if err != nil {
   465  				t.Fatal(err)
   466  			}
   467  			s := res.Text('E')
   468  			if expect != s {
   469  				t.Fatalf("expected %s, got %s", expect, s)
   470  			}
   471  		})
   472  	}
   473  }
   474  
   475  func TestDecodeMultipleDecimalsIntoNonsortingDecimal(t *testing.T) {
   476  	tcs := []struct {
   477  		value []string
   478  	}{
   479  		{
   480  			[]string{"1.0", "5.0", "7.0"},
   481  		},
   482  		{
   483  			[]string{"1.0", "-1.0", "0.0"},
   484  		},
   485  		{
   486  			[]string{"1.0", "-1.0", "10.0"},
   487  		},
   488  		{
   489  			[]string{"nan", "1.0", "-1.0"},
   490  		},
   491  		{
   492  			[]string{"-1.0", "inf", "5.0"},
   493  		},
   494  	}
   495  
   496  	for _, tc := range tcs {
   497  		var actual apd.Decimal
   498  		for _, num := range tc.value {
   499  			expected, _, err := apd.NewFromString(num)
   500  			if err != nil {
   501  				t.Fatal(err)
   502  			}
   503  			enc := EncodeNonsortingDecimal(nil, expected)
   504  			err = DecodeIntoNonsortingDecimal(&actual, enc, nil)
   505  			if err != nil {
   506  				t.Fatal(err)
   507  			}
   508  			if actual.Cmp(expected) != 0 {
   509  				t.Errorf("unexpected mismatch for %v, got %v", expected, &actual)
   510  			}
   511  		}
   512  	}
   513  }
   514  
   515  func TestUpperBoundNonsortingDecimalUnscaledSize(t *testing.T) {
   516  	x := make([]byte, 100)
   517  	d := new(apd.Decimal)
   518  	for i := 0; i < len(x); i++ {
   519  		d.Coeff.SetString(string(x[:i]), 10)
   520  		reference := UpperBoundNonsortingDecimalSize(d)
   521  		bound := upperBoundNonsortingDecimalUnscaledSize(i)
   522  		if bound < reference || bound > reference+bigWordSize {
   523  			t.Errorf("%d: got a bound of %d but expected between %d and %d", i, bound, reference, reference+bigWordSize)
   524  		}
   525  		x[i] = '1'
   526  	}
   527  }
   528  
   529  // randDecimal generates a random decimal with exponent in the
   530  // range [minExp, maxExp].
   531  func randDecimal(rng *rand.Rand, minExp, maxExp int) *apd.Decimal {
   532  	exp := randutil.RandIntInRange(rng, minExp, maxExp+1)
   533  	// Transform random float in [0, 1) to [-1, 1) and multiply by 10^exp.
   534  	floatVal := (rng.Float64()*2 - 1) * math.Pow10(exp)
   535  	return mustDecimalFloat64(floatVal)
   536  }
   537  
   538  // makeDecimalVals creates decimal values with exponents in
   539  // the range [minExp, maxExp].
   540  func makeDecimalVals(minExp, maxExp int) []*apd.Decimal {
   541  	rng, _ := randutil.NewPseudoRand()
   542  	vals := make([]*apd.Decimal, 10000)
   543  	for i := range vals {
   544  		vals[i] = randDecimal(rng, minExp, maxExp)
   545  	}
   546  	return vals
   547  }
   548  
   549  func makeEncodedVals(minExp, maxExp int) [][]byte {
   550  	rng, _ := randutil.NewPseudoRand()
   551  	vals := make([][]byte, 10000)
   552  	for i := range vals {
   553  		vals[i] = EncodeDecimalAscending(nil, randDecimal(rng, minExp, maxExp))
   554  	}
   555  	return vals
   556  }
   557  
   558  func BenchmarkEncodeDecimalSmall(b *testing.B) {
   559  	vals := makeDecimalVals(-40, -1)
   560  	buf := make([]byte, 0, 100)
   561  
   562  	b.ResetTimer()
   563  	for i := 0; i < b.N; i++ {
   564  		_ = EncodeDecimalAscending(buf, vals[i%len(vals)])
   565  	}
   566  }
   567  
   568  func BenchmarkDecodeDecimalSmall(b *testing.B) {
   569  	vals := makeEncodedVals(-40, -1)
   570  	buf := make([]byte, 0, 100)
   571  
   572  	b.ResetTimer()
   573  	for i := 0; i < b.N; i++ {
   574  		_, _, _ = DecodeDecimalAscending(vals[i%len(vals)], buf)
   575  	}
   576  }
   577  
   578  func BenchmarkEncodeDecimalMedium(b *testing.B) {
   579  	vals := makeDecimalVals(0, 10)
   580  	buf := make([]byte, 0, 100)
   581  
   582  	b.ResetTimer()
   583  	for i := 0; i < b.N; i++ {
   584  		_ = EncodeDecimalAscending(buf, vals[i%len(vals)])
   585  	}
   586  }
   587  
   588  func BenchmarkDecodeDecimalMedium(b *testing.B) {
   589  	vals := makeEncodedVals(0, 10)
   590  	buf := make([]byte, 0, 100)
   591  
   592  	b.ResetTimer()
   593  	for i := 0; i < b.N; i++ {
   594  		_, _, _ = DecodeDecimalAscending(vals[i%len(vals)], buf)
   595  	}
   596  }
   597  
   598  func BenchmarkEncodeDecimalLarge(b *testing.B) {
   599  	vals := makeDecimalVals(11, 40)
   600  	buf := make([]byte, 0, 100)
   601  
   602  	b.ResetTimer()
   603  	for i := 0; i < b.N; i++ {
   604  		_ = EncodeDecimalAscending(buf, vals[i%len(vals)])
   605  	}
   606  }
   607  
   608  func BenchmarkDecodeDecimalLarge(b *testing.B) {
   609  	vals := makeEncodedVals(11, 40)
   610  	buf := make([]byte, 0, 100)
   611  
   612  	b.ResetTimer()
   613  	for i := 0; i < b.N; i++ {
   614  		_, _, _ = DecodeDecimalAscending(vals[i%len(vals)], buf)
   615  	}
   616  }
   617  
   618  func BenchmarkPeekLengthDecimal(b *testing.B) {
   619  	vals := makeEncodedVals(-20, 20)
   620  
   621  	b.ResetTimer()
   622  	for i := 0; i < b.N; i++ {
   623  		_, _ = PeekLength(vals[i%len(vals)])
   624  	}
   625  }
   626  
   627  func BenchmarkNonsortingEncodeDecimal(b *testing.B) {
   628  	vals := makeDecimalVals(-20, 20)
   629  	buf := make([]byte, 0, 100)
   630  
   631  	b.ResetTimer()
   632  	for i := 0; i < b.N; i++ {
   633  		_ = EncodeNonsortingDecimal(buf, vals[i%len(vals)])
   634  	}
   635  }
   636  
   637  func BenchmarkNonsortingDecodeDecimal(b *testing.B) {
   638  	rng, _ := randutil.NewPseudoRand()
   639  
   640  	vals := make([][]byte, 10000)
   641  	for i := range vals {
   642  		d := randDecimal(rng, -20, 20)
   643  		vals[i] = EncodeNonsortingDecimal(nil, d)
   644  	}
   645  
   646  	buf := make([]byte, 0, 100)
   647  
   648  	b.ResetTimer()
   649  	for i := 0; i < b.N; i++ {
   650  		_, _ = DecodeNonsortingDecimal(vals[i%len(vals)], buf)
   651  	}
   652  }