Backed out changeset d05089c1e269 (bug 1822297) for causing Documentation related...
[gecko.git] / js / src / jsapi-tests / testExternalStrings.cpp
blob7b615f39c6009d35ee4674e10eaefad58c732906
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "js/CharacterEncoding.h" // JS::FindSmallestEncoding, JS::SmallestEncoding
6 #include "js/GCAPI.h" // JSExternalStringCallbacks, JS_NewExternalUCString, JS_NewExternalStringLatin1, JS_NewMaybeExternalStringUTF8, JS::AutoRequireNoGC
7 #include "js/String.h" // JS::IsExternalStringLatin1
8 #include "jsapi-tests/tests.h"
9 #include "util/Text.h"
11 static const char16_t arr[] = u"hi, don't delete me";
12 static const size_t arrlen = js_strlen(arr);
14 static const char arr2[] = "hi, don't delete me";
15 static const size_t arrlen2 = js_strlen(arr2);
17 static int finalized1 = 0;
18 static int finalized2 = 0;
19 static int finalized3 = 0;
20 static int finalized4 = 0;
22 struct ExternalStringCallbacks : public JSExternalStringCallbacks {
23 int* finalizedCount = nullptr;
24 bool isTwoBytes = false;
26 explicit ExternalStringCallbacks(int* finalizedCount, bool isTwoBytes)
27 : finalizedCount(finalizedCount), isTwoBytes(isTwoBytes) {}
29 void finalize(JS::Latin1Char* chars) const override {
30 MOZ_ASSERT(!isTwoBytes);
31 MOZ_ASSERT(chars == (JS::Latin1Char*)arr2);
32 (*finalizedCount)++;
35 void finalize(char16_t* chars) const override {
36 MOZ_ASSERT(isTwoBytes);
37 MOZ_ASSERT(chars == arr);
38 (*finalizedCount)++;
41 size_t sizeOfBuffer(const JS::Latin1Char* chars,
42 mozilla::MallocSizeOf mallocSizeOf) const override {
43 MOZ_CRASH("Unexpected call");
46 size_t sizeOfBuffer(const char16_t* chars,
47 mozilla::MallocSizeOf mallocSizeOf) const override {
48 MOZ_CRASH("Unexpected call");
52 static const ExternalStringCallbacks callbacks1(&finalized1, true);
53 static const ExternalStringCallbacks callbacks2(&finalized2, true);
54 static const ExternalStringCallbacks callbacks3(&finalized3, false);
55 static const ExternalStringCallbacks callbacks4(&finalized4, false);
57 BEGIN_TEST(testExternalStrings) {
58 const unsigned N = 1000;
60 for (unsigned i = 0; i < N; ++i) {
61 CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks1));
62 CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks2));
63 CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
64 &callbacks3));
65 CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
66 &callbacks4));
69 JS_GC(cx);
71 CHECK((N - finalized1) == 0);
72 CHECK((N - finalized2) == 0);
73 CHECK((N - finalized3) == 0);
74 CHECK((N - finalized4) == 0);
76 return true;
78 END_TEST(testExternalStrings)
80 struct SimpleExternalStringCallbacks : public JSExternalStringCallbacks {
81 SimpleExternalStringCallbacks() = default;
83 void finalize(JS::Latin1Char* chars) const override {}
85 void finalize(char16_t* chars) const override {
86 MOZ_CRASH("Unexpected call");
89 size_t sizeOfBuffer(const JS::Latin1Char* chars,
90 mozilla::MallocSizeOf mallocSizeOf) const override {
91 MOZ_CRASH("Unexpected call");
94 size_t sizeOfBuffer(const char16_t* chars,
95 mozilla::MallocSizeOf mallocSizeOf) const override {
96 MOZ_CRASH("Unexpected call");
100 static const SimpleExternalStringCallbacks simpleCallback;
102 static const char utf8ASCII[] = "hi, I'm UTF-8 string";
103 static const size_t utf8ASCIILen = js_strlen(utf8ASCII);
105 static const char utf8Latin1[] = "hi, I'm \xC3\x9CTF-8 string";
106 static const size_t utf8Latin1Len = js_strlen(utf8Latin1);
108 static const char latin1[] = "hi, I'm \xDCTF-8 string";
109 static const size_t latin1Len = js_strlen(latin1);
111 static const char utf8UTF16[] = "hi, I'm UTF-\xEF\xBC\x98 string";
112 static const size_t utf8UTF16Len = js_strlen(utf8UTF16);
114 static const char16_t utf16[] = u"hi, I'm UTF-8 string";
115 static const size_t utf16Len = js_strlen(utf16);
117 BEGIN_TEST(testExternalStringsUTF8) {
118 // UTF-8 chars with ASCII range content should be converted into external
119 // string.
121 JS::UTF8Chars utf8Chars(utf8ASCII, utf8ASCIILen);
122 CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::ASCII);
123 bool allocatedExternal = false;
124 JS::Rooted<JSString*> str(
125 cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
126 &allocatedExternal));
127 CHECK(str);
128 CHECK(allocatedExternal);
130 const JSExternalStringCallbacks* callbacks = nullptr;
131 const JS::Latin1Char* chars = nullptr;
132 CHECK(JS::IsExternalStringLatin1(str, &callbacks, &chars));
133 CHECK(callbacks == &simpleCallback);
134 CHECK((void*)chars == (void*)utf8ASCII);
136 CHECK(StringHasLatin1Chars(str));
138 JS::AutoAssertNoGC nogc(cx);
139 size_t length;
140 chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &length);
141 CHECK(length == utf8ASCIILen);
142 CHECK(memcmp(chars, utf8ASCII, length) == 0);
145 // UTF-8 chars with latin-1 range content shouldn't be converted into external
146 // string, but regular latin-1 string.
148 JS::UTF8Chars utf8Chars(utf8Latin1, utf8Latin1Len);
149 CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::Latin1);
150 bool allocatedExternal = false;
151 JS::Rooted<JSString*> str(
152 cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
153 &allocatedExternal));
154 CHECK(str);
155 CHECK(!allocatedExternal);
157 const JSExternalStringCallbacks* callbacks = nullptr;
158 const JS::Latin1Char* chars = nullptr;
159 CHECK(!JS::IsExternalStringLatin1(str, &callbacks, &chars));
160 CHECK(!callbacks);
161 CHECK(!chars);
163 CHECK(StringHasLatin1Chars(str));
165 JS::AutoAssertNoGC nogc(cx);
166 size_t length;
167 chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &length);
168 CHECK(length == latin1Len);
169 CHECK(memcmp(chars, latin1, length) == 0);
172 // UTF-8 chars with UTF-16 range content shouldn't be converted into external
173 // string, but regular TwoBytes string.
175 JS::UTF8Chars utf8Chars(utf8UTF16, utf8UTF16Len);
176 CHECK(JS::FindSmallestEncoding(utf8Chars) == JS::SmallestEncoding::UTF16);
177 bool allocatedExternal = false;
178 JS::Rooted<JSString*> str(
179 cx, JS_NewMaybeExternalStringUTF8(cx, utf8Chars, &simpleCallback,
180 &allocatedExternal));
181 CHECK(str);
182 CHECK(!allocatedExternal);
184 const JSExternalStringCallbacks* callbacks = nullptr;
185 const JS::Latin1Char* chars = nullptr;
186 CHECK(!JS::IsExternalStringLatin1(str, &callbacks, &chars));
187 CHECK(!callbacks);
188 CHECK(!chars);
190 CHECK(!StringHasLatin1Chars(str));
192 JS::AutoAssertNoGC nogc(cx);
193 size_t length;
194 const char16_t* chars16 = nullptr;
195 chars16 = JS_GetTwoByteStringCharsAndLength(cx, nogc, str, &length);
196 CHECK(length == utf16Len);
197 CHECK(memcmp(chars16, utf16, length * sizeof(char16_t)) == 0);
200 return true;
202 END_TEST(testExternalStringsUTF8)