src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/vals/num_test.go (about)

     1  package vals
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"testing"
     7  
     8  	"src.elv.sh/pkg/testutil"
     9  	"src.elv.sh/pkg/tt"
    10  )
    11  
    12  // Test utilities.
    13  
    14  const (
    15  	zeros = "0000000000000000000"
    16  	// Values that exceed the range of int64, used for testing BigInt.
    17  	z   = "1" + zeros + "0"
    18  	z1  = "1" + zeros + "1" // z+1
    19  	z2  = "1" + zeros + "2" // z+2
    20  	z3  = "1" + zeros + "3" // z+3
    21  	zz  = "2" + zeros + "0" // 2z
    22  	zz1 = "2" + zeros + "1" // 2z+1
    23  	zz2 = "2" + zeros + "2" // 2z+2
    24  	zz3 = "2" + zeros + "3" // 2z+3
    25  )
    26  
    27  func TestParseNum(t *testing.T) {
    28  	tt.Test(t, ParseNum,
    29  		Args("1").Rets(1),
    30  
    31  		Args(z).Rets(bigInt(z)),
    32  
    33  		Args("1/2").Rets(big.NewRat(1, 2)),
    34  		Args("2/1").Rets(2),
    35  		Args(z+"/1").Rets(bigInt(z)),
    36  
    37  		Args("1.0").Rets(1.0),
    38  		Args("1e-5").Rets(1e-5),
    39  
    40  		Args("x").Rets(nil),
    41  		Args("x/y").Rets(nil),
    42  	)
    43  }
    44  
    45  func TestUnifyNums(t *testing.T) {
    46  	tt.Test(t, UnifyNums,
    47  		Args([]Num{1, 2, 3, 4}, Int).
    48  			Rets([]int{1, 2, 3, 4}),
    49  
    50  		Args([]Num{1, 2, 3, bigInt(z)}, Int).
    51  			Rets([]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3), bigInt(z)}),
    52  
    53  		Args([]Num{1, 2, 3, big.NewRat(1, 2)}, Int).
    54  			Rets([]*big.Rat{
    55  				big.NewRat(1, 1), big.NewRat(2, 1),
    56  				big.NewRat(3, 1), big.NewRat(1, 2)}),
    57  		Args([]Num{1, 2, bigInt(z), big.NewRat(1, 2)}, Int).
    58  			Rets([]*big.Rat{
    59  				big.NewRat(1, 1), big.NewRat(2, 1), bigRat(z), big.NewRat(1, 2)}),
    60  
    61  		Args([]Num{1, 2, 3, 4.0}, Int).
    62  			Rets([]float64{1, 2, 3, 4}),
    63  		Args([]Num{1, 2, big.NewRat(1, 2), 4.0}, Int).
    64  			Rets([]float64{1, 2, 0.5, 4}),
    65  		Args([]Num{1, 2, big.NewInt(3), 4.0}, Int).
    66  			Rets([]float64{1, 2, 3, 4}),
    67  		Args([]Num{1, 2, bigInt(z), 4.0}, Int).
    68  			Rets([]float64{1, 2, math.Inf(1), 4}),
    69  
    70  		Args([]Num{1, 2, 3, 4}, BigInt).
    71  			Rets([]*big.Int{
    72  				big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4)}),
    73  	)
    74  }
    75  
    76  func TestUnifyNums2(t *testing.T) {
    77  	tt.Test(t, UnifyNums2,
    78  		Args(1, 2, Int).Rets(1, 2),
    79  		Args(1, bigInt(z), Int).Rets(big.NewInt(1), bigInt(z)),
    80  		Args(1, big.NewRat(1, 2), Int).Rets(big.NewRat(1, 1), big.NewRat(1, 2)),
    81  		Args(1, 2.0, Int).Rets(1.0, 2.0),
    82  		Args(1, 2, BigInt).Rets(big.NewInt(1), big.NewInt(2)),
    83  	)
    84  }
    85  
    86  func TestInvalidNumType(t *testing.T) {
    87  	tt.Test(t, testutil.Recover,
    88  		Args(func() { UnifyNums([]Num{int32(0)}, 0) }).Rets("invalid num type int32"),
    89  		Args(func() { PromoteToBigInt(int32(0)) }).Rets("invalid num type int32"),
    90  		Args(func() { PromoteToBigRat(int32(0)) }).Rets("invalid num type int32"),
    91  		Args(func() { ConvertToFloat64(int32(0)) }).Rets("invalid num type int32"),
    92  	)
    93  }
    94  
    95  func TestInt64ToNum(t *testing.T) {
    96  	n := Int64ToNum(1)
    97  	if _, isInt := n.(int); !isInt {
    98  		t.Errorf("got %T, want int", n)
    99  	}
   100  
   101  	if math.MaxInt != math.MaxInt64 {
   102  		n = Int64ToNum(math.MaxInt64)
   103  		if _, isBigInt := n.(*big.Int); !isBigInt {
   104  			t.Errorf("got %T, want *big.Int", n)
   105  		}
   106  	}
   107  }
   108  
   109  func TestUint64ToNum(t *testing.T) {
   110  	n := Uint64ToNum(1)
   111  	if _, isInt := n.(int); !isInt {
   112  		t.Errorf("got %T, want int", n)
   113  	}
   114  
   115  	n = Uint64ToNum(math.MaxUint64)
   116  	if _, isBigInt := n.(*big.Int); !isBigInt {
   117  		t.Errorf("got %T, want *big.Int", n)
   118  	}
   119  }
   120  
   121  func bigInt(s string) *big.Int {
   122  	z, ok := new(big.Int).SetString(s, 0)
   123  	if !ok {
   124  		panic("cannot parse as big int: " + s)
   125  	}
   126  	return z
   127  }
   128  
   129  func bigRat(s string) *big.Rat {
   130  	z, ok := new(big.Rat).SetString(s)
   131  	if !ok {
   132  		panic("cannot parse as big rat: " + s)
   133  	}
   134  	return z
   135  }