github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/math/dec_test.go (about)

     1  package math
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  	"pgregory.net/rapid"
     9  )
    10  
    11  func TestDec(t *testing.T) {
    12  	// Property tests
    13  	t.Run("TestNewDecFromInt64", rapid.MakeCheck(testDecInt64))
    14  
    15  	// Properties about addition
    16  	t.Run("TestAddLeftIdentity", rapid.MakeCheck(testAddLeftIdentity))
    17  	t.Run("TestAddRightIdentity", rapid.MakeCheck(testAddRightIdentity))
    18  	t.Run("TestAddCommutative", rapid.MakeCheck(testAddCommutative))
    19  	t.Run("TestAddAssociative", rapid.MakeCheck(testAddAssociative))
    20  
    21  	// Properties about subtraction
    22  	t.Run("TestSubRightIdentity", rapid.MakeCheck(testSubRightIdentity))
    23  	t.Run("TestSubZero", rapid.MakeCheck(testSubZero))
    24  
    25  	// Properties combining operations
    26  	t.Run("TestSubAdd", rapid.MakeCheck(testSubAdd))
    27  	t.Run("TestAddSub", rapid.MakeCheck(testAddSub))
    28  
    29  	// Properties about comparison and equality
    30  	t.Run("TestCmpInverse", rapid.MakeCheck(testCmpInverse))
    31  	t.Run("TestEqualCommutative", rapid.MakeCheck(testEqualCommutative))
    32  
    33  	// Properties about tests on a single Dec
    34  	t.Run("TestIsNegative", rapid.MakeCheck(testIsNegative))
    35  
    36  	// Unit tests
    37  	zero := Dec{}
    38  	one := NewDecFromInt64(1)
    39  	two := NewDecFromInt64(2)
    40  	three := NewDecFromInt64(3)
    41  	four := NewDecFromInt64(4)
    42  	five := NewDecFromInt64(5)
    43  	minusOne := NewDecFromInt64(-1)
    44  
    45  	onePointOneFive, err := NewDecFromString("1.15")
    46  	require.NoError(t, err)
    47  	twoPointThreeFour, err := NewDecFromString("2.34")
    48  	require.NoError(t, err)
    49  	threePointFourNine, err := NewDecFromString("3.49")
    50  	require.NoError(t, err)
    51  	onePointFourNine, err := NewDecFromString("1.49")
    52  	require.NoError(t, err)
    53  	minusFivePointZero, err := NewDecFromString("-5.0")
    54  	require.NoError(t, err)
    55  	_, err = NewDecFromString("inf")
    56  	require.Error(t, err)
    57  	_, err = NewDecFromString("Infinite")
    58  	require.Error(t, err)
    59  	_, err = NewDecFromString("foo")
    60  	require.Error(t, err)
    61  	_, err = NewDecFromString("NaN")
    62  	require.Error(t, err)
    63  
    64  	res, err := two.Add(zero)
    65  	require.NoError(t, err)
    66  	require.True(t, res.Equal(two))
    67  
    68  	res, err = five.Sub(two)
    69  	require.NoError(t, err)
    70  	require.True(t, res.Equal(three))
    71  
    72  	res, err = onePointOneFive.Add(twoPointThreeFour)
    73  	require.NoError(t, err)
    74  	require.True(t, res.Equal(threePointFourNine))
    75  
    76  	res, err = threePointFourNine.Sub(two)
    77  	require.NoError(t, err)
    78  	require.True(t, res.Equal(onePointFourNine))
    79  
    80  	res, err = minusOne.Sub(four)
    81  	require.NoError(t, err)
    82  	require.True(t, res.Equal(minusFivePointZero))
    83  
    84  	_, err = four.Quo(zero)
    85  	require.Error(t, err)
    86  
    87  	res, err = four.Quo(two)
    88  	require.NoError(t, err)
    89  	require.True(t, res.Equal(two))
    90  
    91  	require.False(t, zero.IsNegative())
    92  	require.False(t, one.IsNegative())
    93  	require.True(t, minusOne.IsNegative())
    94  }
    95  
    96  var genDec *rapid.Generator[Dec] = rapid.Custom(func(t *rapid.T) Dec {
    97  	f := rapid.Float64().Draw(t, "f")
    98  	dec, err := NewDecFromString(fmt.Sprintf("%g", f))
    99  	require.NoError(t, err)
   100  	return dec
   101  })
   102  
   103  // A Dec value and the float used to create it
   104  type floatAndDec struct {
   105  	float float64
   106  	dec   Dec
   107  }
   108  
   109  // Generate a Dec value along with the float used to create it
   110  var genFloatAndDec *rapid.Generator[floatAndDec] = rapid.Custom(func(t *rapid.T) floatAndDec {
   111  	f := rapid.Float64().Draw(t, "f")
   112  	dec, err := NewDecFromString(fmt.Sprintf("%g", f))
   113  	require.NoError(t, err)
   114  	return floatAndDec{f, dec}
   115  })
   116  
   117  // Property: n == NewDecFromInt64(n).Int64()
   118  func testDecInt64(t *rapid.T) {
   119  	nIn := rapid.Int64().Draw(t, "n")
   120  	nOut, err := NewDecFromInt64(nIn).Int64()
   121  
   122  	require.NoError(t, err)
   123  	require.Equal(t, nIn, nOut)
   124  }
   125  
   126  // Property: 0 + a == a
   127  func testAddLeftIdentity(t *rapid.T) {
   128  	a := genDec.Draw(t, "a")
   129  	zero := NewDecFromInt64(0)
   130  
   131  	b, err := zero.Add(a)
   132  	require.NoError(t, err)
   133  
   134  	require.True(t, a.Equal(b))
   135  }
   136  
   137  // Property: a + 0 == a
   138  func testAddRightIdentity(t *rapid.T) {
   139  	a := genDec.Draw(t, "a")
   140  	zero := NewDecFromInt64(0)
   141  
   142  	b, err := a.Add(zero)
   143  	require.NoError(t, err)
   144  
   145  	require.True(t, a.Equal(b))
   146  }
   147  
   148  // Property: a + b == b + a
   149  func testAddCommutative(t *rapid.T) {
   150  	a := genDec.Draw(t, "a")
   151  	b := genDec.Draw(t, "b")
   152  
   153  	c, err := a.Add(b)
   154  	require.NoError(t, err)
   155  
   156  	d, err := b.Add(a)
   157  	require.NoError(t, err)
   158  
   159  	require.True(t, c.Equal(d))
   160  }
   161  
   162  // Property: (a + b) + c == a + (b + c)
   163  func testAddAssociative(t *rapid.T) {
   164  	a := genDec.Draw(t, "a")
   165  	b := genDec.Draw(t, "b")
   166  	c := genDec.Draw(t, "c")
   167  
   168  	// (a + b) + c
   169  	d, err := a.Add(b)
   170  	require.NoError(t, err)
   171  
   172  	e, err := d.Add(c)
   173  	require.NoError(t, err)
   174  
   175  	// a + (b + c)
   176  	f, err := b.Add(c)
   177  	require.NoError(t, err)
   178  
   179  	g, err := a.Add(f)
   180  	require.NoError(t, err)
   181  
   182  	require.True(t, e.Equal(g))
   183  }
   184  
   185  // Property: a - 0 == a
   186  func testSubRightIdentity(t *rapid.T) {
   187  	a := genDec.Draw(t, "a")
   188  	zero := NewDecFromInt64(0)
   189  
   190  	b, err := a.Sub(zero)
   191  	require.NoError(t, err)
   192  
   193  	require.True(t, a.Equal(b))
   194  }
   195  
   196  // Property: a - a == 0
   197  func testSubZero(t *rapid.T) {
   198  	a := genDec.Draw(t, "a")
   199  	zero := NewDecFromInt64(0)
   200  
   201  	b, err := a.Sub(a)
   202  	require.NoError(t, err)
   203  
   204  	require.True(t, b.Equal(zero))
   205  }
   206  
   207  // Property: (a - b) + b == a
   208  func testSubAdd(t *rapid.T) {
   209  	a := genDec.Draw(t, "a")
   210  	b := genDec.Draw(t, "b")
   211  
   212  	c, err := a.Sub(b)
   213  	require.NoError(t, err)
   214  
   215  	d, err := c.Add(b)
   216  	require.NoError(t, err)
   217  
   218  	require.True(t, a.Equal(d))
   219  }
   220  
   221  // Property: (a + b) - b == a
   222  func testAddSub(t *rapid.T) {
   223  	a := genDec.Draw(t, "a")
   224  	b := genDec.Draw(t, "b")
   225  
   226  	c, err := a.Add(b)
   227  	require.NoError(t, err)
   228  
   229  	d, err := c.Sub(b)
   230  	require.NoError(t, err)
   231  
   232  	require.True(t, a.Equal(d))
   233  }
   234  
   235  // Property: Cmp(a, b) == -Cmp(b, a)
   236  func testCmpInverse(t *rapid.T) {
   237  	a := genDec.Draw(t, "a")
   238  	b := genDec.Draw(t, "b")
   239  
   240  	require.Equal(t, a.Cmp(b), -b.Cmp(a))
   241  }
   242  
   243  // Property: Equal(a, b) == Equal(b, a)
   244  func testEqualCommutative(t *rapid.T) {
   245  	a := genDec.Draw(t, "a")
   246  	b := genDec.Draw(t, "b")
   247  
   248  	require.Equal(t, a.Equal(b), b.Equal(a))
   249  }
   250  
   251  // Property: isNegative(f) == isNegative(NewDecFromString(f.String()))
   252  func testIsNegative(t *rapid.T) {
   253  	floatAndDec := genFloatAndDec.Draw(t, "floatAndDec")
   254  	f, dec := floatAndDec.float, floatAndDec.dec
   255  
   256  	require.Equal(t, f < 0, dec.IsNegative())
   257  }