blob: ac8385dbd32362de9c54299936d4cf47b2294e22 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "base/run_loop.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
class DisplayLockContextTest : public RenderingTest {
public:
void SetUp() override {
RenderingTest::SetUp();
features_backup_.emplace();
RuntimeEnabledFeatures::SetDisplayLockingEnabled(true);
}
void TearDown() override {
if (features_backup_) {
features_backup_->Restore();
features_backup_.reset();
}
}
static void RunPendingTasks() {
base::RunLoop run_loop;
Thread::Current()->GetTaskRunner()->PostTask(
FROM_HERE, run_loop.QuitWhenIdleClosure());
run_loop.Run();
}
DisplayLockContext::State ContextState(DisplayLockContext* context) const {
return context->state_;
}
private:
base::Optional<RuntimeEnabledFeatures::Backup> features_backup_;
};
class ContextTestEmptyFunction : public ScriptFunction {
public:
static v8::Local<v8::Function> Create(ScriptState* script_state) {
auto* callback =
MakeGarbageCollected<ContextTestEmptyFunction>(script_state);
return callback->BindToV8Function();
}
ContextTestEmptyFunction(ScriptState* script_state)
: ScriptFunction(script_state) {}
ScriptValue Call(ScriptValue value) final { return value; }
};
TEST_F(DisplayLockContextTest, ContextCleanedUpWhenElementDestroyed) {
GetDocument().GetFrame()->GetSettings()->SetScriptEnabled(true);
WeakPersistent<Element> element =
GetDocument().CreateRawElement(html_names::kDivTag);
ScriptPromise script_promise;
{
auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
ScriptState::Scope scope(script_state);
script_promise = element->acquireDisplayLock(
script_state, V8DisplayLockCallback::Create(
ContextTestEmptyFunction::Create(script_state)));
}
WeakPersistent<DisplayLockContext> context = element->GetDisplayLockContext();
ASSERT_TRUE(context);
// Ensure we get to the disconnected state.
RunPendingTasks();
EXPECT_EQ(ContextState(context), DisplayLockContext::kDisconnected);
// This should be able to clean up the element.
ThreadState::Current()->CollectAllGarbage();
EXPECT_FALSE(element);
// Now that the element is gone, HasPendingActivity should return false for
// the context.
EXPECT_FALSE(context->HasPendingActivity());
// That means the following garbage collection should be able to clean up the
// context.
V8GCController::CollectAllGarbageForTesting(
v8::Isolate::GetCurrent(),
v8::EmbedderHeapTracer::EmbedderStackState::kEmpty);
ThreadState::Current()->CollectAllGarbage();
EXPECT_FALSE(context);
}
} // namespace blink