src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/vals/index_test.go (about)

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