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 }