Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 10944) |
+++ test/cctest/test-api.cc (working copy) |
@@ -5529,6 +5529,17 @@ |
} |
+int GetUtf8Length(Handle<String> str) { |
+ int len = str->Utf8Length(); |
+ if (len < 0) { |
+ i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); |
+ i::FlattenString(istr); |
+ len = str->Utf8Length(); |
+ } |
+ return len; |
+} |
+ |
+ |
THREADED_TEST(StringWrite) { |
LocalContext context; |
v8::HandleScope scope; |
@@ -5609,7 +5620,7 @@ |
CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); |
memset(utf8buf, 0x1, sizeof(utf8buf)); |
- len = left_tree->Utf8Length(); |
+ len = GetUtf8Length(left_tree); |
int utf8_expected = |
(0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; |
CHECK_EQ(utf8_expected, len); |
@@ -5623,7 +5634,7 @@ |
CHECK_EQ(1, utf8buf[utf8_expected]); |
memset(utf8buf, 0x1, sizeof(utf8buf)); |
- len = right_tree->Utf8Length(); |
+ len = GetUtf8Length(right_tree); |
CHECK_EQ(utf8_expected, len); |
len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); |
CHECK_EQ(utf8_expected, len); |
@@ -5748,6 +5759,217 @@ |
} |
+static void Utf16Helper( |
+ LocalContext& context, |
+ const char* name, |
+ const char* lengths_name, |
+ int len) { |
+ Local<v8::Array> a = |
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); |
+ Local<v8::Array> alens = |
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); |
+ for (int i = 0; i < len; i++) { |
+ Local<v8::String> string = |
+ Local<v8::String>::Cast(a->Get(i)); |
+ Local<v8::Number> expected_len = |
+ Local<v8::Number>::Cast(alens->Get(i)); |
+ int length = GetUtf8Length(string); |
+ CHECK_EQ(static_cast<int>(expected_len->Value()), length); |
+ } |
+} |
+ |
+ |
+static uint16_t StringGet(Handle<String> str, int index) { |
+ i::Handle<i::String> istring = |
+ v8::Utils::OpenHandle(String::Cast(*str)); |
+ return istring->Get(index); |
+} |
+ |
+ |
+static void WriteUtf8Helper( |
+ LocalContext& context, |
+ const char* name, |
+ const char* lengths_name, |
+ int len) { |
+ Local<v8::Array> b = |
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); |
+ Local<v8::Array> alens = |
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); |
+ char buffer[1000]; |
+ char buffer2[1000]; |
+ for (int i = 0; i < len; i++) { |
+ Local<v8::String> string = |
+ Local<v8::String>::Cast(b->Get(i)); |
+ Local<v8::Number> expected_len = |
+ Local<v8::Number>::Cast(alens->Get(i)); |
+ int utf8_length = static_cast<int>(expected_len->Value()); |
+ for (int j = utf8_length + 1; j >= 0; j--) { |
+ memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer)); |
+ memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2)); |
+ int nchars; |
+ int utf8_written = |
+ string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS); |
+ int utf8_written2 = |
+ string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION); |
+ CHECK_GE(utf8_length + 1, utf8_written); |
+ CHECK_GE(utf8_length, utf8_written2); |
+ for (int k = 0; k < utf8_written2; k++) { |
+ CHECK_EQ(buffer[k], buffer2[k]); |
+ } |
+ CHECK(nchars * 3 >= utf8_written - 1); |
+ CHECK(nchars <= utf8_written); |
+ if (j == utf8_length + 1) { |
+ CHECK_EQ(utf8_written2, utf8_length); |
+ CHECK_EQ(utf8_written2 + 1, utf8_written); |
+ } |
+ CHECK_EQ(buffer[utf8_written], 42); |
+ if (j > utf8_length) { |
+ if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0); |
+ if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42); |
+ Handle<String> roundtrip = v8_str(buffer); |
+ CHECK(roundtrip->Equals(string)); |
+ } else { |
+ if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42); |
+ } |
+ if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42); |
+ if (nchars >= 2) { |
+ uint16_t trail = StringGet(string, nchars - 1); |
+ uint16_t lead = StringGet(string, nchars - 2); |
+ if (((lead & 0xfc00) == 0xd800) && |
+ ((trail & 0xfc00) == 0xdc00)) { |
+ unsigned char u1 = buffer2[utf8_written2 - 4]; |
+ unsigned char u2 = buffer2[utf8_written2 - 3]; |
+ unsigned char u3 = buffer2[utf8_written2 - 2]; |
+ unsigned char u4 = buffer2[utf8_written2 - 1]; |
+ CHECK_EQ((u1 & 0xf8), 0xf0); |
+ CHECK_EQ((u2 & 0xc0), 0x80); |
+ CHECK_EQ((u3 & 0xc0), 0x80); |
+ CHECK_EQ((u4 & 0xc0), 0x80); |
+ uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff); |
+ CHECK_EQ((u4 & 0x3f), (c & 0x3f)); |
+ CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f)); |
+ CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f)); |
+ CHECK_EQ((u1 & 0x3), c >> 18); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+THREADED_TEST(Utf16) { |
+ LocalContext context; |
+ v8::HandleScope scope; |
+ CompileRun( |
+ "var pad = '01234567890123456789';" |
+ "var p = [];" |
+ "var plens = [20, 3, 3];" |
+ "p.push('01234567890123456789');" |
+ "var lead = 0xd800;" |
+ "var trail = 0xdc00;" |
+ "p.push(String.fromCharCode(0xd800));" |
+ "p.push(String.fromCharCode(0xdc00));" |
+ "var a = [];" |
+ "var b = [];" |
+ "var alens = [];" |
+ "for (var i = 0; i < 3; i++) {" |
+ " p[1] = String.fromCharCode(lead++);" |
+ " for (var j = 0; j < 3; j++) {" |
+ " p[2] = String.fromCharCode(trail++);" |
+ " a.push(p[i] + p[j]);" |
+ " b.push(p[i] + p[j]);" |
+ " alens.push(plens[i] + plens[j]);" |
+ " }" |
+ "}" |
+ "alens[5] -= 2;" // Here the surrogate pairs match up. |
+ "var a2 = [];" |
+ "var b2 = [];" |
+ "var a2lens = [];" |
+ "for (var m = 0; m < 9; m++) {" |
+ " for (var n = 0; n < 9; n++) {" |
+ " a2.push(a[m] + a[n]);" |
+ " b2.push(b[m] + b[n]);" |
+ " var utf = alens[m] + alens[n];" // And here. |
+ // The 'n's that start with 0xdc.. are 6-8 |
+ // The 'm's that end with 0xd8.. are 1, 4 and 7 |
+ " if ((m % 3) == 1 && n >= 6) utf -= 2;" |
+ " a2lens.push(utf);" |
+ " }" |
+ "}"); |
+ Utf16Helper(context, "a", "alens", 9); |
+ Utf16Helper(context, "a2", "a2lens", 81); |
+ WriteUtf8Helper(context, "b", "alens", 9); |
+ WriteUtf8Helper(context, "b2", "a2lens", 81); |
+} |
+ |
+ |
+static bool SameSymbol(Handle<String> s1, Handle<String> s2) { |
+ i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); |
+ i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); |
+ return *is1 == *is2; |
+} |
+ |
+ |
+static void SameSymbolHelper(const char* a, const char* b) { |
+ Handle<String> symbol1 = v8::String::NewSymbol(a); |
+ Handle<String> symbol2 = v8::String::NewSymbol(b); |
+ CHECK(SameSymbol(symbol1, symbol2)); |
+} |
+ |
+ |
+THREADED_TEST(Utf16Symbol) { |
+ LocalContext context; |
+ v8::HandleScope scope; |
+ |
+ Handle<String> symbol1 = v8::String::NewSymbol("abc"); |
+ Handle<String> symbol2 = v8::String::NewSymbol("abc"); |
+ CHECK(SameSymbol(symbol1, symbol2)); |
+ |
+ SameSymbolHelper("\360\220\220\205", // 4 byte encoding. |
+ "\355\240\201\355\260\205"); // 2 3-byte surrogates. |
+ SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates. |
+ "\360\220\220\206"); // 4 byte encoding. |
+ SameSymbolHelper("x\360\220\220\205", // 4 byte encoding. |
+ "x\355\240\201\355\260\205"); // 2 3-byte surrogates. |
+ SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates. |
+ "x\360\220\220\206"); // 4 byte encoding. |
+ CompileRun( |
+ "var sym0 = 'benedictus';" |
+ "var sym0b = 'S\303\270ren';" |
+ "var sym1 = '\355\240\201\355\260\207';" |
+ "var sym2 = '\360\220\220\210';" |
+ "var sym3 = 'x\355\240\201\355\260\207';" |
+ "var sym4 = 'x\360\220\220\210';" |
+ "if (sym1.length != 2) throw sym1;" |
+ "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" |
+ "if (sym2.length != 2) throw sym2;" |
+ "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" |
+ "if (sym3.length != 3) throw sym3;" |
+ "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" |
+ "if (sym4.length != 3) throw sym4;" |
+ "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); |
+ Handle<String> sym0 = v8::String::NewSymbol("benedictus"); |
+ Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren"); |
+ Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207"); |
+ Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210"); |
+ Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207"); |
+ Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210"); |
+ v8::Local<v8::Object> global = context->Global(); |
+ Local<Value> s0 = global->Get(v8_str("sym0")); |
+ Local<Value> s0b = global->Get(v8_str("sym0b")); |
+ Local<Value> s1 = global->Get(v8_str("sym1")); |
+ Local<Value> s2 = global->Get(v8_str("sym2")); |
+ Local<Value> s3 = global->Get(v8_str("sym3")); |
+ Local<Value> s4 = global->Get(v8_str("sym4")); |
+ CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0)))); |
+ CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b)))); |
+ CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1)))); |
+ CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2)))); |
+ CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3)))); |
+ CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4)))); |
+} |
+ |
+ |
THREADED_TEST(ToArrayIndex) { |
v8::HandleScope scope; |
LocalContext context; |