github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/builtin_fn_num_test.go (about)

     1  package eval_test
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"strings"
     7  	"testing"
     8  
     9  	. "github.com/markusbkk/elvish/pkg/eval"
    10  	"github.com/markusbkk/elvish/pkg/eval/errs"
    11  	"github.com/markusbkk/elvish/pkg/eval/vals"
    12  
    13  	. "github.com/markusbkk/elvish/pkg/eval/evaltest"
    14  )
    15  
    16  const (
    17  	zeros = "0000000000000000000"
    18  	// Values that exceed the range of int64, used for testing bigint.
    19  	z   = "1" + zeros + "0"
    20  	z1  = "1" + zeros + "1" // z+1
    21  	z2  = "1" + zeros + "2" // z+2
    22  	z3  = "1" + zeros + "3" // z+3
    23  	zz  = "2" + zeros + "0" // 2z
    24  	zz1 = "2" + zeros + "1" // 2z+1
    25  	zz2 = "2" + zeros + "2" // 2z+2
    26  	zz3 = "2" + zeros + "3" // 2z+3
    27  )
    28  
    29  func TestNum(t *testing.T) {
    30  	Test(t,
    31  		That("num 1").Puts(1),
    32  		That("num "+z).Puts(bigInt(z)),
    33  		That("num 1/2").Puts(big.NewRat(1, 2)),
    34  		That("num 0.1").Puts(0.1),
    35  		That("num (num 1)").Puts(1),
    36  	)
    37  }
    38  
    39  func TestExactNum(t *testing.T) {
    40  	Test(t,
    41  		That("exact-num 1").Puts(1),
    42  		That("exact-num 0.125").Puts(big.NewRat(1, 8)),
    43  		That("exact-num inf").Throws(errs.BadValue{
    44  			What: "argument here", Valid: "finite float", Actual: "+Inf"}),
    45  	)
    46  }
    47  
    48  func TestFloat64(t *testing.T) {
    49  	Test(t,
    50  		That("float64 1").Puts(1.0),
    51  		That("float64 (float64 1)").Puts(1.0),
    52  	)
    53  }
    54  
    55  func TestNumCmp(t *testing.T) {
    56  	Test(t,
    57  		// int
    58  		That("< 1 2 3").Puts(true),
    59  		That("< 1 3 2").Puts(false),
    60  		// bigint
    61  		That("< "+args(z1, z2, z3)).Puts(true),
    62  		That("< "+args(z1, z3, z2)).Puts(false),
    63  		// bigint and int
    64  		That("< "+args("1", z1)).Puts(true),
    65  		// bigrat
    66  		That("< 1/4 1/3 1/2").Puts(true),
    67  		That("< 1/4 1/2 1/3").Puts(false),
    68  		// bigrat, bigint and int
    69  		That("< "+args("1/2", "1", z1)).Puts(true),
    70  		That("< "+args("1/2", z1, "1")).Puts(false),
    71  		// float64
    72  		That("< 1.0 2.0 3.0").Puts(true),
    73  		That("< 1.0 3.0 2.0").Puts(false),
    74  		// float64, bigrat and int
    75  		That("< 1.0 3/2 2").Puts(true),
    76  		That("< 1.0 2 3/2").Puts(false),
    77  
    78  		// Mixing of types not tested for commands below; they share the same
    79  		// code path as <.
    80  
    81  		// int
    82  		That("<= 1 1 2").Puts(true),
    83  		That("<= 1 2 1").Puts(false),
    84  		// bigint
    85  		That("<= "+args(z1, z1, z2)).Puts(true),
    86  		That("<= "+args(z1, z2, z1)).Puts(false),
    87  		// bigrat
    88  		That("<= 1/3 1/3 1/2").Puts(true),
    89  		That("<= 1/3 1/2 1/1").Puts(true),
    90  		// float64
    91  		That("<= 1.0 1.0 2.0").Puts(true),
    92  		That("<= 1.0 2.0 1.0").Puts(false),
    93  
    94  		// int
    95  		That("== 1 1 1").Puts(true),
    96  		That("== 1 2 1").Puts(false),
    97  		// bigint
    98  		That("== "+args(z1, z1, z1)).Puts(true),
    99  		That("== "+args(z1, z2, z1)).Puts(false),
   100  		// bigrat
   101  		That("== 1/2 1/2 1/2").Puts(true),
   102  		That("== 1/2 1/3 1/2").Puts(false),
   103  		// float64
   104  		That("== 1.0 1.0 1.0").Puts(true),
   105  		That("== 1.0 2.0 1.0").Puts(false),
   106  
   107  		// int
   108  		That("!= 1 2 1").Puts(true),
   109  		That("!= 1 1 2").Puts(false),
   110  		// bigint
   111  		That("!= "+args(z1, z2, z1)).Puts(true),
   112  		That("!= "+args(z1, z1, z2)).Puts(false),
   113  		// bigrat
   114  		That("!= 1/2 1/3 1/2").Puts(true),
   115  		That("!= 1/2 1/2 1/3").Puts(false),
   116  		// float64
   117  		That("!= 1.0 2.0 1.0").Puts(true),
   118  		That("!= 1.0 1.0 2.0").Puts(false),
   119  
   120  		// int
   121  		That("> 3 2 1").Puts(true),
   122  		That("> 3 1 2").Puts(false),
   123  		// bigint
   124  		That("> "+args(z3, z2, z1)).Puts(true),
   125  		That("> "+args(z3, z1, z2)).Puts(false),
   126  		// bigrat
   127  		That("> 1/2 1/3 1/4").Puts(true),
   128  		That("> 1/2 1/4 1/3").Puts(false),
   129  		// float64
   130  		That("> 3.0 2.0 1.0").Puts(true),
   131  		That("> 3.0 1.0 2.0").Puts(false),
   132  
   133  		// int
   134  		That(">= 3 3 2").Puts(true),
   135  		That(">= 3 2 3").Puts(false),
   136  		// bigint
   137  		That(">= "+args(z3, z3, z2)).Puts(true),
   138  		That(">= "+args(z3, z2, z3)).Puts(false),
   139  		// bigrat
   140  		That(">= 1/2 1/2 1/3").Puts(true),
   141  		That(">= 1/2 1/3 1/2").Puts(false),
   142  		// float64
   143  		That(">= 3.0 3.0 2.0").Puts(true),
   144  		That(">= 3.0 2.0 3.0").Puts(false),
   145  	)
   146  }
   147  
   148  func TestArithmeticCommands(t *testing.T) {
   149  	Test(t,
   150  		// No argument
   151  		That("+").Puts(0),
   152  		// int
   153  		That("+ 233100 233").Puts(233333),
   154  		// bigint
   155  		That("+ "+args(z, z1)).Puts(bigInt(zz1)),
   156  		// bigint and int
   157  		That("+ 1 2 "+z).Puts(bigInt(z3)),
   158  		// bigrat
   159  		That("+ 1/2 1/3 1/4").Puts(big.NewRat(13, 12)),
   160  		// bigrat, bigint and int
   161  		That("+ 1/2 1/2 1 "+z).Puts(bigInt(z2)),
   162  		// float64
   163  		That("+ 0.5 0.25 1.0").Puts(1.75),
   164  		// float64 and other types
   165  		That("+ 0.5 1/4 1").Puts(1.75),
   166  
   167  		// Mixing of types not tested for commands below; they share the same
   168  		// code path as +.
   169  
   170  		That("-").Throws(ErrorWithType(errs.ArityMismatch{})),
   171  		// One argument - negation
   172  		That("- 233").Puts(-233),
   173  		That("- "+z).Puts(bigInt("-"+z)),
   174  		That("- 1/2").Puts(big.NewRat(-1, 2)),
   175  		That("- 1.0").Puts(-1.0),
   176  		// int
   177  		That("- 20 10 2").Puts(8),
   178  		// bigint
   179  		That("- "+args(zz3, z1)).Puts(bigInt(z2)),
   180  		// bigrat
   181  		That("- 1/2 1/3").Puts(big.NewRat(1, 6)),
   182  		// float64
   183  		That("- 2.0 1.0 0.5").Puts(0.5),
   184  
   185  		// No argument
   186  		That("*").Puts(1),
   187  		// int
   188  		That("* 2 7 4").Puts(56),
   189  		// bigint
   190  		That("* 2 "+z1).Puts(bigInt(zz2)),
   191  		// bigrat
   192  		That("* 1/2 1/3").Puts(big.NewRat(1, 6)),
   193  		// float64
   194  		That("* 2.0 0.5 1.75").Puts(1.75),
   195  		// 0 * non-infinity
   196  		That("* 0 1/2 1.0").Puts(0),
   197  		// 0 * infinity
   198  		That("* 0 +Inf").Puts(math.NaN()),
   199  
   200  		// One argument - inversion
   201  		That("/ 2").Puts(big.NewRat(1, 2)),
   202  		That("/ "+z).Puts(bigRat("1/"+z)),
   203  		That("/ 2.0").Puts(0.5),
   204  		// int
   205  		That("/ 233333 353").Puts(661),
   206  		That("/ 3 4 2").Puts(big.NewRat(3, 8)),
   207  		// bigint
   208  		That("/ "+args(zz, z)).Puts(2),
   209  		That("/ "+args(zz, "2")).Puts(bigInt(z)),
   210  		That("/ "+args(z1, z)).Puts(bigRat(z1+"/"+z)),
   211  		// float64
   212  		That("/ 1.0 2.0 4.0").Puts(0.125),
   213  		// 0 / non-zero
   214  		That("/ 0 1/2 0.1").Puts(0),
   215  		// anything / 0
   216  		That("/ 0 0").Throws(ErrDivideByZero, "/ 0 0"),
   217  		That("/ 1 0").Throws(ErrDivideByZero, "/ 1 0"),
   218  		That("/ 1.0 0").Throws(ErrDivideByZero, "/ 1.0 0"),
   219  
   220  		That("% 23 7").Puts(2),
   221  		That("% 1 0").Throws(ErrDivideByZero, "% 1 0"),
   222  	)
   223  }
   224  
   225  func TestRandint(t *testing.T) {
   226  	Test(t,
   227  		That("randint 1 2").Puts(1),
   228  		That("randint 1").Puts(0),
   229  		That("var i = (randint 10 100); and (<= 10 $i) (< $i 100)").Puts(true),
   230  		That("var i = (randint 10); and (<= 0 $i) (< $i 10)").Puts(true),
   231  
   232  		That("randint 2 1").Throws(
   233  			errs.BadValue{What: "high value", Valid: "larger than 2", Actual: "1"},
   234  			"randint 2 1"),
   235  		That("randint").Throws(ErrorWithType(errs.ArityMismatch{}), "randint"),
   236  		That("randint 1 2 3").Throws(ErrorWithType(errs.ArityMismatch{}), "randint 1 2 3"),
   237  	)
   238  }
   239  
   240  func bigInt(s string) *big.Int {
   241  	z, ok := new(big.Int).SetString(s, 0)
   242  	if !ok {
   243  		panic("cannot parse as big int: " + s)
   244  	}
   245  	return z
   246  }
   247  
   248  func bigRat(s string) *big.Rat {
   249  	z, ok := new(big.Rat).SetString(s)
   250  	if !ok {
   251  		panic("cannot parse as big rat: " + s)
   252  	}
   253  	return z
   254  }
   255  
   256  func args(vs ...interface{}) string {
   257  	s := make([]string, len(vs))
   258  	for i, v := range vs {
   259  		s[i] = vals.ToString(v)
   260  	}
   261  	return strings.Join(s, " ")
   262  }