1 package goja
2
3 import "testing"
4
5 func TestSubstr(t *testing.T) {
6 const SCRIPT = `
7 assert.sameValue('abc'.substr(0, false), '', 'start: 0, length: false');
8 assert.sameValue('abc'.substr(1, false), '', 'start: 1, length: false');
9 assert.sameValue('abc'.substr(2, false), '', 'start: 2, length: false');
10 assert.sameValue('abc'.substr(3, false), '', 'start: 3, length: false');
11
12 assert.sameValue('abc'.substr(0, NaN), '', 'start: 0, length: NaN');
13 assert.sameValue('abc'.substr(1, NaN), '', 'start: 1, length: NaN');
14 assert.sameValue('abc'.substr(2, NaN), '', 'start: 2, length: NaN');
15 assert.sameValue('abc'.substr(3, NaN), '', 'start: 3, length: NaN');
16
17 assert.sameValue('abc'.substr(0, ''), '', 'start: 0, length: ""');
18 assert.sameValue('abc'.substr(1, ''), '', 'start: 1, length: ""');
19 assert.sameValue('abc'.substr(2, ''), '', 'start: 2, length: ""');
20 assert.sameValue('abc'.substr(3, ''), '', 'start: 3, length: ""');
21
22 assert.sameValue('abc'.substr(0, null), '', 'start: 0, length: null');
23 assert.sameValue('abc'.substr(1, null), '', 'start: 1, length: null');
24 assert.sameValue('abc'.substr(2, null), '', 'start: 2, length: null');
25 assert.sameValue('abc'.substr(3, null), '', 'start: 3, length: null');
26
27 assert.sameValue('abc'.substr(0, -1), '', '0, -1');
28 assert.sameValue('abc'.substr(0, -2), '', '0, -2');
29 assert.sameValue('abc'.substr(0, -3), '', '0, -3');
30 assert.sameValue('abc'.substr(0, -4), '', '0, -4');
31
32 assert.sameValue('abc'.substr(1, -1), '', '1, -1');
33 assert.sameValue('abc'.substr(1, -2), '', '1, -2');
34 assert.sameValue('abc'.substr(1, -3), '', '1, -3');
35 assert.sameValue('abc'.substr(1, -4), '', '1, -4');
36
37 assert.sameValue('abc'.substr(2, -1), '', '2, -1');
38 assert.sameValue('abc'.substr(2, -2), '', '2, -2');
39 assert.sameValue('abc'.substr(2, -3), '', '2, -3');
40 assert.sameValue('abc'.substr(2, -4), '', '2, -4');
41
42 assert.sameValue('abc'.substr(3, -1), '', '3, -1');
43 assert.sameValue('abc'.substr(3, -2), '', '3, -2');
44 assert.sameValue('abc'.substr(3, -3), '', '3, -3');
45 assert.sameValue('abc'.substr(3, -4), '', '3, -4');
46
47 assert.sameValue('abc'.substr(0, 1), 'a', '0, 1');
48 assert.sameValue('abc'.substr(0, 2), 'ab', '0, 1');
49 assert.sameValue('abc'.substr(0, 3), 'abc', '0, 1');
50 assert.sameValue('abc'.substr(0, 4), 'abc', '0, 1');
51
52 assert.sameValue('abc'.substr(1, 1), 'b', '1, 1');
53 assert.sameValue('abc'.substr(1, 2), 'bc', '1, 1');
54 assert.sameValue('abc'.substr(1, 3), 'bc', '1, 1');
55 assert.sameValue('abc'.substr(1, 4), 'bc', '1, 1');
56
57 assert.sameValue('abc'.substr(2, 1), 'c', '2, 1');
58 assert.sameValue('abc'.substr(2, 2), 'c', '2, 1');
59 assert.sameValue('abc'.substr(2, 3), 'c', '2, 1');
60 assert.sameValue('abc'.substr(2, 4), 'c', '2, 1');
61
62 assert.sameValue('abc'.substr(3, 1), '', '3, 1');
63 assert.sameValue('abc'.substr(3, 2), '', '3, 1');
64 assert.sameValue('abc'.substr(3, 3), '', '3, 1');
65 assert.sameValue('abc'.substr(3, 4), '', '3, 1');
66
67 assert.sameValue('abc'.substr(0), 'abc', 'start: 0, length: unspecified');
68 assert.sameValue('abc'.substr(1), 'bc', 'start: 1, length: unspecified');
69 assert.sameValue('abc'.substr(2), 'c', 'start: 2, length: unspecified');
70 assert.sameValue('abc'.substr(3), '', 'start: 3, length: unspecified');
71
72 assert.sameValue(
73 'abc'.substr(0, undefined), 'abc', 'start: 0, length: undefined'
74 );
75 assert.sameValue(
76 'abc'.substr(1, undefined), 'bc', 'start: 1, length: undefined'
77 );
78 assert.sameValue(
79 'abc'.substr(2, undefined), 'c', 'start: 2, length: undefined'
80 );
81 assert.sameValue(
82 'abc'.substr(3, undefined), '', 'start: 3, length: undefined'
83 );
84
85 assert.sameValue('A—', String.fromCharCode(65, 0x2014));
86
87 `
88
89 testScriptWithTestLib(SCRIPT, _undefined, t)
90 }
91
92 func TestStringMatchSym(t *testing.T) {
93 const SCRIPT = `
94 function Prefix(p) {
95 this.p = p;
96 }
97
98 Prefix.prototype[Symbol.match] = function(s) {
99 return s.substring(0, this.p.length) === this.p;
100 }
101
102 var prefix1 = new Prefix("abc");
103 var 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 testScript(SCRIPT, valueTrue, t)
109 }
110
111 func TestStringMatchAllSym(t *testing.T) {
112 const SCRIPT = `
113 function Prefix(p) {
114 this.p = p;
115 }
116
117 Prefix.prototype[Symbol.matchAll] = function(s) {
118 return s.substring(0, this.p.length) === this.p;
119 }
120
121 var prefix1 = new Prefix("abc");
122 var 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 testScript(SCRIPT, valueTrue, t)
128 }
129
130 func TestGenericSplitter(t *testing.T) {
131 const SCRIPT = `
132 function MyRegexp(pattern, flags) {
133 if (pattern instanceof MyRegexp) {
134 pattern = pattern.wrapped;
135 }
136 this.wrapped = new RegExp(pattern, flags);
137 }
138
139 MyRegexp.prototype.exec = function() {
140 return this.wrapped.exec.apply(this.wrapped, arguments);
141 }
142
143 Object.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
152 Object.defineProperty(MyRegexp.prototype, "flags", {
153 get: function() {
154 return this.wrapped.flags;
155 }
156 });
157
158 MyRegexp[Symbol.species] = MyRegexp;
159 MyRegexp.prototype[Symbol.split] = RegExp.prototype[Symbol.split];
160
161 var r = new MyRegexp(/ /);
162 var res = "a b c".split(r);
163 res.length === 3 && res[0] === "a" && res[1] === "b" && res[2] === "c";
164 `
165 testScript(SCRIPT, valueTrue, t)
166 }
167
168 func TestStringIterSurrPair(t *testing.T) {
169 const SCRIPT = `
170 var lo = '\uD834';
171 var hi = '\uDF06';
172 var pair = lo + hi;
173 var string = 'a' + pair + 'b' + lo + pair + hi + lo;
174 var iterator = string[Symbol.iterator]();
175 var result;
176
177 result = iterator.next();
178 if (result.value !== 'a') {
179 throw new Error("at 0: " + result.value);
180 }
181 result = iterator.next();
182 if (result.value !== pair) {
183 throw new Error("at 1: " + result.value);
184 }
185
186 `
187 testScript(SCRIPT, _undefined, t)
188 }
189
190 func TestValueStringBuilder(t *testing.T) {
191 t.Run("substringASCII", func(t *testing.T) {
192 t.Parallel()
193 var sb StringBuilder
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 StringBuilder
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 StringBuilder
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 StringBuilder
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 StringBuilder
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 StringBuilder
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 t.Run("concat_ASCII_importedASCII", func(t *testing.T) {
257 t.Parallel()
258 var sb StringBuilder
259 sb.WriteString(asciiString("ascii"))
260 sb.WriteString(&importedString{s: " imported_ascii1234567890"})
261 s := sb.String()
262 if res, ok := s.(asciiString); !ok || res != "ascii imported_ascii1234567890" {
263 t.Fatal(s)
264 }
265 })
266
267 t.Run("concat_ASCII_importedUnicode", func(t *testing.T) {
268 t.Parallel()
269 var sb StringBuilder
270 sb.WriteString(asciiString("ascii"))
271 sb.WriteString(&importedString{s: " imported_юникод"})
272 s := sb.String()
273 if res, ok := s.(unicodeString); !ok || !res.SameAs(newStringValue("ascii imported_юникод")) {
274 t.Fatal(s)
275 }
276 })
277
278 }
279
View as plain text