github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/mods/math/math_test.go (about)

     1  package math
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"strconv"
     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/evaltest"
    12  )
    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  )
    21  
    22  var minIntString = strconv.Itoa(minInt)
    23  
    24  func TestMath(t *testing.T) {
    25  	setup := func(ev *eval.Evaler) {
    26  		ev.ExtendGlobal(eval.BuildNs().AddNs("math", Ns))
    27  	}
    28  	TestWithSetup(t, setup,
    29  		That("math:abs 2").Puts(2),
    30  		That("math:abs -2").Puts(2),
    31  		That("math:abs "+minIntString).Puts(bigInt(minIntString[1:])),
    32  		That("math:abs "+z).Puts(bigInt(z)),
    33  		That("math:abs -"+z).Puts(bigInt(z)),
    34  		That("math:abs -1/2").Puts(big.NewRat(1, 2)),
    35  		That("math:abs 1/2").Puts(big.NewRat(1, 2)),
    36  		That("math:abs 2.1").Puts(2.1),
    37  		That("math:abs -2.1").Puts(2.1),
    38  
    39  		That("math:ceil 2").Puts(2),
    40  		That("math:ceil "+z).Puts(bigInt(z)),
    41  		That("math:ceil 3/2").Puts(2),
    42  		That("math:ceil -3/2").Puts(-1),
    43  		That("math:ceil 2.1").Puts(3.0),
    44  		That("math:ceil -2.1").Puts(-2.0),
    45  
    46  		That("math:floor 2").Puts(2),
    47  		That("math:floor "+z).Puts(bigInt(z)),
    48  		That("math:floor 3/2").Puts(1),
    49  		That("math:floor -3/2").Puts(-2),
    50  		That("math:floor 2.1").Puts(2.0),
    51  		That("math:floor -2.1").Puts(-3.0),
    52  
    53  		That("math:round 2").Puts(2),
    54  		That("math:round "+z).Puts(bigInt(z)),
    55  		That("math:round 1/3").Puts(0),
    56  		That("math:round 1/2").Puts(1),
    57  		That("math:round 2/3").Puts(1),
    58  		That("math:round -1/3").Puts(0),
    59  		That("math:round -1/2").Puts(-1),
    60  		That("math:round -2/3").Puts(-1),
    61  		That("math:round 2.1").Puts(2.0),
    62  		That("math:round 2.5").Puts(3.0),
    63  
    64  		That("math:round-to-even 2").Puts(2),
    65  		That("math:round-to-even "+z).Puts(bigInt(z)),
    66  		That("math:round-to-even 1/3").Puts(0),
    67  		That("math:round-to-even 2/3").Puts(1),
    68  		That("math:round-to-even -1/3").Puts(0),
    69  		That("math:round-to-even -2/3").Puts(-1),
    70  		That("math:round-to-even 2.5").Puts(2.0),
    71  		That("math:round-to-even -2.5").Puts(-2.0),
    72  
    73  		That("math:round-to-even 1/2").Puts(0),
    74  		That("math:round-to-even 3/2").Puts(2),
    75  		That("math:round-to-even 5/2").Puts(2),
    76  		That("math:round-to-even 7/2").Puts(4),
    77  		That("math:round-to-even -1/2").Puts(0),
    78  		That("math:round-to-even -3/2").Puts(-2),
    79  		That("math:round-to-even -5/2").Puts(-2),
    80  		That("math:round-to-even -7/2").Puts(-4),
    81  
    82  		That("math:trunc 2").Puts(2),
    83  		That("math:trunc "+z).Puts(bigInt(z)),
    84  		That("math:trunc 3/2").Puts(1),
    85  		That("math:trunc -3/2").Puts(-1),
    86  		That("math:trunc 2.1").Puts(2.0),
    87  		That("math:trunc -2.1").Puts(-2.0),
    88  
    89  		That("math:is-inf 1.3").Puts(false),
    90  		That("math:is-inf &sign=0 inf").Puts(true),
    91  		That("math:is-inf &sign=1 inf").Puts(true),
    92  		That("math:is-inf &sign=-1 -inf").Puts(true),
    93  		That("math:is-inf &sign=1 -inf").Puts(false),
    94  		That("math:is-inf -inf").Puts(true),
    95  		That("math:is-inf nan").Puts(false),
    96  		That("math:is-inf 1").Puts(false),
    97  		That("math:is-inf "+z).Puts(false),
    98  		That("math:is-inf 1/2").Puts(false),
    99  
   100  		That("math:is-nan 1.3").Puts(false),
   101  		That("math:is-nan inf").Puts(false),
   102  		That("math:is-nan nan").Puts(true),
   103  		That("math:is-nan 1").Puts(false),
   104  		That("math:is-nan "+z).Puts(false),
   105  		That("math:is-nan 1/2").Puts(false),
   106  
   107  		That("math:max").Throws(
   108  			errs.ArityMismatch{What: "arguments", ValidLow: 1, ValidHigh: -1, Actual: 0},
   109  			"math:max"),
   110  		That("math:max 42").Puts(42),
   111  		That("math:max -3 3 10 -4").Puts(10),
   112  		That("math:max 2 10 "+z).Puts(bigInt(z)),
   113  		That("math:max "+z1+" "+z2+" "+z).Puts(bigInt(z2)),
   114  		That("math:max 1/2 1/3 2/3").Puts(big.NewRat(2, 3)),
   115  		That("math:max 1.0 2.0").Puts(2.0),
   116  		That("math:max 3 NaN 5").Puts(math.NaN()),
   117  
   118  		That("math:min").Throws(
   119  			errs.ArityMismatch{What: "arguments", ValidLow: 1, ValidHigh: -1, Actual: 0},
   120  			"math:min"),
   121  		That("math:min 42").Puts(42),
   122  		That("math:min -3 3 10 -4").Puts(-4),
   123  		That("math:min 2 10 "+z).Puts(2),
   124  		That("math:min "+z1+" "+z2+" "+z).Puts(bigInt(z)),
   125  		That("math:min 1/2 1/3 2/3").Puts(big.NewRat(1, 3)),
   126  		That("math:min 1.0 2.0").Puts(1.0),
   127  		That("math:min 3 NaN 5").Puts(math.NaN()),
   128  
   129  		// base is int, exp is int
   130  		That("math:pow 2 0").Puts(1),
   131  		That("math:pow 2 1").Puts(2),
   132  		That("math:pow 2 -1").Puts(big.NewRat(1, 2)),
   133  		That("math:pow 2 3").Puts(8),
   134  		That("math:pow 2 -3").Puts(big.NewRat(1, 8)),
   135  		// base is *big.Rat, exp is int
   136  		That("math:pow 2/3 0").Puts(1),
   137  		That("math:pow 2/3 1").Puts(big.NewRat(2, 3)),
   138  		That("math:pow 2/3 -1").Puts(big.NewRat(3, 2)),
   139  		That("math:pow 2/3 3").Puts(big.NewRat(8, 27)),
   140  		That("math:pow 2/3 -3").Puts(big.NewRat(27, 8)),
   141  		// exp is *big.Rat
   142  		That("math:pow 4 1/2").Puts(2.0),
   143  		// exp is float64
   144  		That("math:pow 2 2.0").Puts(4.0),
   145  		That("math:pow 1/2 2.0").Puts(0.25),
   146  		// base is float64
   147  		That("math:pow 2.0 2").Puts(4.0),
   148  
   149  		// Tests below this line are tests against simple bindings for Go's math package.
   150  
   151  		That("put $math:pi").Puts(math.Pi),
   152  		That("put $math:e").Puts(math.E),
   153  
   154  		That("math:trunc 2.1").Puts(2.0),
   155  		That("math:trunc -2.1").Puts(-2.0),
   156  		That("math:trunc 2.5").Puts(2.0),
   157  		That("math:trunc -2.5").Puts(-2.0),
   158  		That("math:trunc (float64 Inf)").Puts(math.Inf(1)),
   159  		That("math:trunc (float64 NaN)").Puts(math.NaN()),
   160  
   161  		That("math:log $math:e").Puts(1.0),
   162  		That("math:log 1").Puts(0.0),
   163  		That("math:log 0").Puts(math.Inf(-1)),
   164  		That("math:log -1").Puts(math.NaN()),
   165  
   166  		That("math:log10 10.0").Puts(1.0),
   167  		That("math:log10 100.0").Puts(2.0),
   168  		That("math:log10 1").Puts(0.0),
   169  		That("math:log10 0").Puts(math.Inf(-1)),
   170  		That("math:log10 -1").Puts(math.NaN()),
   171  
   172  		That("math:log2 8").Puts(3.0),
   173  		That("math:log2 1024.0").Puts(10.0),
   174  		That("math:log2 1").Puts(0.0),
   175  		That("math:log2 0").Puts(math.Inf(-1)),
   176  		That("math:log2 -1").Puts(math.NaN()),
   177  
   178  		That("math:cos 0").Puts(1.0),
   179  		That("math:cos 1").Puts(math.Cos(1.0)),
   180  		That("math:cos $math:pi").Puts(-1.0),
   181  
   182  		That("math:cosh 0").Puts(1.0),
   183  		That("math:cosh inf").Puts(math.Inf(1)),
   184  		That("math:cosh nan").Puts(math.NaN()),
   185  
   186  		That("math:sin 0").Puts(0.0),
   187  		That("math:sin 1").Puts(math.Sin(1.0)),
   188  		That("math:sin $math:pi").Puts(math.Sin(math.Pi)),
   189  
   190  		That("math:sinh 0").Puts(0.0),
   191  		That("math:sinh inf").Puts(math.Inf(1)),
   192  		That("math:sinh nan").Puts(math.NaN()),
   193  
   194  		That("math:tan 0").Puts(0.0),
   195  		That("math:tan 1").Puts(math.Tan(1.0)),
   196  		That("math:tan $math:pi").Puts(math.Tan(math.Pi)),
   197  
   198  		That("math:tanh 0").Puts(0.0),
   199  		That("math:tanh inf").Puts(1.0),
   200  		That("math:tanh nan").Puts(math.NaN()),
   201  
   202  		// This block of tests isn't strictly speaking necessary. But it helps
   203  		// ensure that we're not just confirming Go statements such as
   204  		//    math.Tan(math.Pi) == math.Tan(math.Pi)
   205  		// are true. The ops that should return a zero value do not actually
   206  		// do so. Which illustrates why an approximate match is needed.
   207  		That("math:cos 1").Puts(Approximately{F: 0.5403023058681397174}),
   208  		That("math:sin 1").Puts(Approximately{F: 0.8414709848078965066}),
   209  		That("math:sin $math:pi").Puts(Approximately{F: 0.0}),
   210  		That("math:tan 1").Puts(Approximately{F: 1.5574077246549023}),
   211  		That("math:tan $math:pi").Puts(Approximately{F: 0.0}),
   212  
   213  		That("math:sqrt 0").Puts(0.0),
   214  		That("math:sqrt 4").Puts(2.0),
   215  		That("math:sqrt -4").Puts(math.NaN()),
   216  
   217  		// Test the inverse trigonometric block of functions.
   218  		That("math:acos 0").Puts(math.Acos(0)),
   219  		That("math:acos 1").Puts(math.Acos(1)),
   220  		That("math:acos 1.00001").Puts(math.NaN()),
   221  
   222  		That("math:asin 0").Puts(math.Asin(0)),
   223  		That("math:asin 1").Puts(math.Asin(1)),
   224  		That("math:asin 1.00001").Puts(math.NaN()),
   225  
   226  		That("math:atan 0").Puts(math.Atan(0)),
   227  		That("math:atan 1").Puts(math.Atan(1)),
   228  		That("math:atan inf").Puts(math.Pi/2),
   229  
   230  		// Test the inverse hyperbolic trigonometric block of functions.
   231  		That("math:acosh 0").Puts(math.Acosh(0)),
   232  		That("math:acosh 1").Puts(math.Acosh(1)),
   233  		That("math:acosh nan").Puts(math.NaN()),
   234  
   235  		That("math:asinh 0").Puts(math.Asinh(0)),
   236  		That("math:asinh 1").Puts(math.Asinh(1)),
   237  		That("math:asinh inf").Puts(math.Inf(1)),
   238  
   239  		That("math:atanh 0").Puts(math.Atanh(0)),
   240  		That("math:atanh 1").Puts(math.Inf(1)),
   241  	)
   242  }
   243  
   244  func bigInt(s string) *big.Int {
   245  	z, ok := new(big.Int).SetString(s, 0)
   246  	if !ok {
   247  		panic("cannot parse as big int: " + s)
   248  	}
   249  	return z
   250  }