// Copyright 2020-2026 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package decimal

import (
	"fmt"
	"math"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var nzero = func() float64 {
	zero := float64(0)
	return -zero
}()

func TestParse(t *testing.T) {
	t.Parallel()

	type m map[string]string
	tests := []struct {
		in         string
		invalid    bool
		want, ints m
		u64s, f64s m
	}{
		{
			in: "0",
			want: m{
				"%f":  "0.000000",
				"%F":  "0.000000",
				"%+f": "+0.000000",
				"%+F": "+0.000000",
				"%e":  "0.000000e+00",
				"%E":  "0.000000E+00",
				"%+e": "+0.000000e+00",
				"%+E": "+0.000000E+00",
				"%g":  "0",
				"%G":  "0",
				"%+g": "+0",
				"%+G": "+0",
			},
			f64s: m{"%g": "0"},
		},

		{
			in: "0x00",
			want: m{
				"%f":  "0.000000",
				"%F":  "0.000000",
				"%+f": "+0.000000",
				"%+F": "+0.000000",
				"%e":  "0.000000e+00",
				"%E":  "0.000000E+00",
				"%+e": "+0.000000e+00",
				"%+E": "+0.000000E+00",
				"%g":  "0",
				"%G":  "0",
				"%+g": "+0",
				"%+G": "+0",
			},
			f64s: m{"%g": "0"},
		},

		{
			in: "-0",
			want: m{
				"%f":  "-0.000000",
				"%F":  "-0.000000",
				"%+f": "-0.000000",
				"%+F": "-0.000000",
				"%e":  "-0.000000e+00",
				"%E":  "-0.000000E+00",
				"%+e": "-0.000000e+00",
				"%+E": "-0.000000E+00",
				"%g":  "-0",
				"%G":  "-0",
				"%+g": "-0",
				"%+G": "-0",
			},
			f64s: m{"%g": "-0"},
		},

		{
			in: "-0x00",
			want: m{
				"%f":  "-0.000000",
				"%F":  "-0.000000",
				"%+f": "-0.000000",
				"%+F": "-0.000000",
				"%e":  "-0.000000e+00",
				"%E":  "-0.000000E+00",
				"%+e": "-0.000000e+00",
				"%+E": "-0.000000E+00",
				"%g":  "-0",
				"%G":  "-0",
				"%+g": "-0",
				"%+G": "-0",
			},
			f64s: m{"%g": "-0"},
		},

		{
			in: "1",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "0x01",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "-1",
			want: m{
				"%f":  "-1.000000",
				"%F":  "-1.000000",
				"%+f": "-1.000000",
				"%+F": "-1.000000",
				"%e":  "-1.000000e+00",
				"%E":  "-1.000000E+00",
				"%+e": "-1.000000e+00",
				"%+E": "-1.000000E+00",
				"%g":  "-1",
				"%G":  "-1",
				"%+g": "-1",
				"%+G": "-1",
			},
			f64s: m{"%g": "-1"},
		},

		{
			in: "-0x01",
			want: m{
				"%f":  "-1.000000",
				"%F":  "-1.000000",
				"%+f": "-1.000000",
				"%+F": "-1.000000",
				"%e":  "-1.000000e+00",
				"%E":  "-1.000000E+00",
				"%+e": "-1.000000e+00",
				"%+E": "-1.000000E+00",
				"%g":  "-1",
				"%G":  "-1",
				"%+g": "-1",
				"%+G": "-1",
			},
			f64s: m{"%g": "-1"},
		},

		{
			in: "+1",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "+0x01",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "42",
			want: m{
				"%f":  "42.000000",
				"%F":  "42.000000",
				"%+f": "+42.000000",
				"%+F": "+42.000000",
				"%e":  "4.200000e+01",
				"%E":  "4.200000E+01",
				"%+e": "+4.200000e+01",
				"%+E": "+4.200000E+01",
				"%g":  "42",
				"%G":  "42",
				"%+g": "+42",
				"%+G": "+42",
			},
			f64s: m{"%g": "42"},
		},

		{
			in: "0x42",
			want: m{
				"%f":  "66.000000",
				"%F":  "66.000000",
				"%+f": "+66.000000",
				"%+F": "+66.000000",
				"%e":  "6.600000e+01",
				"%E":  "6.600000E+01",
				"%+e": "+6.600000e+01",
				"%+E": "+6.600000E+01",
				"%g":  "66",
				"%G":  "66",
				"%+g": "+66",
				"%+G": "+66",
			},
			f64s: m{"%g": "66"},
		},

		{
			in: "100",
			want: m{
				"%f":  "100.000000",
				"%F":  "100.000000",
				"%+f": "+100.000000",
				"%+F": "+100.000000",
				"%e":  "1.000000e+02",
				"%E":  "1.000000E+02",
				"%+e": "+1.000000e+02",
				"%+E": "+1.000000E+02",
				"%g":  "100",
				"%G":  "100",
				"%+g": "+100",
				"%+G": "+100",
			},
			f64s: m{"%g": "100"},
		},

		{
			in: "999999",
			want: m{
				"%f":  "999999.000000",
				"%F":  "999999.000000",
				"%+f": "+999999.000000",
				"%+F": "+999999.000000",
				"%e":  "9.999990e+05",
				"%E":  "9.999990E+05",
				"%+e": "+9.999990e+05",
				"%+E": "+9.999990E+05",
				"%g":  "999999",
				"%G":  "999999",
				"%+g": "+999999",
				"%+G": "+999999",
			},
			f64s: m{"%g": "999999"},
		},

		{
			in: "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
			want: m{
				"%f":  "12345678901234567890123456789012345678901234567890123456789012345678901234567890.000000",
				"%F":  "12345678901234567890123456789012345678901234567890123456789012345678901234567890.000000",
				"%+f": "+12345678901234567890123456789012345678901234567890123456789012345678901234567890.000000",
				"%+F": "+12345678901234567890123456789012345678901234567890123456789012345678901234567890.000000",
				"%e":  "1.234567e+79",
				"%E":  "1.234567E+79",
				"%+e": "+1.234567e+79",
				"%+E": "+1.234567E+79",
				"%g":  "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
				"%G":  "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
				"%+g": "+12345678901234567890123456789012345678901234567890123456789012345678901234567890",
				"%+G": "+12345678901234567890123456789012345678901234567890123456789012345678901234567890",
			},
			f64s: m{"%g": "1.2345678901234568e+79"},
		},

		{
			in: "0.12345678901234567890123456789012345678901234567890123456789012345678901234567890",
			want: m{
				"%f":  "0.123456",
				"%F":  "0.123456",
				"%+f": "+0.123456",
				"%+F": "+0.123456",
				"%e":  "1.234567e-01",
				"%E":  "1.234567E-01",
				"%+e": "+1.234567e-01",
				"%+E": "+1.234567E-01",
				"%g":  "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789",
				"%G":  "0.1234567890123456789012345678901234567890123456789012345678901234567890123456789",
				"%+g": "+0.1234567890123456789012345678901234567890123456789012345678901234567890123456789",
				"%+G": "+0.1234567890123456789012345678901234567890123456789012345678901234567890123456789",
			},
			f64s: m{"%g": "0.12345678901234568"},
		},

		{
			in: "0xffffffffffffffffffffffffffffffff",
			want: m{
				"%g": "340282366920938463463374607431768211455",
				"%x": "0xffffffffffffffffffffffffffffffff",
			},
			ints: m{"%#x": "0xffffffffffffffffffffffffffffffff"},
		},

		{
			in: "0.1",
			want: m{
				"%f":  "0.100000",
				"%F":  "0.100000",
				"%+f": "+0.100000",
				"%+F": "+0.100000",
				"%e":  "1.000000e-01",
				"%E":  "1.000000E-01",
				"%+e": "+1.000000e-01",
				"%+E": "+1.000000E-01",
				"%g":  "0.1",
				"%G":  "0.1",
				"%+g": "+0.1",
				"%+G": "+0.1",
			},
			f64s: m{"%g": "0.1"},
		},

		{
			in: "0.5",
			want: m{
				"%f":  "0.500000",
				"%F":  "0.500000",
				"%+f": "+0.500000",
				"%+F": "+0.500000",
				"%e":  "5.000000e-01",
				"%E":  "5.000000E-01",
				"%+e": "+5.000000e-01",
				"%+E": "+5.000000E-01",
				"%g":  "0.5",
				"%G":  "0.5",
				"%+g": "+0.5",
				"%+G": "+0.5",
			},
			f64s: m{"%g": "0.5"},
		},

		{
			in: "1.5",
			want: m{
				"%f":  "1.500000",
				"%F":  "1.500000",
				"%+f": "+1.500000",
				"%+F": "+1.500000",
				"%e":  "1.500000e+00",
				"%E":  "1.500000E+00",
				"%+e": "+1.500000e+00",
				"%+E": "+1.500000E+00",
				"%g":  "1.5",
				"%G":  "1.5",
				"%+g": "+1.5",
				"%+G": "+1.5",
			},
			f64s: m{"%g": "1.5"},
		},

		{
			in: "-1.5",
			want: m{
				"%f":  "-1.500000",
				"%F":  "-1.500000",
				"%+f": "-1.500000",
				"%+F": "-1.500000",
				"%e":  "-1.500000e+00",
				"%E":  "-1.500000E+00",
				"%+e": "-1.500000e+00",
				"%+E": "-1.500000E+00",
				"%g":  "-1.5",
				"%G":  "-1.5",
				"%+g": "-1.5",
				"%+G": "-1.5",
			},
			f64s: m{"%g": "-1.5"},
		},

		{
			in: "3.14",
			want: m{
				"%f":  "3.140000",
				"%F":  "3.140000",
				"%+f": "+3.140000",
				"%+F": "+3.140000",
				"%e":  "3.140000e+00",
				"%E":  "3.140000E+00",
				"%+e": "+3.140000e+00",
				"%+E": "+3.140000E+00",
				"%g":  "3.14",
				"%G":  "3.14",
				"%+g": "+3.14",
				"%+G": "+3.14",
			},
			f64s: m{"%g": "3.14"},
		},

		{
			in: "123.456",
			want: m{
				"%f":  "123.456000",
				"%F":  "123.456000",
				"%+f": "+123.456000",
				"%+F": "+123.456000",
				"%e":  "1.234560e+02",
				"%E":  "1.234560E+02",
				"%+e": "+1.234560e+02",
				"%+E": "+1.234560E+02",
				"%g":  "123.456",
				"%G":  "123.456",
				"%+g": "+123.456",
				"%+G": "+123.456",
			},
			f64s: m{"%g": "123.456"},
		},

		{
			in: "0.001",
			want: m{
				"%f":  "0.001000",
				"%F":  "0.001000",
				"%+f": "+0.001000",
				"%+F": "+0.001000",
				"%e":  "1.000000e-03",
				"%E":  "1.000000E-03",
				"%+e": "+1.000000e-03",
				"%+E": "+1.000000E-03",
				"%g":  "0.001",
				"%G":  "0.001",
				"%+g": "+0.001",
				"%+G": "+0.001",
			},
			f64s: m{"%g": "0.001"},
		},

		{
			in: "0.0001",
			want: m{
				"%f":  "0.000100",
				"%F":  "0.000100",
				"%+f": "+0.000100",
				"%+F": "+0.000100",
				"%e":  "1.000000e-04",
				"%E":  "1.000000E-04",
				"%+e": "+1.000000e-04",
				"%+E": "+1.000000E-04",
				"%g":  "0.0001",
				"%G":  "0.0001",
				"%+g": "+0.0001",
				"%+G": "+0.0001",
			},
			f64s: m{"%g": "0.0001"},
		},

		{
			in: "0.00001",
			want: m{
				"%f":  "0.000010",
				"%F":  "0.000010",
				"%+f": "+0.000010",
				"%+F": "+0.000010",
				"%e":  "1.000000e-05",
				"%E":  "1.000000E-05",
				"%+e": "+1.000000e-05",
				"%+E": "+1.000000E-05",
				"%g":  "1e-05",
				"%G":  "1E-05",
				"%+g": "+1e-05",
				"%+G": "+1E-05",
			},
			f64s: m{"%g": "1e-05"},
		},

		{
			in: "0.00000001",
			want: m{
				"%f":  "0.000000",
				"%F":  "0.000000",
				"%+f": "+0.000000",
				"%+F": "+0.000000",
				"%e":  "1.000000e-08",
				"%E":  "1.000000E-08",
				"%+e": "+1.000000e-08",
				"%+E": "+1.000000E-08",
				"%g":  "1e-08",
				"%G":  "1E-08",
				"%+g": "+1e-08",
				"%+G": "+1E-08",
			},
			f64s: m{"%g": "1e-08"},
		},

		{
			in: "1e0",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "1e-0",
			want: m{
				"%f":  "1.000000",
				"%F":  "1.000000",
				"%+f": "+1.000000",
				"%+F": "+1.000000",
				"%e":  "1.000000e+00",
				"%E":  "1.000000E+00",
				"%+e": "+1.000000e+00",
				"%+E": "+1.000000E+00",
				"%g":  "1",
				"%G":  "1",
				"%+g": "+1",
				"%+G": "+1",
			},
			f64s: m{"%g": "1"},
		},

		{
			in: "1e5",
			want: m{
				"%f":  "100000.000000",
				"%F":  "100000.000000",
				"%+f": "+100000.000000",
				"%+F": "+100000.000000",
				"%e":  "1.000000e+05",
				"%E":  "1.000000E+05",
				"%+e": "+1.000000e+05",
				"%+E": "+1.000000E+05",
				"%g":  "100000",
				"%G":  "100000",
				"%+g": "+100000",
				"%+G": "+100000",
			},
			f64s: m{"%g": "100000"},
		},

		{
			in: "1e+5",
			want: m{
				"%f":  "100000.000000",
				"%F":  "100000.000000",
				"%+f": "+100000.000000",
				"%+F": "+100000.000000",
				"%e":  "1.000000e+05",
				"%E":  "1.000000E+05",
				"%+e": "+1.000000e+05",
				"%+E": "+1.000000E+05",
				"%g":  "100000",
				"%G":  "100000",
				"%+g": "+100000",
				"%+G": "+100000",
			},
			f64s: m{"%g": "100000"},
		},

		{
			in: "1e-5",
			want: m{
				"%f":  "0.000010",
				"%F":  "0.000010",
				"%+f": "+0.000010",
				"%+F": "+0.000010",
				"%e":  "1.000000e-05",
				"%E":  "1.000000E-05",
				"%+e": "+1.000000e-05",
				"%+E": "+1.000000E-05",
				"%g":  "1e-05",
				"%G":  "1E-05",
				"%+g": "+1e-05",
				"%+G": "+1E-05",
			},
			f64s: m{"%g": "1e-05"},
		},

		{
			in: "2.5e3",
			want: m{
				"%f":  "2500.000000",
				"%F":  "2500.000000",
				"%+f": "+2500.000000",
				"%+F": "+2500.000000",
				"%e":  "2.500000e+03",
				"%E":  "2.500000E+03",
				"%+e": "+2.500000e+03",
				"%+E": "+2.500000E+03",
				"%g":  "2500",
				"%G":  "2500",
				"%+g": "+2500",
				"%+G": "+2500",
			},
			f64s: m{"%g": "2500"},
		},

		{
			in: "1_000.5",
			want: m{
				"%f":  "1000.500000",
				"%F":  "1000.500000",
				"%+f": "+1000.500000",
				"%+F": "+1000.500000",
				"%e":  "1.000500e+03",
				"%E":  "1.000500E+03",
				"%+e": "+1.000500e+03",
				"%+E": "+1.000500E+03",
				"%g":  "1000.5",
				"%G":  "1000.5",
				"%+g": "+1000.5",
				"%+G": "+1000.5",
			},
			f64s: m{"%g": "1000.5"},
		},

		// Negative fraction.
		{
			in: "-0.5",
			want: m{
				"%f":  "-0.500000",
				"%F":  "-0.500000",
				"%+f": "-0.500000",
				"%+F": "-0.500000",
				"%e":  "-5.000000e-01",
				"%E":  "-5.000000E-01",
				"%+e": "-5.000000e-01",
				"%+E": "-5.000000E-01",
				"%g":  "-0.5",
				"%G":  "-0.5",
				"%+g": "-0.5",
				"%+G": "-0.5",
			},
			f64s: m{"%g": "-0.5"},
		},

		// Negative with large magnitude and fraction.
		{
			in: "-123.456",
			want: m{
				"%f":  "-123.456000",
				"%F":  "-123.456000",
				"%+f": "-123.456000",
				"%+F": "-123.456000",
				"%e":  "-1.234560e+02",
				"%E":  "-1.234560E+02",
				"%+e": "-1.234560e+02",
				"%+E": "-1.234560E+02",
				"%g":  "-123.456",
				"%G":  "-123.456",
				"%+g": "-123.456",
				"%+G": "-123.456",
			},
			f64s: m{"%g": "-123.456"},
		},

		// Scientific input with negative fractional mantissa.
		{
			in: "-2.5e-3",
			want: m{
				"%f":  "-0.002500",
				"%F":  "-0.002500",
				"%+f": "-0.002500",
				"%+F": "-0.002500",
				"%e":  "-2.500000e-03",
				"%E":  "-2.500000E-03",
				"%+e": "-2.500000e-03",
				"%+E": "-2.500000E-03",
				"%g":  "-0.0025",
				"%G":  "-0.0025",
				"%+g": "-0.0025",
				"%+G": "-0.0025",
			},
			f64s: m{"%g": "-0.0025"},
		},

		{
			in:   ".953e20",
			want: m{"%g": "95300000000000000000"},
			f64s: m{"%g": "9.53e+19"},
			ints: m{"%v": "95300000000000000000"},
		},

		{
			in:   "1.7976931348623157E+308",
			f64s: m{"%g": "1.7976931348623157e+308"},
		},

		{
			in:   "2.2250738585072014E-308",
			want: m{"%g": "2.2250738585072014e-308"},
			ints: m{"%v": "0"},
			f64s: m{"%g": "2.2250738585072014e-308"},
		},

		// Invalid: empty input.
		{in: "", invalid: true},
		// Invalid: non-numeric.
		{in: "abc", invalid: true},
		// Invalid: double dot.
		{in: "1.2.3", invalid: true},
		// Invalid: exponent with no digits.
		{in: "1e", invalid: true},
		// Mixing bases: e is ambiguous here, and when we get to the + we see
		// an error. 0x0.fe4 is valid, because e is a hex digit.
		{in: "0x0.fe+4", invalid: true},
	}

	for _, tt := range tests {
		t.Run(tt.in, func(t *testing.T) {
			t.Parallel()
			z, err := new(Decimal).Parse(tt.in)
			if tt.invalid {
				require.Error(t, err)
				return
			}
			require.NoError(t, err)
			t.Logf("%b", z)

			for format, want := range tt.want {
				t.Run(format, func(t *testing.T) {
					t.Parallel()
					assert.Equal(t, want, fmt.Sprintf(format, z))
				})
			}

			for format, want := range tt.ints {
				t.Run("int/"+format, func(t *testing.T) {
					t.Parallel()
					assert.Equal(t, want, fmt.Sprintf(format, z.Int(nil)))
				})
			}

			for format, want := range tt.u64s {
				t.Run("u64/"+format, func(t *testing.T) {
					t.Parallel()
					assert.Equal(t, want, fmt.Sprintf(format, z.Int(nil).Uint64()))
				})
			}

			for format, want := range tt.f64s {
				t.Run("f64/"+format, func(t *testing.T) {
					t.Parallel()
					f, _ := z.Float64()
					assert.Equal(t, want, fmt.Sprintf(format, f))
				})
			}
		})
	}
}

func TestIsInt(t *testing.T) {
	t.Parallel()
	tests := []struct {
		in   string
		want bool
	}{
		{in: "0", want: true},
		{in: "1", want: true},
		{in: "42", want: true},
		{in: "1000000000000000000000000000000000000000000000000000", want: true},
		{in: "1e100", want: true},
		{in: "1.999e100", want: true},

		{in: "0.5", want: false},
		{in: "1.5", want: false},
		{in: "1e-100", want: false},
		{in: "10000e-6", want: false},
	}

	for _, tt := range tests {
		t.Run(tt.in, func(t *testing.T) {
			t.Parallel()
			z, err := new(Decimal).Parse(tt.in)
			require.NoError(t, err)
			t.Logf("%b", z)

			assert.Equal(t, tt.want, z.IsInt())
		})
	}
}

func TestIsFloat(t *testing.T) {
	t.Parallel()
	tests := []struct {
		in   string
		want bool
	}{
		{in: "0", want: true},
		{in: "1", want: true},
		{in: "42", want: true},
		{in: "1000000000000000000000000000000000000000000000000000", want: true},
		{in: "1e100", want: true},
		{in: "1.999e100", want: true},

		{in: "0.1", want: false},
		{in: "0.3", want: false},
		{in: "1.1", want: false},
		{in: "0.5", want: true},
		{in: "1.5", want: true},
		{in: "1e-100", want: false},
		{in: "10000e-6", want: false},
	}

	for _, tt := range tests {
		t.Run(tt.in, func(t *testing.T) {
			t.Parallel()
			z, err := new(Decimal).Parse(tt.in)
			require.NoError(t, err)
			t.Logf("%b", z)

			assert.Equal(t, tt.want, z.IsFloat())
		})
	}
}

func TestSetFloat(t *testing.T) {
	t.Parallel()
	tests := []struct {
		in   float64
		want string
	}{
		{in: 0, want: "0"},
		{in: nzero, want: "-0"},
		{in: math.Inf(1), want: "Infinity"},
		{in: math.Inf(-11), want: "-Infinity"},

		{in: 1, want: "1"},
		{in: -1, want: "-1"},
		{in: 1.5, want: "1.5"},
		{in: -1.5, want: "-1.5"},
		{in: 0.125, want: "0.125"},
		{in: -0.125, want: "-0.125"},
		{in: 0x42, want: "66"},
		{in: 1e100, want: "10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"},
		{in: 0x1p100, want: "1267650600228229401496703205376"},
	}

	for _, tt := range tests {
		t.Run(fmt.Sprintf("%g", tt.in), func(t *testing.T) {
			t.Parallel()
			z := new(Decimal).SetFloat64(tt.in)
			t.Logf("%b", z)
			t.Logf("%e", z)

			assert.Equal(t, tt.want, fmt.Sprint(z))
		})
	}
}

func TestNonFinite(t *testing.T) {
	t.Parallel()

	n := new(Decimal)
	f, _ := n.Float64()
	assert.True(t, n.IsFinite())
	assert.False(t, n.IsInf())
	assert.False(t, n.IsNaN())
	assert.False(t, n.IsQuietNaN())
	assert.False(t, n.IsSignalingNaN())
	assert.False(t, math.IsInf(f, 0))
	assert.False(t, math.IsNaN(f))
	assert.Equal(t, int64(0), n.Int(nil).Int64())
	assert.Equal(t, int64(-1), n.NaN())

	n = new(Decimal).SetInf(false)
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.True(t, n.IsInf())
	assert.False(t, n.IsNaN())
	assert.False(t, n.IsQuietNaN())
	assert.False(t, n.IsSignalingNaN())
	assert.True(t, math.IsInf(f, 1))
	assert.False(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(-1), n.NaN())

	n = new(Decimal).SetInf(true)
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.True(t, n.IsInf())
	assert.False(t, n.IsNaN())
	assert.False(t, n.IsQuietNaN())
	assert.False(t, n.IsSignalingNaN())
	assert.True(t, math.IsInf(f, -1))
	assert.False(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(-1), n.NaN())

	n = new(Decimal).SetNaN()
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.False(t, n.IsInf())
	assert.True(t, n.IsNaN())
	assert.True(t, n.IsQuietNaN())
	assert.False(t, n.IsSignalingNaN())
	assert.False(t, math.IsInf(f, 0))
	assert.True(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(0x0_0000_0000_0000), n.NaN())

	n = new(Decimal).SetNaNPayload(false, false, 0)
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.False(t, n.IsInf())
	assert.True(t, n.IsNaN())
	assert.False(t, n.IsQuietNaN())
	assert.True(t, n.IsSignalingNaN())
	assert.False(t, math.IsInf(f, 0))
	assert.True(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(0x0_0000_0000_0000), n.NaN())

	n = new(Decimal).SetNaNPayload(false, false, math.MaxUint64)
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.False(t, n.IsInf())
	assert.True(t, n.IsNaN())
	assert.False(t, n.IsQuietNaN())
	assert.True(t, n.IsSignalingNaN())
	assert.False(t, math.IsInf(f, 0))
	assert.True(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(0x7_ffff_ffff_ffff), n.NaN())

	n = new(Decimal).SetNaNPayload(false, true, math.MaxUint64)
	f, _ = n.Float64()
	assert.False(t, n.IsFinite())
	assert.False(t, n.IsInf())
	assert.True(t, n.IsNaN())
	assert.True(t, n.IsQuietNaN())
	assert.False(t, n.IsSignalingNaN())
	assert.False(t, math.IsInf(f, 0))
	assert.True(t, math.IsNaN(f))
	assert.Nil(t, n.Int(nil))
	assert.Equal(t, int64(0x7_ffff_ffff_ffff), n.NaN())
}
