Bug 1592771. Add tests for round-tripping of various external strings through bindings. r=mccr8

Differential Revision: https://phabricator.services.mozilla.com/D51180

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Zbarsky 2019-10-30 22:09:15 +00:00
Родитель 909ce93ac8
Коммит 3d248ab528
4 изменённых файлов: 162 добавлений и 0 удалений

Просмотреть файл

@ -76,6 +76,79 @@ void TestFunctions::GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
// No need to do anything here; aString is already empty.
}
void TestFunctions::GetShortLiteralString(nsAString& aString) {
// JS inline strings can hold 2 * sizeof(void*) chars, which on 32-bit means 8
// chars. Return fewer than that.
aString.AssignLiteral(u"012345");
}
void TestFunctions::GetMediumLiteralString(nsAString& aString) {
// JS inline strings are at most 2 * sizeof(void*) chars, so at most 16 on
// 64-bit. FakeString can hold 63 chars in its inline buffer (plus the null
// terminator). Let's return 40 chars; that way if we ever move to 128-bit
// void* or something this test will still be valid.
aString.AssignLiteral(u"0123456789012345678901234567890123456789");
}
void TestFunctions::GetLongLiteralString(nsAString& aString) {
// Need more than 64 chars.
aString.AssignLiteral(
u"0123456789012345678901234567890123456789" // 40
"0123456789012345678901234567890123456789" // 80
);
}
void TestFunctions::GetStringbufferString(const nsAString& aInput,
nsAString& aRetval) {
// We have to be a bit careful: if aRetval is an autostring, if we just assign
// it won't cause stringbuffer allocation. So we have to round-trip through
// something that definitely causes a stringbuffer allocation.
nsString str;
// Can't use operator= here, because if aInput is a literal string then str
// would end up the same way.
str.Assign(aInput.BeginReading(), aInput.Length());
// Now we might end up hitting our external string cache and getting the wrong
// sort of external string, so replace the last char by a different value
// (replacing, not just appending, to preserve the length). If we have an
// empty string, our caller screwed up and there's not much we can do for
// them.
if (str.Length() > 1) {
char16_t last = str[str.Length() - 1];
str.Truncate(str.Length() - 1);
if (last == 'x') {
str.Append('y');
} else {
str.Append('x');
}
}
// Here we use operator= to preserve stringbufferness.
aRetval = str;
}
StringType TestFunctions::GetStringType(const nsAString& aString) {
if (aString.IsLiteral()) {
return StringType::Literal;
}
if (nsStringBuffer::FromString(aString)) {
return StringType::Stringbuffer;
}
if (aString.GetDataFlags() & nsAString::DataFlags::INLINE) {
return StringType::Inline;
}
return StringType::Other;
}
bool TestFunctions::StringbufferMatchesStored(const nsAString& aString) {
return nsStringBuffer::FromString(aString) &&
nsStringBuffer::FromString(aString) ==
nsStringBuffer::FromString(mStringData);
}
void TestFunctions::TestThrowNsresult(ErrorResult& aError) {
nsCOMPtr<mozITestInterfaceJS> impl =
do_CreateInstance("@mozilla.org/dom/test-interface-js;1");

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/dom/TestFunctionsBinding.h"
#include "nsString.h"
namespace mozilla {
@ -39,6 +40,16 @@ class TestFunctions : public NonRefcountedDOMObject {
void GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
DOMString& aString);
void GetShortLiteralString(nsAString& aString);
void GetMediumLiteralString(nsAString& aString);
void GetLongLiteralString(nsAString& aString);
void GetStringbufferString(const nsAString& aInput, nsAString& aRetval);
StringType GetStringType(const nsAString& aString);
bool StringbufferMatchesStored(const nsAString& aString);
void TestThrowNsresult(ErrorResult& aError);
void TestThrowNsresultFromNative(ErrorResult& aError);
static already_AddRefed<Promise> ThrowToRejectPromise(GlobalObject& aGlobal,

Просмотреть файл

@ -38,6 +38,56 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1334537
is(asShortAString, shortTestString, "Short AString should be short");
is(asAString, testString, "Full AString should be test string");
// These strings should match the strings used in TestFunctions.cpp, but we
// want to launder them through something on the JS side that will convert
// them into strings stored in the JS heap.
function launder(str) {
// This should be sufficient, but if the JIT gets too smart we may need
// to get more clever.
return str.split("").join("");
}
var shortString = launder(t.getShortLiteralString());
var mediumString = launder(t.getMediumLiteralString());
var longString = launder(t.getLongLiteralString());
// A short or medium non-external string will become an inline FakeString.
is(t.getStringType(shortString), "inline",
"Short string should become inline");
is(t.getStringType(mediumString), "inline",
"Medium string should become inline");
// A long string will become a stringbuffer FakeString on the way in.
is(t.getStringType(longString), "stringbuffer",
"Long string should become a stringbuffer");
// A short literal string will become an inline JS string on the way out
// and then become an inline FakeString on the way in.
is(t.getStringType(t.getShortLiteralString()), "inline",
"Short literal string should become inline");
// A medium or long literal string will become an external JS string on the
// way out and then become a literal FakeString on the way in.
is(t.getStringType(t.getMediumLiteralString()), "literal",
"Medium literal string should become literal");
is(t.getStringType(t.getLongLiteralString()), "literal",
"Long literal string should become literal");
// A short stringbuffer string will become an inline JS string on the way
// out and then become an inline FakeString on the way in.
is(t.getStringType(t.getStringbufferString(shortString)), "inline",
"Short stringbuffer string should become inline");
// A medium or long stringbuffer string will become an external JS string
// on the way out and then become a stringbuffer FakeString on the way in.
is(t.getStringType(t.getStringbufferString(mediumString)), "stringbuffer",
"Medium stringbuffer string should become stringbuffer");
is(t.getStringType(t.getStringbufferString(longString)), "stringbuffer",
"Long stringbuffer string should become stringbuffer");
// Now test that roundtripping works fine. We need to make sure the string
// we are storing is not equal to any of the ones we have used above, to
// avoid the external string cache interfering.
t.setStringData(longString + "unique"); // Should store with stringbuffer.
ok(t.stringbufferMatchesStored(t.getStringDataAsAString()),
"Stringbuffer should have roundtripped");
SimpleTest.finish();
}

Просмотреть файл

@ -13,6 +13,14 @@ callback PromiseReturner = Promise<any>();
interface WrapperCachedNonISupportsTestInterface {
};
// The type of string C++ sees.
enum StringType {
"literal", // A string with the LITERAL flag.
"stringbuffer", // A string with the REFCOUNTED flag.
"inline", // A string with the INLINE flag.
"other", // Anything else.
};
[Pref="dom.expose_test_interfaces",
Exposed=Window]
interface TestFunctions {
@ -46,6 +54,26 @@ interface TestFunctions {
// stringbuffers. If length not passed, use our full length.
DOMString getStringDataAsDOMString(optional unsigned long length);
// Get a short (short enough to fit in a JS inline string) literal string.
DOMString getShortLiteralString();
// Get a medium (long enough to not be a JS inline, but short enough
// to fit in a FakeString inline buffer) literal string.
DOMString getMediumLiteralString();
// Get a long (long enough to not fit in any inline buffers) literal string.
DOMString getLongLiteralString();
// Get a stringbuffer string for whatever string is passed in.
DOMString getStringbufferString(DOMString input);
// Get the type of string that the C++ sees after going through bindings.
StringType getStringType(DOMString str);
// Returns true if both the incoming string and the stored (via setStringData())
// string have stringbuffers and they're the same stringbuffer.
boolean stringbufferMatchesStored(DOMString str);
// Functions that just punch through to mozITestInterfaceJS.idl
[Throws]
void testThrowNsresult();