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

     1  package eval_test
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"testing"
     7  	"unsafe"
     8  
     9  	. "github.com/markusbkk/elvish/pkg/eval"
    10  	"github.com/markusbkk/elvish/pkg/eval/errs"
    11  
    12  	. "github.com/markusbkk/elvish/pkg/eval/evaltest"
    13  	"github.com/markusbkk/elvish/pkg/eval/vals"
    14  )
    15  
    16  func TestNsCmd(t *testing.T) {
    17  	Test(t,
    18  		That("put (ns [&name=value])[name]").Puts("value"),
    19  		That("var 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  
    26  func 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  
    48  var (
    49  	maxInt = 1<<((unsafe.Sizeof(0)*8)-1) - 1
    50  	minInt = -maxInt - 1
    51  
    52  	maxDenseIntInFloat = float64(1 << 53)
    53  )
    54  
    55  func 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  
   130  func 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  
   137  func 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  
   145  func 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  
   152  func 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  
   161  func TestOne(t *testing.T) {
   162  	Test(t,
   163  		That(`put foo | one`).Puts("foo"),
   164  		That(`put | one`).Throws(ErrorWithType(errs.ArityMismatch{})),
   165  		That(`put foo bar | one`).Throws(ErrorWithType(errs.ArityMismatch{})),
   166  		That(`one [foo]`).Puts("foo"),
   167  		That(`one []`).Throws(ErrorWithType(errs.ArityMismatch{})),
   168  		That(`one [foo bar]`).Throws(ErrorWithType(errs.ArityMismatch{})),
   169  		thatOutputErrorIsBubbled("one [foo]"),
   170  	)
   171  }
   172  
   173  func 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  
   180  func 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  
   187  func 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  
   197  func 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  
   208  func 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  
   220  func 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  
   232  func 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  
   264  func 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  }