github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/mysql/decimal_test.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2015 Spring, Inc.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  // - Based on https://yougam/libraries/oguzbilgic/fpd, which has the following license:
    24  // """
    25  // The MIT License (MIT)
    26  
    27  // Copyright (c) 2013 Oguz Bilgic
    28  
    29  // Permission is hereby granted, free of charge, to any person obtaining a copy of
    30  // this software and associated documentation files (the "Software"), to deal in
    31  // the Software without restriction, including without limitation the rights to
    32  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
    33  // the Software, and to permit persons to whom the Software is furnished to do so,
    34  // subject to the following conditions:
    35  
    36  // The above copyright notice and this permission notice shall be included in all
    37  // copies or substantial portions of the Software.
    38  
    39  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    40  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    41  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    42  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    43  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    44  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    45  // """
    46  
    47  // Copyright 2015 PingCAP, Inc.
    48  //
    49  // Licensed under the Apache License, Version 2.0 (the "License");
    50  // you may not use this file except in compliance with the License.
    51  // You may obtain a copy of the License at
    52  //
    53  //     http://www.apache.org/licenses/LICENSE-2.0
    54  //
    55  // Unless required by applicable law or agreed to in writing, software
    56  // distributed under the License is distributed on an "AS IS" BASIS,
    57  // See the License for the specific language governing permissions and
    58  // limitations under the License.
    59  
    60  package mysql
    61  
    62  import (
    63  	"encoding/json"
    64  	"encoding/xml"
    65  	"math"
    66  	"strings"
    67  	"testing"
    68  )
    69  
    70  var testTable = map[float64]string{
    71  	3.141592653589793:   "3.141592653589793",
    72  	3:                   "3",
    73  	1234567890123456:    "1234567890123456",
    74  	1234567890123456000: "1234567890123456000",
    75  	1234.567890123456:   "1234.567890123456",
    76  	.1234567890123456:   "0.1234567890123456",
    77  	0:                   "0",
    78  	.1111111111111110:   "0.111111111111111",
    79  	.1111111111111111:   "0.1111111111111111",
    80  	.1111111111111119:   "0.1111111111111119",
    81  	.000000000000000001: "0.000000000000000001",
    82  	.000000000000000002: "0.000000000000000002",
    83  	.000000000000000003: "0.000000000000000003",
    84  	.000000000000000005: "0.000000000000000005",
    85  	.000000000000000008: "0.000000000000000008",
    86  	.1000000000000001:   "0.1000000000000001",
    87  	.1000000000000002:   "0.1000000000000002",
    88  	.1000000000000003:   "0.1000000000000003",
    89  	.1000000000000005:   "0.1000000000000005",
    90  	.1000000000000008:   "0.1000000000000008",
    91  }
    92  
    93  func init() {
    94  	// add negatives
    95  	for f, s := range testTable {
    96  		if f > 0 {
    97  			testTable[-f] = "-" + s
    98  		}
    99  	}
   100  }
   101  
   102  func TestNewFromFloat(t *testing.T) {
   103  	for f, s := range testTable {
   104  		d := NewDecimalFromFloat(f)
   105  		if d.String() != s {
   106  			t.Errorf("expected %s, got %s (%s, %d)",
   107  				s, d.String(),
   108  				d.value.String(), d.exp)
   109  		}
   110  	}
   111  
   112  	shouldPanicOn := []float64{
   113  		math.NaN(),
   114  		math.Inf(1),
   115  		math.Inf(-1),
   116  	}
   117  
   118  	for _, n := range shouldPanicOn {
   119  		var d Decimal
   120  		if !didPanic(func() { d = NewDecimalFromFloat(n) }) {
   121  			t.Fatalf("Expected panic when creating a Decimal from %v, got %v instead", n, d.String())
   122  		}
   123  	}
   124  }
   125  
   126  func TestNewFromString(t *testing.T) {
   127  	for _, s := range testTable {
   128  		d, err := ParseDecimal(s)
   129  		if err != nil {
   130  			t.Errorf("error while parsing %s", s)
   131  		} else if d.String() != s {
   132  			t.Errorf("expected %s, got %s (%s, %d)",
   133  				s, d.String(),
   134  				d.value.String(), d.exp)
   135  		}
   136  	}
   137  }
   138  
   139  func TestNewFromStringErrs(t *testing.T) {
   140  	tests := []string{
   141  		"",
   142  		"qwert",
   143  		"-",
   144  		".",
   145  		"-.",
   146  		".-",
   147  		"234-.56",
   148  		"234-56",
   149  		"2-",
   150  		"..",
   151  		"2..",
   152  		"..2",
   153  		".5.2",
   154  		"8..2",
   155  		"8.1.",
   156  	}
   157  
   158  	for _, s := range tests {
   159  		_, err := ParseDecimal(s)
   160  
   161  		if err == nil {
   162  			t.Errorf("error expected when parsing %s", s)
   163  		}
   164  	}
   165  }
   166  
   167  func TestNewFromFloatWithExponent(t *testing.T) {
   168  	type Inp struct {
   169  		float float64
   170  		exp   int32
   171  	}
   172  	tests := map[Inp]string{
   173  		Inp{123.4, -3}:      "123.400",
   174  		Inp{123.4, -1}:      "123.4",
   175  		Inp{123.412345, 1}:  "120",
   176  		Inp{123.412345, 0}:  "123",
   177  		Inp{123.412345, -5}: "123.41235",
   178  		Inp{123.412345, -6}: "123.412345",
   179  		Inp{123.412345, -7}: "123.4123450",
   180  	}
   181  
   182  	// add negatives
   183  	for p, s := range tests {
   184  		if p.float > 0 {
   185  			tests[Inp{-p.float, p.exp}] = "-" + s
   186  		}
   187  	}
   188  
   189  	for input, s := range tests {
   190  		d := NewDecimalFromFloatWithExponent(input.float, input.exp)
   191  		if d.String() != s {
   192  			t.Errorf("expected %s, got %s (%s, %d)",
   193  				s, d.String(),
   194  				d.value.String(), d.exp)
   195  		}
   196  	}
   197  
   198  	shouldPanicOn := []float64{
   199  		math.NaN(),
   200  		math.Inf(1),
   201  		math.Inf(-1),
   202  	}
   203  
   204  	for _, n := range shouldPanicOn {
   205  		var d Decimal
   206  		if !didPanic(func() { d = NewDecimalFromFloatWithExponent(n, 0) }) {
   207  			t.Fatalf("Expected panic when creating a Decimal from %v, got %v instead", n, d.String())
   208  		}
   209  	}
   210  }
   211  
   212  func TestJSON(t *testing.T) {
   213  	for _, s := range testTable {
   214  		var doc struct {
   215  			Amount Decimal `json:"amount"`
   216  		}
   217  		docStr := `{"amount":"` + s + `"}`
   218  		err := json.Unmarshal([]byte(docStr), &doc)
   219  		if err != nil {
   220  			t.Errorf("error unmarshaling %s: %v", docStr, err)
   221  		} else if doc.Amount.String() != s {
   222  			t.Errorf("expected %s, got %s (%s, %d)",
   223  				s, doc.Amount.String(),
   224  				doc.Amount.value.String(), doc.Amount.exp)
   225  		}
   226  
   227  		out, err := json.Marshal(&doc)
   228  		if err != nil {
   229  			t.Errorf("error marshaling %+v: %v", doc, err)
   230  		} else if string(out) != docStr {
   231  			t.Errorf("expected %s, got %s", docStr, string(out))
   232  		}
   233  	}
   234  }
   235  
   236  func TestBadJSON(t *testing.T) {
   237  	for _, testCase := range []string{
   238  		"]o_o[",
   239  		"{",
   240  		`{"amount":""`,
   241  		`{"amount":""}`,
   242  		`{"amount":"nope"}`,
   243  		`0.333`,
   244  	} {
   245  		var doc struct {
   246  			Amount Decimal `json:"amount"`
   247  		}
   248  		err := json.Unmarshal([]byte(testCase), &doc)
   249  		if err == nil {
   250  			t.Errorf("expected error, got %+v", doc)
   251  		}
   252  	}
   253  }
   254  
   255  func TestXML(t *testing.T) {
   256  	for _, s := range testTable {
   257  		var doc struct {
   258  			XMLName xml.Name `xml:"account"`
   259  			Amount  Decimal  `xml:"amount"`
   260  		}
   261  		docStr := `<account><amount>` + s + `</amount></account>`
   262  		err := xml.Unmarshal([]byte(docStr), &doc)
   263  		if err != nil {
   264  			t.Errorf("error unmarshaling %s: %v", docStr, err)
   265  		} else if doc.Amount.String() != s {
   266  			t.Errorf("expected %s, got %s (%s, %d)",
   267  				s, doc.Amount.String(),
   268  				doc.Amount.value.String(), doc.Amount.exp)
   269  		}
   270  
   271  		out, err := xml.Marshal(&doc)
   272  		if err != nil {
   273  			t.Errorf("error marshaling %+v: %v", doc, err)
   274  		} else if string(out) != docStr {
   275  			t.Errorf("expected %s, got %s", docStr, string(out))
   276  		}
   277  	}
   278  }
   279  
   280  func TestBadXML(t *testing.T) {
   281  	for _, testCase := range []string{
   282  		"o_o",
   283  		"<abc",
   284  		"<account><amount>7",
   285  		`<html><body></body></html>`,
   286  		`<account><amount></amount></account>`,
   287  		`<account><amount>nope</amount></account>`,
   288  		`0.333`,
   289  	} {
   290  		var doc struct {
   291  			XMLName xml.Name `xml:"account"`
   292  			Amount  Decimal  `xml:"amount"`
   293  		}
   294  		err := xml.Unmarshal([]byte(testCase), &doc)
   295  		if err == nil {
   296  			t.Errorf("expected error, got %+v", doc)
   297  		}
   298  	}
   299  }
   300  
   301  func TestDecimal_rescale(t *testing.T) {
   302  	type Inp struct {
   303  		int     int64
   304  		exp     int32
   305  		rescale int32
   306  	}
   307  	tests := map[Inp]string{
   308  		Inp{1234, -3, -5}: "1.234",
   309  		Inp{1234, -3, 0}:  "1.000",
   310  		Inp{1234, 3, 0}:   "1234000",
   311  		Inp{1234, -4, -4}: "0.1234",
   312  	}
   313  
   314  	// add negatives
   315  	for p, s := range tests {
   316  		if p.int > 0 {
   317  			tests[Inp{-p.int, p.exp, p.rescale}] = "-" + s
   318  		}
   319  	}
   320  
   321  	for input, s := range tests {
   322  		d := NewDecimalFromInt(input.int, input.exp).rescale(input.rescale)
   323  
   324  		if d.String() != s {
   325  			t.Errorf("expected %s, got %s (%s, %d)",
   326  				s, d.String(),
   327  				d.value.String(), d.exp)
   328  		}
   329  
   330  		// test StringScaled
   331  		s2 := NewDecimalFromInt(input.int, input.exp).StringScaled(input.rescale)
   332  		if s2 != s {
   333  			t.Errorf("expected %s, got %s", s, s2)
   334  		}
   335  	}
   336  }
   337  
   338  func TestDecimal_Floor(t *testing.T) {
   339  	type testData struct {
   340  		input    string
   341  		expected string
   342  	}
   343  	tests := []testData{
   344  		{"1.999", "1"},
   345  		{"1", "1"},
   346  		{"1.01", "1"},
   347  		{"0", "0"},
   348  		{"0.9", "0"},
   349  		{"0.1", "0"},
   350  		{"-0.9", "-1"},
   351  		{"-0.1", "-1"},
   352  		{"-1.00", "-1"},
   353  		{"-1.01", "-2"},
   354  		{"-1.999", "-2"},
   355  	}
   356  	for _, test := range tests {
   357  		d, _ := ParseDecimal(test.input)
   358  		expected, _ := ParseDecimal(test.expected)
   359  		got := d.Floor()
   360  		if !got.Equals(expected) {
   361  			t.Errorf("Floor(%s): got %s, expected %s", d, got, expected)
   362  		}
   363  	}
   364  }
   365  
   366  func TestDecimal_Ceil(t *testing.T) {
   367  	type testData struct {
   368  		input    string
   369  		expected string
   370  	}
   371  	tests := []testData{
   372  		{"1.999", "2"},
   373  		{"1", "1"},
   374  		{"1.01", "2"},
   375  		{"0", "0"},
   376  		{"0.9", "1"},
   377  		{"0.1", "1"},
   378  		{"-0.9", "0"},
   379  		{"-0.1", "0"},
   380  		{"-1.00", "-1"},
   381  		{"-1.01", "-1"},
   382  		{"-1.999", "-1"},
   383  	}
   384  	for _, test := range tests {
   385  		d, _ := ParseDecimal(test.input)
   386  		expected, _ := ParseDecimal(test.expected)
   387  		got := d.Ceil()
   388  		if !got.Equals(expected) {
   389  			t.Errorf("Ceil(%s): got %s, expected %s", d, got, expected)
   390  		}
   391  	}
   392  }
   393  
   394  func TestDecimal_RoundAndStringFixed(t *testing.T) {
   395  	type testData struct {
   396  		input         string
   397  		places        int32
   398  		expected      string
   399  		expectedFixed string
   400  	}
   401  	tests := []testData{
   402  		{"1.454", 0, "1", ""},
   403  		{"1.454", 1, "1.5", ""},
   404  		{"1.454", 2, "1.45", ""},
   405  		{"1.454", 3, "1.454", ""},
   406  		{"1.454", 4, "1.454", "1.4540"},
   407  		{"1.454", 5, "1.454", "1.45400"},
   408  		{"1.554", 0, "2", ""},
   409  		{"1.554", 1, "1.6", ""},
   410  		{"1.554", 2, "1.55", ""},
   411  		{"0.554", 0, "1", ""},
   412  		{"0.454", 0, "0", ""},
   413  		{"0.454", 5, "0.454", "0.45400"},
   414  		{"0", 0, "0", ""},
   415  		{"0", 1, "0", "0.0"},
   416  		{"0", 2, "0", "0.00"},
   417  		{"0", -1, "0", ""},
   418  		{"5", 2, "5", "5.00"},
   419  		{"5", 1, "5", "5.0"},
   420  		{"5", 0, "5", ""},
   421  		{"500", 2, "500", "500.00"},
   422  		{"545", -1, "550", ""},
   423  		{"545", -2, "500", ""},
   424  		{"545", -3, "1000", ""},
   425  		{"545", -4, "0", ""},
   426  		{"499", -3, "0", ""},
   427  		{"499", -4, "0", ""},
   428  	}
   429  
   430  	// add negative number tests
   431  	for _, test := range tests {
   432  		expected := test.expected
   433  		if expected != "0" {
   434  			expected = "-" + expected
   435  		}
   436  		expectedStr := test.expectedFixed
   437  		if strings.ContainsAny(expectedStr, "123456789") && expectedStr != "" {
   438  			expectedStr = "-" + expectedStr
   439  		}
   440  		tests = append(tests,
   441  			testData{"-" + test.input, test.places, expected, expectedStr})
   442  	}
   443  
   444  	for _, test := range tests {
   445  		d, err := ParseDecimal(test.input)
   446  		if err != nil {
   447  			panic(err)
   448  		}
   449  
   450  		// test Round
   451  		expected, err := ParseDecimal(test.expected)
   452  		if err != nil {
   453  			panic(err)
   454  		}
   455  		got := d.Round(test.places)
   456  		if !got.Equals(expected) {
   457  			t.Errorf("Rounding %s to %d places, got %s, expected %s",
   458  				d, test.places, got, expected)
   459  		}
   460  		// test StringFixed
   461  		if test.expectedFixed == "" {
   462  			test.expectedFixed = test.expected
   463  		}
   464  		gotStr := d.StringFixed(test.places)
   465  		if gotStr != test.expectedFixed {
   466  			t.Errorf("(%s).StringFixed(%d): got %s, expected %s",
   467  				d, test.places, gotStr, test.expectedFixed)
   468  		}
   469  	}
   470  }
   471  
   472  func TestDecimal_Uninitialized(t *testing.T) {
   473  	a := Decimal{}
   474  	b := Decimal{}
   475  
   476  	decs := []Decimal{
   477  		a,
   478  		a.rescale(10),
   479  		a.Abs(),
   480  		a.Add(b),
   481  		a.Sub(b),
   482  		a.Mul(b),
   483  		a.Floor(),
   484  		a.Ceil(),
   485  	}
   486  
   487  	for _, d := range decs {
   488  		if d.String() != "0" {
   489  			t.Errorf("expected 0, got %s", d.String())
   490  		}
   491  		if d.StringFixed(3) != "0.000" {
   492  			t.Errorf("expected 0, got %s", d.StringFixed(3))
   493  		}
   494  		if d.StringScaled(-2) != "0" {
   495  			t.Errorf("expected 0, got %s", d.StringScaled(-2))
   496  		}
   497  	}
   498  
   499  	if a.Cmp(b) != 0 {
   500  		t.Errorf("a != b")
   501  	}
   502  	if a.Exponent() != 0 {
   503  		t.Errorf("a.Exponent() != 0")
   504  	}
   505  	if a.IntPart() != 0 {
   506  		t.Errorf("a.IntPar() != 0")
   507  	}
   508  	f, _ := a.Float64()
   509  	if f != 0 {
   510  		t.Errorf("a.Float64() != 0")
   511  	}
   512  	if a.Rat().RatString() != "0" {
   513  		t.Errorf("a.Rat() != 0, got %s", a.Rat().RatString())
   514  	}
   515  }
   516  
   517  func TestDecimal_Add(t *testing.T) {
   518  	type Inp struct {
   519  		a string
   520  		b string
   521  	}
   522  
   523  	inputs := map[Inp]string{
   524  		Inp{"2", "3"}:                     "5",
   525  		Inp{"2454495034", "3451204593"}:   "5905699627",
   526  		Inp{"24544.95034", ".3451204593"}: "24545.2954604593",
   527  		Inp{".1", ".1"}:                   "0.2",
   528  		Inp{".1", "-.1"}:                  "0.0",
   529  		Inp{"0", "1.001"}:                 "1.001",
   530  	}
   531  
   532  	for inp, res := range inputs {
   533  		a, err := ParseDecimal(inp.a)
   534  		if err != nil {
   535  			t.FailNow()
   536  		}
   537  		b, err := ParseDecimal(inp.b)
   538  		if err != nil {
   539  			t.FailNow()
   540  		}
   541  		c := a.Add(b)
   542  		if c.String() != res {
   543  			t.Errorf("expected %s, got %s", res, c.String())
   544  		}
   545  	}
   546  }
   547  
   548  func TestDecimal_Sub(t *testing.T) {
   549  	type Inp struct {
   550  		a string
   551  		b string
   552  	}
   553  
   554  	inputs := map[Inp]string{
   555  		Inp{"2", "3"}:                     "-1",
   556  		Inp{"12", "3"}:                    "9",
   557  		Inp{"-2", "9"}:                    "-11",
   558  		Inp{"2454495034", "3451204593"}:   "-996709559",
   559  		Inp{"24544.95034", ".3451204593"}: "24544.6052195407",
   560  		Inp{".1", "-.1"}:                  "0.2",
   561  		Inp{".1", ".1"}:                   "0.0",
   562  		Inp{"0", "1.001"}:                 "-1.001",
   563  		Inp{"1.001", "0"}:                 "1.001",
   564  		Inp{"2.3", ".3"}:                  "2.0",
   565  	}
   566  
   567  	for inp, res := range inputs {
   568  		a, err := ParseDecimal(inp.a)
   569  		if err != nil {
   570  			t.FailNow()
   571  		}
   572  		b, err := ParseDecimal(inp.b)
   573  		if err != nil {
   574  			t.FailNow()
   575  		}
   576  		c := a.Sub(b)
   577  		if c.String() != res {
   578  			t.Errorf("expected %s, got %s", res, c.String())
   579  		}
   580  	}
   581  }
   582  
   583  func TestDecimal_Mul(t *testing.T) {
   584  	type Inp struct {
   585  		a string
   586  		b string
   587  	}
   588  
   589  	inputs := map[Inp]string{
   590  		Inp{"2", "3"}:                     "6",
   591  		Inp{"2454495034", "3451204593"}:   "8470964534836491162",
   592  		Inp{"24544.95034", ".3451204593"}: "8470.964534836491162",
   593  		Inp{".1", ".1"}:                   "0.01",
   594  		Inp{"0", "1.001"}:                 "0.000",
   595  	}
   596  
   597  	for inp, res := range inputs {
   598  		a, err := ParseDecimal(inp.a)
   599  		if err != nil {
   600  			t.FailNow()
   601  		}
   602  		b, err := ParseDecimal(inp.b)
   603  		if err != nil {
   604  			t.FailNow()
   605  		}
   606  		c := a.Mul(b)
   607  		if c.String() != res {
   608  			t.Errorf("expected %s, got %s", res, c.String())
   609  		}
   610  	}
   611  
   612  	// positive scale
   613  	c := NewDecimalFromInt(1234, 5).Mul(NewDecimalFromInt(45, -1))
   614  	if c.String() != "555300000.0" {
   615  		t.Errorf("Expected %s, got %s", "555300000.0", c.String())
   616  	}
   617  }
   618  
   619  func TestDecimal_Div(t *testing.T) {
   620  	type Inp struct {
   621  		a string
   622  		b string
   623  	}
   624  
   625  	inputs := map[Inp]string{
   626  		Inp{"6", "3"}:                            "2.0000",
   627  		Inp{"10", "2"}:                           "5.0000",
   628  		Inp{"2.2", "1.1"}:                        "2.00000",
   629  		Inp{"-2.2", "-1.1"}:                      "2.00000",
   630  		Inp{"12.88", "5.6"}:                      "2.300000",
   631  		Inp{"1023427554493", "43432632"}:         "23563.5629", // rounded
   632  		Inp{"1", "434324545566634"}:              "0.0000",
   633  		Inp{"1", "3"}:                            "0.3333",
   634  		Inp{"2", "3"}:                            "0.6667", // rounded
   635  		Inp{"10000", "3"}:                        "3333.3333",
   636  		Inp{"10234274355545544493", "-3"}:        "-3411424785181848164.3333",
   637  		Inp{"-4612301402398.4753343454", "23.5"}: "-196268144782.91384401469787",
   638  	}
   639  
   640  	for inp, expected := range inputs {
   641  		num, err := ParseDecimal(inp.a)
   642  		if err != nil {
   643  			t.FailNow()
   644  		}
   645  		denom, err := ParseDecimal(inp.b)
   646  		if err != nil {
   647  			t.FailNow()
   648  		}
   649  		got := num.Div(denom)
   650  		if got.String() != expected {
   651  			t.Errorf("expected %s when dividing %v by %v, got %v",
   652  				expected, num, denom, got)
   653  		}
   654  	}
   655  
   656  	type Inp2 struct {
   657  		n    int64
   658  		exp  int32
   659  		n2   int64
   660  		exp2 int32
   661  	}
   662  
   663  	// test code path where exp > 0
   664  	inputs2 := map[Inp2]string{
   665  		Inp2{124, 10, 3, 1}: "41333333333.3333",
   666  		Inp2{124, 10, 3, 0}: "413333333333.3333",
   667  		Inp2{124, 10, 6, 1}: "20666666666.6667",
   668  		Inp2{124, 10, 6, 0}: "206666666666.6667",
   669  		Inp2{10, 10, 10, 1}: "1000000000.0000",
   670  	}
   671  
   672  	for inp, expectedAbs := range inputs2 {
   673  		for i := -1; i <= 1; i += 2 {
   674  			for j := -1; j <= 1; j += 2 {
   675  				n := inp.n * int64(i)
   676  				n2 := inp.n2 * int64(j)
   677  				num := NewDecimalFromInt(n, inp.exp)
   678  				denom := NewDecimalFromInt(n2, inp.exp2)
   679  				expected := expectedAbs
   680  				if i != j {
   681  					expected = "-" + expectedAbs
   682  				}
   683  				got := num.Div(denom)
   684  				if got.String() != expected {
   685  					t.Errorf("expected %s when dividing %v by %v, got %v",
   686  						expected, num, denom, got)
   687  				}
   688  			}
   689  		}
   690  	}
   691  }
   692  
   693  func TestDecimal_Overflow(t *testing.T) {
   694  	if !didPanic(func() { NewDecimalFromInt(1, math.MinInt32).Mul(NewDecimalFromInt(1, math.MinInt32)) }) {
   695  		t.Fatalf("should have gotten an overflow panic")
   696  	}
   697  	if !didPanic(func() { NewDecimalFromInt(1, math.MaxInt32).Mul(NewDecimalFromInt(1, math.MaxInt32)) }) {
   698  		t.Fatalf("should have gotten an overflow panic")
   699  	}
   700  }
   701  
   702  func TestIntPart(t *testing.T) {
   703  	for _, testCase := range []struct {
   704  		Dec     string
   705  		IntPart int64
   706  	}{
   707  		{"0.01", 0},
   708  		{"12.1", 12},
   709  		{"9999.999", 9999},
   710  		{"-32768.01234", -32768},
   711  	} {
   712  		d, err := ParseDecimal(testCase.Dec)
   713  		if err != nil {
   714  			t.Fatal(err)
   715  		}
   716  		if d.IntPart() != testCase.IntPart {
   717  			t.Errorf("expect %d, got %d", testCase.IntPart, d.IntPart())
   718  		}
   719  	}
   720  }
   721  
   722  // old tests after this line
   723  
   724  func TestDecimal_Scale(t *testing.T) {
   725  	a := NewDecimalFromInt(1234, -3)
   726  	if a.Exponent() != -3 {
   727  		t.Errorf("error")
   728  	}
   729  }
   730  
   731  func TestDecimal_Abs1(t *testing.T) {
   732  	a := NewDecimalFromInt(-1234, -4)
   733  	b := NewDecimalFromInt(1234, -4)
   734  
   735  	c := a.Abs()
   736  	if c.Cmp(b) != 0 {
   737  		t.Errorf("error")
   738  	}
   739  }
   740  
   741  func TestDecimal_Abs2(t *testing.T) {
   742  	a := NewDecimalFromInt(-1234, -4)
   743  	b := NewDecimalFromInt(1234, -4)
   744  
   745  	c := b.Abs()
   746  	if c.Cmp(a) == 0 {
   747  		t.Errorf("error")
   748  	}
   749  }
   750  
   751  func TestDecimal_Equal(t *testing.T) {
   752  	a := NewDecimalFromInt(1234, 3)
   753  	b := NewDecimalFromInt(1234, 3)
   754  
   755  	if !a.Equals(b) {
   756  		t.Errorf("%q should equal %q", a, b)
   757  	}
   758  }
   759  
   760  func TestDecimal_ScalesNotEqual(t *testing.T) {
   761  	a := NewDecimalFromInt(1234, 2)
   762  	b := NewDecimalFromInt(1234, 3)
   763  	if a.Equals(b) {
   764  		t.Errorf("%q should not equal %q", a, b)
   765  	}
   766  }
   767  
   768  func TestDecimal_Cmp1(t *testing.T) {
   769  	a := NewDecimalFromInt(123, 3)
   770  	b := NewDecimalFromInt(-1234, 2)
   771  
   772  	if a.Cmp(b) != 1 {
   773  		t.Errorf("Error")
   774  	}
   775  }
   776  
   777  func TestDecimal_Cmp2(t *testing.T) {
   778  	a := NewDecimalFromInt(123, 3)
   779  	b := NewDecimalFromInt(1234, 2)
   780  
   781  	if a.Cmp(b) != -1 {
   782  		t.Errorf("Error")
   783  	}
   784  }
   785  
   786  func TestDecimal_Cmp3(t *testing.T) {
   787  	a := NewDecimalFromInt(2, 0)
   788  	b := NewDecimalFromInt(3, 0)
   789  	if n := a.Div(b).Mul(b).Cmp(a); n != -1 {
   790  		t.Errorf("Error %d", n)
   791  	}
   792  }
   793  
   794  func TestDecimalConvert(t *testing.T) {
   795  	a, err := ConvertToDecimal(1235.3)
   796  	if err != nil || a.String() != "1235.3" {
   797  		t.Error("Error")
   798  	}
   799  	a, err = ConvertToDecimal(1235)
   800  	if err != nil || a.String() != "1235" {
   801  		t.Error("Error")
   802  	}
   803  	a, err = ConvertToDecimal("-234.23")
   804  	if err != nil || a.String() != "-234.23" {
   805  		t.Error("Error")
   806  	}
   807  	a, err = ConvertToDecimal(NewDecimalFromFloat(23.45))
   808  	if err != nil || a.String() != "23.45" {
   809  		t.Error("Error")
   810  	}
   811  }
   812  
   813  func TestDecimalComplex(t *testing.T) {
   814  	result := NewDecimalFromFloat(3).Div(NewDecimalFromFloat(5)).Mul(NewDecimalFromFloat(15)).String()
   815  	if result != "9.0000" {
   816  		t.Errorf("got %s", result)
   817  	}
   818  	result = NewDecimalFromFloat(3.553).Mul(NewDecimalFromFloat(2.34)).Div(NewDecimalFromFloat(24.8)).String()
   819  	if result != "0.335242742" {
   820  		t.Errorf("got %s", result)
   821  	}
   822  	result = NewDecimalFromFloat(4.67).Div(NewDecimalFromFloat(32.099)).Div(NewDecimalFromFloat(9.32)).String()
   823  	if result != "0.0156102359" {
   824  		t.Errorf("got %s", result)
   825  	}
   826  	a, _ := ParseDecimal("23.342983749572929843520960646")
   827  	b, _ := ParseDecimal("23.234122323452345412351235351")
   828  	result = a.Mul(b).String()
   829  	if result != "542.353739831937742603572001528416" {
   830  		t.Errorf("got %s", result)
   831  	}
   832  }
   833  
   834  func TestDecimalRoundTruncateFragDigits(t *testing.T) {
   835  	a, err := ConvertToDecimal("12.3456")
   836  	if err != nil || a.fracDigits != 4 {
   837  		t.Error("Error")
   838  	}
   839  	a = a.Truncate(3)
   840  	if a.fracDigits != 3 {
   841  		t.Error("Error")
   842  	}
   843  	if a.String() != "12.345" {
   844  		t.Error("Error")
   845  	}
   846  	a = a.Round(2)
   847  	if a.fracDigits != 2 {
   848  		t.Error("Error")
   849  	}
   850  	if a.String() != "12.35" {
   851  		t.Error("Error")
   852  	}
   853  }
   854  
   855  func didPanic(f func()) bool {
   856  	ret := false
   857  	func() {
   858  
   859  		defer func() {
   860  			if message := recover(); message != nil {
   861  				ret = true
   862  			}
   863  		}()
   864  
   865  		// call the target function
   866  		f()
   867  
   868  	}()
   869  
   870  	return ret
   871  }
   872  
   873  func TestDecimalScientificNotation(t *testing.T) {
   874  	tbl := []struct {
   875  		Input    string
   876  		Expected float64
   877  	}{
   878  		{"314e-2", 3.14},
   879  		{"1e2", 100},
   880  		{"2E-1", 0.2},
   881  		{"2E0", 2},
   882  		{"2.2E-1", 0.22},
   883  	}
   884  
   885  	for _, c := range tbl {
   886  		n, err := ParseDecimal(c.Input)
   887  		if err != nil {
   888  			t.Error(err)
   889  		}
   890  
   891  		f, _ := n.Float64()
   892  		if f != c.Expected {
   893  			t.Errorf("%f != %f", f, c.Expected)
   894  		}
   895  	}
   896  
   897  	tblErr := []string{
   898  		"12ee",
   899  		"ae10",
   900  		"12e1a",
   901  		"12e1.2",
   902  		"e1",
   903  	}
   904  
   905  	for _, c := range tblErr {
   906  		_, err := ParseDecimal(c)
   907  		if err == nil {
   908  			t.Errorf("%s must be invalid decimal", c)
   909  		}
   910  	}
   911  }