...

Source file src/github.com/jackc/pgtype/numeric_test.go

Documentation: github.com/jackc/pgtype

     1  package pgtype_test
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"math/rand"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/jackc/pgtype"
    11  	"github.com/jackc/pgtype/testutil"
    12  )
    13  
    14  // For test purposes only. Note that it does not normalize values. e.g. (Int: 1, Exp: 3) will not equal (Int: 1000, Exp: 0)
    15  func numericEqual(left, right *pgtype.Numeric) bool {
    16  	return left.Status == right.Status &&
    17  		left.Exp == right.Exp &&
    18  		((left.Int == nil && right.Int == nil) || (left.Int != nil && right.Int != nil && left.Int.Cmp(right.Int) == 0)) &&
    19  		left.NaN == right.NaN
    20  }
    21  
    22  // For test purposes only.
    23  func numericNormalizedEqual(left, right *pgtype.Numeric) bool {
    24  	if left.Status != right.Status {
    25  		return false
    26  	}
    27  
    28  	normLeft := &pgtype.Numeric{Int: (&big.Int{}).Set(left.Int), Status: left.Status}
    29  	normRight := &pgtype.Numeric{Int: (&big.Int{}).Set(right.Int), Status: right.Status}
    30  
    31  	if left.Exp < right.Exp {
    32  		mul := (&big.Int{}).Exp(big.NewInt(10), big.NewInt(int64(right.Exp-left.Exp)), nil)
    33  		normRight.Int.Mul(normRight.Int, mul)
    34  	} else if left.Exp > right.Exp {
    35  		mul := (&big.Int{}).Exp(big.NewInt(10), big.NewInt(int64(left.Exp-right.Exp)), nil)
    36  		normLeft.Int.Mul(normLeft.Int, mul)
    37  	}
    38  
    39  	return normLeft.Int.Cmp(normRight.Int) == 0
    40  }
    41  
    42  func mustParseBigInt(t *testing.T, src string) *big.Int {
    43  	i := &big.Int{}
    44  	if _, ok := i.SetString(src, 10); !ok {
    45  		t.Fatalf("could not parse big.Int: %s", src)
    46  	}
    47  	return i
    48  }
    49  
    50  func TestNumericNormalize(t *testing.T) {
    51  	testutil.TestSuccessfulNormalize(t, []testutil.NormalizeTest{
    52  		{
    53  			SQL:   "select '0'::numeric",
    54  			Value: &pgtype.Numeric{Int: big.NewInt(0), Exp: 0, Status: pgtype.Present},
    55  		},
    56  		{
    57  			SQL:   "select '1'::numeric",
    58  			Value: &pgtype.Numeric{Int: big.NewInt(1), Exp: 0, Status: pgtype.Present},
    59  		},
    60  		{
    61  			SQL:   "select '10.00'::numeric",
    62  			Value: &pgtype.Numeric{Int: big.NewInt(1000), Exp: -2, Status: pgtype.Present},
    63  		},
    64  		{
    65  			SQL:   "select '1e-3'::numeric",
    66  			Value: &pgtype.Numeric{Int: big.NewInt(1), Exp: -3, Status: pgtype.Present},
    67  		},
    68  		{
    69  			SQL:   "select '-1'::numeric",
    70  			Value: &pgtype.Numeric{Int: big.NewInt(-1), Exp: 0, Status: pgtype.Present},
    71  		},
    72  		{
    73  			SQL:   "select '10000'::numeric",
    74  			Value: &pgtype.Numeric{Int: big.NewInt(1), Exp: 4, Status: pgtype.Present},
    75  		},
    76  		{
    77  			SQL:   "select '3.14'::numeric",
    78  			Value: &pgtype.Numeric{Int: big.NewInt(314), Exp: -2, Status: pgtype.Present},
    79  		},
    80  		{
    81  			SQL:   "select '1.1'::numeric",
    82  			Value: &pgtype.Numeric{Int: big.NewInt(11), Exp: -1, Status: pgtype.Present},
    83  		},
    84  		{
    85  			SQL:   "select '100010001'::numeric",
    86  			Value: &pgtype.Numeric{Int: big.NewInt(100010001), Exp: 0, Status: pgtype.Present},
    87  		},
    88  		{
    89  			SQL:   "select '100010001.0001'::numeric",
    90  			Value: &pgtype.Numeric{Int: big.NewInt(1000100010001), Exp: -4, Status: pgtype.Present},
    91  		},
    92  		{
    93  			SQL: "select '4237234789234789289347892374324872138321894178943189043890124832108934.43219085471578891547854892438945012347981'::numeric",
    94  			Value: &pgtype.Numeric{
    95  				Int:    mustParseBigInt(t, "423723478923478928934789237432487213832189417894318904389012483210893443219085471578891547854892438945012347981"),
    96  				Exp:    -41,
    97  				Status: pgtype.Present,
    98  			},
    99  		},
   100  		{
   101  			SQL: "select '0.8925092023480223478923478978978937897879595901237890234789243679037419057877231734823098432903527585734549035904590854890345905434578345789347890402348952348905890489054234237489234987723894789234'::numeric",
   102  			Value: &pgtype.Numeric{
   103  				Int:    mustParseBigInt(t, "8925092023480223478923478978978937897879595901237890234789243679037419057877231734823098432903527585734549035904590854890345905434578345789347890402348952348905890489054234237489234987723894789234"),
   104  				Exp:    -196,
   105  				Status: pgtype.Present,
   106  			},
   107  		},
   108  		{
   109  			SQL: "select '0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123'::numeric",
   110  			Value: &pgtype.Numeric{
   111  				Int:    mustParseBigInt(t, "123"),
   112  				Exp:    -186,
   113  				Status: pgtype.Present,
   114  			},
   115  		},
   116  	})
   117  }
   118  
   119  func TestNumericTranscode(t *testing.T) {
   120  	max := new(big.Int).Exp(big.NewInt(10), big.NewInt(147454), nil)
   121  	max.Add(max, big.NewInt(1))
   122  	longestNumeric := &pgtype.Numeric{Int: max, Exp: -16383, Status: pgtype.Present}
   123  
   124  	testutil.TestSuccessfulTranscodeEqFunc(t, "numeric", []interface{}{
   125  		&pgtype.Numeric{NaN: true, Status: pgtype.Present},
   126  		&pgtype.Numeric{InfinityModifier: pgtype.Infinity, Status: pgtype.Present},
   127  		&pgtype.Numeric{InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present},
   128  
   129  		&pgtype.Numeric{Int: big.NewInt(0), Exp: 0, Status: pgtype.Present},
   130  		&pgtype.Numeric{Int: big.NewInt(1), Exp: 0, Status: pgtype.Present},
   131  		&pgtype.Numeric{Int: big.NewInt(-1), Exp: 0, Status: pgtype.Present},
   132  		&pgtype.Numeric{Int: big.NewInt(1), Exp: 6, Status: pgtype.Present},
   133  
   134  		// preserves significant zeroes
   135  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -1, Status: pgtype.Present},
   136  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -2, Status: pgtype.Present},
   137  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -3, Status: pgtype.Present},
   138  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -4, Status: pgtype.Present},
   139  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -5, Status: pgtype.Present},
   140  		&pgtype.Numeric{Int: big.NewInt(10000000), Exp: -6, Status: pgtype.Present},
   141  
   142  		&pgtype.Numeric{Int: big.NewInt(314), Exp: -2, Status: pgtype.Present},
   143  		&pgtype.Numeric{Int: big.NewInt(123), Exp: -7, Status: pgtype.Present},
   144  		&pgtype.Numeric{Int: big.NewInt(123), Exp: -8, Status: pgtype.Present},
   145  		&pgtype.Numeric{Int: big.NewInt(123), Exp: -9, Status: pgtype.Present},
   146  		&pgtype.Numeric{Int: big.NewInt(123), Exp: -1500, Status: pgtype.Present},
   147  		&pgtype.Numeric{Int: mustParseBigInt(t, "2437"), Exp: 23790, Status: pgtype.Present},
   148  		&pgtype.Numeric{Int: mustParseBigInt(t, "243723409723490243842378942378901237502734019231380123"), Exp: 23790, Status: pgtype.Present},
   149  		&pgtype.Numeric{Int: mustParseBigInt(t, "43723409723490243842378942378901237502734019231380123"), Exp: 80, Status: pgtype.Present},
   150  		&pgtype.Numeric{Int: mustParseBigInt(t, "3723409723490243842378942378901237502734019231380123"), Exp: 81, Status: pgtype.Present},
   151  		&pgtype.Numeric{Int: mustParseBigInt(t, "723409723490243842378942378901237502734019231380123"), Exp: 82, Status: pgtype.Present},
   152  		&pgtype.Numeric{Int: mustParseBigInt(t, "23409723490243842378942378901237502734019231380123"), Exp: 83, Status: pgtype.Present},
   153  		&pgtype.Numeric{Int: mustParseBigInt(t, "3409723490243842378942378901237502734019231380123"), Exp: 84, Status: pgtype.Present},
   154  		&pgtype.Numeric{Int: mustParseBigInt(t, "913423409823409243892349028349023482934092340892390101"), Exp: -14021, Status: pgtype.Present},
   155  		&pgtype.Numeric{Int: mustParseBigInt(t, "13423409823409243892349028349023482934092340892390101"), Exp: -90, Status: pgtype.Present},
   156  		&pgtype.Numeric{Int: mustParseBigInt(t, "3423409823409243892349028349023482934092340892390101"), Exp: -91, Status: pgtype.Present},
   157  		&pgtype.Numeric{Int: mustParseBigInt(t, "423409823409243892349028349023482934092340892390101"), Exp: -92, Status: pgtype.Present},
   158  		&pgtype.Numeric{Int: mustParseBigInt(t, "23409823409243892349028349023482934092340892390101"), Exp: -93, Status: pgtype.Present},
   159  		&pgtype.Numeric{Int: mustParseBigInt(t, "3409823409243892349028349023482934092340892390101"), Exp: -94, Status: pgtype.Present},
   160  
   161  		longestNumeric,
   162  
   163  		&pgtype.Numeric{Status: pgtype.Null},
   164  	}, func(aa, bb interface{}) bool {
   165  		a := aa.(pgtype.Numeric)
   166  		b := bb.(pgtype.Numeric)
   167  
   168  		return numericEqual(&a, &b)
   169  	})
   170  
   171  }
   172  
   173  func TestNumericTranscodeFuzz(t *testing.T) {
   174  	r := rand.New(rand.NewSource(0))
   175  	max := &big.Int{}
   176  	max.SetString("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 10)
   177  
   178  	values := make([]interface{}, 0, 2000)
   179  	for i := 0; i < 10; i++ {
   180  		for j := -50; j < 50; j++ {
   181  			num := (&big.Int{}).Rand(r, max)
   182  			negNum := &big.Int{}
   183  			negNum.Neg(num)
   184  			values = append(values, &pgtype.Numeric{Int: num, Exp: int32(j), Status: pgtype.Present})
   185  			values = append(values, &pgtype.Numeric{Int: negNum, Exp: int32(j), Status: pgtype.Present})
   186  		}
   187  	}
   188  
   189  	testutil.TestSuccessfulTranscodeEqFunc(t, "numeric", values,
   190  		func(aa, bb interface{}) bool {
   191  			a := aa.(pgtype.Numeric)
   192  			b := bb.(pgtype.Numeric)
   193  
   194  			return numericNormalizedEqual(&a, &b)
   195  		})
   196  }
   197  
   198  func TestNumericSet(t *testing.T) {
   199  	successfulTests := []struct {
   200  		source interface{}
   201  		result *pgtype.Numeric
   202  	}{
   203  		{source: float32(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   204  		{source: float32(math.Copysign(0, -1)), result: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Present}},
   205  		{source: float64(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   206  		{source: float64(math.Copysign(0, -1)), result: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Present}},
   207  		{source: int8(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   208  		{source: int16(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   209  		{source: int32(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   210  		{source: int64(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   211  		{source: int8(-1), result: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}},
   212  		{source: int16(-1), result: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}},
   213  		{source: int32(-1), result: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}},
   214  		{source: int64(-1), result: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}},
   215  		{source: uint8(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   216  		{source: uint16(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   217  		{source: uint32(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   218  		{source: uint64(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   219  		{source: "1", result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   220  		{source: _int8(1), result: &pgtype.Numeric{Int: big.NewInt(1), Status: pgtype.Present}},
   221  		{source: float64(1000), result: &pgtype.Numeric{Int: big.NewInt(1), Exp: 3, Status: pgtype.Present}},
   222  		{source: float64(1234), result: &pgtype.Numeric{Int: big.NewInt(1234), Exp: 0, Status: pgtype.Present}},
   223  		{source: float64(12345678900), result: &pgtype.Numeric{Int: big.NewInt(123456789), Exp: 2, Status: pgtype.Present}},
   224  		{source: float64(12345.678901), result: &pgtype.Numeric{Int: big.NewInt(12345678901), Exp: -6, Status: pgtype.Present}},
   225  		{source: math.NaN(), result: &pgtype.Numeric{Int: nil, Exp: 0, Status: pgtype.Present, NaN: true}},
   226  		{source: float32(math.NaN()), result: &pgtype.Numeric{Int: nil, Exp: 0, Status: pgtype.Present, NaN: true}},
   227  		{source: pgtype.Infinity, result: &pgtype.Numeric{InfinityModifier: pgtype.Infinity, Status: pgtype.Present}},
   228  		{source: math.Inf(1), result: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.Infinity}},
   229  		{source: float32(math.Inf(1)), result: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.Infinity}},
   230  		{source: pgtype.NegativeInfinity, result: &pgtype.Numeric{InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}},
   231  		{source: math.Inf(-1), result: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.NegativeInfinity}},
   232  		{source: float32(math.Inf(1)), result: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.Infinity}},
   233  	}
   234  
   235  	for i, tt := range successfulTests {
   236  		r := &pgtype.Numeric{}
   237  		err := r.Set(tt.source)
   238  		if err != nil {
   239  			t.Errorf("%d: %v", i, err)
   240  		}
   241  
   242  		if !numericEqual(r, tt.result) {
   243  			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
   244  		}
   245  	}
   246  }
   247  
   248  func TestNumericAssignTo(t *testing.T) {
   249  	var i8 int8
   250  	var i16 int16
   251  	var i32 int32
   252  	var i64 int64
   253  	var i int
   254  	var ui8 uint8
   255  	var ui16 uint16
   256  	var ui32 uint32
   257  	var ui64 uint64
   258  	var ui uint
   259  	var pi8 *int8
   260  	var _i8 _int8
   261  	var _pi8 *_int8
   262  	var f32 float32
   263  	var f64 float64
   264  	var pf32 *float32
   265  	var pf64 *float64
   266  	var br = new(big.Rat)
   267  
   268  	simpleTests := []struct {
   269  		src      *pgtype.Numeric
   270  		dst      interface{}
   271  		expected interface{}
   272  	}{
   273  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f32, expected: float32(42)},
   274  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &f64, expected: float64(42)},
   275  		{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: -1, Status: pgtype.Present}, dst: &f32, expected: float32(4.2)},
   276  		{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: -1, Status: pgtype.Present}, dst: &f64, expected: float64(4.2)},
   277  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i16, expected: int16(42)},
   278  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i32, expected: int32(42)},
   279  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i64, expected: int64(42)},
   280  		{src: &pgtype.Numeric{Int: big.NewInt(42), Exp: 3, Status: pgtype.Present}, dst: &i64, expected: int64(42000)},
   281  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &i, expected: int(42)},
   282  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui8, expected: uint8(42)},
   283  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui16, expected: uint16(42)},
   284  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui32, expected: uint32(42)},
   285  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui64, expected: uint64(42)},
   286  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &ui, expected: uint(42)},
   287  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &_i8, expected: _int8(42)},
   288  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Null}, dst: &pi8, expected: ((*int8)(nil))},
   289  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Null}, dst: &_pi8, expected: ((*_int8)(nil))},
   290  		{src: &pgtype.Numeric{Int: big.NewInt(1006), Exp: -2, Status: pgtype.Present}, dst: &f64, expected: float64(10.06)}, // https://github.com/jackc/pgtype/issues/27
   291  		{src: &pgtype.Numeric{Status: pgtype.Present, NaN: true}, dst: &f64, expected: math.NaN()},
   292  		{src: &pgtype.Numeric{Status: pgtype.Present, NaN: true}, dst: &f32, expected: float32(math.NaN())},
   293  		{src: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.Infinity}, dst: &f64, expected: math.Inf(1)},
   294  		{src: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.Infinity}, dst: &f32, expected: float32(math.Inf(1))},
   295  		{src: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.NegativeInfinity}, dst: &f64, expected: math.Inf(-1)},
   296  		{src: &pgtype.Numeric{Status: pgtype.Present, InfinityModifier: pgtype.NegativeInfinity}, dst: &f32, expected: float32(math.Inf(-1))},
   297  		{src: &pgtype.Numeric{Int: big.NewInt(-1023), Exp: -2, Status: pgtype.Present}, dst: br, expected: big.NewRat(-1023, 100)},
   298  		{src: &pgtype.Numeric{Int: big.NewInt(-1023), Exp: 2, Status: pgtype.Present}, dst: br, expected: big.NewRat(-102300, 1)},
   299  		{src: &pgtype.Numeric{Int: big.NewInt(23), Exp: 0, Status: pgtype.Present}, dst: br, expected: big.NewRat(23, 1)},
   300  	}
   301  
   302  	for i, tt := range simpleTests {
   303  		err := tt.src.AssignTo(tt.dst)
   304  		if err != nil {
   305  			t.Errorf("%d: %v", i, err)
   306  		}
   307  
   308  		dst := reflect.ValueOf(tt.dst).Elem().Interface()
   309  		switch dstTyped := dst.(type) {
   310  		case float32:
   311  			nanExpected := math.IsNaN(float64(tt.expected.(float32)))
   312  			if nanExpected && !math.IsNaN(float64(dstTyped)) {
   313  				t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   314  			} else if !nanExpected && dst != tt.expected {
   315  				t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   316  			}
   317  		case float64:
   318  			nanExpected := math.IsNaN(tt.expected.(float64))
   319  			if nanExpected && !math.IsNaN(dstTyped) {
   320  				t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   321  			} else if !nanExpected && dst != tt.expected {
   322  				t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   323  			}
   324  		case big.Rat:
   325  			if (&dstTyped).Cmp(tt.expected.(*big.Rat)) != 0 {
   326  				t.Errorf("%d: expected %v to assign %v, but result was %v",
   327  					i, tt.src, tt.expected, dst)
   328  			}
   329  		default:
   330  			if dst != tt.expected {
   331  				t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   332  			}
   333  		}
   334  	}
   335  
   336  	pointerAllocTests := []struct {
   337  		src      *pgtype.Numeric
   338  		dst      interface{}
   339  		expected interface{}
   340  	}{
   341  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &pf32, expected: float32(42)},
   342  		{src: &pgtype.Numeric{Int: big.NewInt(42), Status: pgtype.Present}, dst: &pf64, expected: float64(42)},
   343  	}
   344  
   345  	for i, tt := range pointerAllocTests {
   346  		err := tt.src.AssignTo(tt.dst)
   347  		if err != nil {
   348  			t.Errorf("%d: %v", i, err)
   349  		}
   350  
   351  		if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
   352  			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
   353  		}
   354  	}
   355  
   356  	errorTests := []struct {
   357  		src *pgtype.Numeric
   358  		dst interface{}
   359  	}{
   360  		{src: &pgtype.Numeric{Int: big.NewInt(150), Status: pgtype.Present}, dst: &i8},
   361  		{src: &pgtype.Numeric{Int: big.NewInt(40000), Status: pgtype.Present}, dst: &i16},
   362  		{src: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}, dst: &ui8},
   363  		{src: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}, dst: &ui16},
   364  		{src: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}, dst: &ui32},
   365  		{src: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}, dst: &ui64},
   366  		{src: &pgtype.Numeric{Int: big.NewInt(-1), Status: pgtype.Present}, dst: &ui},
   367  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Null}, dst: &i32},
   368  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Null}, dst: br},
   369  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Present, NaN: true}, dst: br},
   370  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Present, InfinityModifier: pgtype.Infinity}, dst: br},
   371  		{src: &pgtype.Numeric{Int: big.NewInt(0), Status: pgtype.Present, InfinityModifier: pgtype.NegativeInfinity}, dst: br},
   372  	}
   373  
   374  	for i, tt := range errorTests {
   375  		err := tt.src.AssignTo(tt.dst)
   376  		if err == nil {
   377  			t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
   378  		}
   379  	}
   380  }
   381  
   382  func TestNumericEncodeDecodeBinary(t *testing.T) {
   383  	ci := pgtype.NewConnInfo()
   384  	tests := []interface{}{
   385  		123,
   386  		0.000012345,
   387  		1.00002345,
   388  		math.NaN(),
   389  		float32(math.NaN()),
   390  		math.Inf(1),
   391  		float32(math.Inf(1)),
   392  		math.Inf(-1),
   393  		float32(math.Inf(-1)),
   394  	}
   395  
   396  	for i, tt := range tests {
   397  		toString := func(n *pgtype.Numeric) string {
   398  			ci := pgtype.NewConnInfo()
   399  			text, err := n.EncodeText(ci, nil)
   400  			if err != nil {
   401  				t.Errorf("%d (EncodeText): %v", i, err)
   402  			}
   403  			return string(text)
   404  		}
   405  		numeric := &pgtype.Numeric{}
   406  		numeric.Set(tt)
   407  
   408  		encoded, err := numeric.EncodeBinary(ci, nil)
   409  		if err != nil {
   410  			t.Errorf("%d (EncodeBinary): %v", i, err)
   411  		}
   412  		decoded := &pgtype.Numeric{}
   413  		err = decoded.DecodeBinary(ci, encoded)
   414  		if err != nil {
   415  			t.Errorf("%d (DecodeBinary): %v", i, err)
   416  		}
   417  
   418  		text0 := toString(numeric)
   419  		text1 := toString(decoded)
   420  
   421  		if text0 != text1 {
   422  			t.Errorf("%d: expected %v to equal to %v, but doesn't", i, text0, text1)
   423  		}
   424  	}
   425  }
   426  

View as plain text