Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gc/FinalizationObservers.h"
#include "jsapi-tests/tests.h"
#include "vm/JSContext.h"
#include "vm/NativeObject.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using namespace js::gc;
namespace {
class TestObserverListElement : public ObserverListObject {
public:
static const JSClass class_;
static TestObserverListElement* New(JSContext* cx) {
return NewObjectWithGivenProto<TestObserverListElement>(cx, nullptr);
}
private:
static const JSClassOps classOps_;
static void Finalize(JS::GCContext* gcx, JSObject* obj) {
obj->as<TestObserverListElement>().unlink();
}
};
const JSClassOps TestObserverListElement::classOps_ = {
.finalize = Finalize,
};
const JSClass TestObserverListElement::class_ = {
"TestObserverListElement",
JSCLASS_HAS_RESERVED_SLOTS(ObserverListObject::SlotCount) |
JSCLASS_FOREGROUND_FINALIZE,
&classOps_, JS_NULL_CLASS_SPEC, &classExtension_};
} // namespace
BEGIN_TEST(testObserverList_insertAndUnlink) {
gc::AutoSuppressGC suppress(cx);
ObserverList list;
CHECK(list.isEmpty());
Rooted<TestObserverListElement*> a(cx, TestObserverListElement::New(cx));
CHECK(a);
CHECK(!a->isInList());
list.insertFront(a);
CHECK(!list.isEmpty());
CHECK(a->isInList());
CHECK(list.getFirst() == a);
Rooted<TestObserverListElement*> b(cx, TestObserverListElement::New(cx));
CHECK(b);
CHECK(!b->isInList());
list.insertFront(b);
CHECK(!list.isEmpty());
CHECK(b->isInList());
CHECK(list.getFirst() == b);
Rooted<TestObserverListElement*> c(cx, TestObserverListElement::New(cx));
CHECK(c);
list.insertFront(c);
CHECK(list.getFirst() == c);
// Unlink an element from the middle.
b->unlink();
CHECK(!b->isInList());
CHECK(!list.isEmpty());
CHECK(list.getFirst() == c);
// Unlink the front element.
c->unlink();
CHECK(!c->isInList());
CHECK(!list.isEmpty());
CHECK(list.getFirst() == a);
// Unlink the last remaining element.
a->unlink();
CHECK(!a->isInList());
CHECK(list.isEmpty());
return true;
}
END_TEST(testObserverList_insertAndUnlink)
BEGIN_TEST(testObserverList_move) {
gc::AutoSuppressGC suppress(cx);
Rooted<TestObserverListElement*> a(cx, TestObserverListElement::New(cx));
Rooted<TestObserverListElement*> b(cx, TestObserverListElement::New(cx));
CHECK(a && b);
// Move construction from an empty list.
{
ObserverList src;
ObserverList dst(std::move(src));
CHECK(src.isEmpty());
CHECK(dst.isEmpty());
}
// Move construction from a non-empty list.
{
ObserverList src;
src.insertFront(a);
src.insertFront(b);
CHECK(src.getFirst() == b);
ObserverList dst(std::move(src));
CHECK(src.isEmpty());
CHECK(!dst.isEmpty());
CHECK(dst.getFirst() == b);
b->unlink();
a->unlink();
CHECK(dst.isEmpty());
}
// Move assignment from a non-empty list.
{
ObserverList src;
src.insertFront(a);
src.insertFront(b);
ObserverList dst;
dst = std::move(src);
CHECK(src.isEmpty());
CHECK(dst.getFirst() == b);
b->unlink();
a->unlink();
CHECK(dst.isEmpty());
}
return true;
}
END_TEST(testObserverList_move)
BEGIN_TEST(testObserverList_append) {
gc::AutoSuppressGC suppress(cx);
ObserverList list1;
ObserverList list2;
CHECK(list1.isEmpty());
CHECK(list2.isEmpty());
// Append empty to empty.
list1.append(std::move(list2));
CHECK(list1.isEmpty());
CHECK(list2.isEmpty());
Rooted<TestObserverListElement*> a(cx, TestObserverListElement::New(cx));
Rooted<TestObserverListElement*> b(cx, TestObserverListElement::New(cx));
Rooted<TestObserverListElement*> c(cx, TestObserverListElement::New(cx));
CHECK(a);
CHECK(b);
CHECK(c);
// Append empty to non-empty.
list1.insertFront(a);
list1.insertFront(b);
list1.append(std::move(list2));
CHECK(!list1.isEmpty());
CHECK(list2.isEmpty());
CHECK(list1.getFirst() == b);
// Append non-empty to empty.
list2.append(std::move(list1));
CHECK(list1.isEmpty());
CHECK(!list2.isEmpty());
CHECK(list2.getFirst() == b);
// Build list1 = [c, b], list2 = [a].
a->unlink();
b->unlink();
CHECK(list2.isEmpty());
list1.insertFront(b);
list1.insertFront(c);
list2.insertFront(a);
// Append non-empty to non-empty: list1 becomes [c, b, a].
list1.append(std::move(list2));
CHECK(list2.isEmpty());
CHECK(!list1.isEmpty());
CHECK(list1.getFirst() == c);
c->unlink();
CHECK(list1.getFirst() == b);
b->unlink();
CHECK(list1.getFirst() == a);
a->unlink();
CHECK(list1.isEmpty());
return true;
}
END_TEST(testObserverList_append)