github.com/elves/elvish@v0.15.0/pkg/eval/vals/index_test.go (about) 1 package vals 2 3 import ( 4 "testing" 5 6 "github.com/elves/elvish/pkg/eval/errs" 7 . "github.com/elves/elvish/pkg/tt" 8 ) 9 10 var ( 11 li0 = EmptyList 12 li4 = MakeList("foo", "bar", "lorem", "ipsum") 13 m = MakeMap("foo", "bar", "lorem", "ipsum") 14 ) 15 16 func TestIndex(t *testing.T) { 17 Test(t, Fn("Index", Index), Table{ 18 // String indices 19 Args("abc", "0").Rets("a", nil), 20 Args("abc", 0.0).Rets("a", nil), 21 Args("你好", "0").Rets("你", nil), 22 Args("你好", "3").Rets("好", nil), 23 Args("你好", "2").Rets(Any, errIndexNotAtRuneBoundary), 24 // String slices with half-open range. 25 Args("abc", "1..2").Rets("b", nil), 26 Args("abc", "1..").Rets("bc", nil), 27 Args("abc", "..").Rets("abc", nil), 28 Args("abc", "..0").Rets("", nil), // i == j == 0 is allowed 29 Args("abc", "3..").Rets("", nil), // i == j == n is allowed 30 // String slices with half-open range, using deprecated syntax. 31 Args("abc", "1:2").Rets("b", nil), 32 Args("abc", "1:").Rets("bc", nil), 33 Args("abc", ":").Rets("abc", nil), 34 Args("abc", ":0").Rets("", nil), // i == j == 0 is allowed 35 Args("abc", "3:").Rets("", nil), // i == j == n is allowed 36 // String slices with closed range. 37 Args("abc", "0..=1").Rets("ab", nil), 38 Args("abc", "1..=").Rets("bc", nil), 39 Args("abc", "..=1").Rets("ab", nil), 40 Args("abc", "..=").Rets("abc", nil), 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(Any, errs.OutOfRange{ 49 What: "index here", ValidLow: "0", ValidHigh: "-1", Actual: "0"}), 50 Args(li4, "4").Rets(Any, errs.OutOfRange{ 51 What: "index here", ValidLow: "0", ValidHigh: "3", Actual: "4"}), 52 Args(li4, "5").Rets(Any, errs.OutOfRange{ 53 What: "index here", ValidLow: "0", ValidHigh: "3", Actual: "5"}), 54 // Negative indices: -n <= i < 0. 55 Args(li4, "-1").Rets("ipsum", nil), 56 Args(li4, "-4").Rets("foo", nil), 57 Args(li4, "-5").Rets(Any, errs.OutOfRange{ 58 What: "negative index here", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}), 59 // Decimal indices are not allowed even if the value is an integer. 60 Args(li4, "0.0").Rets(Any, errIndexMustBeInteger), 61 62 // Float64 indices are allowed as long as they are integers. 63 Args(li4, 0.0).Rets("foo", nil), 64 Args(li4, 3.0).Rets("ipsum", nil), 65 Args(li4, 5.0).Rets(nil, errs.OutOfRange{ 66 What: "index here", ValidLow: "0", ValidHigh: "3", Actual: "5"}), 67 Args(li4, -1.0).Rets("ipsum", nil), 68 Args(li4, -5.0).Rets(nil, errs.OutOfRange{ 69 What: "negative index here", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}), 70 Args(li4, 0.5).Rets(Any, errIndexMustBeInteger), 71 72 // Half-open slices. 73 Args(li4, "1..3").Rets(Eq(MakeList("bar", "lorem")), nil), 74 Args(li4, "3..4").Rets(Eq(MakeList("ipsum")), nil), 75 Args(li4, "0..0").Rets(Eq(EmptyList), nil), // i == j == 0 is allowed 76 Args(li4, "4..4").Rets(Eq(EmptyList), nil), // i == j == n is allowed 77 // i defaults to 0 78 Args(li4, "..2").Rets(Eq(MakeList("foo", "bar")), nil), 79 Args(li4, "..-1").Rets(Eq(MakeList("foo", "bar", "lorem")), nil), 80 // j defaults to n 81 Args(li4, "3..").Rets(Eq(MakeList("ipsum")), nil), 82 Args(li4, "-2..").Rets(Eq(MakeList("lorem", "ipsum")), nil), 83 // Both indices can be omitted. 84 Args(li0, "..").Rets(Eq(li0), nil), 85 Args(li4, "..").Rets(Eq(li4), nil), 86 87 // Half-open slices using deprecated syntax. 88 Args(li4, "1:3").Rets(Eq(MakeList("bar", "lorem")), nil), 89 Args(li4, "3:4").Rets(Eq(MakeList("ipsum")), nil), 90 Args(li4, "0:0").Rets(Eq(EmptyList), nil), // i == j == 0 is allowed 91 Args(li4, "4:4").Rets(Eq(EmptyList), nil), // i == j == n is allowed 92 Args(li4, ":2").Rets(Eq(MakeList("foo", "bar")), nil), 93 Args(li4, ":-1").Rets(Eq(MakeList("foo", "bar", "lorem")), nil), 94 Args(li4, "3:").Rets(Eq(MakeList("ipsum")), nil), 95 Args(li4, "-2:").Rets(Eq(MakeList("lorem", "ipsum")), nil), 96 Args(li0, ":").Rets(Eq(li0), nil), 97 Args(li4, ":").Rets(Eq(li4), nil), 98 99 // Closed slices. 100 Args(li4, "1..=2").Rets(Eq(MakeList("bar", "lorem")), nil), 101 Args(li4, "..=1").Rets(Eq(MakeList("foo", "bar")), nil), 102 Args(li4, "..=-2").Rets(Eq(MakeList("foo", "bar", "lorem")), nil), 103 Args(li4, "3..=").Rets(Eq(MakeList("ipsum")), nil), 104 Args(li4, "..=").Rets(Eq(li4), nil), 105 106 // Index out of range. 107 Args(li4, "-5:1").Rets(nil, errs.OutOfRange{ 108 What: "negative index here", ValidLow: "-4", ValidHigh: "-1", Actual: "-5"}), 109 Args(li4, "0:5").Rets(nil, errs.OutOfRange{ 110 What: "index here", ValidLow: "0", ValidHigh: "4", Actual: "5"}), 111 Args(li4, "3:2").Rets(nil, errs.OutOfRange{ 112 What: "slice upper index here", ValidLow: "3", ValidHigh: "4", Actual: "2"}), 113 114 // Malformed list indices. 115 Args(li4, "a").Rets(Any, errIndexMustBeInteger), 116 // TODO(xiaq): Make the error more accurate. 117 Args(li4, "1:3:2").Rets(Any, errIndexMustBeInteger), 118 119 // Map indices 120 // ============ 121 122 Args(m, "foo").Rets("bar", nil), 123 Args(m, "bad").Rets(Any, NoSuchKey("bad")), 124 }) 125 } 126 127 func TestCheckDeprecatedIndex(t *testing.T) { 128 Test(t, Fn("CheckDeprecatedIndex", CheckDeprecatedIndex), Table{ 129 Args("ab", "1:2").Rets("using : for slice is deprecated; use .. instead"), 130 Args("ab", "1").Rets(""), 131 Args("ab", "1..2").Rets(""), 132 Args("ab", 1.0).Rets(""), 133 Args(li4, "1:2").Rets("using : for slice is deprecated; use .. instead"), 134 Args(li4, "1").Rets(""), 135 Args(li4, "1..2").Rets(""), 136 Args(li4, 1.0).Rets(""), 137 }) 138 }