func TestNonsortingEncodeDecimal(t *testing.T) { testCases := []struct { Value *inf.Dec Encoding []byte }{ {inf.NewDec(-99122, -99999), []byte{0x1a, 0xf8, 0x01, 0x86, 0xa4, 0x01, 0x83, 0x32}}, // Three duplicates to make sure -13*10^1000 <= -130*10^999 <= -13*10^1000 {inf.NewDec(-13, -1000), []byte{0x1a, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(-130, -999), []byte{0x1a, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(-13, -1000), []byte{0x1a, 0xf7, 0x03, 0xea, 0x0d}}, {decimal.NewDecFromFloat(-math.MaxFloat64), []byte{0x1a, 0xf7, 0x01, 0x35, 0x3f, 0xdd, 0xec, 0x7f, 0x2f, 0xaf, 0x35}}, {inf.NewDec(-130, -100), []byte{0x1a, 0xef, 0x0d}}, {inf.NewDec(-13, 0), []byte{0x1a, 0x8a, 0x0d}}, {inf.NewDec(-11, 0), []byte{0x1a, 0x8a, 0x0b}}, {inf.NewDec(-1, 0), []byte{0x1a, 0x89, 0x01}}, {inf.NewDec(-8, 1), []byte{0x25, 0x08}}, {inf.NewDec(-1, 1), []byte{0x25, 0x01}}, {inf.NewDec(-11, 4), []byte{0x26, 0x8a, 0x0b}}, {inf.NewDec(-11, 6), []byte{0x26, 0x8c, 0x0b}}, {decimal.NewDecFromFloat(-math.SmallestNonzeroFloat64), []byte{0x26, 0xf7, 0x01, 0x43, 0x05}}, {inf.NewDec(-11, 66666), []byte{0x26, 0xf8, 0x01, 0x04, 0x68, 0x0b}}, {inf.NewDec(0, 0), []byte{0x27}}, {decimal.NewDecFromFloat(math.SmallestNonzeroFloat64), []byte{0x28, 0xf7, 0x01, 0x43, 0x05}}, {inf.NewDec(11, 6), []byte{0x28, 0x8c, 0x0b}}, {inf.NewDec(11, 4), []byte{0x28, 0x8a, 0x0b}}, {inf.NewDec(1, 1), []byte{0x29, 0x01}}, {inf.NewDec(12345, 5), []byte{0x29, 0x30, 0x39}}, {inf.NewDec(8, 1), []byte{0x29, 0x08}}, {inf.NewDec(1, 0), []byte{0x34, 0x89, 0x01}}, {inf.NewDec(11, 0), []byte{0x34, 0x8a, 0x0b}}, {inf.NewDec(13, 0), []byte{0x34, 0x8a, 0x0d}}, // Note that this does not sort correctly! {inf.NewDec(255, 0), []byte{0x34, 0x8b, 0xff}}, {inf.NewDec(256, 0), []byte{0x34, 0x8b, 0x01, 0x00}}, {decimal.NewDecFromFloat(math.MaxFloat64), []byte{0x34, 0xf7, 0x01, 0x35, 0x3f, 0xdd, 0xec, 0x7f, 0x2f, 0xaf, 0x35}}, // Four duplicates to make sure 13*10^1000 <= 130*10^999 <= 1300*10^998 <= 13*10^1000 {inf.NewDec(13, -1000), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(130, -999), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(1300, -998), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(13, -1000), []byte{0x34, 0xf7, 0x03, 0xea, 0x0d}}, {inf.NewDec(99122, -99999), []byte{0x34, 0xf8, 0x01, 0x86, 0xa4, 0x01, 0x83, 0x32}}, {inf.NewDec(99122839898321208, -99999), []byte{0x34, 0xf8, 0x01, 0x86, 0xb0, 0x01, 0x60, 0x27, 0xb2, 0x9d, 0x44, 0x71, 0x38}}, } rng, _ := randutil.NewPseudoRand() for _, tmp := range [][]byte{nil, make([]byte, 0, 100)} { for i, c := range testCases { enc := EncodeNonsortingDecimal(nil, c.Value) dec, err := DecodeNonsortingDecimal(enc, tmp) if err != nil { t.Error(err) continue } if !bytes.Equal(enc, c.Encoding) { t.Errorf("unexpected mismatch for %s. expected [% x], got [% x]", c.Value, c.Encoding, enc) } if dec.Cmp(c.Value) != 0 { t.Errorf("%d unexpected mismatch for %v. got %v", i, c.Value, dec) } // Test that appending the decimal to an existing buffer works. It // is important to test with various values, slice lengths, and // capacities because the various encoding paths try to use any // spare capacity to avoid allocations. for trials := 0; trials < 5; trials++ { orig := randBuf(rng, 30) origLen := len(orig) bufCap := origLen + rng.Intn(30) buf := make([]byte, origLen, bufCap) copy(buf, orig) enc := EncodeNonsortingDecimal(buf, c.Value) dec, err := DecodeNonsortingDecimal(enc[origLen:], tmp) if err != nil { t.Fatal(err) } if dec.Cmp(c.Value) != 0 { t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec) } // Verify the existing values weren't modified. for i := range orig { if enc[i] != orig[i] { t.Errorf("existing byte %d changed after encoding (from %d to %d)", i, orig[i], enc[i]) } } } } } }
// randDecimal generates a random decimal with exponent in the // range [minExp, maxExp]. func randDecimal(rng *rand.Rand, minExp, maxExp int) *inf.Dec { exp := randutil.RandIntInRange(rng, minExp, maxExp+1) // Transform random float in [0, 1) to [-1, 1) and multiply by 10^exp. floatVal := (rng.Float64()*2 - 1) * math.Pow10(exp) return decimal.NewDecFromFloat(floatVal) }
func TestEncodeDecimal(t *testing.T) { testCases := []struct { Value *inf.Dec Encoding []byte }{ {inf.NewDec(-99122, -99999), []byte{0x1a, 0x86, 0x3c, 0xad, 0x38, 0xe6, 0xd7, 0x00}}, // Three duplicates to make sure -13*10^1000 <= -130*10^999 <= -13*10^1000 {inf.NewDec(-13, -1000), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}}, {inf.NewDec(-130, -999), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}}, {inf.NewDec(-13, -1000), []byte{0x1a, 0x86, 0xfe, 0x0a, 0xe5, 0x00}}, {decimal.NewDecFromFloat(-math.MaxFloat64), []byte{0x1a, 0x87, 0x64, 0xfc, 0x60, 0x66, 0x44, 0xe4, 0x9e, 0x82, 0xc0, 0x8d, 0x00}}, {inf.NewDec(-130, -100), []byte{0x1a, 0x87, 0xcb, 0xfc, 0xc3, 0x00}}, {inf.NewDec(-13, 0), []byte{0x24, 0xe5, 0x00}}, {inf.NewDec(-11, 0), []byte{0x24, 0xe9, 0x00}}, {mustDecimal("-10.123456789"), []byte{0x24, 0xea, 0xe6, 0xba, 0x8e, 0x62, 0x4b, 0x00}}, {mustDecimal("-10"), []byte{0x24, 0xeb, 0x00}}, {mustDecimal("-9.123456789"), []byte{0x24, 0xec, 0xe6, 0xba, 0x8e, 0x62, 0x4b, 0x00}}, {mustDecimal("-9"), []byte{0x24, 0xed, 0x00}}, {mustDecimal("-1.1"), []byte{0x24, 0xfc, 0xeb, 0x00}}, {inf.NewDec(-1, 0), []byte{0x24, 0xfd, 0x00}}, {inf.NewDec(-8, 1), []byte{0x25, 0x5f, 0x00}}, {inf.NewDec(-1, 1), []byte{0x25, 0xeb, 0x00}}, {mustDecimal("-.09"), []byte{0x25, 0xed, 0x00}}, {mustDecimal("-.054321"), []byte{0x25, 0xf4, 0xa8, 0xd5, 0x00}}, {mustDecimal("-.012"), []byte{0x25, 0xfc, 0xd7, 0x00}}, {inf.NewDec(-11, 4), []byte{0x26, 0x89, 0xe9, 0x00}}, {inf.NewDec(-11, 6), []byte{0x26, 0x8a, 0xe9, 0x00}}, {decimal.NewDecFromFloat(-math.SmallestNonzeroFloat64), []byte{0x26, 0xf6, 0xa1, 0xf5, 0x00}}, {inf.NewDec(-11, 66666), []byte{0x26, 0xf7, 0x82, 0x34, 0xe9, 0x00}}, {inf.NewDec(0, 0), []byte{0x27}}, {decimal.NewDecFromFloat(math.SmallestNonzeroFloat64), []byte{0x28, 0x87, 0x5e, 0x0a, 0x00}}, {inf.NewDec(11, 6), []byte{0x28, 0x87, 0xfd, 0x16, 0x00}}, {inf.NewDec(11, 4), []byte{0x28, 0x87, 0xfe, 0x16, 0x00}}, {inf.NewDec(1, 1), []byte{0x29, 0x14, 0x00}}, {inf.NewDec(8, 1), []byte{0x29, 0xa0, 0x00}}, {inf.NewDec(1, 0), []byte{0x2a, 0x02, 0x00}}, {mustDecimal("1.1"), []byte{0x2a, 0x03, 0x14, 0x00}}, {inf.NewDec(11, 0), []byte{0x2a, 0x16, 0x00}}, {inf.NewDec(13, 0), []byte{0x2a, 0x1a, 0x00}}, {decimal.NewDecFromFloat(math.MaxFloat64), []byte{0x34, 0xf6, 0x9b, 0x03, 0x9f, 0x99, 0xbb, 0x1b, 0x61, 0x7d, 0x3f, 0x72, 0x00}}, // Four duplicates to make sure 13*10^1000 <= 130*10^999 <= 1300*10^998 <= 13*10^1000 {inf.NewDec(13, -1000), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}}, {inf.NewDec(130, -999), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}}, {inf.NewDec(1300, -998), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}}, {inf.NewDec(13, -1000), []byte{0x34, 0xf7, 0x01, 0xf5, 0x1a, 0x00}}, {inf.NewDec(99122, -99999), []byte{0x34, 0xf7, 0xc3, 0x52, 0xc7, 0x19, 0x28, 0x00}}, {inf.NewDec(99122839898321208, -99999), []byte{0x34, 0xf7, 0xc3, 0x58, 0xc7, 0x19, 0x39, 0x4f, 0xb3, 0xa7, 0x2b, 0x29, 0xa0, 0x00}}, } rng, _ := randutil.NewPseudoRand() var lastEncoded []byte for _, dir := range []Direction{Ascending, Descending} { for _, tmp := range [][]byte{nil, make([]byte, 0, 100)} { for i, c := range testCases { enc := encodeDecimalWithDir(dir, nil, c.Value) _, dec := decodeDecimalWithDir(t, dir, enc, tmp) if dir == Ascending && !bytes.Equal(enc, c.Encoding) { t.Errorf("unexpected mismatch for %s. expected [% x], got [% x]", c.Value, c.Encoding, enc) } if i > 0 { if (bytes.Compare(lastEncoded, enc) > 0 && dir == Ascending) || (bytes.Compare(lastEncoded, enc) < 0 && dir == Descending) { t.Errorf("%v: expected [% x] to be less than or equal to [% x]", c.Value, testCases[i-1].Encoding, enc) } } testPeekLength(t, enc) if dec.Cmp(c.Value) != 0 { t.Errorf("%d unexpected mismatch for %v. got %v", i, c.Value, dec) } lastEncoded = enc // Test that appending the decimal to an existing buffer works. It // is important to test with various values, slice lengths, and // capacities because the various encoding paths try to use any // spare capacity to avoid allocations. for trials := 0; trials < 5; trials++ { orig := randBuf(rng, 30) origLen := len(orig) bufCap := origLen + rng.Intn(30) buf := make([]byte, origLen, bufCap) copy(buf, orig) enc := encodeDecimalWithDir(dir, buf, c.Value) // Append some random bytes enc = append(enc, randBuf(rng, 20)...) _, dec := decodeDecimalWithDir(t, dir, enc[origLen:], tmp) if dec.Cmp(c.Value) != 0 { t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec) } // Verify the existing values weren't modified. for i := range orig { if enc[i] != orig[i] { t.Errorf("existing byte %d changed after encoding (from %d to %d)", i, orig[i], enc[i]) } } } } } } }