blob: 74ab8255a909439fd29b6d259f6ff300a218c992 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "base/fuchsia/mem_buffer_util.h"
#include "base/run_loop.h"
#include "content/public/test/browser_test.h"
#include "fuchsia_web/common/test/frame_for_test.h"
#include "fuchsia_web/common/test/frame_test_util.h"
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/webengine/test/test_data.h"
#include "fuchsia_web/webengine/test/web_engine_browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kFaviconPageUrl[] = "/favicon.html";
void QuitLoopIfFaviconUpdated(
base::RepeatingClosure quit_run_loop_closure,
const fuchsia::web::NavigationState& change,
fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback
ack_callback) {
if (change.has_favicon())
quit_run_loop_closure.Run();
ack_callback();
}
void RunUntilFaviconUpdated(TestNavigationListener* test_navigation_listener) {
base::RunLoop run_loop;
test_navigation_listener->SetBeforeAckHook(
base::BindRepeating(&QuitLoopIfFaviconUpdated, run_loop.QuitClosure()));
run_loop.Run();
}
void ValidateFavicon(const fuchsia::web::Favicon& favicon,
size_t expected_width,
size_t expected_height,
size_t check_point_x,
size_t check_point_y,
uint32_t expected_color) {
ASSERT_TRUE(favicon.has_width());
EXPECT_EQ(favicon.width(), expected_width);
ASSERT_TRUE(favicon.has_height());
EXPECT_EQ(favicon.height(), expected_height);
ASSERT_TRUE(favicon.has_data());
std::optional<std::string> data = base::StringFromMemBuffer(favicon.data());
ASSERT_TRUE(data.has_value());
size_t expected_size = expected_width * expected_height * sizeof(uint32_t);
ASSERT_EQ(data->size(), expected_size);
size_t offset = check_point_x + check_point_y * expected_width;
uint32_t color = reinterpret_cast<const uint32_t*>(data->data())[offset];
EXPECT_EQ(color, expected_color);
}
} // namespace
class FaviconTest : public WebEngineBrowserTest {
public:
FaviconTest() { set_test_server_root(base::FilePath(kTestServerRoot)); }
~FaviconTest() override = default;
protected:
void SetUpOnMainThread() override {
WebEngineBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
frame_ = FrameForTest::Create(context(), {});
}
void TearDownOnMainThread() override {
frame_ = {};
WebEngineBrowserTest::TearDownOnMainThread();
}
FrameForTest frame_;
};
// Verify that favicons are not loaded by default.
IN_PROC_BROWSER_TEST_F(FaviconTest, Disabled) {
GURL url = embedded_test_server()->GetURL(kFaviconPageUrl);
EXPECT_TRUE(LoadUrlAndExpectResponse(frame_.GetNavigationController(), {},
url.spec()));
frame_.navigation_listener().RunUntilUrlAndTitleEquals(url, "Favicon");
// Favicon should not be sent.
EXPECT_FALSE(frame_.navigation_listener().current_state()->has_favicon());
}
// Check that the favicon for the page is sent after the page is loaded. Also
// verify that the icon is reloaded when the page changes.
IN_PROC_BROWSER_TEST_F(FaviconTest, LoadAndUpdate) {
frame_.CreateAndAttachNavigationListener(
fuchsia::web::NavigationEventListenerFlags::FAVICON);
GURL url = embedded_test_server()->GetURL(kFaviconPageUrl);
EXPECT_TRUE(LoadUrlAndExpectResponse(frame_.GetNavigationController(), {},
url.spec()));
// An empty favicon should be sent first.
RunUntilFaviconUpdated(&frame_.navigation_listener());
EXPECT_TRUE(
frame_.navigation_listener().current_state()->favicon().IsEmpty());
// The image is sent later.
RunUntilFaviconUpdated(&frame_.navigation_listener());
ValidateFavicon(frame_.navigation_listener().current_state()->favicon(), 16,
16, 7, 4, 0xA6272536);
EXPECT_EQ(frame_.navigation_listener().current_state()->url(), url.spec());
EXPECT_EQ(frame_.navigation_listener().current_state()->title(), "Favicon");
// Update the icon from the page and verify that it's updated as expected.
ExecuteJavaScript(frame_.get(),
"document.getElementById('favicon').href = 'favicon2.png'");
RunUntilFaviconUpdated(&frame_.navigation_listener());
ValidateFavicon(frame_.navigation_listener().current_state()->favicon(), 16,
16, 12, 7, 0xB5A39C1A);
// URL and Title should not change when the favicon is loaded.
EXPECT_FALSE(frame_.navigation_listener().last_changes()->has_url());
EXPECT_FALSE(frame_.navigation_listener().last_changes()->has_title());
}
// Check that the favicon updates after a navigation.
IN_PROC_BROWSER_TEST_F(FaviconTest, FaviconNavigations) {
frame_.CreateAndAttachNavigationListener(
fuchsia::web::NavigationEventListenerFlags::FAVICON);
GURL url = embedded_test_server()->GetURL(kFaviconPageUrl);
EXPECT_TRUE(LoadUrlAndExpectResponse(frame_.GetNavigationController(), {},
url.spec()));
// An empty favicon should be sent first.
RunUntilFaviconUpdated(&frame_.navigation_listener());
EXPECT_TRUE(
frame_.navigation_listener().current_state()->favicon().IsEmpty());
// The image is sent later.
RunUntilFaviconUpdated(&frame_.navigation_listener());
ValidateFavicon(frame_.navigation_listener().current_state()->favicon(), 16,
16, 7, 4, 0xA6272536);
// Reload the same page with a different query string.
url = embedded_test_server()->GetURL(std::string(kFaviconPageUrl) +
"?favicon=favicon2.png");
EXPECT_TRUE(LoadUrlAndExpectResponse(frame_.GetNavigationController(), {},
url.spec()));
// An empty icon should be sent when navigating to a new page.
frame_.navigation_listener().RunUntilUrlEquals(url);
EXPECT_TRUE(
frame_.navigation_listener().current_state()->favicon().IsEmpty());
// The favicon is sent later.
RunUntilFaviconUpdated(&frame_.navigation_listener());
ValidateFavicon(frame_.navigation_listener().current_state()->favicon(), 16,
16, 12, 7, 0xB5A39C1A);
}