michael@0: // for-of works on strings and String objects. michael@0: michael@0: load(libdir + "string.js"); michael@0: michael@0: function test(s, expectedCodePoints) { michael@0: var copy = ''; michael@0: var codepoints = 0; michael@0: var singleHighSurrogate = false; michael@0: for (var v of s) { michael@0: assertEq(typeof v, 'string'); michael@0: assertEq(v.length, isSurrogatePair(v) ? 2 : 1); michael@0: assertEq(false, singleHighSurrogate && isLowSurrogate(v)); michael@0: copy += v; michael@0: codepoints += 1; michael@0: singleHighSurrogate = !isSurrogatePair(v) && isHighSurrogate(v); michael@0: } michael@0: assertEq(copy, String(s)); michael@0: assertEq(codepoints, expectedCodePoints); michael@0: } michael@0: michael@0: test('', 0); michael@0: test('abc', 3); michael@0: test('a \0 \ufffe \ufeff', 7); michael@0: michael@0: // Non-BMP characters are generally passed to JS in UTF-16, as surrogate pairs. michael@0: // ES6 requires that such pairs be treated as a single code point in for-of. michael@0: test('\ud808\udf45', 1); michael@0: michael@0: // Also test invalid surrogate pairs: michael@0: // (1) High surrogate not followed by low surrogate michael@0: test('\ud808', 1); michael@0: test('\ud808\u0000', 2); michael@0: // (2) Low surrogate not preceded by high surrogate michael@0: test('\udf45', 1); michael@0: test('\u0000\udf45', 2); michael@0: // (3) Low surrogate followed by high surrogate michael@0: test('\udf45\ud808', 2); michael@0: michael@0: test(new String(''), 0); michael@0: test(new String('abc'), 3); michael@0: test(new String('a \0 \ufffe \ufeff'), 7); michael@0: test(new String('\ud808\udf45'), 1); michael@0: test(new String('\ud808'), 1); michael@0: test(new String('\ud808\u0000'), 2); michael@0: test(new String('\udf45'), 1); michael@0: test(new String('\u0000\udf45'), 2); michael@0: test(new String('\udf45\ud808'), 2);