Commit 3d20e407 authored by Hesen Zhang's avatar Hesen Zhang Committed by Commit Bot

Reland "[Upboarding]: Add a tile group proto."

This is a reland of 02f002af

Original change's description:
> [Upboarding]: Add a tile group proto.
>
> Bug: 1068368
> Change-Id: I1a2da9a32a71537abb3fd3626ef2614dcd24e0ca
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2145703
> Commit-Queue: Hesen Zhang <hesen@chromium.org>
> Reviewed-by: Hesen Zhang <hesen@chromium.org>
> Reviewed-by: Xing Liu <xingliu@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#758600}

Bug: 1068368
Change-Id: I1a935a01394b0fed138581ad293c8c2378290163
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2148118
Commit-Queue: Hesen Zhang <hesen@chromium.org>
Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759534}
parent c0de9cda
......@@ -26,6 +26,8 @@ source_set("internal") {
"query_tile_store.h",
"query_tile_types.h",
"store.h",
"tile_group.cc",
"tile_group.h",
"tile_info_fetcher.cc",
"tile_info_fetcher.h",
"tile_service_impl.cc",
......@@ -55,6 +57,7 @@ source_set("unit_tests") {
"image_decoder_unittest.cc",
"proto_conversion_unittest.cc",
"query_tile_store_unittest.cc",
"tile_group_unittest.cc",
"tile_info_fetcher_unittest.cc",
]
......
......@@ -10,6 +10,21 @@
#include "base/strings/utf_string_conversions.h"
namespace upboarding {
namespace {
// Helper method to convert base::Time to integer for serialization. Loses
// precision beyond milliseconds.
int64_t TimeToMilliseconds(const base::Time& time) {
return time.ToDeltaSinceWindowsEpoch().InMilliseconds();
}
// Helper method to convert serialized time as integer to base::Time for
// deserialization. Loses precision beyond milliseconds.
base::Time MillisecondsToTime(int64_t serialized_time_ms) {
return base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMilliseconds(serialized_time_ms));
}
} // namespace
void QueryTileEntryToProto(
upboarding::QueryTileEntry* entry,
......@@ -56,4 +71,27 @@ void QueryTileEntryFromProto(
}
}
void TileGroupToProto(TileGroup* group,
upboarding::query_tiles::proto::QueryTileGroup* proto) {
proto->set_id(group->id);
proto->set_locale(group->locale);
proto->set_last_updated_time_ms(TimeToMilliseconds(group->last_updated_ts));
for (auto& tile : group->tiles) {
QueryTileEntryToProto(tile.get(), proto->add_tiles());
}
}
void TileGroupFromProto(upboarding::query_tiles::proto::QueryTileGroup* proto,
TileGroup* group) {
group->id = proto->id();
group->locale = proto->locale();
group->last_updated_ts = MillisecondsToTime(proto->last_updated_time_ms());
for (int i = 0; i < proto->tiles().size(); i++) {
auto entry_proto = proto->tiles(i);
auto child = std::make_unique<QueryTileEntry>();
QueryTileEntryFromProto(&entry_proto, child.get());
group->tiles.emplace_back(std::move(child));
}
}
} // namespace upboarding
......@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_PROTO_CONVERSION_H_
#define CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_PROTO_CONVERSION_H_
#include "chrome/browser/upboarding/query_tiles/internal/tile_group.h"
#include "chrome/browser/upboarding/query_tiles/proto/query_tile_entry.pb.h"
#include "chrome/browser/upboarding/query_tiles/query_tile_entry.h"
......@@ -20,6 +21,14 @@ void QueryTileEntryFromProto(
upboarding::query_tiles::proto::QueryTileEntry* proto,
upboarding::QueryTileEntry* entry);
// Converts a TileGroup to proto.
void TileGroupToProto(TileGroup* group,
upboarding::query_tiles::proto::QueryTileGroup* proto);
// Converts a proto to TileGroup.
void TileGroupFromProto(upboarding::query_tiles::proto::QueryTileGroup* proto,
TileGroup* group);
} // namespace upboarding
#endif // CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_PROTO_CONVERSION_H_
......@@ -4,11 +4,6 @@
#include "chrome/browser/upboarding/query_tiles/internal/proto_conversion.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "chrome/browser/upboarding/query_tiles/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -20,34 +15,35 @@ void TestQueryTileEntryConversion(QueryTileEntry& expected) {
QueryTileEntry actual;
QueryTileEntryToProto(&expected, &proto);
QueryTileEntryFromProto(&proto, &actual);
EXPECT_TRUE(expected == actual)
EXPECT_TRUE(test::AreTilesIdentical(expected, actual))
<< "actual: \n"
<< test::DebugString(&actual) << "expected: \n"
<< test::DebugString(&expected);
}
void TestTileGroupConversion(TileGroup& expected) {
upboarding::query_tiles::proto::QueryTileGroup proto;
TileGroup actual;
TileGroupToProto(&expected, &proto);
TileGroupFromProto(&proto, &actual);
EXPECT_TRUE(test::AreTileGroupsIdentical(expected, actual))
<< "actual: \n"
<< test::DebugString(&actual) << "expected: \n"
<< test::DebugString(&expected);
}
TEST(ProtoConversionTest, QueryTileEntryConversion) {
TEST(QueryTileProtoConversionTest, ConvertTileEntryGroudtrip) {
QueryTileEntry entry;
entry.id = "test-guid-root";
entry.query_text = "test query str";
entry.display_text = "test display text";
entry.accessibility_text = "read this test display text";
entry.image_metadatas.emplace_back("image-test-id-1",
GURL("www.example.com"));
entry.image_metadatas.emplace_back("image-test-id-2",
GURL("www.fakeurl.com"));
auto entry1 = std::make_unique<QueryTileEntry>();
entry1->id = "test-guid-001";
auto entry2 = std::make_unique<QueryTileEntry>();
entry2->id = "test-guid-002";
auto entry3 = std::make_unique<QueryTileEntry>();
entry3->id = "test-guid-003";
entry1->sub_tiles.emplace_back(std::move(entry3));
entry.sub_tiles.emplace_back(std::move(entry1));
entry.sub_tiles.emplace_back(std::move(entry2));
test::ResetTestEntry(&entry);
TestQueryTileEntryConversion(entry);
}
TEST(QueryTileProtoConversionTest, ConvertTileGroupRoundtrip) {
TileGroup group;
test::ResetTestGroup(&group);
TestTileGroupConversion(group);
}
} // namespace
} // namespace upboarding
......@@ -10,14 +10,14 @@
namespace leveldb_proto {
void DataToProto(upboarding::QueryTileEntry* data,
upboarding::query_tiles::proto::QueryTileEntry* proto) {
QueryTileEntryToProto(data, proto);
void DataToProto(upboarding::TileGroup* data,
upboarding::query_tiles::proto::QueryTileGroup* proto) {
TileGroupToProto(data, proto);
}
void ProtoToData(upboarding::query_tiles::proto::QueryTileEntry* proto,
upboarding::QueryTileEntry* data) {
QueryTileEntryFromProto(proto, data);
void ProtoToData(upboarding::query_tiles::proto::QueryTileGroup* proto,
upboarding::TileGroup* data) {
TileGroupFromProto(proto, data);
}
} // namespace leveldb_proto
......@@ -35,10 +35,10 @@ void QueryTileStore::InitAndLoad(LoadCallback callback) {
}
void QueryTileStore::Update(const std::string& key,
const QueryTileEntry& entry,
const TileGroup& group,
UpdateCallback callback) {
auto entries_to_save = std::make_unique<KeyEntryVector>();
QueryTileEntry entry_to_save = entry;
TileGroup entry_to_save = group;
entries_to_save->emplace_back(key, std::move(entry_to_save));
db_->UpdateEntries(std::move(entries_to_save),
std::make_unique<KeyVector>() /*keys_to_remove*/,
......@@ -67,8 +67,7 @@ void QueryTileStore::OnDbInitialized(LoadCallback callback,
void QueryTileStore::OnDataLoaded(
LoadCallback callback,
bool success,
std::unique_ptr<std::map<std::string, QueryTileEntry>>
loaded_keys_and_entries) {
std::unique_ptr<std::map<std::string, TileGroup>> loaded_keys_and_entries) {
if (!success || !loaded_keys_and_entries) {
std::move(callback).Run(success, KeysAndEntries());
return;
......@@ -76,9 +75,9 @@ void QueryTileStore::OnDataLoaded(
KeysAndEntries keys_and_entries;
for (auto& it : *loaded_keys_and_entries) {
std::unique_ptr<QueryTileEntry> entry =
std::make_unique<QueryTileEntry>(std::move(it.second));
keys_and_entries.emplace(it.first, std::move(entry));
std::unique_ptr<TileGroup> group =
std::make_unique<TileGroup>(std::move(it.second));
keys_and_entries.emplace(it.first, std::move(group));
}
std::move(callback).Run(true, std::move(keys_and_entries));
......
......@@ -15,26 +15,29 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/upboarding/query_tiles/internal/store.h"
#include "chrome/browser/upboarding/query_tiles/internal/tile_group.h"
#include "chrome/browser/upboarding/query_tiles/proto/query_tile_entry.pb.h"
#include "chrome/browser/upboarding/query_tiles/query_tile_entry.h"
#include "components/leveldb_proto/public/proto_database.h"
namespace leveldb_proto {
void DataToProto(upboarding::QueryTileEntry* data,
upboarding::query_tiles::proto::QueryTileEntry* proto);
void ProtoToData(upboarding::query_tiles::proto::QueryTileEntry* proto,
upboarding::QueryTileEntry* data);
void DataToProto(upboarding::TileGroup* data,
upboarding::query_tiles::proto::QueryTileGroup* proto);
void ProtoToData(upboarding::query_tiles::proto::QueryTileGroup* proto,
upboarding::TileGroup* data);
} // namespace leveldb_proto
namespace upboarding {
class QueryTileStore : public Store<QueryTileEntry> {
// QueryTileStore is the storage layer of all TileGroup which contains
// the top-level tile entries and group metadata. Sub-level tiles are
// recursively owned by their parents.
class QueryTileStore : public Store<TileGroup> {
public:
using QueryTileProtoDb = std::unique_ptr<
leveldb_proto::ProtoDatabase<query_tiles::proto::QueryTileEntry,
QueryTileEntry>>;
leveldb_proto::ProtoDatabase<query_tiles::proto::QueryTileGroup,
TileGroup>>;
explicit QueryTileStore(QueryTileProtoDb db);
~QueryTileStore() override;
......@@ -42,14 +45,14 @@ class QueryTileStore : public Store<QueryTileEntry> {
QueryTileStore& operator=(const QueryTileStore& other) = delete;
private:
using KeyEntryVector = std::vector<std::pair<std::string, QueryTileEntry>>;
using KeyEntryVector = std::vector<std::pair<std::string, TileGroup>>;
using KeyVector = std::vector<std::string>;
using EntryVector = std::vector<QueryTileEntry>;
using EntryVector = std::vector<TileGroup>;
// Store<QueryTileEntry> implementation.
// Store<TileGroup> implementation.
void InitAndLoad(LoadCallback callback) override;
void Update(const std::string& key,
const QueryTileEntry& entry,
const TileGroup& entry,
UpdateCallback callback) override;
void Delete(const std::string& key, DeleteCallback callback) override;
......@@ -61,7 +64,7 @@ class QueryTileStore : public Store<QueryTileEntry> {
void OnDataLoaded(
LoadCallback callback,
bool success,
std::unique_ptr<std::map<std::string, QueryTileEntry>> loaded_entries);
std::unique_ptr<std::map<std::string, TileGroup>> loaded_entries);
QueryTileProtoDb db_;
......
......@@ -22,16 +22,13 @@ using InitStatus = leveldb_proto::Enums::InitStatus;
namespace upboarding {
namespace {
const char kGuid[] = "test_guid";
const char kTestDisplayText[] = "test_display_text";
class QueryTileStoreTest : public testing::Test {
public:
using QueryTileEntryProto = query_tiles::proto::QueryTileEntry;
using EntriesMap = std::map<std::string, std::unique_ptr<QueryTileEntry>>;
using ProtoMap = std::map<std::string, QueryTileEntryProto>;
using KeysAndEntries = std::map<std::string, QueryTileEntry>;
using TestEntries = std::vector<QueryTileEntry>;
using TileGroupProto = query_tiles::proto::QueryTileGroup;
using EntriesMap = std::map<std::string, std::unique_ptr<TileGroup>>;
using ProtoMap = std::map<std::string, TileGroupProto>;
using KeysAndEntries = std::map<std::string, TileGroup>;
using TestEntries = std::vector<TileGroup>;
QueryTileStoreTest() : load_result_(false), db_(nullptr) {}
~QueryTileStoreTest() override = default;
......@@ -42,8 +39,7 @@ class QueryTileStoreTest : public testing::Test {
protected:
void Init(TestEntries input, InitStatus status) {
CreateTestDbEntries(std::move(input));
auto db = std::make_unique<FakeDB<QueryTileEntryProto, QueryTileEntry>>(
&db_entries_);
auto db = std::make_unique<FakeDB<TileGroupProto, TileGroup>>(&db_entries_);
db_ = db.get();
store_ = std::make_unique<QueryTileStore>(std::move(db));
store_->InitAndLoad(base::BindOnce(&QueryTileStoreTest::OnEntriesLoaded,
......@@ -58,8 +54,8 @@ class QueryTileStoreTest : public testing::Test {
void CreateTestDbEntries(TestEntries input) {
for (auto& entry : input) {
QueryTileEntryProto proto;
upboarding::QueryTileEntryToProto(&entry, &proto);
TileGroupProto proto;
upboarding::TileGroupToProto(&entry, &proto);
db_entries_.emplace(entry.id, proto);
}
}
......@@ -80,26 +76,27 @@ class QueryTileStoreTest : public testing::Test {
DCHECK(loaded_entries);
for (auto it = loaded_entries->begin(); it != loaded_entries->end(); it++) {
EXPECT_NE(expected->count(it->first), 0u);
auto& actual_loaded_tree = it->second;
auto& expected_tree = expected->at(it->first);
EXPECT_EQ(actual_loaded_tree, expected_tree)
<< "\n Actual: " << test::DebugString(&actual_loaded_tree)
<< "\n Expected: " << test::DebugString(&expected_tree);
auto& actual_loaded_group = it->second;
auto& expected_group = expected->at(it->first);
EXPECT_TRUE(
test::AreTileGroupsIdentical(actual_loaded_group, expected_group))
<< "\n Actual: " << test::DebugString(&actual_loaded_group)
<< "\n Expected: " << test::DebugString(&expected_group);
}
}
bool load_result() const { return load_result_; }
const EntriesMap& in_memory_entries() const { return in_memory_entries_; }
FakeDB<QueryTileEntryProto, QueryTileEntry>* db() { return db_; }
Store<QueryTileEntry>* store() { return store_.get(); }
FakeDB<TileGroupProto, TileGroup>* db() { return db_; }
Store<TileGroup>* store() { return store_.get(); }
private:
base::test::TaskEnvironment task_environment_;
bool load_result_;
EntriesMap in_memory_entries_;
ProtoMap db_entries_;
FakeDB<QueryTileEntryProto, QueryTileEntry>* db_;
std::unique_ptr<Store<QueryTileEntry>> store_;
FakeDB<TileGroupProto, TileGroup>* db_;
std::unique_ptr<Store<TileGroup>> store_;
};
// Test Initializing and loading an empty database .
......@@ -114,24 +111,26 @@ TEST_F(QueryTileStoreTest, InitSuccessEmptyDb) {
// Test Initializing and loading a non-empty database.
TEST_F(QueryTileStoreTest, InitSuccessWithData) {
auto test_data = TestEntries();
QueryTileEntry test_entry;
test_entry.id = kGuid;
test_data.emplace_back(std::move(test_entry));
TileGroup test_group;
test::ResetTestGroup(&test_group);
std::string id = test_group.id;
test_data.emplace_back(std::move(test_group));
Init(std::move(test_data), InitStatus::kOK);
db()->LoadCallback(true);
EXPECT_EQ(load_result(), true);
EXPECT_EQ(in_memory_entries().size(), 1u);
auto actual = in_memory_entries().begin();
EXPECT_EQ(actual->first, kGuid);
EXPECT_EQ(actual->second.get()->id, kGuid);
EXPECT_EQ(actual->first, id);
EXPECT_EQ(actual->second.get()->id, id);
}
// Test Initializing and loading a non-empty database failed.
TEST_F(QueryTileStoreTest, InitFailedWithData) {
auto test_data = TestEntries();
QueryTileEntry test_entry;
test_entry.id = kGuid;
test_data.emplace_back(std::move(test_entry));
TileGroup test_group;
test::ResetTestGroup(&test_group);
std::string id = test_group.id;
test_data.emplace_back(std::move(test_group));
Init(std::move(test_data), InitStatus::kOK);
db()->LoadCallback(false);
EXPECT_EQ(load_result(), false);
......@@ -147,10 +146,13 @@ TEST_F(QueryTileStoreTest, AddAndUpdateDataFailed) {
EXPECT_TRUE(in_memory_entries().empty());
// Add an entry failed.
QueryTileEntry test_entry_1;
test_entry_1.id = "test_entry_id_1";
test_entry_1.display_text = "test_entry_test_display_text";
store()->Update(test_entry_1.id, test_entry_1,
TileGroup test_group;
test_group.id = "test_group_id";
auto test_entry_1 = std::make_unique<QueryTileEntry>();
test_entry_1->id = "test_entry_id_1";
test_entry_1->display_text = "test_entry_test_display_text";
test_group.tiles.emplace_back(std::move(test_entry_1));
store()->Update(test_group.id, test_group,
base::BindOnce([](bool success) { EXPECT_FALSE(success); }));
db()->UpdateCallback(false);
}
......@@ -162,41 +164,33 @@ TEST_F(QueryTileStoreTest, AddAndUpdateDataSuccess) {
EXPECT_EQ(load_result(), true);
EXPECT_TRUE(in_memory_entries().empty());
// Add an entry successfully.
QueryTileEntry test_entry_1;
test_entry_1.id = "test_entry_id_1";
test_entry_1.display_text = kTestDisplayText;
auto test_entry_2 = std::make_unique<QueryTileEntry>();
test_entry_2->id = "test_entry_id_2";
test_entry_1.sub_tiles.emplace_back(std::move(test_entry_2));
store()->Update(test_entry_1.id, test_entry_1,
// Add a group successfully.
TileGroup test_group;
test::ResetTestGroup(&test_group);
store()->Update(test_group.id, test_group,
base::BindOnce([](bool success) { EXPECT_TRUE(success); }));
db()->UpdateCallback(true);
auto expected = std::make_unique<KeysAndEntries>();
expected->emplace(test_entry_1.id, std::move(test_entry_1));
expected->emplace(test_group.id, std::move(test_group));
VerifyDataInDb(std::move(expected));
}
// Test deleting from db.
TEST_F(QueryTileStoreTest, DeleteSuccess) {
auto test_data = TestEntries();
QueryTileEntry test_entry_1;
test_entry_1.id = kGuid;
test_entry_1.display_text = kTestDisplayText;
auto test_entry_2 = std::make_unique<QueryTileEntry>();
test_entry_2->id = "test_entry_id_2";
test_entry_1.sub_tiles.emplace_back(std::move(test_entry_2));
test_data.emplace_back(std::move(test_entry_1));
TileGroup test_group;
test::ResetTestGroup(&test_group);
std::string id = test_group.id;
test_data.emplace_back(std::move(test_group));
Init(std::move(test_data), InitStatus::kOK);
db()->LoadCallback(true);
EXPECT_EQ(load_result(), true);
EXPECT_EQ(in_memory_entries().size(), 1u);
auto actual = in_memory_entries().begin();
EXPECT_EQ(actual->first, kGuid);
EXPECT_EQ(actual->second.get()->id, kGuid);
store()->Delete(kGuid,
EXPECT_EQ(actual->first, id);
EXPECT_EQ(actual->second.get()->id, id);
store()->Delete(id,
base::BindOnce([](bool success) { EXPECT_TRUE(success); }));
db()->UpdateCallback(true);
// No entry is expected in db.
......
// Copyright 2020 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 "chrome/browser/upboarding/query_tiles/internal/tile_group.h"
#include <utility>
namespace upboarding {
namespace {
void DeepCopyGroup(const TileGroup& input, TileGroup* output) {
DCHECK(output);
output->id = input.id;
output->locale = input.locale;
output->last_updated_ts = input.last_updated_ts;
output->tiles.clear();
for (const auto& tile : input.tiles)
output->tiles.emplace_back(std::make_unique<QueryTileEntry>(*tile.get()));
}
} // namespace
TileGroup::TileGroup() = default;
TileGroup::~TileGroup() = default;
bool TileGroup::operator==(const TileGroup& other) const {
return id == other.id && locale == other.locale &&
last_updated_ts == other.last_updated_ts &&
tiles.size() == other.tiles.size();
}
bool TileGroup::operator!=(const TileGroup& other) const {
return !(*this == other);
}
TileGroup::TileGroup(const TileGroup& other) {
DeepCopyGroup(other, this);
}
TileGroup::TileGroup(TileGroup&& other) = default;
TileGroup& TileGroup::operator=(const TileGroup& other) {
DeepCopyGroup(other, this);
return *this;
}
TileGroup& TileGroup::operator=(TileGroup&& other) = default;
} // namespace upboarding
// Copyright 2020 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.
#ifndef CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_TILE_GROUP_H_
#define CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_TILE_GROUP_H_
#include <memory>
#include <string>
#include <vector>
#include "base/time/time.h"
#include "chrome/browser/upboarding/query_tiles/query_tile_entry.h"
namespace upboarding {
// A group of query tiles and metadata.
struct TileGroup {
TileGroup();
TileGroup(const TileGroup& other);
TileGroup(TileGroup&& other);
~TileGroup();
TileGroup& operator=(const TileGroup& other);
TileGroup& operator=(TileGroup&& other);
bool operator==(const TileGroup& other) const;
bool operator!=(const TileGroup& other) const;
// Unique id for the group.
std::string id;
// Locale setting of this group.
std::string locale;
// Last updated timestamp in milliseconds.
base::Time last_updated_ts;
// Top level tiles.
std::vector<std::unique_ptr<QueryTileEntry>> tiles;
};
} // namespace upboarding
#endif // CHROME_BROWSER_UPBOARDING_QUERY_TILES_INTERNAL_TILE_GROUP_H_
// Copyright 2020 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 "chrome/browser/upboarding/query_tiles/internal/tile_group.h"
#include <iostream>
#include <type_traits>
#include <utility>
#include "base/test/task_environment.h"
#include "chrome/browser/upboarding/query_tiles/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace upboarding {
namespace {
TEST(QueryTileGroupTest, CompareOperators) {
TileGroup lhs, rhs;
test::ResetTestGroup(&lhs);
test::ResetTestGroup(&rhs);
EXPECT_EQ(lhs, rhs);
rhs.id = "changed";
EXPECT_NE(lhs, rhs);
test::ResetTestGroup(&rhs);
rhs.locale = "changed";
EXPECT_NE(lhs, rhs);
test::ResetTestGroup(&rhs);
rhs.last_updated_ts += base::TimeDelta::FromDays(1);
EXPECT_NE(lhs, rhs);
test::ResetTestGroup(&rhs);
rhs.tiles.clear();
EXPECT_NE(lhs, rhs);
}
TEST(QueryTileGroupTest, DeepCompareOperators) {
TileGroup lhs, rhs;
test::ResetTestGroup(&lhs);
test::ResetTestGroup(&rhs);
EXPECT_TRUE(test::AreTileGroupsIdentical(lhs, rhs));
// Verify the order of tiles does not matter.
std::reverse(rhs.tiles.begin(), rhs.tiles.end());
EXPECT_TRUE(test::AreTileGroupsIdentical(lhs, rhs));
test::ResetTestGroup(&rhs);
// Verify change on children tiles will make them different.
rhs.tiles.front()->id = "changed";
EXPECT_FALSE(test::AreTileGroupsIdentical(lhs, rhs));
}
TEST(QueryTileGroupTest, CopyOperator) {
TileGroup lhs;
test::ResetTestGroup(&lhs);
TileGroup rhs = lhs;
EXPECT_TRUE(test::AreTileGroupsIdentical(lhs, rhs));
}
TEST(QueryTileGroupTest, MoveOperator) {
TileGroup lhs;
test::ResetTestGroup(&lhs);
TileGroup rhs = std::move(lhs);
TileGroup expected;
test::ResetTestGroup(&expected);
EXPECT_TRUE(test::AreTileGroupsIdentical(expected, rhs));
}
} // namespace
} // namespace upboarding
......@@ -39,3 +39,19 @@ message QueryTileEntry {
// Sub level children.
repeated QueryTileEntry sub_tiles = 6;
}
// Data schema of a group of entries and its metadata.
// Next tag: 5
message QueryTileGroup {
// Unique id of each group.
string id = 1;
// Locale setting of this group.
string locale = 2;
// Last updated timestamp in ms;
int64 last_updated_time_ms = 3;
// Top level tiles;
repeated QueryTileEntry tiles = 4;
}
......@@ -9,56 +9,22 @@
namespace upboarding {
namespace {
void DeepCopyTiles(const QueryTileEntry* input, QueryTileEntry* out) {
if (!input || !out)
return;
out->id = input->id;
out->display_text = input->display_text;
out->query_text = input->query_text;
out->accessibility_text = input->accessibility_text;
out->image_metadatas = input->image_metadatas;
void DeepCopyTiles(const QueryTileEntry& input, QueryTileEntry* out) {
DCHECK(out);
out->id = input.id;
out->display_text = input.display_text;
out->query_text = input.query_text;
out->accessibility_text = input.accessibility_text;
out->image_metadatas = input.image_metadatas;
out->sub_tiles.clear();
for (const auto& child : input->sub_tiles) {
for (const auto& child : input.sub_tiles) {
auto entry = std::make_unique<QueryTileEntry>();
DeepCopyTiles(child.get(), entry.get());
DeepCopyTiles(*child.get(), entry.get());
out->sub_tiles.emplace_back(std::move(entry));
}
}
bool AreTreesIdentical(const QueryTileEntry* lhs, const QueryTileEntry* rhs) {
if (!lhs && !rhs)
return true;
if (!lhs || !rhs || lhs->id != rhs->id ||
lhs->display_text != rhs->display_text ||
lhs->query_text != rhs->query_text ||
lhs->accessibility_text != rhs->accessibility_text ||
lhs->image_metadatas.size() != rhs->image_metadatas.size() ||
lhs->sub_tiles.size() != rhs->sub_tiles.size())
return false;
for (const auto& it : lhs->image_metadatas) {
auto found =
std::find_if(rhs->image_metadatas.begin(), rhs->image_metadatas.end(),
[it](const ImageMetadata& image) { return image == it; });
if (found == rhs->image_metadatas.end())
return false;
}
for (auto& it : lhs->sub_tiles) {
auto* target = it.get();
auto found =
std::find_if(rhs->sub_tiles.begin(), rhs->sub_tiles.end(),
[&target](const std::unique_ptr<QueryTileEntry>& entry) {
return entry->id == target->id;
});
if (found == rhs->sub_tiles.end() ||
!AreTreesIdentical(target, found->get()))
return false;
}
return true;
}
} // namespace
ImageMetadata::ImageMetadata() = default;
......@@ -74,28 +40,33 @@ bool ImageMetadata::operator==(const ImageMetadata& other) const {
return id == other.id && url == other.url;
}
QueryTileEntry::QueryTileEntry() = default;
bool QueryTileEntry::operator==(const QueryTileEntry& other) const {
return id == other.id && display_text == other.display_text &&
query_text == other.query_text &&
accessibility_text == other.accessibility_text &&
image_metadatas.size() == other.image_metadatas.size() &&
sub_tiles.size() == other.sub_tiles.size();
}
QueryTileEntry::~QueryTileEntry() = default;
bool QueryTileEntry::operator!=(const QueryTileEntry& other) const {
return !(*this == other);
}
QueryTileEntry::QueryTileEntry(const QueryTileEntry& other) {
DeepCopyTiles(&other, this);
DeepCopyTiles(other, this);
}
QueryTileEntry::QueryTileEntry(QueryTileEntry&& other) {
id = std::move(other.id);
query_text = std::move(other.query_text);
display_text = std::move(other.display_text);
accessibility_text = std::move(other.accessibility_text);
image_metadatas = std::move(other.image_metadatas);
sub_tiles = std::move(other.sub_tiles);
}
QueryTileEntry::QueryTileEntry() = default;
bool QueryTileEntry::operator==(const QueryTileEntry& other) const {
return AreTreesIdentical(this, &other);
}
bool QueryTileEntry::operator!=(const QueryTileEntry& other) const {
return !(*this == other);
QueryTileEntry::QueryTileEntry(QueryTileEntry&& other) = default;
QueryTileEntry::~QueryTileEntry() = default;
QueryTileEntry& QueryTileEntry::operator=(const QueryTileEntry& other) {
DeepCopyTiles(other, this);
return *this;
}
QueryTileEntry& QueryTileEntry::operator=(QueryTileEntry&& other) = default;
} // namespace upboarding
......@@ -9,7 +9,7 @@
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/time/time.h"
#include "url/gurl.h"
namespace upboarding {
......@@ -37,7 +37,11 @@ struct QueryTileEntry {
bool operator!=(const QueryTileEntry& other) const;
QueryTileEntry(const QueryTileEntry& other);
QueryTileEntry(QueryTileEntry&& other);
QueryTileEntry(QueryTileEntry&& other) noexcept;
QueryTileEntry& operator=(const QueryTileEntry& other);
QueryTileEntry& operator=(QueryTileEntry&& other) noexcept;
// Unique Id for each entry.
std::string id;
......
......@@ -4,6 +4,8 @@
#include "chrome/browser/upboarding/query_tiles/query_tile_entry.h"
#include <utility>
#include "base/test/task_environment.h"
#include "chrome/browser/upboarding/query_tiles/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -11,105 +13,95 @@
namespace upboarding {
namespace {
void ResetTestCase(QueryTileEntry& entry) {
entry.id = "test-guid-root";
entry.query_text = "test query str";
entry.display_text = "test display text";
entry.accessibility_text = "read this test display text";
entry.image_metadatas.clear();
entry.image_metadatas.emplace_back("image-test-id-1",
GURL("http://www.example.com"));
entry.image_metadatas.emplace_back("image-test-id-2",
GURL("http://www.fakeurl.com"));
auto entry1 = std::make_unique<QueryTileEntry>();
entry1->id = "test-guid-001";
auto entry2 = std::make_unique<QueryTileEntry>();
entry2->id = "test-guid-002";
auto entry3 = std::make_unique<QueryTileEntry>();
entry3->id = "test-guid-003";
entry1->sub_tiles.clear();
entry1->sub_tiles.emplace_back(std::move(entry3));
entry.sub_tiles.clear();
entry.sub_tiles.emplace_back(std::move(entry1));
entry.sub_tiles.emplace_back(std::move(entry2));
}
TEST(QueryTileEntryTest, CompareOperators) {
QueryTileEntry lhs, rhs;
ResetTestCase(lhs);
ResetTestCase(rhs);
test::ResetTestEntry(&lhs);
test::ResetTestEntry(&rhs);
EXPECT_EQ(lhs, rhs);
EXPECT_FALSE(lhs != rhs);
// Test any data field changed.
rhs.id = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
test::ResetTestEntry(&rhs);
rhs.query_text = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
test::ResetTestEntry(&rhs);
rhs.display_text = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
test::ResetTestEntry(&rhs);
rhs.accessibility_text = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
test::ResetTestEntry(&rhs);
}
TEST(QueryTileEntryTest, DeepComparison) {
QueryTileEntry lhs, rhs;
test::ResetTestEntry(&lhs);
test::ResetTestEntry(&rhs);
EXPECT_TRUE(test::AreTilesIdentical(lhs, rhs));
// Test image metadatas changed.
rhs.image_metadatas.front().id = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
rhs.image_metadatas.front().url = GURL("http://www.url-changed.com");
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
rhs.image_metadatas.pop_back();
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
rhs.image_metadatas.emplace_back(ImageMetadata());
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
std::reverse(rhs.image_metadatas.begin(), rhs.image_metadatas.end());
EXPECT_TRUE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
// Test children changed.
rhs.sub_tiles.front()->id = "changed";
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
rhs.sub_tiles.pop_back();
EXPECT_NE(lhs, rhs);
ResetTestCase(rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
rhs.sub_tiles.emplace_back(std::make_unique<QueryTileEntry>());
EXPECT_NE(lhs, rhs);
EXPECT_FALSE(test::AreTilesIdentical(lhs, rhs));
test::ResetTestEntry(&rhs);
std::reverse(rhs.sub_tiles.begin(), rhs.sub_tiles.end());
EXPECT_TRUE(test::AreTilesIdentical(lhs, rhs));
}
TEST(QueryTileEntryTest, CopyOperator) {
QueryTileEntry lhs;
ResetTestCase(lhs);
test::ResetTestEntry(&lhs);
QueryTileEntry rhs(lhs);
EXPECT_EQ(lhs, rhs);
EXPECT_TRUE(test::AreTilesIdentical(lhs, rhs));
}
TEST(QueryTileEntryTest, AssignOperator) {
QueryTileEntry lhs;
ResetTestCase(lhs);
test::ResetTestEntry(&lhs);
QueryTileEntry rhs = lhs;
EXPECT_EQ(lhs, rhs);
EXPECT_TRUE(test::AreTilesIdentical(lhs, rhs));
}
TEST(QueryTileEntryTest, MoveOperator) {
QueryTileEntry lhs;
ResetTestCase(lhs);
test::ResetTestEntry(&lhs);
QueryTileEntry rhs = std::move(lhs);
EXPECT_EQ(lhs, QueryTileEntry());
QueryTileEntry expected;
ResetTestCase(expected);
EXPECT_EQ(expected, rhs);
test::ResetTestEntry(&expected);
EXPECT_TRUE(test::AreTilesIdentical(expected, rhs));
}
} // namespace
......
......@@ -9,12 +9,16 @@
#include <map>
#include <memory>
#include <sstream>
#include <utility>
#include <vector>
namespace upboarding {
namespace test {
namespace {
const char kTimeStr[] = "03/18/20 01:00:00 AM";
void SerializeEntry(const QueryTileEntry* entry, std::stringstream& out) {
if (!entry)
return;
......@@ -29,7 +33,7 @@ void SerializeEntry(const QueryTileEntry* entry, std::stringstream& out) {
} // namespace
const std::string DebugString(const QueryTileEntry* root) {
std::string DebugString(const QueryTileEntry* root) {
if (!root)
return std::string();
std::stringstream out;
......@@ -62,6 +66,105 @@ const std::string DebugString(const QueryTileEntry* root) {
return out.str();
}
std::string DebugString(const TileGroup* group) {
if (!group)
return std::string();
std::stringstream out;
out << "Group detail: \n";
out << "id: " << group->id << " locale: " << group->locale
<< " last_updated_ts: " << group->last_updated_ts << " \n";
for (const auto& tile : group->tiles) {
out << DebugString(tile.get());
}
return out.str();
}
void ResetTestEntry(QueryTileEntry* entry) {
entry->id = "guid-1-1";
entry->query_text = "test query str";
entry->display_text = "test display text";
entry->accessibility_text = "read this test display text";
entry->image_metadatas.clear();
entry->image_metadatas.emplace_back("image-test-id-1",
GURL("http://www.example.com"));
entry->image_metadatas.emplace_back("image-test-id-2",
GURL("http://www.fakeurl.com"));
auto entry1 = std::make_unique<QueryTileEntry>();
entry1->id = "guid-2-1";
auto entry2 = std::make_unique<QueryTileEntry>();
entry2->id = "guid-2-2";
auto entry3 = std::make_unique<QueryTileEntry>();
entry3->id = "guid-3-1";
entry1->sub_tiles.emplace_back(std::move(entry3));
entry->sub_tiles.clear();
entry->sub_tiles.emplace_back(std::move(entry1));
entry->sub_tiles.emplace_back(std::move(entry2));
}
void ResetTestGroup(TileGroup* group) {
group->id = "group_guid";
group->locale = "en-US";
DCHECK(base::Time::FromString(kTimeStr, &group->last_updated_ts));
group->tiles.clear();
auto test_entry_1 = std::make_unique<QueryTileEntry>();
ResetTestEntry(test_entry_1.get());
auto test_entry_2 = std::make_unique<QueryTileEntry>();
test_entry_2->id = "guid-1-2";
auto test_entry_3 = std::make_unique<QueryTileEntry>();
test_entry_3->id = "guid-1-3";
auto test_entry_4 = std::make_unique<QueryTileEntry>();
test_entry_4->id = "guid-1-4";
test_entry_3->sub_tiles.emplace_back(std::move(test_entry_4));
group->tiles.emplace_back(std::move(test_entry_1));
group->tiles.emplace_back(std::move(test_entry_2));
group->tiles.emplace_back(std::move(test_entry_3));
}
bool AreTileGroupsIdentical(const TileGroup& lhs, const TileGroup& rhs) {
if (lhs != rhs)
return false;
for (const auto& it : lhs.tiles) {
auto* target = it.get();
auto found =
std::find_if(rhs.tiles.begin(), rhs.tiles.end(),
[&target](const std::unique_ptr<QueryTileEntry>& entry) {
return entry->id == target->id;
});
if (found == rhs.tiles.end() || *target != *found->get())
return false;
}
return true;
}
bool AreTilesIdentical(const QueryTileEntry& lhs, const QueryTileEntry& rhs) {
if (lhs != rhs)
return false;
for (const auto& it : lhs.image_metadatas) {
auto found =
std::find_if(rhs.image_metadatas.begin(), rhs.image_metadatas.end(),
[it](const ImageMetadata& image) { return image == it; });
if (found == rhs.image_metadatas.end())
return false;
}
for (const auto& it : lhs.sub_tiles) {
auto* target = it.get();
auto found =
std::find_if(rhs.sub_tiles.begin(), rhs.sub_tiles.end(),
[&target](const std::unique_ptr<QueryTileEntry>& entry) {
return entry->id == target->id;
});
if (found == rhs.sub_tiles.end() ||
!AreTilesIdentical(*target, *found->get()))
return false;
}
return true;
}
} // namespace test
} // namespace upboarding
......@@ -7,6 +7,7 @@
#include <string>
#include "chrome/browser/upboarding/query_tiles/internal/tile_group.h"
#include "chrome/browser/upboarding/query_tiles/query_tile_entry.h"
namespace upboarding {
......@@ -14,10 +15,24 @@ namespace test {
// Print data in QueryTileEntry, also with tree represent by adjacent nodes
// key-value[parent id: {children id}] pairs.
const std::string DebugString(const QueryTileEntry* entry);
std::string DebugString(const QueryTileEntry* entry);
} // namespace test
// Print data in TileGroup.
std::string DebugString(const TileGroup* group);
// Build and reset the TileGroup for test usage.
void ResetTestGroup(TileGroup* group);
// Build and reset the TileEntry for test usage.
void ResetTestEntry(QueryTileEntry* entry);
// Returns true if all data in two TileGroups are identical.
bool AreTileGroupsIdentical(const TileGroup& lhs, const TileGroup& rhs);
// Returns true if all data in two QueryTileEntries are identical.
bool AreTilesIdentical(const QueryTileEntry& lhs, const QueryTileEntry& rhs);
} // namespace test
} // namespace upboarding
#endif // CHROME_BROWSER_UPBOARDING_QUERY_TILES_TEST_TEST_UTILS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment