1package goja 2 3import "testing" 4 5func TestSubstr(t *testing.T) { 6 const SCRIPT = ` 7assert.sameValue('abc'.substr(0, false), '', 'start: 0, length: false'); 8assert.sameValue('abc'.substr(1, false), '', 'start: 1, length: false'); 9assert.sameValue('abc'.substr(2, false), '', 'start: 2, length: false'); 10assert.sameValue('abc'.substr(3, false), '', 'start: 3, length: false'); 11 12assert.sameValue('abc'.substr(0, NaN), '', 'start: 0, length: NaN'); 13assert.sameValue('abc'.substr(1, NaN), '', 'start: 1, length: NaN'); 14assert.sameValue('abc'.substr(2, NaN), '', 'start: 2, length: NaN'); 15assert.sameValue('abc'.substr(3, NaN), '', 'start: 3, length: NaN'); 16 17assert.sameValue('abc'.substr(0, ''), '', 'start: 0, length: ""'); 18assert.sameValue('abc'.substr(1, ''), '', 'start: 1, length: ""'); 19assert.sameValue('abc'.substr(2, ''), '', 'start: 2, length: ""'); 20assert.sameValue('abc'.substr(3, ''), '', 'start: 3, length: ""'); 21 22assert.sameValue('abc'.substr(0, null), '', 'start: 0, length: null'); 23assert.sameValue('abc'.substr(1, null), '', 'start: 1, length: null'); 24assert.sameValue('abc'.substr(2, null), '', 'start: 2, length: null'); 25assert.sameValue('abc'.substr(3, null), '', 'start: 3, length: null'); 26 27assert.sameValue('abc'.substr(0, -1), '', '0, -1'); 28assert.sameValue('abc'.substr(0, -2), '', '0, -2'); 29assert.sameValue('abc'.substr(0, -3), '', '0, -3'); 30assert.sameValue('abc'.substr(0, -4), '', '0, -4'); 31 32assert.sameValue('abc'.substr(1, -1), '', '1, -1'); 33assert.sameValue('abc'.substr(1, -2), '', '1, -2'); 34assert.sameValue('abc'.substr(1, -3), '', '1, -3'); 35assert.sameValue('abc'.substr(1, -4), '', '1, -4'); 36 37assert.sameValue('abc'.substr(2, -1), '', '2, -1'); 38assert.sameValue('abc'.substr(2, -2), '', '2, -2'); 39assert.sameValue('abc'.substr(2, -3), '', '2, -3'); 40assert.sameValue('abc'.substr(2, -4), '', '2, -4'); 41 42assert.sameValue('abc'.substr(3, -1), '', '3, -1'); 43assert.sameValue('abc'.substr(3, -2), '', '3, -2'); 44assert.sameValue('abc'.substr(3, -3), '', '3, -3'); 45assert.sameValue('abc'.substr(3, -4), '', '3, -4'); 46 47assert.sameValue('abc'.substr(0, 1), 'a', '0, 1'); 48assert.sameValue('abc'.substr(0, 2), 'ab', '0, 1'); 49assert.sameValue('abc'.substr(0, 3), 'abc', '0, 1'); 50assert.sameValue('abc'.substr(0, 4), 'abc', '0, 1'); 51 52assert.sameValue('abc'.substr(1, 1), 'b', '1, 1'); 53assert.sameValue('abc'.substr(1, 2), 'bc', '1, 1'); 54assert.sameValue('abc'.substr(1, 3), 'bc', '1, 1'); 55assert.sameValue('abc'.substr(1, 4), 'bc', '1, 1'); 56 57assert.sameValue('abc'.substr(2, 1), 'c', '2, 1'); 58assert.sameValue('abc'.substr(2, 2), 'c', '2, 1'); 59assert.sameValue('abc'.substr(2, 3), 'c', '2, 1'); 60assert.sameValue('abc'.substr(2, 4), 'c', '2, 1'); 61 62assert.sameValue('abc'.substr(3, 1), '', '3, 1'); 63assert.sameValue('abc'.substr(3, 2), '', '3, 1'); 64assert.sameValue('abc'.substr(3, 3), '', '3, 1'); 65assert.sameValue('abc'.substr(3, 4), '', '3, 1'); 66 67assert.sameValue('abc'.substr(0), 'abc', 'start: 0, length: unspecified'); 68assert.sameValue('abc'.substr(1), 'bc', 'start: 1, length: unspecified'); 69assert.sameValue('abc'.substr(2), 'c', 'start: 2, length: unspecified'); 70assert.sameValue('abc'.substr(3), '', 'start: 3, length: unspecified'); 71 72assert.sameValue( 73 'abc'.substr(0, undefined), 'abc', 'start: 0, length: undefined' 74); 75assert.sameValue( 76 'abc'.substr(1, undefined), 'bc', 'start: 1, length: undefined' 77); 78assert.sameValue( 79 'abc'.substr(2, undefined), 'c', 'start: 2, length: undefined' 80); 81assert.sameValue( 82 'abc'.substr(3, undefined), '', 'start: 3, length: undefined' 83); 84 85assert.sameValue('A—', String.fromCharCode(65, 0x2014)); 86 87 ` 88 89 testScript1(TESTLIB+SCRIPT, _undefined, t) 90} 91 92func TestStringMatchSym(t *testing.T) { 93 const SCRIPT = ` 94function Prefix(p) { 95 this.p = p; 96} 97 98Prefix.prototype[Symbol.match] = function(s) { 99 return s.substring(0, this.p.length) === this.p; 100} 101 102var prefix1 = new Prefix("abc"); 103var prefix2 = new Prefix("def"); 104 105"abc123".match(prefix1) === true && "abc123".match(prefix2) === false && 106"def123".match(prefix1) === false && "def123".match(prefix2) === true; 107` 108 testScript1(SCRIPT, valueTrue, t) 109} 110 111func TestStringMatchAllSym(t *testing.T) { 112 const SCRIPT = ` 113function Prefix(p) { 114 this.p = p; 115} 116 117Prefix.prototype[Symbol.matchAll] = function(s) { 118 return s.substring(0, this.p.length) === this.p; 119} 120 121var prefix1 = new Prefix("abc"); 122var prefix2 = new Prefix("def"); 123 124"abc123".matchAll(prefix1) === true && "abc123".matchAll(prefix2) === false && 125"def123".matchAll(prefix1) === false && "def123".matchAll(prefix2) === true; 126` 127 testScript1(SCRIPT, valueTrue, t) 128} 129 130func TestGenericSplitter(t *testing.T) { 131 const SCRIPT = ` 132function MyRegexp(pattern, flags) { 133 if (pattern instanceof MyRegexp) { 134 pattern = pattern.wrapped; 135 } 136 this.wrapped = new RegExp(pattern, flags); 137} 138 139MyRegexp.prototype.exec = function() { 140 return this.wrapped.exec.apply(this.wrapped, arguments); 141} 142 143Object.defineProperty(MyRegexp.prototype, "lastIndex", { 144 get: function() { 145 return this.wrapped.lastIndex; 146 }, 147 set: function(v) { 148 this.wrapped.lastIndex = v; 149 } 150}); 151 152Object.defineProperty(MyRegexp.prototype, "flags", { 153 get: function() { 154 return this.wrapped.flags; 155 } 156}); 157 158MyRegexp[Symbol.species] = MyRegexp; 159MyRegexp.prototype[Symbol.split] = RegExp.prototype[Symbol.split]; 160 161var r = new MyRegexp(/ /); 162var res = "a b c".split(r); 163res.length === 3 && res[0] === "a" && res[1] === "b" && res[2] === "c"; 164` 165 testScript1(SCRIPT, valueTrue, t) 166} 167 168func TestStringIterSurrPair(t *testing.T) { 169 const SCRIPT = ` 170var lo = '\uD834'; 171var hi = '\uDF06'; 172var pair = lo + hi; 173var string = 'a' + pair + 'b' + lo + pair + hi + lo; 174var iterator = string[Symbol.iterator](); 175var result; 176 177result = iterator.next(); 178if (result.value !== 'a') { 179 throw new Error("at 0: " + result.value); 180} 181result = iterator.next(); 182if (result.value !== pair) { 183 throw new Error("at 1: " + result.value); 184} 185 186` 187 testScript1(SCRIPT, _undefined, t) 188} 189 190func TestValueStringBuilder(t *testing.T) { 191 t.Run("substringASCII", func(t *testing.T) { 192 t.Parallel() 193 var sb valueStringBuilder 194 str := newStringValue("a\U00010000b") 195 sb.WriteSubstring(str, 0, 1) 196 res := sb.String() 197 if res != asciiString("a") { 198 t.Fatal(res) 199 } 200 }) 201 202 t.Run("substringASCIIPure", func(t *testing.T) { 203 t.Parallel() 204 var sb valueStringBuilder 205 str := newStringValue("ab") 206 sb.WriteSubstring(str, 0, 1) 207 res := sb.String() 208 if res != asciiString("a") { 209 t.Fatal(res) 210 } 211 }) 212 213 t.Run("substringUnicode", func(t *testing.T) { 214 t.Parallel() 215 var sb valueStringBuilder 216 str := newStringValue("a\U00010000b") 217 sb.WriteSubstring(str, 1, 3) 218 res := sb.String() 219 if !res.SameAs(unicodeStringFromRunes([]rune{0x10000})) { 220 t.Fatal(res) 221 } 222 }) 223 224 t.Run("substringASCIIUnicode", func(t *testing.T) { 225 t.Parallel() 226 var sb valueStringBuilder 227 str := newStringValue("a\U00010000b") 228 sb.WriteSubstring(str, 0, 2) 229 res := sb.String() 230 if !res.SameAs(unicodeStringFromRunes([]rune{'a', 0xD800})) { 231 t.Fatal(res) 232 } 233 }) 234 235 t.Run("substringUnicodeASCII", func(t *testing.T) { 236 t.Parallel() 237 var sb valueStringBuilder 238 str := newStringValue("a\U00010000b") 239 sb.WriteSubstring(str, 2, 4) 240 res := sb.String() 241 if !res.SameAs(unicodeStringFromRunes([]rune{0xDC00, 'b'})) { 242 t.Fatal(res) 243 } 244 }) 245 246 t.Run("concatSubstringUnicodeASCII", func(t *testing.T) { 247 t.Parallel() 248 var sb valueStringBuilder 249 sb.WriteString(newStringValue("юникод")) 250 sb.WriteSubstring(asciiString(" ascii"), 0, 6) 251 if res := sb.String(); !res.SameAs(newStringValue("юникод ascii")) { 252 t.Fatal(res) 253 } 254 }) 255} 256