1package eval_test 2 3import ( 4 "math" 5 "math/big" 6 "testing" 7 "unsafe" 8 9 . "src.elv.sh/pkg/eval" 10 "src.elv.sh/pkg/eval/errs" 11 12 . "src.elv.sh/pkg/eval/evaltest" 13 "src.elv.sh/pkg/eval/vals" 14) 15 16func TestNsCmd(t *testing.T) { 17 Test(t, 18 That("put (ns [&name=value])[name]").Puts("value"), 19 That("n: = (ns [&name=value]); put $n:name").Puts("value"), 20 That("ns [&[]=[]]").Throws(errs.BadValue{ 21 What: `key of argument of "ns"`, 22 Valid: "string", Actual: "list"}), 23 ) 24} 25 26func TestMakeMap(t *testing.T) { 27 Test(t, 28 That("make-map []").Puts(vals.EmptyMap), 29 That("make-map [[k v]]").Puts(vals.MakeMap("k", "v")), 30 That("make-map [[k v] [k v2]]").Puts(vals.MakeMap("k", "v2")), 31 That("make-map [[k1 v1] [k2 v2]]"). 32 Puts(vals.MakeMap("k1", "v1", "k2", "v2")), 33 That("make-map [kv]").Puts(vals.MakeMap("k", "v")), 34 That("make-map [{ } [k v]]"). 35 Throws( 36 errs.BadValue{ 37 What: "input to make-map", Valid: "iterable", Actual: "fn"}, 38 "make-map [{ } [k v]]"), 39 That("make-map [[k v] [k]]"). 40 Throws( 41 errs.BadValue{ 42 What: "input to make-map", Valid: "iterable with 2 elements", 43 Actual: "list with 1 elements"}, 44 "make-map [[k v] [k]]"), 45 ) 46} 47 48var ( 49 maxInt = 1<<((unsafe.Sizeof(0)*8)-1) - 1 50 minInt = -maxInt - 1 51 52 maxDenseIntInFloat = float64(1 << 53) 53) 54 55func TestRange(t *testing.T) { 56 Test(t, 57 // Basic argument sanity checks. 58 That("range").Throws(ErrorWithType(errs.ArityMismatch{})), 59 That("range 0 1 2").Throws(ErrorWithType(errs.ArityMismatch{})), 60 61 // Int count up. 62 That("range 3").Puts(0, 1, 2), 63 That("range 1 3").Puts(1, 2), 64 // Int count down. 65 That("range -1 10 &step=3").Puts(-1, 2, 5, 8), 66 That("range 3 -3").Puts(3, 2, 1, 0, -1, -2), 67 // Near maxInt or minInt. 68 That("range "+args(maxInt-2, maxInt)).Puts(maxInt-2, maxInt-1), 69 That("range "+args(maxInt, maxInt-2)).Puts(maxInt, maxInt-1), 70 That("range "+args(minInt, minInt+2)).Puts(minInt, minInt+1), 71 That("range "+args(minInt+2, minInt)).Puts(minInt+2, minInt+1), 72 // Invalid step given the "start" and "end" values of the range. 73 That("range &step=-1 1"). 74 Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-1"}), 75 That("range &step=1 1 0"). 76 Throws(errs.BadValue{What: "step", Valid: "negative", Actual: "1"}), 77 thatOutputErrorIsBubbled("range 2"), 78 79 // Big int count up. 80 That("range "+z+" "+z3).Puts(bigInt(z), bigInt(z1), bigInt(z2)), 81 That("range "+z+" "+z3+" &step=2").Puts(bigInt(z), bigInt(z2)), 82 // Big int count down. 83 That("range "+z3+" "+z).Puts(bigInt(z3), bigInt(z2), bigInt(z1)), 84 That("range "+z3+" "+z+" &step=-2").Puts(bigInt(z3), bigInt(z1)), 85 // Invalid big int step. 86 That("range &step=-"+z+" 10"). 87 Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-" + z}), 88 That("range &step="+z+" 10 0"). 89 Throws(errs.BadValue{What: "step", Valid: "negative", Actual: z}), 90 thatOutputErrorIsBubbled("range "+z+" "+z1), 91 92 // Rational count up. 93 That("range 23/10").Puts(0, 1, 2), 94 That("range 1/10 23/10").Puts( 95 big.NewRat(1, 10), big.NewRat(11, 10), big.NewRat(21, 10)), 96 That("range 23/10 1/10").Puts( 97 big.NewRat(23, 10), big.NewRat(13, 10), big.NewRat(3, 10)), 98 That("range 1/10 9/10 &step=3/10").Puts( 99 big.NewRat(1, 10), big.NewRat(4, 10), big.NewRat(7, 10)), 100 // Rational count down. 101 That("range 9/10 0/10 &step=-3/10").Puts( 102 big.NewRat(9, 10), big.NewRat(6, 10), big.NewRat(3, 10)), 103 // Invalid rational step. 104 That("range &step=-1/2 10"). 105 Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-1/2"}), 106 That("range &step=1/2 10 0"). 107 Throws(errs.BadValue{What: "step", Valid: "negative", Actual: "1/2"}), 108 thatOutputErrorIsBubbled("range 1/2 3/2"), 109 110 // Float64 count up. 111 That("range 1.2").Puts(0.0, 1.0), 112 That("range &step=0.5 1 3").Puts(1.0, 1.5, 2.0, 2.5), 113 // Float64 count down. 114 That("range 1.2 -1.2").Puts(1.2, Approximately{F: 0.2}, Approximately{F: -0.8}), 115 That("range &step=-0.5 3 1").Puts(3.0, 2.5, 2.0, 1.5), 116 // Near maxDenseIntInFloat. 117 That("range "+args(maxDenseIntInFloat-2, "+inf")). 118 Puts(maxDenseIntInFloat-2, maxDenseIntInFloat-1, maxDenseIntInFloat), 119 That("range "+args(maxDenseIntInFloat, maxDenseIntInFloat-2)). 120 Puts(maxDenseIntInFloat, maxDenseIntInFloat-1), 121 // Invalid float64 step. 122 That("range &step=-0.5 10"). 123 Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-0.5"}), 124 That("range &step=0.5 10 0"). 125 Throws(errs.BadValue{What: "step", Valid: "negative", Actual: "0.5"}), 126 thatOutputErrorIsBubbled("range 1.2"), 127 ) 128} 129 130func TestRepeat(t *testing.T) { 131 Test(t, 132 That(`repeat 4 foo`).Puts("foo", "foo", "foo", "foo"), 133 thatOutputErrorIsBubbled("repeat 1 foo"), 134 ) 135} 136 137func TestAssoc(t *testing.T) { 138 Test(t, 139 That(`put (assoc [0] 0 zero)[0]`).Puts("zero"), 140 That(`put (assoc [&] k v)[k]`).Puts("v"), 141 That(`put (assoc [&k=v] k v2)[k]`).Puts("v2"), 142 ) 143} 144 145func TestDissoc(t *testing.T) { 146 Test(t, 147 That(`has-key (dissoc [&k=v] k) k`).Puts(false), 148 That("dissoc foo 0").Throws(ErrorWithMessage("cannot dissoc")), 149 ) 150} 151 152func TestAll(t *testing.T) { 153 Test(t, 154 That(`put foo bar | all`).Puts("foo", "bar"), 155 That(`echo foobar | all`).Puts("foobar"), 156 That(`all [foo bar]`).Puts("foo", "bar"), 157 thatOutputErrorIsBubbled("all [foo bar]"), 158 ) 159} 160 161func TestOne(t *testing.T) { 162 Test(t, 163 That(`put foo | one`).Puts("foo"), 164 That(`put | one`).Throws(AnyError), 165 That(`put foo bar | one`).Throws(AnyError), 166 That(`one [foo]`).Puts("foo"), 167 That(`one []`).Throws(AnyError), 168 That(`one [foo bar]`).Throws(AnyError), 169 thatOutputErrorIsBubbled("one [foo]"), 170 ) 171} 172 173func TestTake(t *testing.T) { 174 Test(t, 175 That(`range 100 | take 2`).Puts(0, 1), 176 thatOutputErrorIsBubbled("take 1 [foo bar]"), 177 ) 178} 179 180func TestDrop(t *testing.T) { 181 Test(t, 182 That(`range 100 | drop 98`).Puts(98, 99), 183 thatOutputErrorIsBubbled("drop 1 [foo bar lorem]"), 184 ) 185} 186 187func TestHasKey(t *testing.T) { 188 Test(t, 189 That(`has-key [foo bar] 0`).Puts(true), 190 That(`has-key [foo bar] 0..1`).Puts(true), 191 That(`has-key [foo bar] 0..20`).Puts(false), 192 That(`has-key [&lorem=ipsum &foo=bar] lorem`).Puts(true), 193 That(`has-key [&lorem=ipsum &foo=bar] loremwsq`).Puts(false), 194 ) 195} 196 197func TestHasValue(t *testing.T) { 198 Test(t, 199 That(`has-value [&lorem=ipsum &foo=bar] lorem`).Puts(false), 200 That(`has-value [&lorem=ipsum &foo=bar] bar`).Puts(true), 201 That(`has-value [foo bar] bar`).Puts(true), 202 That(`has-value [foo bar] badehose`).Puts(false), 203 That(`has-value "foo" o`).Puts(true), 204 That(`has-value "foo" d`).Puts(false), 205 ) 206} 207 208func TestCount(t *testing.T) { 209 Test(t, 210 That(`range 100 | count`).Puts(100), 211 That(`count [(range 100)]`).Puts(100), 212 That(`count 123`).Puts(3), 213 That(`count 1 2 3`).Throws( 214 errs.ArityMismatch{What: "arguments", ValidLow: 0, ValidHigh: 1, Actual: 3}, 215 "count 1 2 3"), 216 That(`count $true`).Throws(ErrorWithMessage("cannot get length of a bool")), 217 ) 218} 219 220func TestKeys(t *testing.T) { 221 Test(t, 222 That(`keys [&]`).DoesNothing(), 223 That(`keys [&a=foo]`).Puts("a"), 224 // Windows does not have an external sort command. Disabled until we have a 225 // builtin sort command. 226 That(`keys [&a=foo &b=bar] | order`).Puts("a", "b"), 227 That("keys (num 1)").Throws(ErrorWithMessage("cannot iterate keys of number")), 228 thatOutputErrorIsBubbled("keys [&a=foo]"), 229 ) 230} 231 232func TestCompare(t *testing.T) { 233 Test(t, 234 // Comparing strings. 235 That("compare a b").Puts(-1), 236 That("compare b a").Puts(1), 237 That("compare x x").Puts(0), 238 239 // Comparing numbers. 240 That("compare (num 1) (num 2)").Puts(-1), 241 That("compare (num 2) (num 1)").Puts(1), 242 That("compare (num 3) (num 3)").Puts(0), 243 244 That("compare (num 1/4) (num 1/2)").Puts(-1), 245 That("compare (num 1/3) (num 0.2)").Puts(1), 246 That("compare (num 3.0) (num 3)").Puts(0), 247 248 That("compare (num nan) (num 3)").Puts(-1), 249 That("compare (num 3) (num nan)").Puts(1), 250 That("compare (num nan) (num nan)").Puts(0), 251 252 // Comparing lists. 253 That("compare [a, b] [a, a]").Puts(1), 254 That("compare [a, a] [a, b]").Puts(-1), 255 That("compare [x, y] [x, y]").Puts(0), 256 257 // Uncomparable values. 258 That("compare 1 (num 1)").Throws(ErrUncomparable), 259 That("compare x [x]").Throws(ErrUncomparable), 260 That("compare a [&a=x]").Throws(ErrUncomparable), 261 ) 262} 263 264func TestOrder(t *testing.T) { 265 Test(t, 266 // Ordering strings 267 That("put foo bar ipsum | order").Puts("bar", "foo", "ipsum"), 268 That("put foo bar bar | order").Puts("bar", "bar", "foo"), 269 That("put 10 1 5 2 | order").Puts("1", "10", "2", "5"), 270 271 // Ordering typed numbers 272 // Only small integers 273 That("put 10 1 1 | each $num~ | order").Puts(1, 1, 10), 274 That("put 10 1 5 2 -1 | each $num~ | order").Puts(-1, 1, 2, 5, 10), 275 // Small and large integers 276 That("put 1 "+z+" 2 "+z+" | each $num~ | order").Puts(1, 2, bigInt(z), bigInt(z)), 277 // Integers and rationals 278 That("put 1 2 3/2 3/2 | each $num~ | order"). 279 Puts(1, big.NewRat(3, 2), big.NewRat(3, 2), 2), 280 // Integers and floats 281 That("put 1 1.5 2 1.5 | each $num~ | order"). 282 Puts(1, 1.5, 1.5, 2), 283 // Mixed integers and floats. 284 That("put (num 1) (float64 1.5) (float64 2) (num 1.5) | order"). 285 Puts(1, 1.5, 1.5, 2.0), 286 // For the sake of ordering, NaN's are considered smaller than other numbers 287 That("put NaN -1 NaN | each $num~ | order").Puts(math.NaN(), math.NaN(), -1), 288 289 // Ordering lists 290 That("put [b] [a] | order").Puts(vals.MakeList("a"), vals.MakeList("b")), 291 That("put [a] [b] [a] | order"). 292 Puts(vals.MakeList("a"), vals.MakeList("a"), vals.MakeList("b")), 293 That("put [(float64 10)] [(float64 2)] | order"). 294 Puts(vals.MakeList(2.0), vals.MakeList(10.0)), 295 That("put [a b] [b b] [a c] | order"). 296 Puts( 297 vals.MakeList("a", "b"), 298 vals.MakeList("a", "c"), vals.MakeList("b", "b")), 299 That("put [a] [] [a (float64 2)] [a (float64 1)] | order"). 300 Puts(vals.EmptyList, vals.MakeList("a"), 301 vals.MakeList("a", 1.0), vals.MakeList("a", 2.0)), 302 303 // Attempting to order uncomparable values 304 That("put (num 1) 1 | order"). 305 Throws(ErrUncomparable, "order"), 306 That("put 1 (float64 1) | order"). 307 Throws(ErrUncomparable, "order"), 308 That("put 1 (float64 1) b | order"). 309 Throws(ErrUncomparable, "order"), 310 That("put [a] a | order"). 311 Throws(ErrUncomparable, "order"), 312 That("put [a] [(float64 1)] | order"). 313 Throws(ErrUncomparable, "order"), 314 315 // &reverse 316 That("put foo bar ipsum | order &reverse").Puts("ipsum", "foo", "bar"), 317 318 // &less-than 319 That("put 1 10 2 5 | order &less-than={|a b| < $a $b }"). 320 Puts("1", "2", "5", "10"), 321 322 // &less-than writing more than one value 323 That("put 1 10 2 5 | order &less-than={|a b| put $true $false }"). 324 Throws( 325 errs.BadValue{ 326 What: "output of the &less-than callback", 327 Valid: "a single boolean", Actual: "2 values"}, 328 "order &less-than={|a b| put $true $false }"), 329 330 // &less-than writing non-boolean value 331 That("put 1 10 2 5 | order &less-than={|a b| put x }"). 332 Throws( 333 errs.BadValue{ 334 What: "output of the &less-than callback", 335 Valid: "boolean", Actual: "string"}, 336 "order &less-than={|a b| put x }"), 337 338 // &less-than throwing an exception 339 That("put 1 10 2 5 | order &less-than={|a b| fail bad }"). 340 Throws( 341 FailError{"bad"}, 342 "fail bad ", "order &less-than={|a b| fail bad }"), 343 344 // &less-than and &reverse 345 That("put 1 10 2 5 | order &reverse &less-than={|a b| < $a $b }"). 346 Puts("10", "5", "2", "1"), 347 348 // Sort should be stable - test by pretending that all values but one 349 // are equal, an check that the order among them has not changed. 350 That("put l x o x r x e x m | order &less-than={|a b| eq $a x }"). 351 Puts("x", "x", "x", "x", "l", "o", "r", "e", "m"), 352 353 thatOutputErrorIsBubbled("order [foo]"), 354 ) 355} 356