...

Source file src/github.com/cockroachdb/apd/v3/decimal_test.go

Documentation: github.com/cockroachdb/apd/v3

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied. See the License for the specific language governing
    13  // permissions and limitations under the License.
    14  
    15  package apd
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"math"
    21  	"math/bits"
    22  	"strings"
    23  	"testing"
    24  	"unsafe"
    25  )
    26  
    27  var (
    28  	testCtx = &BaseContext
    29  )
    30  
    31  func (d *Decimal) GoString() string {
    32  	return fmt.Sprintf(`{Coeff: %s, Exponent: %d, Negative: %v, Form: %s}`, d.Coeff.String(), d.Exponent, d.Negative, d.Form)
    33  }
    34  
    35  // testExponentError skips t if err was caused by an exponent being outside
    36  // of the package's supported exponent range. Since the exponent is so large,
    37  // we don't support those tests yet (i.e., it's an expected failure, so we
    38  // skip it).
    39  func testExponentError(t *testing.T, err error) {
    40  	if err == nil {
    41  		return
    42  	}
    43  	if err.Error() == errExponentOutOfRangeStr {
    44  		t.Skip(err)
    45  	}
    46  }
    47  
    48  func newDecimal(t *testing.T, c *Context, s string) *Decimal {
    49  	d, _, err := c.NewFromString(s)
    50  	testExponentError(t, err)
    51  	if err != nil {
    52  		t.Fatalf("%s: %+v", s, err)
    53  	}
    54  	return d
    55  }
    56  
    57  func TestNewWithBigInt(t *testing.T) {
    58  	tests := []string{
    59  		"0",
    60  		"1",
    61  		"-1",
    62  	}
    63  	for _, tc := range tests {
    64  		t.Run(tc, func(t *testing.T) {
    65  			expect, _, err := new(Decimal).SetString(tc)
    66  			if err != nil {
    67  				t.Fatal(err)
    68  			}
    69  			b, ok := new(BigInt).SetString(tc, 10)
    70  			if !ok {
    71  				t.Fatal("bad bigint")
    72  			}
    73  			d := NewWithBigInt(b, 0)
    74  			if d.Coeff.Sign() < 0 {
    75  				t.Fatal("unexpected negative coeff")
    76  			}
    77  			// Verify that changing b doesn't change d.
    78  			b.Set(NewBigInt(1234))
    79  			if d.CmpTotal(expect) != 0 {
    80  				t.Fatalf("expected %s, got %s", expect, d)
    81  			}
    82  		})
    83  	}
    84  }
    85  
    86  func TestUpscale(t *testing.T) {
    87  	tests := []struct {
    88  		x, y *Decimal
    89  		a, b *BigInt
    90  		s    int32
    91  	}{
    92  		{x: New(1, 0), y: New(100, -1), a: NewBigInt(10), b: NewBigInt(100), s: -1},
    93  		{x: New(1, 0), y: New(10, -1), a: NewBigInt(10), b: NewBigInt(10), s: -1},
    94  		{x: New(1, 0), y: New(10, 0), a: NewBigInt(1), b: NewBigInt(10), s: 0},
    95  		{x: New(1, 1), y: New(1, 0), a: NewBigInt(10), b: NewBigInt(1), s: 0},
    96  		{x: New(10, -2), y: New(1, -1), a: NewBigInt(10), b: NewBigInt(10), s: -2},
    97  		{x: New(1, -2), y: New(100, 1), a: NewBigInt(1), b: NewBigInt(100000), s: -2},
    98  	}
    99  	for _, tc := range tests {
   100  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   101  			a, b, s, err := upscale(tc.x, tc.y, new(BigInt))
   102  			if err != nil {
   103  				t.Fatal(err)
   104  			}
   105  			if a.Cmp(tc.a) != 0 {
   106  				t.Errorf("a: expected %s, got %s", tc.a, a)
   107  			}
   108  			if b.Cmp(tc.b) != 0 {
   109  				t.Errorf("b: expected %s, got %s", tc.b, b)
   110  			}
   111  			if s != tc.s {
   112  				t.Errorf("s: expected %d, got %d", tc.s, s)
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestAdd(t *testing.T) {
   119  	tests := []struct {
   120  		x, y string
   121  		r    string
   122  	}{
   123  		{x: "1", y: "10", r: "11"},
   124  		{x: "1", y: "1e1", r: "11"},
   125  		{x: "1e1", y: "1", r: "11"},
   126  		{x: ".1e1", y: "100e-1", r: "11.0"},
   127  	}
   128  	for _, tc := range tests {
   129  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   130  			x := newDecimal(t, testCtx, tc.x)
   131  			y := newDecimal(t, testCtx, tc.y)
   132  			d := new(Decimal)
   133  			_, err := testCtx.Add(d, x, y)
   134  			if err != nil {
   135  				t.Fatal(err)
   136  			}
   137  			s := d.String()
   138  			if s != tc.r {
   139  				t.Fatalf("expected: %s, got: %s", tc.r, s)
   140  			}
   141  		})
   142  	}
   143  }
   144  
   145  func TestCmp(t *testing.T) {
   146  	tests := []struct {
   147  		x, y string
   148  		c    int
   149  	}{
   150  		{x: "1", y: "10", c: -1},
   151  		{x: "1", y: "1e1", c: -1},
   152  		{x: "1e1", y: "1", c: 1},
   153  		{x: ".1e1", y: "100e-1", c: -1},
   154  
   155  		{x: ".1e1", y: "100e-2", c: 0},
   156  		{x: "1", y: ".1e1", c: 0},
   157  		{x: "1", y: "1", c: 0},
   158  	}
   159  	for _, tc := range tests {
   160  		t.Run(fmt.Sprintf("%s, %s", tc.x, tc.y), func(t *testing.T) {
   161  			x := newDecimal(t, testCtx, tc.x)
   162  			y := newDecimal(t, testCtx, tc.y)
   163  			c := x.Cmp(y)
   164  			if c != tc.c {
   165  				t.Fatalf("expected: %d, got: %d", tc.c, c)
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func TestModf(t *testing.T) {
   172  	tests := []struct {
   173  		x string
   174  		i string
   175  		f string
   176  	}{
   177  		{x: "1", i: "1", f: "0"},
   178  		{x: "1.0", i: "1", f: "0.0"},
   179  		{x: "1.0e1", i: "10", f: "0"},
   180  		{x: "1.0e2", i: "1.0E+2", f: "0"},
   181  		{x: "1.0e-1", i: "0", f: "0.10"},
   182  		{x: "1.0e-2", i: "0", f: "0.010"},
   183  		{x: "1.1", i: "1", f: "0.1"},
   184  		{x: "1234.56", i: "1234", f: "0.56"},
   185  		{x: "1234.56e2", i: "123456", f: "0"},
   186  		{x: "1234.56e4", i: "1.23456E+7", f: "0"},
   187  		{x: "1234.56e-2", i: "12", f: "0.3456"},
   188  		{x: "1234.56e-4", i: "0", f: "0.123456"},
   189  		{x: "1234.56e-6", i: "0", f: "0.00123456"},
   190  		{x: "123456e-8", i: "0", f: "0.00123456"},
   191  		{x: ".123456e8", i: "1.23456E+7", f: "0"},
   192  
   193  		{x: "-1", i: "-1", f: "-0"},
   194  		{x: "-1.0", i: "-1", f: "-0.0"},
   195  		{x: "-1.0e1", i: "-10", f: "-0"},
   196  		{x: "-1.0e2", i: "-1.0E+2", f: "-0"},
   197  		{x: "-1.0e-1", i: "-0", f: "-0.10"},
   198  		{x: "-1.0e-2", i: "-0", f: "-0.010"},
   199  		{x: "-1.1", i: "-1", f: "-0.1"},
   200  		{x: "-1234.56", i: "-1234", f: "-0.56"},
   201  		{x: "-1234.56e2", i: "-123456", f: "-0"},
   202  		{x: "-1234.56e4", i: "-1.23456E+7", f: "-0"},
   203  		{x: "-1234.56e-2", i: "-12", f: "-0.3456"},
   204  		{x: "-1234.56e-4", i: "-0", f: "-0.123456"},
   205  		{x: "-1234.56e-6", i: "-0", f: "-0.00123456"},
   206  		{x: "-123456e-8", i: "-0", f: "-0.00123456"},
   207  		{x: "-.123456e8", i: "-1.23456E+7", f: "-0"},
   208  	}
   209  	for _, tc := range tests {
   210  		t.Run(tc.x, func(t *testing.T) {
   211  			x := newDecimal(t, testCtx, tc.x)
   212  			integ, frac := new(Decimal), new(Decimal)
   213  			x.Modf(integ, frac)
   214  			if tc.i != integ.String() {
   215  				t.Fatalf("integ: expected: %s, got: %s", tc.i, integ)
   216  			}
   217  			if tc.f != frac.String() {
   218  				t.Fatalf("frac: expected: %s, got: %s", tc.f, frac)
   219  			}
   220  			a := new(Decimal)
   221  			if _, err := testCtx.Add(a, integ, frac); err != nil {
   222  				t.Fatal(err)
   223  			}
   224  			if a.Cmp(x) != 0 {
   225  				t.Fatalf("%s != %s", a, x)
   226  			}
   227  			if integ.Exponent < 0 {
   228  				t.Fatal(integ.Exponent)
   229  			}
   230  			if frac.Exponent > 0 {
   231  				t.Fatal(frac.Exponent)
   232  			}
   233  
   234  			integ2, frac2 := new(Decimal), new(Decimal)
   235  			x.Modf(integ2, nil)
   236  			x.Modf(nil, frac2)
   237  			if integ.CmpTotal(integ2) != 0 {
   238  				t.Fatalf("got %s, expected %s", integ2, integ)
   239  			}
   240  			if frac.CmpTotal(frac2) != 0 {
   241  				t.Fatalf("got %s, expected %s", frac2, frac)
   242  			}
   243  		})
   244  	}
   245  
   246  	// Ensure we don't panic on both nil.
   247  	a := new(Decimal)
   248  	a.Modf(nil, nil)
   249  }
   250  
   251  func TestInt64(t *testing.T) {
   252  	tests := []struct {
   253  		x   string
   254  		i   int64
   255  		err bool
   256  	}{
   257  		{x: "0.12e1", err: true},
   258  		{x: "0.1e1", i: 1},
   259  		{x: "10", i: 10},
   260  		{x: "12.3e3", i: 12300},
   261  		{x: "1e-1", err: true},
   262  		{x: "1e2", i: 100},
   263  		{x: "1", i: 1},
   264  		{x: "NaN", err: true},
   265  		{x: "Inf", err: true},
   266  		{x: "9223372036854775807", i: 9223372036854775807},
   267  		{x: "-9223372036854775808", i: -9223372036854775808},
   268  		{x: "9223372036854775808", err: true},
   269  	}
   270  	for _, tc := range tests {
   271  		t.Run(tc.x, func(t *testing.T) {
   272  			x := newDecimal(t, testCtx, tc.x)
   273  			i, err := x.Int64()
   274  			hasErr := err != nil
   275  			if tc.err != hasErr {
   276  				t.Fatalf("expected error: %v, got error: %v", tc.err, err)
   277  			}
   278  			if hasErr {
   279  				return
   280  			}
   281  			if i != tc.i {
   282  				t.Fatalf("expected: %v, got %v", tc.i, i)
   283  			}
   284  		})
   285  	}
   286  }
   287  
   288  func TestQuoErr(t *testing.T) {
   289  	tests := []struct {
   290  		x, y string
   291  		p    uint32
   292  		err  string
   293  	}{
   294  		{x: "1", y: "1", p: 0, err: errZeroPrecisionStr},
   295  		{x: "1", y: "0", p: 1, err: "division by zero"},
   296  	}
   297  	for _, tc := range tests {
   298  		c := testCtx.WithPrecision(tc.p)
   299  		x := newDecimal(t, testCtx, tc.x)
   300  		y := newDecimal(t, testCtx, tc.y)
   301  		d := new(Decimal)
   302  		_, err := c.Quo(d, x, y)
   303  		if err == nil {
   304  			t.Fatal("expected error")
   305  		}
   306  		if err.Error() != tc.err {
   307  			t.Fatalf("expected %s, got %s", tc.err, err)
   308  		}
   309  	}
   310  }
   311  
   312  func TestConditionString(t *testing.T) {
   313  	tests := map[Condition]string{
   314  		Overflow:             "overflow",
   315  		Overflow | Underflow: "overflow, underflow",
   316  		Subnormal | Inexact:  "inexact, subnormal",
   317  	}
   318  	for c, s := range tests {
   319  		t.Run(s, func(t *testing.T) {
   320  			cs := c.String()
   321  			if cs != s {
   322  				t.Errorf("expected %s; got %s", s, cs)
   323  			}
   324  		})
   325  	}
   326  }
   327  
   328  func TestFloat64(t *testing.T) {
   329  	tests := []float64{
   330  		0,
   331  		1,
   332  		-1,
   333  		math.MaxFloat32,
   334  		math.SmallestNonzeroFloat32,
   335  		math.MaxFloat64,
   336  		math.SmallestNonzeroFloat64,
   337  	}
   338  
   339  	for _, tc := range tests {
   340  		t.Run(fmt.Sprint(tc), func(t *testing.T) {
   341  			d := new(Decimal)
   342  			d.SetFloat64(tc)
   343  			f, err := d.Float64()
   344  			if err != nil {
   345  				t.Fatal(err)
   346  			}
   347  			if tc != f {
   348  				t.Fatalf("expected %v, got %v", tc, f)
   349  			}
   350  		})
   351  	}
   352  }
   353  
   354  func TestCeil(t *testing.T) {
   355  	tests := map[float64]int64{
   356  		0:    0,
   357  		-0.1: 0,
   358  		0.1:  1,
   359  		-0.9: 0,
   360  		0.9:  1,
   361  		-1:   -1,
   362  		1:    1,
   363  		-1.1: -1,
   364  		1.1:  2,
   365  	}
   366  
   367  	for f, r := range tests {
   368  		t.Run(fmt.Sprint(f), func(t *testing.T) {
   369  			d, err := new(Decimal).SetFloat64(f)
   370  			if err != nil {
   371  				t.Fatal(err)
   372  			}
   373  			_, err = testCtx.Ceil(d, d)
   374  			if err != nil {
   375  				t.Fatal(err)
   376  			}
   377  			i, err := d.Int64()
   378  			if err != nil {
   379  				t.Fatal(err)
   380  			}
   381  			if i != r {
   382  				t.Fatalf("got %v, expected %v", i, r)
   383  			}
   384  		})
   385  	}
   386  }
   387  
   388  func TestFloor(t *testing.T) {
   389  	tests := map[float64]int64{
   390  		0:    0,
   391  		-0.1: -1,
   392  		0.1:  0,
   393  		-0.9: -1,
   394  		0.9:  0,
   395  		-1:   -1,
   396  		1:    1,
   397  		-1.1: -2,
   398  		1.1:  1,
   399  	}
   400  
   401  	for f, r := range tests {
   402  		t.Run(fmt.Sprint(f), func(t *testing.T) {
   403  			d, err := new(Decimal).SetFloat64(f)
   404  			if err != nil {
   405  				t.Fatal(err)
   406  			}
   407  			_, err = testCtx.Floor(d, d)
   408  			if err != nil {
   409  				t.Fatal(err)
   410  			}
   411  			i, err := d.Int64()
   412  			if err != nil {
   413  				t.Fatal(err)
   414  			}
   415  			if i != r {
   416  				t.Fatalf("got %v, expected %v", i, r)
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func TestFormat(t *testing.T) {
   423  	tests := map[string]struct {
   424  		e, E, f, g, G string
   425  	}{
   426  		"NaN":       {},
   427  		"Infinity":  {},
   428  		"-Infinity": {},
   429  		"sNaN":      {},
   430  		"0": {
   431  			e: "0e+0",
   432  			E: "0E+0",
   433  		},
   434  		"-0": {
   435  			e: "-0e+0",
   436  			E: "-0E+0",
   437  		},
   438  		"0.0": {
   439  			e: "0e-1",
   440  			E: "0E-1",
   441  		},
   442  		"-0.0": {
   443  			e: "-0e-1",
   444  			E: "-0E-1",
   445  		},
   446  		"0E+2": {
   447  			e: "0e+2",
   448  			f: "000",
   449  			g: "0e+2",
   450  		},
   451  		"0E-9": {
   452  			e: "0e-9",
   453  			f: "0.000000000",
   454  			g: "0.000000000",
   455  			G: "0.000000000",
   456  		},
   457  		"0E-2000": {
   458  			e: "0e-2000",
   459  			f: "0." + strings.Repeat("0", 2000),
   460  			g: "0." + strings.Repeat("0", 2000),
   461  			G: "0." + strings.Repeat("0", 2000),
   462  		},
   463  		"0E-2001": {
   464  			e: "0e-2001",
   465  			f: "0." + strings.Repeat("0", 2001),
   466  			g: "0e-2001",
   467  			G: "0E-2001",
   468  		},
   469  	}
   470  	verbs := []string{"%e", "%E", "%f", "%g", "%G"}
   471  
   472  	for input, tc := range tests {
   473  		t.Run(input, func(t *testing.T) {
   474  			d, _, err := NewFromString(input)
   475  			if err != nil {
   476  				t.Fatal(err)
   477  			}
   478  			for i, s := range []string{tc.e, tc.E, tc.f, tc.g, tc.G} {
   479  				if s == "" {
   480  					s = input
   481  				}
   482  				v := verbs[i]
   483  				t.Run(v, func(t *testing.T) {
   484  					out := fmt.Sprintf(v, d)
   485  					if out != s {
   486  						t.Fatalf("expected %s, got %s", s, out)
   487  					}
   488  				})
   489  			}
   490  		})
   491  	}
   492  }
   493  
   494  func TestFormatFlags(t *testing.T) {
   495  	const stdD = "1.23E+56"
   496  	tests := []struct {
   497  		d   string
   498  		fmt string
   499  		out string
   500  	}{
   501  		{
   502  			d:   stdD,
   503  			fmt: "%3G",
   504  			out: "1.23E+56",
   505  		},
   506  		{
   507  			d:   stdD,
   508  			fmt: "%010G",
   509  			out: "001.23E+56",
   510  		},
   511  		{
   512  			d:   stdD,
   513  			fmt: "%10G",
   514  			out: "  1.23E+56",
   515  		},
   516  		{
   517  			d:   stdD,
   518  			fmt: "%+G",
   519  			out: "+1.23E+56",
   520  		},
   521  		{
   522  			d:   stdD,
   523  			fmt: "% G",
   524  			out: " 1.23E+56",
   525  		},
   526  		{
   527  			d:   stdD,
   528  			fmt: "%-10G",
   529  			out: "1.23E+56  ",
   530  		},
   531  		{
   532  			d:   stdD,
   533  			fmt: "%-010G",
   534  			out: "1.23E+56  ",
   535  		},
   536  		{
   537  			d:   "nan",
   538  			fmt: "%-10G",
   539  			out: "NaN       ",
   540  		},
   541  		{
   542  			d:   "nan",
   543  			fmt: "%10G",
   544  			out: "       NaN",
   545  		},
   546  		{
   547  			d:   "nan",
   548  			fmt: "%010G",
   549  			out: "       NaN",
   550  		},
   551  		{
   552  			d:   "inf",
   553  			fmt: "%-10G",
   554  			out: "Infinity  ",
   555  		},
   556  		{
   557  			d:   "inf",
   558  			fmt: "%10G",
   559  			out: "  Infinity",
   560  		},
   561  		{
   562  			d:   "inf",
   563  			fmt: "%010G",
   564  			out: "  Infinity",
   565  		},
   566  		{
   567  			d:   "-inf",
   568  			fmt: "%-10G",
   569  			out: "-Infinity ",
   570  		},
   571  		{
   572  			d:   "-inf",
   573  			fmt: "%10G",
   574  			out: " -Infinity",
   575  		},
   576  		{
   577  			d:   "-inf",
   578  			fmt: "%010G",
   579  			out: " -Infinity",
   580  		},
   581  		{
   582  			d:   "0",
   583  			fmt: "%d",
   584  			out: "%!d(*apd.Decimal=0)",
   585  		},
   586  	}
   587  	for _, tc := range tests {
   588  		t.Run(fmt.Sprintf("%s: %s", tc.d, tc.fmt), func(t *testing.T) {
   589  			d := newDecimal(t, &BaseContext, tc.d)
   590  			s := fmt.Sprintf(tc.fmt, d)
   591  			if s != tc.out {
   592  				t.Fatalf("expected %q, got %q", tc.out, s)
   593  			}
   594  		})
   595  	}
   596  }
   597  
   598  func TestContextSetStringt(t *testing.T) {
   599  	tests := []struct {
   600  		s      string
   601  		c      *Context
   602  		expect string
   603  	}{
   604  		{
   605  			s:      "1.234",
   606  			c:      &BaseContext,
   607  			expect: "1.234",
   608  		},
   609  		{
   610  			s:      "1.234",
   611  			c:      BaseContext.WithPrecision(2),
   612  			expect: "1.2",
   613  		},
   614  	}
   615  	for i, tc := range tests {
   616  		t.Run(fmt.Sprintf("%d: %s", i, tc.s), func(t *testing.T) {
   617  			d := new(Decimal)
   618  			if _, _, err := tc.c.SetString(d, tc.s); err != nil {
   619  				t.Fatal(err)
   620  			}
   621  			got := d.String()
   622  			if got != tc.expect {
   623  				t.Fatalf("expected: %s, got: %s", tc.expect, got)
   624  			}
   625  		})
   626  	}
   627  }
   628  
   629  func TestQuantize(t *testing.T) {
   630  	tests := []struct {
   631  		s      string
   632  		e      int32
   633  		expect string
   634  	}{
   635  		{
   636  			s:      "1.00",
   637  			e:      -1,
   638  			expect: "1.0",
   639  		},
   640  		{
   641  			s:      "2.0",
   642  			e:      -1,
   643  			expect: "2.0",
   644  		},
   645  		{
   646  			s:      "3",
   647  			e:      -1,
   648  			expect: "3.0",
   649  		},
   650  		{
   651  			s:      "9.9999",
   652  			e:      -2,
   653  			expect: "10.00",
   654  		},
   655  	}
   656  	c := BaseContext.WithPrecision(10)
   657  	for _, tc := range tests {
   658  		t.Run(fmt.Sprintf("%s: %d", tc.s, tc.e), func(t *testing.T) {
   659  			d, _, err := NewFromString(tc.s)
   660  			if err != nil {
   661  				t.Fatal(err)
   662  			}
   663  			if _, err := c.Quantize(d, d, tc.e); err != nil {
   664  				t.Fatal(err)
   665  			}
   666  			s := d.String()
   667  			if s != tc.expect {
   668  				t.Fatalf("expected: %s, got: %s", tc.expect, s)
   669  			}
   670  		})
   671  	}
   672  }
   673  
   674  func TestCmpOrder(t *testing.T) {
   675  	tests := []struct {
   676  		s     string
   677  		order int
   678  	}{
   679  		{s: "-NaN", order: -4},
   680  		{s: "-sNaN", order: -3},
   681  		{s: "-Infinity", order: -2},
   682  		{s: "-127", order: -1},
   683  		{s: "-1.00", order: -1},
   684  		{s: "-1", order: -1},
   685  		{s: "-0.000", order: -1},
   686  		{s: "-0", order: -1},
   687  		{s: "0", order: 1},
   688  		{s: "1.2300", order: 1},
   689  		{s: "1.23", order: 1},
   690  		{s: "1E+9", order: 1},
   691  		{s: "Infinity", order: 2},
   692  		{s: "sNaN", order: 3},
   693  		{s: "NaN", order: 4},
   694  	}
   695  
   696  	for _, tc := range tests {
   697  		t.Run(tc.s, func(t *testing.T) {
   698  			d, _, err := NewFromString(tc.s)
   699  			if err != nil {
   700  				t.Fatal(err)
   701  			}
   702  			o := d.cmpOrder()
   703  			if o != tc.order {
   704  				t.Fatalf("got %d, expected %d", o, tc.order)
   705  			}
   706  		})
   707  	}
   708  }
   709  
   710  func TestIsZero(t *testing.T) {
   711  	tests := []struct {
   712  		s    string
   713  		zero bool
   714  	}{
   715  		{s: "-NaN", zero: false},
   716  		{s: "-sNaN", zero: false},
   717  		{s: "-Infinity", zero: false},
   718  		{s: "-127", zero: false},
   719  		{s: "-1.00", zero: false},
   720  		{s: "-1", zero: false},
   721  		{s: "-0.000", zero: true},
   722  		{s: "-0", zero: true},
   723  		{s: "0", zero: true},
   724  		{s: "1.2300", zero: false},
   725  		{s: "1.23", zero: false},
   726  		{s: "1E+9", zero: false},
   727  		{s: "Infinity", zero: false},
   728  		{s: "sNaN", zero: false},
   729  		{s: "NaN", zero: false},
   730  	}
   731  
   732  	for _, tc := range tests {
   733  		t.Run(tc.s, func(t *testing.T) {
   734  			d, _, err := NewFromString(tc.s)
   735  			if err != nil {
   736  				t.Fatal(err)
   737  			}
   738  			z := d.IsZero()
   739  			if z != tc.zero {
   740  				t.Fatalf("got %v, expected %v", z, tc.zero)
   741  			}
   742  		})
   743  	}
   744  }
   745  
   746  func TestNeg(t *testing.T) {
   747  	tests := map[string]string{
   748  		"0":          "0",
   749  		"-0":         "0",
   750  		"-0.000":     "0.000",
   751  		"-00.000100": "0.000100",
   752  	}
   753  
   754  	for tc, expect := range tests {
   755  		t.Run(tc, func(t *testing.T) {
   756  			d, _, err := NewFromString(tc)
   757  			if err != nil {
   758  				t.Fatal(err)
   759  			}
   760  			var z Decimal
   761  			z.Neg(d)
   762  			s := z.String()
   763  			if s != expect {
   764  				t.Fatalf("expected %s, got %s", expect, s)
   765  			}
   766  		})
   767  	}
   768  }
   769  
   770  func TestReduce(t *testing.T) {
   771  	tests := map[string]int{
   772  		"-0":        0,
   773  		"0":         0,
   774  		"0.0":       0,
   775  		"00":        0,
   776  		"0.00":      0,
   777  		"-01000":    3,
   778  		"01000":     3,
   779  		"-1":        0,
   780  		"1":         0,
   781  		"-10.000E4": 4,
   782  		"10.000E4":  4,
   783  		"-10.00":    3,
   784  		"10.00":     3,
   785  		"-10":       1,
   786  		"10":        1,
   787  		"-143200000000000000000000000000000000000000000000000000000000": 56,
   788  		"143200000000000000000000000000000000000000000000000000000000":  56,
   789  		"Inf": 0,
   790  		"NaN": 0,
   791  	}
   792  
   793  	for s, n := range tests {
   794  		t.Run(s, func(t *testing.T) {
   795  			d, _, err := NewFromString(s)
   796  			if err != nil {
   797  				t.Fatal(err)
   798  			}
   799  			_, got := d.Reduce(d)
   800  			if n != got {
   801  				t.Fatalf("got %v, expected %v", got, n)
   802  			}
   803  		})
   804  	}
   805  }
   806  
   807  // TestSizeof is meant to catch changes that unexpectedly increase
   808  // the size of the BigInt, Decimal, and Context structs.
   809  func TestSizeof(t *testing.T) {
   810  	// map[uint_size][type]sizeof
   811  	exp := map[int]map[string]uintptr{
   812  		32: {
   813  			"BigInt":  20,
   814  			"Decimal": 28,
   815  			"Context": 24,
   816  		},
   817  		64: {
   818  			"BigInt":  24,
   819  			"Decimal": 32,
   820  			"Context": 32,
   821  		},
   822  	}[bits.UintSize]
   823  
   824  	var b BigInt
   825  	if s := unsafe.Sizeof(b); s != exp["BigInt"] {
   826  		t.Errorf("sizeof(BigInt) changed: %d", s)
   827  	}
   828  	var d Decimal
   829  	if s := unsafe.Sizeof(d); s != exp["Decimal"] {
   830  		t.Errorf("sizeof(Decimal) changed: %d", s)
   831  	}
   832  	var c Context
   833  	if s := unsafe.Sizeof(c); s != exp["Context"] {
   834  		t.Errorf("sizeof(Context) changed: %d", s)
   835  	}
   836  }
   837  
   838  // TestSize tests the Size method on BigInt and Decimal. Unlike Sizeof, which
   839  // returns the shallow size of the structs, the Size method reports the total
   840  // memory footprint of each struct and all referenced objects.
   841  func TestSize(t *testing.T) {
   842  	// map[uint_size][is_inline][type]size
   843  	exp := map[int]map[bool]map[string]uintptr{
   844  		32: {
   845  			true: {
   846  				"BigInt":  20,
   847  				"Decimal": 28,
   848  			},
   849  			false: {
   850  				"BigInt":  72,
   851  				"Decimal": 80,
   852  			},
   853  		},
   854  		64: {
   855  			true: {
   856  				"BigInt":  24,
   857  				"Decimal": 32,
   858  			},
   859  			false: {
   860  				"BigInt":  112,
   861  				"Decimal": 120,
   862  			},
   863  		},
   864  	}[bits.UintSize]
   865  
   866  	var d Decimal
   867  	if e, s := exp[true]["Decimal"], d.Size(); e != s {
   868  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   869  	}
   870  	if e, s := exp[true]["BigInt"], d.Coeff.Size(); e != s {
   871  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   872  	}
   873  	// Set to an inlinable value.
   874  	d.SetInt64(1234)
   875  	if e, s := exp[true]["Decimal"], d.Size(); e != s {
   876  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   877  	}
   878  	if e, s := exp[true]["BigInt"], d.Coeff.Size(); e != s {
   879  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   880  	}
   881  	// Set to a non-inlinable value.
   882  	if _, _, err := d.SetString("123456789123456789123456789.123456789123456789"); err != nil {
   883  		t.Fatal(err)
   884  	}
   885  	if d.Coeff.isInline() {
   886  		// Sanity-check, in case inlineWords changes.
   887  		t.Fatal("BigInt inlined large value. Did inlineWords change?")
   888  	}
   889  	if e, s := exp[false]["Decimal"], d.Size(); e != s {
   890  		t.Errorf("(*Decimal).Size() != %d: %d", e, s)
   891  	}
   892  	if e, s := exp[false]["BigInt"], d.Coeff.Size(); e != s {
   893  		t.Errorf("(*BigInt).Size() != %d: %d", e, s)
   894  	}
   895  }
   896  
   897  func TestJSONEncoding(t *testing.T) {
   898  	var encodingTests = []string{
   899  		"0",
   900  		"1",
   901  		"2",
   902  		"10",
   903  		"1000",
   904  		"1234567890",
   905  		"298472983472983471903246121093472394872319615612417471234712061",
   906  		"0.0",
   907  		"NaN",
   908  		"Inf",
   909  		"123.456",
   910  		"1E1",
   911  		"1E-1",
   912  		"1.2E3",
   913  	}
   914  
   915  	for _, test := range encodingTests {
   916  		for _, sign := range []string{"", "+", "-"} {
   917  			x := sign + test
   918  			var tx Decimal
   919  			tx.SetString(x)
   920  			b, err := json.Marshal(&tx)
   921  			if err != nil {
   922  				t.Errorf("marshaling of %s failed: %s", &tx, err)
   923  				continue
   924  			}
   925  			var rx Decimal
   926  			if err := json.Unmarshal(b, &rx); err != nil {
   927  				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
   928  				continue
   929  			}
   930  			if rx.CmpTotal(&tx) != 0 {
   931  				t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
   932  			}
   933  		}
   934  	}
   935  }
   936  

View as plain text