// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/mahi/mahi_browser_delegate_ash.h"
#include <memory>
#include <string>
#include "base/memory/raw_ref.h"
#include "base/test/task_environment.h"
#include "base/unguessable_token.h"
#include "chromeos/crosapi/mojom/mahi.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
// Check the received page content is equal to the expected page context.
void OnGetContent(crosapi::mojom::MahiPageContentPtr expected_page_content,
crosapi::mojom::MahiPageContentPtr page_content) {
// If no page content is returned, both should be empty.
if (!expected_page_content) {
EXPECT_FALSE(page_content);
return;
}
// Otherwise, the returned page content should be the same as expected.
EXPECT_EQ(expected_page_content->client_id, page_content->client_id);
EXPECT_EQ(expected_page_content->page_id, page_content->page_id);
EXPECT_EQ(expected_page_content->page_content, page_content->page_content);
}
} // namespace
class FakeMahiBrowserCppClient : public crosapi::mojom::MahiBrowserClient {
public:
explicit FakeMahiBrowserCppClient(
MahiBrowserDelegateAsh& mahi_browser_delegate)
: client_id_(base::UnguessableToken::Create()),
mahi_browser_delegate_(mahi_browser_delegate) {
mahi_browser_delegate_->RegisterCppClient(this, client_id_);
}
FakeMahiBrowserCppClient(const FakeMahiBrowserCppClient&) = delete;
FakeMahiBrowserCppClient& operator=(const FakeMahiBrowserCppClient&) = delete;
~FakeMahiBrowserCppClient() override {
mahi_browser_delegate_->UnregisterClient(client_id_);
}
void set_valid_id(const base::UnguessableToken& id) { valid_id_ = id; }
void set_content(const std::u16string content) { content_ = content; }
const base::UnguessableToken& client_id() { return client_id_; }
const base::UnguessableToken& last_id() { return last_id_; }
void GetContent(const base::UnguessableToken& content_id,
GetContentCallback callback) override {
last_id_ = content_id;
if (!valid_id_ || valid_id_ != content_id) {
std::move(callback).Run(std::move(nullptr));
return;
}
crosapi::mojom::MahiPageContentPtr page_content =
crosapi::mojom::MahiPageContent::New();
page_content->client_id = client_id_;
page_content->page_id = content_id;
page_content->page_content = content_;
std::move(callback).Run(std::move(page_content));
}
private:
base::UnguessableToken client_id_;
const raw_ref<MahiBrowserDelegateAsh> mahi_browser_delegate_;
// The valid id for the content.
base::UnguessableToken valid_id_;
std::u16string content_;
base::UnguessableToken last_id_;
};
class MahiBrowserDelegateTest : public testing::Test {
public:
MahiBrowserDelegateAsh& mahi_browser_delegate() {
return mahi_browser_delegate_;
}
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
private:
MahiBrowserDelegateAsh mahi_browser_delegate_;
base::test::TaskEnvironment task_environment_;
};
TEST_F(MahiBrowserDelegateTest, GetContent) {
std::unique_ptr<FakeMahiBrowserCppClient> client1 =
std::make_unique<FakeMahiBrowserCppClient>(mahi_browser_delegate());
const base::UnguessableToken client1_content_id =
base::UnguessableToken::Create();
const std::u16string client1_content = u"content for client 1";
client1->set_valid_id(client1_content_id);
client1->set_content(client1_content);
// Basic functioning.
// Unmatched contents won't be returned.
const base::UnguessableToken random_id = base::UnguessableToken::Create();
ASSERT_NE(client1_content_id, random_id);
crosapi::mojom::MahiPageContentPtr null_page_content = nullptr;
mahi_browser_delegate().GetContentFromClient(
client1->client_id(), random_id,
base::BindOnce(&OnGetContent, std::move(null_page_content)));
RunUntilIdle();
// Client1 receives the request.
EXPECT_EQ(client1->last_id(), random_id);
// Matched contents will be returned properly.
crosapi::mojom::MahiPageContentPtr expected_page_content1 =
crosapi::mojom::MahiPageContent::New();
expected_page_content1->client_id = client1->client_id();
expected_page_content1->page_id = client1_content_id;
expected_page_content1->page_content = client1_content;
mahi_browser_delegate().GetContentFromClient(
client1->client_id(), client1_content_id,
base::BindOnce(&OnGetContent, std::move(expected_page_content1)));
RunUntilIdle();
EXPECT_EQ(client1->last_id(), client1_content_id);
// Multiple clients.
std::unique_ptr<FakeMahiBrowserCppClient> client2 =
std::make_unique<FakeMahiBrowserCppClient>(mahi_browser_delegate());
const base::UnguessableToken client2_content_id =
base::UnguessableToken::Create();
ASSERT_NE(client1_content_id, client2_content_id);
const std::u16string client2_content = u"content for client 2";
client2->set_valid_id(client2_content_id);
client2->set_content(client2_content);
// Only the client with matched contents will return.
crosapi::mojom::MahiPageContentPtr expected_page_content2 =
crosapi::mojom::MahiPageContent::New();
expected_page_content2->client_id = client2->client_id();
expected_page_content2->page_id = client2_content_id;
expected_page_content2->page_content = client2_content;
mahi_browser_delegate().GetContentFromClient(
client2->client_id(), client2_content_id,
base::BindOnce(&OnGetContent, std::move(expected_page_content2)));
RunUntilIdle();
EXPECT_EQ(client2->last_id(), client2_content_id);
// client1 is not visited.
EXPECT_EQ(client1->last_id(), client1_content_id);
// Destructed client will be removed from the list.
const base::UnguessableToken client1_id = client1->client_id();
client1.reset();
mahi_browser_delegate().GetContentFromClient(
client1_id, client1_content_id,
base::BindOnce(&OnGetContent, std::move(null_page_content)));
RunUntilIdle();
}
} // namespace ash