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

     1  package vals
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/markusbkk/elvish/pkg/eval/errs"
     8  	"github.com/markusbkk/elvish/pkg/testutil"
     9  	. "github.com/markusbkk/elvish/pkg/tt"
    10  )
    11  
    12  var (
    13  	li0 = EmptyList
    14  	li4 = MakeList("foo", "bar", "lorem", "ipsum")
    15  	m   = MakeMap("foo", "bar", "lorem", "ipsum")
    16  )
    17  
    18  func TestIndex(t *testing.T) {
    19  	Test(t, Fn("Index", Index), Table{
    20  		// String indices
    21  		Args("abc", "0").Rets("a", nil),
    22  		Args("abc", 0).Rets("a", nil),
    23  		Args("你好", "0").Rets("你", nil),
    24  		Args("你好", "3").Rets("好", nil),
    25  		Args("你好", "2").Rets(Any, errIndexNotAtRuneBoundary),
    26  		// String slices with half-open range.
    27  		Args("abc", "1..2").Rets("b", nil),
    28  		Args("abc", "1..").Rets("bc", nil),
    29  		Args("abc", "..").Rets("abc", nil),
    30  		Args("abc", "..0").Rets("", nil), // i == j == 0 is allowed
    31  		Args("abc", "3..").Rets("", nil), // i == j == n is allowed
    32  		// String slices with closed range.
    33  		Args("abc", "0..=1").Rets("ab", nil),
    34  		Args("abc", "1..=").Rets("bc", nil),
    35  		Args("abc", "..=1").Rets("ab", nil),
    36  		Args("abc", "..=").Rets("abc", nil),
    37  		// String slices not at rune boundary.
    38  		Args("你好", "2..").Rets(Any, errIndexNotAtRuneBoundary),
    39  		Args("你好", "..2").Rets(Any, errIndexNotAtRuneBoundary),
    40  
    41  		// List indices
    42  		// ============
    43  
    44  		// Simple indices: 0 <= i < n.
    45  		Args(li4, "0").Rets("foo", nil),
    46  		Args(li4, "3").Rets("ipsum", nil),
    47  		Args(li0, "0").Rets(Any, errs.OutOfRange{
    48  			What: "index", ValidLow: "0", ValidHigh: "-1", Actual: "0"}),
    49  		Args(li4, "4").Rets(Any, errs.OutOfRange{
    50  			What: "index", ValidLow: "0", ValidHigh: "3", Actual: "4"}),
    51  		Args(li4, "5").Rets(Any, errs.OutOfRange{
    52  			What: "index", ValidLow: "0", ValidHigh: "3", Actual: "5"}),
    53  		Args(li4, z).Rets(Any,
    54  			errs.OutOfRange{What: "index", ValidLow: "0", ValidHigh: "3", Actual: z}),
    55  		// Negative indices: -n <= i < 0.
    56  		Args(li4, "-1").Rets("ipsum", nil),
    57  		Args(li4, "-4").Rets("foo", nil),
    58  		Args(li4, "-5").Rets(Any, errs.OutOfRange{
    59  			What: "negative index", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}),
    60  		Args(li4, "-"+z).Rets(Any,
    61  			errs.OutOfRange{What: "negative index", ValidLow: "-4", ValidHigh: "-1", Actual: "-" + z}),
    62  		// Float indices are not allowed even if the value is an integer.
    63  		Args(li4, 0.0).Rets(Any, errIndexMustBeInteger),
    64  
    65  		// Integer indices are allowed.
    66  		Args(li4, 0).Rets("foo", nil),
    67  		Args(li4, 3).Rets("ipsum", nil),
    68  		Args(li4, 5).Rets(nil, errs.OutOfRange{
    69  			What: "index", ValidLow: "0", ValidHigh: "3", Actual: "5"}),
    70  		Args(li4, -1).Rets("ipsum", nil),
    71  		Args(li4, -5).Rets(nil, errs.OutOfRange{
    72  			What: "negative index", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}),
    73  
    74  		// Half-open slices.
    75  		Args(li4, "1..3").Rets(eq(MakeList("bar", "lorem")), nil),
    76  		Args(li4, "3..4").Rets(eq(MakeList("ipsum")), nil),
    77  		Args(li4, "0..0").Rets(eq(EmptyList), nil), // i == j == 0 is allowed
    78  		Args(li4, "4..4").Rets(eq(EmptyList), nil), // i == j == n is allowed
    79  		// i defaults to 0
    80  		Args(li4, "..2").Rets(eq(MakeList("foo", "bar")), nil),
    81  		Args(li4, "..-1").Rets(eq(MakeList("foo", "bar", "lorem")), nil),
    82  		// j defaults to n
    83  		Args(li4, "3..").Rets(eq(MakeList("ipsum")), nil),
    84  		Args(li4, "-2..").Rets(eq(MakeList("lorem", "ipsum")), nil),
    85  		// Both indices can be omitted.
    86  		Args(li0, "..").Rets(eq(li0), nil),
    87  		Args(li4, "..").Rets(eq(li4), nil),
    88  
    89  		// Closed slices.
    90  		Args(li4, "1..=2").Rets(eq(MakeList("bar", "lorem")), nil),
    91  		Args(li4, "..=1").Rets(eq(MakeList("foo", "bar")), nil),
    92  		Args(li4, "..=-2").Rets(eq(MakeList("foo", "bar", "lorem")), nil),
    93  		Args(li4, "3..=").Rets(eq(MakeList("ipsum")), nil),
    94  		Args(li4, "..=").Rets(eq(li4), nil),
    95  
    96  		// Slice index out of range.
    97  		Args(li4, "-5..1").Rets(nil, errs.OutOfRange{
    98  			What: "negative index", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}),
    99  		Args(li4, "0..5").Rets(nil, errs.OutOfRange{
   100  			What: "index", ValidLow: "0", ValidHigh: "4", Actual: "5"}),
   101  		Args(li4, z+"..").Rets(nil,
   102  			errs.OutOfRange{What: "index", ValidLow: "0", ValidHigh: "4", Actual: z}),
   103  		// Slice index upper < lower
   104  		Args(li4, "3..2").Rets(nil, errs.OutOfRange{
   105  			What: "slice upper index", ValidLow: "3", ValidHigh: "4", Actual: "2"}),
   106  		Args(li4, "-1..-2").Rets(nil,
   107  			errs.OutOfRange{What: "negative slice upper index",
   108  				ValidLow: "-1", ValidHigh: "-1", Actual: "-2"}),
   109  
   110  		// Malformed list indices.
   111  		Args(li4, "a").Rets(Any, errIndexMustBeInteger),
   112  		// TODO(xiaq): Make the error more accurate.
   113  		Args(li4, "1:3:2").Rets(Any, errIndexMustBeInteger),
   114  
   115  		// Map indices
   116  		// ============
   117  
   118  		Args(m, "foo").Rets("bar", nil),
   119  		Args(m, "bad").Rets(Any, NoSuchKey("bad")),
   120  
   121  		// Not indexable
   122  		Args(1, "foo").Rets(nil, errNotIndexable),
   123  	})
   124  }
   125  
   126  func TestIndex_File(t *testing.T) {
   127  	testutil.InTempDir(t)
   128  	f, err := os.Create("f")
   129  	if err != nil {
   130  		t.Skip("create file:", err)
   131  	}
   132  
   133  	Test(t, Fn("Index", Index), Table{
   134  		Args(f, "fd").Rets(int(f.Fd()), nil),
   135  		Args(f, "name").Rets(f.Name(), nil),
   136  		Args(f, "x").Rets(nil, NoSuchKey("x")),
   137  	})
   138  }