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