Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index 4524574ff1815bbbe53de73c66e9ab8494751e36..e0765b888678fb794c21382193df30528899ac87 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -709,9 +709,294 @@ TEST(ExternalStringWithDisposeHandling) { |
} |
+static void TestNewLatin1String(int encoding1, int encoding2) { |
+ const char* chars1 = "ASCII 123"; |
+ const char* chars1js = "'ASCII 123'"; |
+ int str1_len = strlen(chars1); |
+ const char* chars2 = "Non-ASCII \xAB\xCD\xEF"; |
+ const char* chars2js = "'Non-ASCII \\u00ab\\u00cd\\u00ef'"; |
+ int str2_len = strlen(chars2); |
+ |
+ Local<String> str1 = String::New(chars1, str1_len, encoding1); |
+ Local<String> str2 = String::New(chars2, str2_len, encoding2); |
+ Local<String> str1_compare = CompileRun(chars1js)->ToString(); |
+ Local<String> str2_compare = CompileRun(chars2js)->ToString(); |
+ |
+ if (encoding1 & String::NOT_ASCII_HINT) { |
+ CHECK(v8::Utils::OpenHandle(*str1)->IsSeqTwoByteString()); |
+ } else { |
+ CHECK(v8::Utils::OpenHandle(*str1)->IsSeqAsciiString()); |
+ } |
+ CHECK(v8::Utils::OpenHandle(*str1_compare)->IsSeqAsciiString()); |
+ CHECK(v8::Utils::OpenHandle(*str2)->IsSeqTwoByteString()); |
+ CHECK(v8::Utils::OpenHandle(*str2_compare)->IsSeqTwoByteString()); |
+ |
+ CHECK(str1_compare->Equals(str1)); |
+ CHECK(str2_compare->Equals(str2)); |
+} |
+ |
+ |
+TEST(CreateLatin1String) { |
+ v8::HandleScope scope; |
+ LocalContext env; |
+ |
+ int latin1 = String::LATIN1_ENCODING; |
+ int l_noascii = String::LATIN1_ENCODING | String::NOT_ASCII_HINT; |
+ int l_ascii = String::LATIN1_ENCODING | String::ASCII_HINT; |
+ |
+ TestNewLatin1String(latin1, latin1); |
+ TestNewLatin1String(l_ascii, latin1); |
+ TestNewLatin1String(l_noascii, l_noascii); |
+} |
+ |
+ |
+TEST(ExternalStringEncoding) { |
+ v8::HandleScope scope; |
+ LocalContext env; |
+ int counter = 0; |
+ |
+ { HandleScope scope; |
+ uint16_t* two_byte_ascii = AsciiToTwoByteString("two byte ascii"); |
+ uint16_t* two_byte = AsciiToTwoByteString("two byte non-ascii \x99"); |
+ char* ascii = i::StrDup("ascii"); |
+ |
+ TestResource* two_byte_resource = new TestResource(two_byte, &counter); |
+ TestResource* two_byte_ascii_resource = |
+ new TestResource(two_byte_ascii, &counter); |
+ TestAsciiResource* ascii_resource = |
+ new TestAsciiResource(ascii, &counter); |
+ |
+ Local<String> two_byte_external = String::NewExternal(two_byte_resource); |
+ Local<String> two_byte_ascii_external = |
+ String::NewExternal(two_byte_ascii_resource); |
+ Local<String> ascii_external = String::NewExternal(ascii_resource); |
+ Local<String> not_external = v8_str("not external"); |
+ |
+ CHECK_EQ(String::UTF_16_ENCODING | String::NOT_ASCII_HINT, |
+ two_byte_external->GetExternalStringEncoding()); |
+ CHECK_EQ(String::UTF_16_ENCODING | String::ASCII_HINT, |
+ two_byte_ascii_external->GetExternalStringEncoding()); |
+ CHECK_EQ(String::LATIN1_ENCODING | String::ASCII_HINT, |
+ ascii_external->GetExternalStringEncoding()); |
+ CHECK_EQ(String::INVALID_ENCODING, |
+ not_external->GetExternalStringEncoding()); |
+ |
+ CHECK_EQ(two_byte_resource, two_byte_external->GetExternalStringResource()); |
+ CHECK_EQ(two_byte_ascii_resource, |
+ two_byte_ascii_external->GetExternalStringResourceBase()); |
+ CHECK_EQ(ascii_resource, ascii_external->GetExternalStringResourceBase()); |
+ |
+ CHECK_EQ(0, counter); |
+ } |
+ |
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); |
+ |
+ CHECK_EQ(3, counter); |
+} |
+ |
+ |
+TEST(WriteLatin1String) { |
+ HandleScope scope; |
+ LocalContext env; |
+ const char* latin1_ascii = "latin1 ascii"; |
+ const char* latin1 = "\x99 latin1 non-ascii \xF8"; |
+ const char* concat = "latin1 ascii\x99 latin1 non-ascii \xF8"; |
+ const char* sub = "latin1 non-ascii \xF8"; |
+ |
+ Local<String> latin1_ascii_string = String::New(latin1_ascii, |
+ String::kUndefinedLength, |
+ String::LATIN1_ENCODING); |
+ Local<String> latin1_string = String::New(latin1, |
+ String::kUndefinedLength, |
+ String::LATIN1_ENCODING); |
+ Local<String> concat_string = String::Concat(latin1_ascii_string, |
+ latin1_string); |
+ Local<String> sub_string = v8::Utils::ToLocal( |
+ FACTORY->NewSubString( |
+ v8::Utils::OpenHandle(*latin1_string), 2, latin1_string->Length())); |
+ |
+ CHECK(v8::Utils::OpenHandle(*latin1_ascii_string)->IsSeqAsciiString()); |
+ CHECK(v8::Utils::OpenHandle(*latin1_string)->IsSeqTwoByteString()); |
+ CHECK(v8::Utils::OpenHandle(*concat_string)->IsConsString()); |
+ CHECK(v8::Utils::OpenHandle(*sub_string)->IsSlicedString()); |
+ |
+ char buffer[64]; |
+ CHECK_EQ(strlen(latin1_ascii), latin1_ascii_string->WriteLatin1(buffer)); |
+ CHECK_EQ(0, strcmp(latin1_ascii, buffer)); |
+ CHECK_EQ(strlen(latin1), latin1_string->WriteLatin1(buffer)); |
+ CHECK_EQ(0, strcmp(latin1, buffer)); |
+ CHECK_EQ(strlen(concat), concat_string->WriteLatin1(buffer)); |
+ CHECK_EQ(0, strcmp(concat, buffer)); |
+ CHECK_EQ(strlen(sub), sub_string->WriteLatin1(buffer)); |
+ CHECK_EQ(0, strcmp(sub, buffer)); |
+ |
+ memset(buffer, 0x1, sizeof(buffer)); |
+ CHECK_EQ(strlen(latin1), |
+ latin1_string->WriteLatin1(buffer, |
+ 0, |
+ String::kUndefinedLength, |
+ String::NO_NULL_TERMINATION)); |
+ CHECK_EQ(0, strncmp(latin1, buffer, strlen(latin1))); |
+ CHECK_NE(0, strcmp(latin1, buffer)); |
+ buffer[strlen(latin1)] = '\0'; |
+ CHECK_EQ(0, strcmp(latin1, buffer)); |
+ |
+ CHECK_EQ(strlen(latin1) - 2, |
+ latin1_string->WriteLatin1(buffer, 2)); |
+ CHECK_EQ(0, strncmp(latin1 + 2, buffer, strlen(latin1))); |
+} |
+ |
+ |
+class TestLatin1Resource: public String::ExternalLatin1StringResource { |
+ public: |
+ explicit TestLatin1Resource(const char* data, int* counter = NULL) |
+ : data_(data), length_(strlen(data)), counter_(counter) { } |
+ |
+ ~TestLatin1Resource() { |
+ i::DeleteArray(data_); |
+ if (counter_ != NULL) ++*counter_; |
+ } |
+ |
+ const char* data() const { |
+ return data_; |
+ } |
+ |
+ size_t length() const { |
+ return length_; |
+ } |
+ private: |
+ const char* data_; |
+ size_t length_; |
+ int* counter_; |
+}; |
+ |
+ |
+TEST(ExternalLatin1String) { |
+ HandleScope scope; |
+ LocalContext env; |
+ int counter = 0; |
+ |
+ { HandleScope scope; |
+ char* latin1_ascii_a = i::StrDup("latin1 ascii a"); |
+ char* latin1_ascii_b = i::StrDup("latin1 ascii b"); |
+ char* latin1_a = i::StrDup("latin non-ascii \xAA"); |
+ char* latin1_b = i::StrDup("latin non-ascii \xBB"); |
+ |
+ TestLatin1Resource* latin1_ascii_a_resource = |
+ new TestLatin1Resource(latin1_ascii_a, &counter); |
+ TestLatin1Resource* latin1_ascii_b_resource = |
+ new TestLatin1Resource(latin1_ascii_b, &counter); |
+ TestLatin1Resource* latin1_a_resource = |
+ new TestLatin1Resource(latin1_a, &counter); |
+ TestLatin1Resource* latin1_b_resource = |
+ new TestLatin1Resource(latin1_b, &counter); |
+ |
+ Local<String> latin1_ascii_a_external = |
+ String::NewExternal(latin1_ascii_a_resource); |
+ Local<String> latin1_ascii_b_external = String::NewExternal( |
+ latin1_ascii_b_resource, |
+ String::LATIN1_ENCODING | String::ASCII_HINT); |
+ CHECK_EQ(0, counter); |
+ |
+ // Non-ascii latin1 strings are internalized immediately as two-byte |
+ // string and the external resource is disposed. |
+ Local<String> latin1_a_external = String::NewExternal(latin1_a_resource); |
+ Local<String> latin1_b_external = String::NewExternal( |
+ latin1_b_resource, String::LATIN1_ENCODING | String::NOT_ASCII_HINT); |
+ CHECK(v8::Utils::OpenHandle(*latin1_a_external)->IsSeqTwoByteString()); |
+ CHECK(v8::Utils::OpenHandle(*latin1_b_external)->IsSeqTwoByteString()); |
+ CHECK_EQ(2, counter); |
+ |
+ CHECK_EQ(latin1_ascii_a_external->GetExternalStringEncoding(), |
+ (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); |
+ CHECK_EQ(latin1_ascii_b_external->GetExternalStringEncoding(), |
+ (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); |
+ CHECK_EQ(latin1_a_external->GetExternalStringEncoding(), |
+ v8::String::INVALID_ENCODING); |
+ CHECK_EQ(latin1_b_external->GetExternalStringEncoding(), |
+ v8::String::INVALID_ENCODING); |
+ |
+ CHECK_EQ(latin1_ascii_a_resource, |
+ latin1_ascii_a_external->GetExternalStringResourceBase()); |
+ CHECK_EQ(latin1_ascii_b_resource, |
+ latin1_ascii_b_external->GetExternalStringResourceBase()); |
+ } |
+ |
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); |
+ CHECK_EQ(4, counter); |
+} |
+ |
+ |
+TEST(ExternalizeLatin1String) { |
+ HandleScope scope; |
+ LocalContext env; |
+ int counter = 0; |
+ |
+ { HandleScope scope; |
+ Local<String> latin1_a_ascii = String::New("latin1 a ascii"); |
+ Local<String> latin1_b_ascii = String::New("latin1 b ascii"); |
+ Local<String> latin1 = String::New("latin1 non-ascii \xAA", |
+ String::kUndefinedLength, |
+ String::LATIN1_ENCODING); |
+ |
+ CHECK(v8::Utils::OpenHandle(*latin1_a_ascii)->IsSeqAsciiString()); |
+ CHECK(v8::Utils::OpenHandle(*latin1_b_ascii)->IsSeqAsciiString()); |
+ CHECK(v8::Utils::OpenHandle(*latin1)->IsSeqTwoByteString()); |
+ |
+ // Run GC twice to put those strings into old space for externalizing. |
+ HEAP->CollectGarbage(i::NEW_SPACE); |
+ HEAP->CollectGarbage(i::NEW_SPACE); |
+ |
+ char* latin1_a_ascii_chars = i::NewArray<char>(64); |
+ uint16_t* latin1_b_ascii_chars = i::NewArray<uint16_t>(64); |
+ uint16_t* latin1_chars = i::NewArray<uint16_t>(64); |
+ |
+ latin1_a_ascii->WriteLatin1(latin1_a_ascii_chars); |
+ latin1_b_ascii->Write(latin1_b_ascii_chars); |
+ latin1->Write(latin1_chars); |
+ |
+ TestLatin1Resource* latin1_a_ascii_resource = |
+ new TestLatin1Resource(latin1_a_ascii_chars, &counter); |
+ TestResource* latin1_b_ascii_resource = |
+ new TestResource(latin1_b_ascii_chars, &counter); |
+ TestResource* latin1_resource = |
+ new TestResource(latin1_chars, &counter); |
+ |
+ CHECK(latin1_a_ascii->MakeExternal(latin1_a_ascii_resource)); |
+ CHECK(latin1_a_ascii->IsExternalAscii()); |
+ CHECK_EQ(latin1_a_ascii->GetExternalStringEncoding(), |
+ (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); |
+ CHECK_EQ(latin1_a_ascii_resource, |
+ latin1_a_ascii->GetExternalStringResourceBase()); |
+ CHECK(latin1_a_ascii->Equals(String::New("latin1 a ascii"))); |
+ |
+ CHECK(latin1_b_ascii->MakeExternal(latin1_b_ascii_resource)); |
+ CHECK(latin1_b_ascii->IsExternal()); |
+ CHECK_EQ(latin1_b_ascii->GetExternalStringEncoding(), |
+ (v8::String::UTF_16_ENCODING | v8::String::ASCII_HINT)); |
+ CHECK_EQ(latin1_b_ascii_resource, |
+ latin1_b_ascii->GetExternalStringResourceBase()); |
+ CHECK(latin1_b_ascii->Equals(String::New("latin1 b ascii"))); |
+ |
+ CHECK(latin1->MakeExternal(latin1_resource)); |
+ CHECK(latin1->IsExternal()); |
+ CHECK_EQ(latin1->GetExternalStringEncoding(), |
+ (v8::String::UTF_16_ENCODING | v8::String::NOT_ASCII_HINT)); |
+ CHECK_EQ(latin1_resource, |
+ latin1->GetExternalStringResourceBase()); |
+ CHECK(latin1->Equals(String::New("latin1 non-ascii \xAA", |
+ String::kUndefinedLength, |
+ String::LATIN1_ENCODING))); |
+ } |
+ |
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); |
+ CHECK_EQ(3, counter); |
+} |
+ |
+ |
THREADED_TEST(StringConcat) { |
{ |
- v8::HandleScope scope; |
+ HandleScope scope; |
LocalContext env; |
const char* one_byte_string_1 = "function a_times_t"; |
const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; |