most_visited_sites_unittest.cc 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/ntp_tiles/most_visited_sites.h"
  5. #include <stddef.h>
  6. #include <map>
  7. #include <memory>
  8. #include <ostream>
  9. #include <string>
  10. #include <tuple>
  11. #include <utility>
  12. #include <vector>
  13. #include "base/bind.h"
  14. #include "base/callback_list.h"
  15. #include "base/command_line.h"
  16. #include "base/feature_list.h"
  17. #include "base/memory/raw_ptr.h"
  18. #include "base/run_loop.h"
  19. #include "base/strings/utf_string_conversions.h"
  20. #include "base/task/cancelable_task_tracker.h"
  21. #include "base/test/gmock_callback_support.h"
  22. #include "base/test/scoped_feature_list.h"
  23. #include "base/test/task_environment.h"
  24. #include "base/threading/thread_task_runner_handle.h"
  25. #include "build/build_config.h"
  26. #include "components/history/core/browser/top_sites.h"
  27. #include "components/history/core/browser/top_sites_observer.h"
  28. #include "components/ntp_tiles/custom_links_manager.h"
  29. #include "components/ntp_tiles/features.h"
  30. #include "components/ntp_tiles/icon_cacher.h"
  31. #include "components/ntp_tiles/popular_sites_impl.h"
  32. #include "components/ntp_tiles/pref_names.h"
  33. #include "components/ntp_tiles/section_type.h"
  34. #include "components/ntp_tiles/switches.h"
  35. #include "components/sync_preferences/testing_pref_service_syncable.h"
  36. #include "components/webapps/common/constants.h"
  37. #include "extensions/buildflags/buildflags.h"
  38. #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
  39. #include "services/network/public/cpp/shared_url_loader_factory.h"
  40. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  41. #include "services/network/test/test_url_loader_factory.h"
  42. #include "testing/gmock/include/gmock/gmock.h"
  43. #include "testing/gtest/include/gtest/gtest.h"
  44. namespace ntp_tiles {
  45. // Defined for googletest. Must be defined in the same namespace.
  46. void PrintTo(const NTPTile& tile, std::ostream* os) {
  47. *os << "{\"" << tile.title << "\", \"" << tile.url << "\", "
  48. << static_cast<int>(tile.source) << "}";
  49. }
  50. namespace {
  51. using history::MostVisitedURL;
  52. using history::MostVisitedURLList;
  53. using history::TopSites;
  54. using testing::_;
  55. using testing::AllOf;
  56. using testing::AnyNumber;
  57. using testing::AtLeast;
  58. using testing::ByMove;
  59. using testing::Contains;
  60. using testing::DoAll;
  61. using testing::ElementsAre;
  62. using testing::Eq;
  63. using testing::Ge;
  64. using testing::InSequence;
  65. using testing::Invoke;
  66. using testing::IsEmpty;
  67. using testing::Key;
  68. using testing::Mock;
  69. using testing::Not;
  70. using testing::Pair;
  71. using testing::Return;
  72. using testing::ReturnRef;
  73. using testing::SaveArg;
  74. using testing::SizeIs;
  75. using testing::StrictMock;
  76. const char kHomepageUrl[] = "http://homepa.ge/";
  77. const char16_t kHomepageTitle[] = u"Homepage";
  78. const char kTestExploreUrl[] = "https://example.com/";
  79. const char16_t kTestExploreTitle[] = u"Example";
  80. std::string PrintTile(const std::u16string& title,
  81. const std::string& url,
  82. TileSource source) {
  83. return std::string("has title \"") + base::UTF16ToUTF8(title) +
  84. std::string("\" and url \"") + url + std::string("\" and source ") +
  85. testing::PrintToString(static_cast<int>(source));
  86. }
  87. MATCHER_P3(MatchesTile, title, url, source, PrintTile(title, url, source)) {
  88. return arg.title == title && arg.url == GURL(url) && arg.source == source;
  89. }
  90. std::string PrintTileSource(TileSource source) {
  91. return std::string("has source ") +
  92. testing::PrintToString(static_cast<int>(source));
  93. }
  94. MATCHER_P(TileWithSource, source, PrintTileSource(source)) {
  95. return arg.source == source;
  96. }
  97. MATCHER_P3(LastTileIs,
  98. title,
  99. url,
  100. source,
  101. std::string("last tile ") + PrintTile(title, url, source)) {
  102. const NTPTilesVector& tiles = arg.at(SectionType::PERSONALIZED);
  103. if (tiles.empty())
  104. return false;
  105. const NTPTile& last = tiles.back();
  106. return last.title == title && last.url == GURL(url) && last.source == source;
  107. }
  108. MATCHER_P3(FirstPersonalizedTileIs,
  109. title,
  110. url,
  111. source,
  112. std::string("first tile ") + PrintTile(title, url, source)) {
  113. if (arg.count(SectionType::PERSONALIZED) == 0) {
  114. return false;
  115. }
  116. const NTPTilesVector& tiles = arg.at(SectionType::PERSONALIZED);
  117. return !tiles.empty() && tiles[0].title == title &&
  118. tiles[0].url == GURL(url) && tiles[0].source == source;
  119. }
  120. NTPTile MakeTile(const std::u16string& title,
  121. const std::string& url,
  122. TileSource source) {
  123. NTPTile tile;
  124. tile.title = title;
  125. tile.url = GURL(url);
  126. tile.source = source;
  127. return tile;
  128. }
  129. MostVisitedURL MakeMostVisitedURL(const std::u16string& title,
  130. const std::string& url) {
  131. MostVisitedURL result;
  132. result.title = title;
  133. result.url = GURL(url);
  134. return result;
  135. }
  136. class MockTopSites : public TopSites {
  137. public:
  138. MOCK_METHOD0(ShutdownOnUIThread, void());
  139. MOCK_METHOD1(GetMostVisitedURLs, void(GetMostVisitedURLsCallback callback));
  140. MOCK_METHOD0(SyncWithHistory, void());
  141. MOCK_CONST_METHOD0(HasBlockedUrls, bool());
  142. MOCK_METHOD1(AddBlockedUrl, void(const GURL& url));
  143. MOCK_METHOD1(RemoveBlockedUrl, void(const GURL& url));
  144. MOCK_METHOD1(IsBlocked, bool(const GURL& url));
  145. MOCK_METHOD0(ClearBlockedUrls, void());
  146. MOCK_METHOD0(StartQueryForMostVisited, base::CancelableTaskTracker::TaskId());
  147. MOCK_METHOD1(IsKnownURL, bool(const GURL& url));
  148. MOCK_CONST_METHOD1(GetCanonicalURLString,
  149. const std::string&(const GURL& url));
  150. MOCK_METHOD0(IsFull, bool());
  151. MOCK_CONST_METHOD0(loaded, bool());
  152. MOCK_METHOD0(GetPrepopulatedPages, history::PrepopulatedPageList());
  153. MOCK_METHOD1(OnNavigationCommitted, void(const GURL& url));
  154. // Publicly expose notification to observers, since the implementation cannot
  155. // be overriden.
  156. using TopSites::NotifyTopSitesChanged;
  157. protected:
  158. ~MockTopSites() override = default;
  159. };
  160. class MockMostVisitedSitesObserver : public MostVisitedSites::Observer {
  161. public:
  162. MOCK_METHOD1(OnURLsAvailable,
  163. void(const std::map<SectionType, NTPTilesVector>& sections));
  164. MOCK_METHOD1(OnIconMadeAvailable, void(const GURL& site_url));
  165. };
  166. class FakeHomepageClient : public MostVisitedSites::HomepageClient {
  167. public:
  168. FakeHomepageClient()
  169. : homepage_tile_enabled_(false), homepage_url_(kHomepageUrl) {}
  170. ~FakeHomepageClient() override {}
  171. bool IsHomepageTileEnabled() const override { return homepage_tile_enabled_; }
  172. GURL GetHomepageUrl() const override { return homepage_url_; }
  173. void QueryHomepageTitle(TitleCallback title_callback) override {
  174. std::move(title_callback).Run(homepage_title_);
  175. }
  176. void SetHomepageTileEnabled(bool homepage_tile_enabled) {
  177. homepage_tile_enabled_ = homepage_tile_enabled;
  178. }
  179. void SetHomepageUrl(GURL homepage_url) { homepage_url_ = homepage_url; }
  180. void SetHomepageTitle(const absl::optional<std::u16string>& homepage_title) {
  181. homepage_title_ = homepage_title;
  182. }
  183. private:
  184. bool homepage_tile_enabled_;
  185. GURL homepage_url_;
  186. absl::optional<std::u16string> homepage_title_;
  187. };
  188. class FakeExploreSitesClient : public MostVisitedSites::ExploreSitesClient {
  189. public:
  190. ~FakeExploreSitesClient() override = default;
  191. GURL GetExploreSitesUrl() const override { return GURL(kTestExploreUrl); }
  192. std::u16string GetExploreSitesTitle() const override {
  193. return kTestExploreTitle;
  194. }
  195. };
  196. class MockIconCacher : public IconCacher {
  197. public:
  198. MOCK_METHOD3(StartFetchPopularSites,
  199. void(PopularSites::Site site,
  200. base::OnceClosure icon_available,
  201. base::OnceClosure preliminary_icon_available));
  202. MOCK_METHOD2(StartFetchMostLikely,
  203. void(const GURL& page_url, base::OnceClosure icon_available));
  204. };
  205. class MockCustomLinksManager : public CustomLinksManager {
  206. public:
  207. MOCK_METHOD1(Initialize, bool(const NTPTilesVector& tiles));
  208. MOCK_METHOD0(Uninitialize, void());
  209. MOCK_CONST_METHOD0(IsInitialized, bool());
  210. MOCK_CONST_METHOD0(GetLinks, const std::vector<CustomLinksManager::Link>&());
  211. MOCK_METHOD2(AddLink, bool(const GURL& url, const std::u16string& title));
  212. MOCK_METHOD3(UpdateLink,
  213. bool(const GURL& url,
  214. const GURL& new_url,
  215. const std::u16string& new_title));
  216. MOCK_METHOD2(ReorderLink, bool(const GURL& url, size_t new_pos));
  217. MOCK_METHOD1(DeleteLink, bool(const GURL& url));
  218. MOCK_METHOD0(UndoAction, bool());
  219. MOCK_METHOD1(RegisterCallbackForOnChanged,
  220. base::CallbackListSubscription(base::RepeatingClosure callback));
  221. };
  222. class PopularSitesFactoryForTest {
  223. public:
  224. explicit PopularSitesFactoryForTest(
  225. sync_preferences::TestingPrefServiceSyncable* pref_service)
  226. : prefs_(pref_service) {
  227. test_shared_loader_factory_ =
  228. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  229. &test_url_loader_factory_);
  230. PopularSitesImpl::RegisterProfilePrefs(pref_service->registry());
  231. }
  232. void SeedWithSampleData() {
  233. prefs_->SetString(prefs::kPopularSitesOverrideCountry, "IN");
  234. prefs_->SetString(prefs::kPopularSitesOverrideVersion, "5");
  235. test_url_loader_factory_.ClearResponses();
  236. test_url_loader_factory_.AddResponse(
  237. "https://www.gstatic.com/chrome/ntp/suggested_sites_IN_5.json",
  238. R"([{
  239. "title": "PopularSite1",
  240. "url": "http://popularsite1/",
  241. "favicon_url": "http://popularsite1/favicon.ico"
  242. },
  243. {
  244. "title": "PopularSite2",
  245. "url": "http://popularsite2/",
  246. "favicon_url": "http://popularsite2/favicon.ico"
  247. }
  248. ])");
  249. test_url_loader_factory_.AddResponse(
  250. "https://www.gstatic.com/chrome/ntp/suggested_sites_US_5.json",
  251. R"([{
  252. "title": "ESPN",
  253. "url": "http://www.espn.com",
  254. "favicon_url": "http://www.espn.com/favicon.ico"
  255. }, {
  256. "title": "Mobile",
  257. "url": "http://www.mobile.de",
  258. "favicon_url": "http://www.mobile.de/favicon.ico"
  259. }, {
  260. "title": "Google News",
  261. "url": "http://news.google.com",
  262. "favicon_url": "http://news.google.com/favicon.ico"
  263. }
  264. ])");
  265. test_url_loader_factory_.AddResponse(
  266. "https://www.gstatic.com/chrome/ntp/suggested_sites_IN_6.json",
  267. R"([{
  268. "section": 1, // PERSONALIZED
  269. "sites": [{
  270. "title": "PopularSite1",
  271. "url": "http://popularsite1/",
  272. "favicon_url": "http://popularsite1/favicon.ico"
  273. },
  274. {
  275. "title": "PopularSite2",
  276. "url": "http://popularsite2/",
  277. "favicon_url": "http://popularsite2/favicon.ico"
  278. },
  279. ]
  280. },
  281. {
  282. "section": 4, // NEWS
  283. "sites": [{
  284. "large_icon_url": "https://news.google.com/icon.ico",
  285. "title": "Google News",
  286. "url": "https://news.google.com/"
  287. },
  288. {
  289. "favicon_url": "https://news.google.com/icon.ico",
  290. "title": "Google News Germany",
  291. "url": "https://news.google.de/"
  292. }]
  293. },
  294. {
  295. "section": 2, // SOCIAL
  296. "sites": [{
  297. "large_icon_url": "https://ssl.gstatic.com/icon.png",
  298. "title": "Google+",
  299. "url": "https://plus.google.com/"
  300. }]
  301. },
  302. {
  303. "section": 3, // ENTERTAINMENT
  304. "sites": [
  305. // Intentionally empty site list.
  306. ]
  307. }
  308. ])");
  309. }
  310. std::unique_ptr<PopularSites> New() {
  311. return std::make_unique<PopularSitesImpl>(prefs_,
  312. /*template_url_service=*/nullptr,
  313. /*variations_service=*/nullptr,
  314. test_shared_loader_factory_);
  315. }
  316. private:
  317. raw_ptr<PrefService> prefs_;
  318. network::TestURLLoaderFactory test_url_loader_factory_;
  319. scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
  320. };
  321. } // namespace
  322. // Param specifies whether Popular Sites is enabled via variations.
  323. class MostVisitedSitesTest : public ::testing::TestWithParam<bool> {
  324. protected:
  325. using TopSitesCallbackList =
  326. base::OnceCallbackList<TopSites::GetMostVisitedURLsCallback::RunType>;
  327. MostVisitedSitesTest() {
  328. MostVisitedSites::RegisterProfilePrefs(pref_service_.registry());
  329. std::vector<base::Feature> enabled_features;
  330. // Disable FaviconServer in most tests and override in specific tests.
  331. std::vector<base::Feature> disabled_features = {
  332. kNtpMostLikelyFaviconsFromServerFeature};
  333. if (IsPopularSitesFeatureEnabled()) {
  334. enabled_features.push_back(kUsePopularSitesSuggestions);
  335. } else {
  336. disabled_features.push_back(kUsePopularSitesSuggestions);
  337. }
  338. // Updating list value in pref with default gmail URL for unit testing.
  339. // Also adding migration feature to be enabled for unit test.
  340. base::Value::List defaults;
  341. defaults.Append("pjkljhegncpnkpknbcohdijeoejaedia");
  342. pref_service_.registry()->RegisterListPref(
  343. webapps::kWebAppsMigratedPreinstalledApps,
  344. base::Value(std::move(defaults)));
  345. feature_list_.InitWithFeatures(enabled_features, disabled_features);
  346. if (IsPopularSitesFeatureEnabled())
  347. popular_sites_factory_.SeedWithSampleData();
  348. RecreateMostVisitedSites();
  349. }
  350. void RecreateMostVisitedSites() {
  351. // We use StrictMock to make sure the object is not used unless Popular
  352. // Sites is enabled.
  353. auto icon_cacher = std::make_unique<StrictMock<MockIconCacher>>();
  354. icon_cacher_ = icon_cacher.get();
  355. // Custom links needs to be nullptr when MostVisitedSites is created, unless
  356. // the custom links feature is enabled. Custom links is disabled for
  357. // Android, iOS, and third-party NTPs.
  358. std::unique_ptr<StrictMock<MockCustomLinksManager>> mock_custom_links;
  359. if (is_custom_links_enabled_) {
  360. mock_custom_links =
  361. std::make_unique<StrictMock<MockCustomLinksManager>>();
  362. mock_custom_links_ = mock_custom_links.get();
  363. }
  364. if (IsPopularSitesFeatureEnabled()) {
  365. // Populate Popular Sites' internal cache by mimicking a past usage of
  366. // PopularSitesImpl.
  367. auto tmp_popular_sites = popular_sites_factory_.New();
  368. base::RunLoop loop;
  369. bool save_success = false;
  370. tmp_popular_sites->MaybeStartFetch(
  371. /*force_download=*/true,
  372. base::BindOnce(
  373. [](bool* save_success, base::RunLoop* loop, bool success) {
  374. *save_success = success;
  375. loop->Quit();
  376. },
  377. &save_success, &loop));
  378. loop.Run();
  379. EXPECT_TRUE(save_success);
  380. // With PopularSites enabled, blocked urls is exercised.
  381. EXPECT_CALL(*mock_top_sites_, IsBlocked(_)).WillRepeatedly(Return(false));
  382. // Mock icon cacher never replies, and we also don't verify whether the
  383. // code uses it correctly.
  384. EXPECT_CALL(*icon_cacher, StartFetchPopularSites(_, _, _))
  385. .Times(AtLeast(0));
  386. }
  387. EXPECT_CALL(*icon_cacher, StartFetchMostLikely(_, _)).Times(AtLeast(0));
  388. most_visited_sites_ = std::make_unique<MostVisitedSites>(
  389. &pref_service_, mock_top_sites_, popular_sites_factory_.New(),
  390. std::move(mock_custom_links), std::move(icon_cacher),
  391. /*supervisor=*/nullptr, true);
  392. }
  393. bool IsPopularSitesFeatureEnabled() const { return GetParam(); }
  394. bool VerifyAndClearExpectations() {
  395. base::RunLoop().RunUntilIdle();
  396. const bool success =
  397. Mock::VerifyAndClearExpectations(mock_top_sites_.get()) &&
  398. Mock::VerifyAndClearExpectations(&mock_observer_);
  399. // For convenience, restore the expectations for IsBlocked().
  400. if (IsPopularSitesFeatureEnabled()) {
  401. EXPECT_CALL(*mock_top_sites_, IsBlocked(_)).WillRepeatedly(Return(false));
  402. }
  403. return success;
  404. }
  405. FakeHomepageClient* RegisterNewHomepageClient() {
  406. auto homepage_client = std::make_unique<FakeHomepageClient>();
  407. FakeHomepageClient* raw_client_ptr = homepage_client.get();
  408. most_visited_sites_->SetHomepageClient(std::move(homepage_client));
  409. return raw_client_ptr;
  410. }
  411. FakeExploreSitesClient* RegisterNewExploreSitesClient() {
  412. auto explore_sites_client = std::make_unique<FakeExploreSitesClient>();
  413. FakeExploreSitesClient* raw_client_ptr = explore_sites_client.get();
  414. most_visited_sites_->SetExploreSitesClient(std::move(explore_sites_client));
  415. return raw_client_ptr;
  416. }
  417. void EnableCustomLinks() { is_custom_links_enabled_ = true; }
  418. bool is_custom_links_enabled_ = false;
  419. TopSitesCallbackList top_sites_callbacks_;
  420. base::test::SingleThreadTaskEnvironment task_environment_;
  421. data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
  422. sync_preferences::TestingPrefServiceSyncable pref_service_;
  423. PopularSitesFactoryForTest popular_sites_factory_{&pref_service_};
  424. scoped_refptr<StrictMock<MockTopSites>> mock_top_sites_ =
  425. base::MakeRefCounted<StrictMock<MockTopSites>>();
  426. StrictMock<MockMostVisitedSitesObserver> mock_observer_;
  427. StrictMock<MockMostVisitedSitesObserver> mock_other_observer_;
  428. std::unique_ptr<MostVisitedSites> most_visited_sites_;
  429. base::test::ScopedFeatureList feature_list_;
  430. raw_ptr<MockCustomLinksManager> mock_custom_links_;
  431. raw_ptr<MockIconCacher> icon_cacher_;
  432. };
  433. TEST_P(MostVisitedSitesTest, ShouldStartNoCallInConstructor) {
  434. // No call to mocks expected by the mere fact of instantiating
  435. // MostVisitedSites.
  436. base::RunLoop().RunUntilIdle();
  437. }
  438. TEST_P(MostVisitedSitesTest, ShouldRefreshBackends) {
  439. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  440. most_visited_sites_->Refresh();
  441. }
  442. TEST_P(MostVisitedSitesTest, ShouldIncludeTileForHomepage) {
  443. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  444. homepage_client->SetHomepageTileEnabled(true);
  445. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  446. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  447. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  448. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  449. .Times(AnyNumber())
  450. .WillRepeatedly(Return(false));
  451. EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
  452. u"", kHomepageUrl, TileSource::HOMEPAGE)));
  453. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  454. /*max_num_sites=*/3);
  455. base::RunLoop().RunUntilIdle();
  456. }
  457. TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomepageWithoutClient) {
  458. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  459. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  460. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  461. EXPECT_CALL(mock_observer_,
  462. OnURLsAvailable(Contains(
  463. Pair(SectionType::PERSONALIZED,
  464. Not(Contains(MatchesTile(u"", kHomepageUrl,
  465. TileSource::HOMEPAGE)))))));
  466. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  467. /*max_num_sites=*/3);
  468. base::RunLoop().RunUntilIdle();
  469. }
  470. TEST_P(MostVisitedSitesTest, ShouldIncludeHomeTileWithUrlBeforeQueryingName) {
  471. // Because the query time for the real name might take a while, provide the
  472. // home tile with URL as title immediately and update the tiles as soon as the
  473. // real title was found.
  474. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  475. homepage_client->SetHomepageTileEnabled(true);
  476. homepage_client->SetHomepageTitle(kHomepageTitle);
  477. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  478. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  479. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  480. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  481. .Times(AnyNumber())
  482. .WillRepeatedly(Return(false));
  483. {
  484. testing::Sequence seq;
  485. EXPECT_CALL(mock_observer_,
  486. OnURLsAvailable(Contains(
  487. Pair(SectionType::PERSONALIZED,
  488. Not(Contains(MatchesTile(u"", kHomepageUrl,
  489. TileSource::HOMEPAGE)))))));
  490. EXPECT_CALL(mock_observer_,
  491. OnURLsAvailable(Contains(
  492. Pair(SectionType::PERSONALIZED,
  493. Not(Contains(MatchesTile(kHomepageTitle, kHomepageUrl,
  494. TileSource::HOMEPAGE)))))));
  495. }
  496. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  497. /*max_num_sites=*/3);
  498. base::RunLoop().RunUntilIdle();
  499. }
  500. TEST_P(MostVisitedSitesTest, ShouldUpdateHomepageTileWhenRefreshHomepageTile) {
  501. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  502. homepage_client->SetHomepageTileEnabled(true);
  503. // Ensure that home tile is available as usual.
  504. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  505. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  506. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  507. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  508. .Times(AnyNumber())
  509. .WillRepeatedly(Return(false));
  510. EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
  511. u"", kHomepageUrl, TileSource::HOMEPAGE)));
  512. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  513. /*max_num_sites=*/3);
  514. base::RunLoop().RunUntilIdle();
  515. VerifyAndClearExpectations();
  516. // Disable home page and rebuild _without_ Resync. The tile should be gone.
  517. homepage_client->SetHomepageTileEnabled(false);
  518. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  519. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  520. EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(0);
  521. EXPECT_CALL(mock_observer_, OnURLsAvailable(Not(FirstPersonalizedTileIs(
  522. u"", kHomepageUrl, TileSource::HOMEPAGE))));
  523. most_visited_sites_->RefreshTiles();
  524. base::RunLoop().RunUntilIdle();
  525. }
  526. TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomepageIfNoTileRequested) {
  527. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  528. homepage_client->SetHomepageTileEnabled(true);
  529. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  530. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  531. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  532. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  533. .Times(AnyNumber())
  534. .WillRepeatedly(Return(false));
  535. EXPECT_CALL(
  536. mock_observer_,
  537. OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, IsEmpty()))));
  538. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  539. /*max_num_sites=*/0);
  540. base::RunLoop().RunUntilIdle();
  541. }
  542. TEST_P(MostVisitedSitesTest, ShouldReturnHomepageIfOneTileRequested) {
  543. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  544. homepage_client->SetHomepageTileEnabled(true);
  545. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  546. .WillRepeatedly(base::test::RunOnceCallback<0>((
  547. MostVisitedURLList{MakeMostVisitedURL(u"Site 1", "http://site1/")})));
  548. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  549. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  550. .Times(AnyNumber())
  551. .WillRepeatedly(Return(false));
  552. EXPECT_CALL(
  553. mock_observer_,
  554. OnURLsAvailable(Contains(Pair(
  555. SectionType::PERSONALIZED,
  556. ElementsAre(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE))))));
  557. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  558. /*max_num_sites=*/1);
  559. base::RunLoop().RunUntilIdle();
  560. }
  561. TEST_P(MostVisitedSitesTest, ShouldHaveHomepageFirstInListWhenFull) {
  562. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  563. homepage_client->SetHomepageTileEnabled(true);
  564. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  565. .WillRepeatedly(base::test::RunOnceCallback<0>((MostVisitedURLList{
  566. MakeMostVisitedURL(u"Site 1", "http://site1/"),
  567. MakeMostVisitedURL(u"Site 2", "http://site2/"),
  568. MakeMostVisitedURL(u"Site 3", "http://site3/"),
  569. MakeMostVisitedURL(u"Site 4", "http://site4/"),
  570. MakeMostVisitedURL(u"Site 5", "http://site5/"),
  571. })));
  572. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  573. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  574. .Times(AnyNumber())
  575. .WillRepeatedly(Return(false));
  576. std::map<SectionType, NTPTilesVector> sections;
  577. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  578. .WillOnce(SaveArg<0>(&sections));
  579. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  580. /*max_num_sites=*/4);
  581. base::RunLoop().RunUntilIdle();
  582. ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
  583. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  584. ASSERT_THAT(tiles.size(), Ge(4ul));
  585. // Assert that the home page is appended as the final tile.
  586. EXPECT_THAT(tiles[0], MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE));
  587. }
  588. // The following test exercises behavior with a preinstalled chrome app; this
  589. // is only relevant if extensions and apps are enabled.
  590. #if BUILDFLAG(ENABLE_EXTENSIONS)
  591. TEST_P(MostVisitedSitesTest, ShouldNotContainDefaultPreinstalledApp) {
  592. const char kTestUrl[] = "http://site1/";
  593. const char16_t kTestTitle[] = u"Site 1";
  594. const char kGmailUrl[] =
  595. "chrome-extension://pjkljhegncpnkpknbcohdijeoejaedia/index.html";
  596. const char16_t kGmailTitle[] = u"Gmail";
  597. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  598. .WillRepeatedly(base::test::RunOnceCallback<0>(
  599. MostVisitedURLList{MakeMostVisitedURL(kGmailTitle, kGmailUrl),
  600. MakeMostVisitedURL(kTestTitle, kTestUrl)}));
  601. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  602. std::map<SectionType, NTPTilesVector> sections;
  603. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  604. .WillRepeatedly(SaveArg<0>(&sections));
  605. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  606. /*max_num_sites=*/2);
  607. base::RunLoop().RunUntilIdle();
  608. EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
  609. AllOf(Not(Contains(MatchesTile(kGmailTitle, kGmailUrl,
  610. TileSource::TOP_SITES))),
  611. Contains(MatchesTile(kTestTitle, kTestUrl,
  612. TileSource::TOP_SITES))));
  613. }
  614. #endif // BUILDFLAG(ENABLE_EXTENSIONS)
  615. TEST_P(MostVisitedSitesTest, ShouldHaveHomepageFirstInListWhenNotFull) {
  616. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  617. homepage_client->SetHomepageTileEnabled(true);
  618. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  619. .WillRepeatedly(base::test::RunOnceCallback<0>((MostVisitedURLList{
  620. MakeMostVisitedURL(u"Site 1", "http://site1/"),
  621. MakeMostVisitedURL(u"Site 2", "http://site2/"),
  622. MakeMostVisitedURL(u"Site 3", "http://site3/"),
  623. MakeMostVisitedURL(u"Site 4", "http://site4/"),
  624. MakeMostVisitedURL(u"Site 5", "http://site5/"),
  625. })));
  626. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  627. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  628. .Times(AnyNumber())
  629. .WillRepeatedly(Return(false));
  630. std::map<SectionType, NTPTilesVector> sections;
  631. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  632. .WillOnce(SaveArg<0>(&sections));
  633. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  634. /*max_num_sites=*/8);
  635. base::RunLoop().RunUntilIdle();
  636. ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
  637. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  638. ASSERT_THAT(tiles.size(), Ge(6ul));
  639. // Assert that the home page is the first tile.
  640. EXPECT_THAT(tiles[0], MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE));
  641. }
  642. TEST_P(MostVisitedSitesTest, ShouldDeduplicateHomepageWithTopSites) {
  643. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  644. homepage_client->SetHomepageTileEnabled(true);
  645. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  646. .WillRepeatedly(base::test::RunOnceCallback<0>(
  647. (MostVisitedURLList{MakeMostVisitedURL(u"Site 1", "http://site1/"),
  648. MakeMostVisitedURL(u"", kHomepageUrl)})));
  649. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  650. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  651. .Times(AnyNumber())
  652. .WillRepeatedly(Return(false));
  653. EXPECT_CALL(
  654. mock_observer_,
  655. OnURLsAvailable(Contains(Pair(
  656. SectionType::PERSONALIZED,
  657. AllOf(Contains(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE)),
  658. Not(Contains(MatchesTile(u"", kHomepageUrl,
  659. TileSource::TOP_SITES))))))));
  660. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  661. /*max_num_sites=*/3);
  662. base::RunLoop().RunUntilIdle();
  663. }
  664. TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomepageIfThereIsNone) {
  665. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  666. homepage_client->SetHomepageTileEnabled(false);
  667. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  668. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  669. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  670. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  671. .Times(AnyNumber())
  672. .WillRepeatedly(Return(false));
  673. EXPECT_CALL(mock_observer_,
  674. OnURLsAvailable(Contains(
  675. Pair(SectionType::PERSONALIZED,
  676. Not(Contains(MatchesTile(u"", kHomepageUrl,
  677. TileSource::HOMEPAGE)))))));
  678. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  679. /*max_num_sites=*/3);
  680. base::RunLoop().RunUntilIdle();
  681. }
  682. TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomepageIfEmptyUrl) {
  683. const std::string kEmptyHomepageUrl;
  684. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  685. homepage_client->SetHomepageTileEnabled(true);
  686. homepage_client->SetHomepageUrl(GURL(kEmptyHomepageUrl));
  687. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  688. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  689. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  690. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(kEmptyHomepageUrl)))
  691. .Times(AnyNumber())
  692. .WillRepeatedly(Return(false));
  693. EXPECT_CALL(mock_observer_,
  694. OnURLsAvailable(Not(FirstPersonalizedTileIs(
  695. u"", kEmptyHomepageUrl, TileSource::HOMEPAGE))));
  696. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  697. /*max_num_sites=*/3);
  698. base::RunLoop().RunUntilIdle();
  699. }
  700. TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomepageIfBlocked) {
  701. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  702. homepage_client->SetHomepageTileEnabled(true);
  703. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  704. .WillRepeatedly(base::test::RunOnceCallback<0>(
  705. (MostVisitedURLList{MakeMostVisitedURL(u"", kHomepageUrl)})));
  706. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  707. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  708. .Times(AnyNumber())
  709. .WillRepeatedly(Return(false));
  710. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  711. .Times(AtLeast(1))
  712. .WillRepeatedly(Return(true));
  713. EXPECT_CALL(mock_observer_,
  714. OnURLsAvailable(Contains(
  715. Pair(SectionType::PERSONALIZED,
  716. Not(Contains(MatchesTile(u"", kHomepageUrl,
  717. TileSource::HOMEPAGE)))))));
  718. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  719. /*max_num_sites=*/3);
  720. base::RunLoop().RunUntilIdle();
  721. }
  722. TEST_P(MostVisitedSitesTest, ShouldPinHomepageAgainIfBlockedUndone) {
  723. FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
  724. homepage_client->SetHomepageTileEnabled(true);
  725. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  726. .WillOnce(base::test::RunOnceCallback<0>(
  727. (MostVisitedURLList{MakeMostVisitedURL(u"", kHomepageUrl)})));
  728. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  729. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  730. .Times(AtLeast(1))
  731. .WillRepeatedly(Return(true));
  732. EXPECT_CALL(mock_observer_,
  733. OnURLsAvailable(Contains(
  734. Pair(SectionType::PERSONALIZED,
  735. Not(Contains(MatchesTile(u"", kHomepageUrl,
  736. TileSource::HOMEPAGE)))))));
  737. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  738. /*max_num_sites=*/3);
  739. base::RunLoop().RunUntilIdle();
  740. VerifyAndClearExpectations();
  741. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  742. .WillOnce(base::test::RunOnceCallback<0>(MostVisitedURLList{}));
  743. EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
  744. .Times(AtLeast(1))
  745. .WillRepeatedly(Return(false));
  746. EXPECT_CALL(
  747. mock_observer_,
  748. OnURLsAvailable(Contains(Pair(
  749. SectionType::PERSONALIZED,
  750. Contains(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE))))));
  751. most_visited_sites_->OnBlockedSitesChanged();
  752. base::RunLoop().RunUntilIdle();
  753. }
  754. TEST_P(MostVisitedSitesTest, ShouldNotIncludeTileForExploreSitesIfNoClient) {
  755. // Does not register an explore sites client.
  756. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  757. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{
  758. MakeMostVisitedURL(u"ESPN", "http://espn.com/"),
  759. MakeMostVisitedURL(u"Mobile", "http://m.mobile.de/"),
  760. MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
  761. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  762. EXPECT_CALL(mock_observer_,
  763. OnURLsAvailable(Not(Contains(
  764. Pair(SectionType::PERSONALIZED,
  765. Contains(TileWithSource(TileSource::EXPLORE)))))));
  766. // Note that 5 sites are requested, this means that there should be the 3 from
  767. // top sites and two from popular sites.
  768. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  769. /*max_num_sites=*/5);
  770. base::RunLoop().RunUntilIdle();
  771. }
  772. // Tests that the explore sites tile appears when there is a mix of top sites
  773. // and popular sites.
  774. TEST_P(MostVisitedSitesTest, ShouldIncludeTileForExploreSites) {
  775. RegisterNewExploreSitesClient();
  776. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  777. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{
  778. MakeMostVisitedURL(u"ESPN", "http://espn.com/"),
  779. MakeMostVisitedURL(u"Mobile", "http://m.mobile.de/"),
  780. MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
  781. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  782. EXPECT_CALL(mock_observer_,
  783. OnURLsAvailable(LastTileIs(kTestExploreTitle, kTestExploreUrl,
  784. TileSource::EXPLORE)));
  785. // Note that 5 sites are requested, this means that there should be the 3 from
  786. // top sites, one from popular sites, and one explore tile.
  787. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  788. /*max_num_sites=*/5);
  789. base::RunLoop().RunUntilIdle();
  790. }
  791. TEST_P(MostVisitedSitesTest, RemovesPersonalSiteIfExploreSitesTilePresent) {
  792. RegisterNewExploreSitesClient();
  793. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  794. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{
  795. MakeMostVisitedURL(u"ESPN", "http://espn.com/"),
  796. MakeMostVisitedURL(u"Mobile", "http://m.mobile.de/"),
  797. MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
  798. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  799. EXPECT_CALL(mock_observer_,
  800. OnURLsAvailable(Contains(Pair(
  801. SectionType::PERSONALIZED,
  802. ElementsAre(MatchesTile(u"ESPN", "http://espn.com/",
  803. TileSource::TOP_SITES),
  804. MatchesTile(u"Mobile", "http://m.mobile.de/",
  805. TileSource::TOP_SITES),
  806. MatchesTile(kTestExploreTitle, kTestExploreUrl,
  807. TileSource::EXPLORE))))));
  808. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  809. /*max_num_sites=*/3);
  810. base::RunLoop().RunUntilIdle();
  811. }
  812. TEST_P(MostVisitedSitesTest, ShouldInformSuggestionSourcesWhenBlocked) {
  813. EXPECT_CALL(*mock_top_sites_, AddBlockedUrl(Eq(GURL(kHomepageUrl)))).Times(1);
  814. most_visited_sites_->AddOrRemoveBlockedUrl(GURL(kHomepageUrl),
  815. /*add_url=*/true);
  816. EXPECT_CALL(*mock_top_sites_, RemoveBlockedUrl(Eq(GURL(kHomepageUrl))))
  817. .Times(1);
  818. most_visited_sites_->AddOrRemoveBlockedUrl(GURL(kHomepageUrl),
  819. /*add_url=*/false);
  820. }
  821. TEST_P(MostVisitedSitesTest,
  822. ShouldDeduplicatePopularSitesWithMostVisitedIffHostAndTitleMatches) {
  823. pref_service_.SetString(prefs::kPopularSitesOverrideCountry, "US");
  824. RecreateMostVisitedSites(); // Refills cache with ESPN and Google News.
  825. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  826. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{
  827. MakeMostVisitedURL(u"ESPN", "http://espn.com/"),
  828. MakeMostVisitedURL(u"Mobile", "http://m.mobile.de/"),
  829. MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
  830. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  831. std::map<SectionType, NTPTilesVector> sections;
  832. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  833. .WillOnce(SaveArg<0>(&sections));
  834. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  835. /*max_num_sites=*/6);
  836. base::RunLoop().RunUntilIdle();
  837. ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
  838. EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
  839. Contains(MatchesTile(u"Google", "http://www.google.com/",
  840. TileSource::TOP_SITES)));
  841. if (IsPopularSitesFeatureEnabled()) {
  842. EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
  843. Contains(MatchesTile(u"Google News", "http://news.google.com/",
  844. TileSource::POPULAR)));
  845. }
  846. EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
  847. AllOf(Contains(MatchesTile(u"ESPN", "http://espn.com/",
  848. TileSource::TOP_SITES)),
  849. Contains(MatchesTile(u"Mobile", "http://m.mobile.de/",
  850. TileSource::TOP_SITES)),
  851. Not(Contains(MatchesTile(u"ESPN", "http://www.espn.com/",
  852. TileSource::POPULAR))),
  853. Not(Contains(MatchesTile(u"Mobile", "http://www.mobile.de/",
  854. TileSource::POPULAR)))));
  855. }
  856. TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
  857. // If cached, TopSites returns the tiles synchronously, running the callback
  858. // even before the function returns.
  859. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  860. .WillRepeatedly(base::test::RunOnceCallback<0>(
  861. MostVisitedURLList{MakeMostVisitedURL(u"Site 1", "http://site1/")}));
  862. InSequence seq;
  863. if (IsPopularSitesFeatureEnabled()) {
  864. EXPECT_CALL(
  865. mock_observer_,
  866. OnURLsAvailable(Contains(Pair(
  867. SectionType::PERSONALIZED,
  868. ElementsAre(
  869. MatchesTile(u"Site 1", "http://site1/", TileSource::TOP_SITES),
  870. MatchesTile(u"PopularSite1", "http://popularsite1/",
  871. TileSource::POPULAR),
  872. MatchesTile(u"PopularSite2", "http://popularsite2/",
  873. TileSource::POPULAR))))));
  874. } else {
  875. EXPECT_CALL(mock_observer_,
  876. OnURLsAvailable(Contains(
  877. Pair(SectionType::PERSONALIZED,
  878. ElementsAre(MatchesTile(u"Site 1", "http://site1/",
  879. TileSource::TOP_SITES))))));
  880. }
  881. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  882. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  883. /*max_num_sites=*/3);
  884. VerifyAndClearExpectations();
  885. CHECK(top_sites_callbacks_.empty());
  886. // Update by TopSites is propagated.
  887. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  888. .WillOnce(base::test::RunOnceCallback<0>(
  889. MostVisitedURLList{MakeMostVisitedURL(u"Site 2", "http://site2/")}));
  890. if (IsPopularSitesFeatureEnabled()) {
  891. EXPECT_CALL(*mock_top_sites_, IsBlocked(_)).WillRepeatedly(Return(false));
  892. }
  893. EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
  894. mock_top_sites_->NotifyTopSitesChanged(
  895. history::TopSitesObserver::ChangeReason::MOST_VISITED);
  896. base::RunLoop().RunUntilIdle();
  897. }
  898. // Tests that multiple observers can be added to the MostVisitedSites.
  899. TEST_P(MostVisitedSitesTest, MultipleObservers) {
  900. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  901. .WillRepeatedly(base::test::RunOnceCallback<0>(MostVisitedURLList{
  902. MakeMostVisitedURL(u"ESPN", "http://espn.com/"),
  903. MakeMostVisitedURL(u"Mobile", "http://m.mobile.de/"),
  904. MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
  905. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  906. std::map<SectionType, NTPTilesVector> sections;
  907. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  908. .WillOnce(SaveArg<0>(&sections));
  909. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  910. /*max_num_sites=*/2);
  911. base::RunLoop().RunUntilIdle();
  912. EXPECT_THAT(
  913. sections.at(SectionType::PERSONALIZED),
  914. AllOf(Contains(MatchesTile(u"ESPN", "http://espn.com/",
  915. TileSource::TOP_SITES)),
  916. Contains(MatchesTile(u"Mobile", "http://m.mobile.de/",
  917. TileSource::TOP_SITES)),
  918. Not(Contains(MatchesTile(u"Google", "http://www.google.com/",
  919. TileSource::TOP_SITES)))));
  920. // Verifies that multiple observers can be added.
  921. sections.clear();
  922. std::map<SectionType, NTPTilesVector> sections_other;
  923. EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(1);
  924. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  925. .WillRepeatedly(SaveArg<0>(&sections));
  926. EXPECT_CALL(mock_other_observer_, OnURLsAvailable(_))
  927. .WillOnce(SaveArg<0>(&sections_other));
  928. most_visited_sites_->RefreshTiles();
  929. most_visited_sites_->AddMostVisitedURLsObserver(&mock_other_observer_,
  930. /*max_num_sites=*/2);
  931. base::RunLoop().RunUntilIdle();
  932. // Verifies that two observers will be notified with the same suggestions.
  933. EXPECT_TRUE(sections == sections_other);
  934. ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
  935. EXPECT_THAT(
  936. sections.at(SectionType::PERSONALIZED),
  937. AllOf(Contains(MatchesTile(u"ESPN", "http://espn.com/",
  938. TileSource::TOP_SITES)),
  939. Contains(MatchesTile(u"Mobile", "http://m.mobile.de/",
  940. TileSource::TOP_SITES)),
  941. Not(Contains(MatchesTile(u"Google", "http://www.google.com/",
  942. TileSource::TOP_SITES)))));
  943. }
  944. INSTANTIATE_TEST_SUITE_P(MostVisitedSitesTest,
  945. MostVisitedSitesTest,
  946. ::testing::Bool());
  947. TEST(MostVisitedSitesTest, ShouldDeduplicateDomainWithNoWwwDomain) {
  948. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.mobile.de"},
  949. "mobile.de"));
  950. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.de"},
  951. "www.mobile.de"));
  952. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.co.uk"},
  953. "www.mobile.co.uk"));
  954. }
  955. TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByRemovingMobilePrefixes) {
  956. EXPECT_TRUE(
  957. MostVisitedSites::IsHostOrMobilePageKnown({"bbc.co.uk"}, "m.bbc.co.uk"));
  958. EXPECT_TRUE(
  959. MostVisitedSites::IsHostOrMobilePageKnown({"m.bbc.co.uk"}, "bbc.co.uk"));
  960. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"},
  961. "edition.cnn.com"));
  962. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"edition.cnn.com"},
  963. "cnn.com"));
  964. EXPECT_TRUE(
  965. MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"}, "mobile.cnn.com"));
  966. EXPECT_TRUE(
  967. MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"}, "cnn.com"));
  968. }
  969. TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByReplacingMobilePrefixes) {
  970. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.bbc.co.uk"},
  971. "m.bbc.co.uk"));
  972. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"m.mobile.de"},
  973. "www.mobile.de"));
  974. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.cnn.com"},
  975. "edition.cnn.com"));
  976. EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"},
  977. "www.cnn.com"));
  978. }
  979. #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  980. class MostVisitedSitesWithCustomLinksTest : public MostVisitedSitesTest {
  981. public:
  982. MostVisitedSitesWithCustomLinksTest() {
  983. EnableCustomLinks();
  984. RecreateMostVisitedSites();
  985. }
  986. void ExpectBuildWithTopSites(
  987. const MostVisitedURLList& expected_list,
  988. std::map<SectionType, NTPTilesVector>* sections) {
  989. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  990. .WillRepeatedly(base::test::RunOnceCallback<0>(expected_list));
  991. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  992. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  993. .WillRepeatedly(Return(false));
  994. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  995. .WillOnce(SaveArg<0>(sections));
  996. }
  997. void ExpectBuildWithCustomLinks(
  998. const std::vector<CustomLinksManager::Link>& expected_links,
  999. std::map<SectionType, NTPTilesVector>* sections) {
  1000. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1001. .WillRepeatedly(Return(true));
  1002. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1003. .WillOnce(ReturnRef(expected_links));
  1004. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1005. .WillOnce(SaveArg<0>(sections));
  1006. }
  1007. };
  1008. TEST_P(MostVisitedSitesWithCustomLinksTest, ChangeVisibility) {
  1009. const char kTestUrl[] = "http://site1/";
  1010. const char16_t kTestTitle[] = u"Site 1";
  1011. std::map<SectionType, NTPTilesVector> sections;
  1012. // Build tiles when custom links is not initialized. Tiles should be Top
  1013. // Sites.
  1014. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1015. ExpectBuildWithTopSites(
  1016. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1017. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1018. /*max_num_sites=*/1);
  1019. base::RunLoop().RunUntilIdle();
  1020. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1021. ASSERT_THAT(tiles.size(), Ge(1ul));
  1022. ASSERT_THAT(tiles[0],
  1023. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1024. EXPECT_TRUE(most_visited_sites_->IsCustomLinksEnabled());
  1025. EXPECT_TRUE(most_visited_sites_->IsShortcutsVisible());
  1026. // Hide shortcuts. Observer should get notified.
  1027. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1028. most_visited_sites_->SetShortcutsVisible(false);
  1029. base::RunLoop().RunUntilIdle();
  1030. EXPECT_TRUE(most_visited_sites_->IsCustomLinksEnabled());
  1031. EXPECT_FALSE(most_visited_sites_->IsShortcutsVisible());
  1032. // Attempt to hide the shortcuts again. This should be ignored.
  1033. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0);
  1034. most_visited_sites_->SetShortcutsVisible(false);
  1035. base::RunLoop().RunUntilIdle();
  1036. // Make the shortcuts visible. Observer should get notified.
  1037. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1038. most_visited_sites_->SetShortcutsVisible(true);
  1039. base::RunLoop().RunUntilIdle();
  1040. EXPECT_TRUE(most_visited_sites_->IsCustomLinksEnabled());
  1041. EXPECT_TRUE(most_visited_sites_->IsShortcutsVisible());
  1042. }
  1043. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1044. ShouldOnlyBuildCustomLinksWhenInitialized) {
  1045. const char kTestUrl[] = "http://site1/";
  1046. const char16_t kTestTitle[] = u"Site 1";
  1047. std::vector<CustomLinksManager::Link> expected_links(
  1048. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle}});
  1049. std::map<SectionType, NTPTilesVector> sections;
  1050. // Build tiles when custom links is not initialized. Tiles should be Top
  1051. // Sites.
  1052. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1053. ExpectBuildWithTopSites(
  1054. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1055. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1056. /*max_num_sites=*/1);
  1057. base::RunLoop().RunUntilIdle();
  1058. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1059. ASSERT_THAT(tiles.size(), Ge(1ul));
  1060. ASSERT_THAT(tiles[0],
  1061. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1062. // Initialize custom links and rebuild tiles. Tiles should be custom links.
  1063. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1064. ExpectBuildWithCustomLinks(expected_links, &sections);
  1065. most_visited_sites_->InitializeCustomLinks();
  1066. most_visited_sites_->RefreshTiles();
  1067. base::RunLoop().RunUntilIdle();
  1068. EXPECT_THAT(
  1069. sections.at(SectionType::PERSONALIZED),
  1070. ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::CUSTOM_LINKS)));
  1071. // Uninitialize custom links and rebuild tiles. Tiles should be Top Sites.
  1072. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1073. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  1074. .WillRepeatedly(base::test::RunOnceCallback<0>(
  1075. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
  1076. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1077. .WillRepeatedly(Return(false));
  1078. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1079. .WillOnce(SaveArg<0>(&sections));
  1080. most_visited_sites_->UninitializeCustomLinks();
  1081. base::RunLoop().RunUntilIdle();
  1082. tiles = sections.at(SectionType::PERSONALIZED);
  1083. ASSERT_THAT(tiles.size(), Ge(1ul));
  1084. ASSERT_THAT(tiles[0],
  1085. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1086. }
  1087. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1088. ShouldFavorCustomLinksOverTopSites) {
  1089. const char kTestUrl[] = "http://site1/";
  1090. const char16_t kTestTitle[] = u"Site 1";
  1091. std::vector<CustomLinksManager::Link> expected_links(
  1092. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle}});
  1093. std::map<SectionType, NTPTilesVector> sections;
  1094. // Build tiles when custom links is not initialized. Tiles should be Top
  1095. // Sites.
  1096. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1097. ExpectBuildWithTopSites(
  1098. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1099. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1100. /*max_num_sites=*/1);
  1101. base::RunLoop().RunUntilIdle();
  1102. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1103. ASSERT_THAT(tiles.size(), Ge(1ul));
  1104. ASSERT_THAT(tiles[0],
  1105. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1106. // Initialize custom links and rebuild tiles. Tiles should be custom links.
  1107. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1108. ExpectBuildWithCustomLinks(expected_links, &sections);
  1109. most_visited_sites_->InitializeCustomLinks();
  1110. most_visited_sites_->RefreshTiles();
  1111. base::RunLoop().RunUntilIdle();
  1112. ASSERT_THAT(
  1113. sections.at(SectionType::PERSONALIZED),
  1114. ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::CUSTOM_LINKS)));
  1115. // Initiate notification for new Top Sites. This should be ignored.
  1116. VerifyAndClearExpectations();
  1117. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0);
  1118. top_sites_callbacks_.Notify(
  1119. MostVisitedURLList({MakeMostVisitedURL(u"Site 2", "http://site2/")}));
  1120. base::RunLoop().RunUntilIdle();
  1121. }
  1122. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1123. DisableCustomLinksWhenNotInitialized) {
  1124. const char kTestUrl[] = "http://site1/";
  1125. const char16_t kTestTitle16[] = u"Site 1";
  1126. std::vector<CustomLinksManager::Link> expected_links(
  1127. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle16}});
  1128. std::map<SectionType, NTPTilesVector> sections;
  1129. // Build tiles when custom links is not initialized. Tiles should be from
  1130. // Top Sites.
  1131. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1132. ExpectBuildWithTopSites(
  1133. MostVisitedURLList{MakeMostVisitedURL(kTestTitle16, kTestUrl)},
  1134. &sections);
  1135. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1136. /*max_num_sites=*/1);
  1137. base::RunLoop().RunUntilIdle();
  1138. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1139. ASSERT_THAT(tiles.size(), Ge(1ul));
  1140. ASSERT_THAT(tiles[0],
  1141. MatchesTile(kTestTitle16, kTestUrl, TileSource::TOP_SITES));
  1142. // Disable custom links. Tiles should rebuild.
  1143. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  1144. .WillRepeatedly(base::test::RunOnceCallback<0>(
  1145. MostVisitedURLList{MakeMostVisitedURL(kTestTitle16, kTestUrl)}));
  1146. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1147. most_visited_sites_->EnableCustomLinks(false);
  1148. base::RunLoop().RunUntilIdle();
  1149. // Try to disable custom links again. This should not rebuild the tiles.
  1150. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_)).Times(0);
  1151. EXPECT_CALL(*mock_custom_links_, GetLinks()).Times(0);
  1152. most_visited_sites_->EnableCustomLinks(false);
  1153. base::RunLoop().RunUntilIdle();
  1154. }
  1155. TEST_P(MostVisitedSitesWithCustomLinksTest, DisableCustomLinksWhenInitialized) {
  1156. const char kTestUrl[] = "http://site1/";
  1157. const char16_t kTestTitle16[] = u"Site 1";
  1158. std::vector<CustomLinksManager::Link> expected_links(
  1159. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle16}});
  1160. std::map<SectionType, NTPTilesVector> sections;
  1161. // Build tiles when custom links is initialized and not disabled. Tiles should
  1162. // be custom links.
  1163. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1164. EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
  1165. ExpectBuildWithCustomLinks(expected_links, &sections);
  1166. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1167. /*max_num_sites=*/1);
  1168. base::RunLoop().RunUntilIdle();
  1169. ASSERT_THAT(sections.at(SectionType::PERSONALIZED),
  1170. ElementsAre(MatchesTile(kTestTitle16, kTestUrl,
  1171. TileSource::CUSTOM_LINKS)));
  1172. // Disable custom links. Tiles should rebuild and return Top Sites.
  1173. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  1174. .WillRepeatedly(base::test::RunOnceCallback<0>(
  1175. MostVisitedURLList{MakeMostVisitedURL(kTestTitle16, kTestUrl)}));
  1176. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1177. .WillRepeatedly(Return(false));
  1178. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1179. .WillOnce(SaveArg<0>(&sections));
  1180. most_visited_sites_->EnableCustomLinks(false);
  1181. base::RunLoop().RunUntilIdle();
  1182. EXPECT_THAT(
  1183. sections.at(SectionType::PERSONALIZED),
  1184. ElementsAre(MatchesTile(kTestTitle16, kTestUrl, TileSource::TOP_SITES)));
  1185. // Re-enable custom links. Tiles should rebuild and return custom links.
  1186. ExpectBuildWithCustomLinks(expected_links, &sections);
  1187. most_visited_sites_->EnableCustomLinks(true);
  1188. base::RunLoop().RunUntilIdle();
  1189. ASSERT_THAT(sections.at(SectionType::PERSONALIZED),
  1190. ElementsAre(MatchesTile(kTestTitle16, kTestUrl,
  1191. TileSource::CUSTOM_LINKS)));
  1192. }
  1193. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1194. ShouldGenerateShortTitleForTopSites) {
  1195. std::string kTestUrl1 = "https://www.imdb.com/";
  1196. std::u16string kTestTitle1 = u"IMDb - Movies, TV and Celebrities - IMDb";
  1197. std::string kTestUrl2 = "https://drive.google.com/";
  1198. std::u16string kTestTitle2 =
  1199. u"Google Drive - Cloud Storage & File Backup for Photos, Docs & More";
  1200. std::string kTestUrl3 = "https://amazon.com/";
  1201. std::u16string kTestTitle3 =
  1202. u"Amazon.com: Online Shopping for Electronics, Apparel, Computers, "
  1203. u"Books, "
  1204. u"DVDs & more";
  1205. std::map<SectionType, NTPTilesVector> sections;
  1206. // Build tiles from Top Sites. The tiles should have short titles.
  1207. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1208. ExpectBuildWithTopSites(
  1209. MostVisitedURLList{MakeMostVisitedURL(kTestTitle1, kTestUrl1),
  1210. MakeMostVisitedURL(kTestTitle2, kTestUrl2),
  1211. MakeMostVisitedURL(kTestTitle3, kTestUrl3)},
  1212. &sections);
  1213. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1214. /*max_num_sites=*/3);
  1215. base::RunLoop().RunUntilIdle();
  1216. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1217. ASSERT_THAT(tiles.size(), Ge(3ul));
  1218. ASSERT_THAT(
  1219. tiles[0],
  1220. MatchesTile(/* The short title generated by the heuristic */ u"IMDb",
  1221. kTestUrl1, TileSource::TOP_SITES));
  1222. ASSERT_THAT(
  1223. tiles[1],
  1224. MatchesTile(
  1225. /* The short title generated by the heuristic */ u"Google Drive",
  1226. kTestUrl2, TileSource::TOP_SITES));
  1227. ASSERT_THAT(
  1228. tiles[2],
  1229. MatchesTile(
  1230. /* The short title generated by the heuristic */ u"Amazon.com",
  1231. kTestUrl3, TileSource::TOP_SITES));
  1232. }
  1233. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1234. ShouldNotCrashIfReceiveAnEmptyTitle) {
  1235. std::string kTestUrl1 = "https://site1/";
  1236. std::u16string kTestTitle1 = u""; // Empty title
  1237. std::string kTestUrl2 = "https://site2/";
  1238. std::u16string kTestTitle2 = u" "; // Title only contains spaces
  1239. std::map<SectionType, NTPTilesVector> sections;
  1240. // Build tiles from Top Sites. The tiles should have short titles.
  1241. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1242. ExpectBuildWithTopSites(
  1243. MostVisitedURLList{MakeMostVisitedURL(kTestTitle1, kTestUrl1),
  1244. MakeMostVisitedURL(kTestTitle2, kTestUrl2)},
  1245. &sections);
  1246. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1247. /*max_num_sites=*/2);
  1248. base::RunLoop().RunUntilIdle();
  1249. // Both cases should not crash and generate an empty title tile.
  1250. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1251. ASSERT_THAT(tiles.size(), Ge(2ul));
  1252. ASSERT_THAT(tiles[0], MatchesTile(u"", kTestUrl1, TileSource::TOP_SITES));
  1253. ASSERT_THAT(tiles[1], MatchesTile(u"", kTestUrl2, TileSource::TOP_SITES));
  1254. }
  1255. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1256. UninitializeCustomLinksOnUndoAfterFirstAction) {
  1257. const char kTestUrl[] = "http://site1/";
  1258. const char16_t kTestTitle[] = u"Site 1";
  1259. std::vector<CustomLinksManager::Link> expected_links(
  1260. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle}});
  1261. std::map<SectionType, NTPTilesVector> sections;
  1262. // Build initial tiles with Top Sites.
  1263. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1264. ExpectBuildWithTopSites(
  1265. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1266. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1267. /*max_num_sites=*/1);
  1268. base::RunLoop().RunUntilIdle();
  1269. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1270. ASSERT_THAT(tiles.size(), Ge(1ul));
  1271. ASSERT_THAT(tiles[0],
  1272. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1273. // Initialize custom links and complete a custom link action.
  1274. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1275. EXPECT_CALL(*mock_custom_links_, AddLink(_, _)).WillOnce(Return(true));
  1276. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1277. .WillRepeatedly(Return(true));
  1278. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1279. .WillRepeatedly(ReturnRef(expected_links));
  1280. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1281. .WillOnce(SaveArg<0>(&sections));
  1282. most_visited_sites_->AddCustomLink(GURL("test.com"), u"test");
  1283. base::RunLoop().RunUntilIdle();
  1284. ASSERT_THAT(
  1285. sections.at(SectionType::PERSONALIZED),
  1286. ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::CUSTOM_LINKS)));
  1287. // Undo the action. This should uninitialize custom links.
  1288. EXPECT_CALL(*mock_custom_links_, UndoAction()).Times(0);
  1289. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1290. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  1291. .WillRepeatedly(base::test::RunOnceCallback<0>(
  1292. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
  1293. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1294. .WillRepeatedly(Return(false));
  1295. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1296. .WillOnce(SaveArg<0>(&sections));
  1297. most_visited_sites_->UndoCustomLinkAction();
  1298. base::RunLoop().RunUntilIdle();
  1299. tiles = sections.at(SectionType::PERSONALIZED);
  1300. ASSERT_THAT(tiles.size(), Ge(1ul));
  1301. ASSERT_THAT(tiles[0],
  1302. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1303. }
  1304. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1305. DontUninitializeCustomLinksOnUndoAfterMultipleActions) {
  1306. const char kTestUrl[] = "http://site1/";
  1307. const char16_t kTestTitle[] = u"Site 1";
  1308. std::vector<CustomLinksManager::Link> expected_links(
  1309. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle}});
  1310. std::map<SectionType, NTPTilesVector> sections;
  1311. // Build initial tiles with Top Sites.
  1312. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1313. ExpectBuildWithTopSites(
  1314. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1315. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1316. /*max_num_sites=*/1);
  1317. base::RunLoop().RunUntilIdle();
  1318. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1319. ASSERT_THAT(tiles.size(), Ge(1ul));
  1320. ASSERT_THAT(tiles[0],
  1321. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1322. // Initialize custom links and complete a custom link action.
  1323. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1324. EXPECT_CALL(*mock_custom_links_, UpdateLink(_, _, _)).WillOnce(Return(true));
  1325. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1326. .WillRepeatedly(Return(true));
  1327. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1328. .WillRepeatedly(ReturnRef(expected_links));
  1329. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1330. .WillRepeatedly(SaveArg<0>(&sections));
  1331. most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test.com"),
  1332. u"test");
  1333. base::RunLoop().RunUntilIdle();
  1334. ASSERT_THAT(
  1335. sections.at(SectionType::PERSONALIZED),
  1336. ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::CUSTOM_LINKS)));
  1337. // Complete a second custom link action.
  1338. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(false));
  1339. EXPECT_CALL(*mock_custom_links_, DeleteLink(_)).WillOnce(Return(true));
  1340. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1341. .WillRepeatedly(Return(true));
  1342. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1343. .WillOnce(ReturnRef(expected_links));
  1344. most_visited_sites_->DeleteCustomLink(GURL("test.com"));
  1345. base::RunLoop().RunUntilIdle();
  1346. // Undo the second action. This should not uninitialize custom links.
  1347. EXPECT_CALL(*mock_custom_links_, UndoAction()).WillOnce(Return(true));
  1348. EXPECT_CALL(*mock_custom_links_, Uninitialize()).Times(0);
  1349. EXPECT_CALL(*mock_custom_links_, IsInitialized()).WillOnce(Return(true));
  1350. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1351. .WillOnce(ReturnRef(expected_links));
  1352. most_visited_sites_->UndoCustomLinkAction();
  1353. base::RunLoop().RunUntilIdle();
  1354. }
  1355. TEST_P(MostVisitedSitesWithCustomLinksTest,
  1356. UninitializeCustomLinksIfFirstActionFails) {
  1357. const char kTestUrl[] = "http://site1/";
  1358. const char16_t kTestTitle[] = u"Site 1";
  1359. std::vector<CustomLinksManager::Link> expected_links(
  1360. {CustomLinksManager::Link{GURL(kTestUrl), kTestTitle}});
  1361. std::map<SectionType, NTPTilesVector> sections;
  1362. // Build initial tiles with Top Sites.
  1363. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_));
  1364. ExpectBuildWithTopSites(
  1365. MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}, &sections);
  1366. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1367. /*max_num_sites=*/1);
  1368. base::RunLoop().RunUntilIdle();
  1369. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1370. ASSERT_THAT(tiles.size(), Ge(1ul));
  1371. ASSERT_THAT(tiles[0],
  1372. MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
  1373. // Fail to add a custom link. This should not initialize custom links but
  1374. // notify.
  1375. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1376. EXPECT_CALL(*mock_custom_links_, AddLink(_, _)).WillOnce(Return(false));
  1377. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1378. .WillRepeatedly(Return(false));
  1379. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1380. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1381. most_visited_sites_->AddCustomLink(GURL(kTestUrl), u"test");
  1382. base::RunLoop().RunUntilIdle();
  1383. // Fail to edit a custom link. This should not initialize custom links but
  1384. // notify.
  1385. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1386. EXPECT_CALL(*mock_custom_links_, UpdateLink(_, _, _)).WillOnce(Return(false));
  1387. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1388. .WillRepeatedly(Return(false));
  1389. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1390. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1391. most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test2.com"),
  1392. u"test");
  1393. base::RunLoop().RunUntilIdle();
  1394. // Fail to reorder a custom link. This should not initialize custom links but
  1395. // notify.
  1396. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1397. EXPECT_CALL(*mock_custom_links_, ReorderLink(_, _)).WillOnce(Return(false));
  1398. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1399. .WillRepeatedly(Return(false));
  1400. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1401. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1402. most_visited_sites_->ReorderCustomLink(GURL("test.com"), 1);
  1403. base::RunLoop().RunUntilIdle();
  1404. // Fail to delete a custom link. This should not initialize custom links but
  1405. // notify.
  1406. EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
  1407. EXPECT_CALL(*mock_custom_links_, DeleteLink(_)).WillOnce(Return(false));
  1408. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1409. .WillRepeatedly(Return(false));
  1410. EXPECT_CALL(*mock_custom_links_, Uninitialize());
  1411. EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
  1412. most_visited_sites_->DeleteCustomLink(GURL("test.com"));
  1413. base::RunLoop().RunUntilIdle();
  1414. }
  1415. TEST_P(MostVisitedSitesWithCustomLinksTest, RebuildTilesOnCustomLinksChanged) {
  1416. const char kTestUrl1[] = "http://site1/";
  1417. const char kTestUrl2[] = "http://site2/";
  1418. const char16_t kTestTitle1[] = u"Site 1";
  1419. const char16_t kTestTitle2[] = u"Site 2";
  1420. std::vector<CustomLinksManager::Link> expected_links(
  1421. {CustomLinksManager::Link{GURL(kTestUrl2), kTestTitle2}});
  1422. std::map<SectionType, NTPTilesVector> sections;
  1423. // Build initial tiles with Top Sites.
  1424. base::RepeatingClosure custom_links_callback;
  1425. EXPECT_CALL(*mock_custom_links_, RegisterCallbackForOnChanged(_))
  1426. .WillOnce(DoAll(SaveArg<0>(&custom_links_callback),
  1427. Return(ByMove(base::CallbackListSubscription()))));
  1428. ExpectBuildWithTopSites(
  1429. MostVisitedURLList{MakeMostVisitedURL(kTestTitle1, kTestUrl1)},
  1430. &sections);
  1431. most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
  1432. /*max_num_sites=*/1);
  1433. base::RunLoop().RunUntilIdle();
  1434. NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
  1435. ASSERT_THAT(tiles.size(), Ge(1ul));
  1436. ASSERT_THAT(tiles[0],
  1437. MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES));
  1438. // Notify that there is a new set of custom links. This should replace the
  1439. // current tiles with custom links.
  1440. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1441. .WillRepeatedly(Return(true));
  1442. EXPECT_CALL(*mock_custom_links_, GetLinks())
  1443. .WillRepeatedly(ReturnRef(expected_links));
  1444. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1445. .WillOnce(SaveArg<0>(&sections));
  1446. custom_links_callback.Run();
  1447. base::RunLoop().RunUntilIdle();
  1448. EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
  1449. ElementsAre(MatchesTile(kTestTitle2, kTestUrl2,
  1450. TileSource::CUSTOM_LINKS)));
  1451. // Notify that custom links have been uninitialized. This should rebuild the
  1452. // tiles with Top Sites.
  1453. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1454. .WillRepeatedly(Return(false));
  1455. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
  1456. .WillRepeatedly(base::test::RunOnceCallback<0>(
  1457. MostVisitedURLList{MakeMostVisitedURL(kTestTitle1, kTestUrl1)}));
  1458. EXPECT_CALL(*mock_custom_links_, IsInitialized())
  1459. .WillRepeatedly(Return(false));
  1460. EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
  1461. .WillOnce(SaveArg<0>(&sections));
  1462. custom_links_callback.Run();
  1463. base::RunLoop().RunUntilIdle();
  1464. tiles = sections.at(SectionType::PERSONALIZED);
  1465. ASSERT_THAT(tiles.size(), Ge(1ul));
  1466. ASSERT_THAT(tiles[0],
  1467. MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES));
  1468. }
  1469. // These exclude Android and iOS.
  1470. INSTANTIATE_TEST_SUITE_P(MostVisitedSitesWithCustomLinksTest,
  1471. MostVisitedSitesWithCustomLinksTest,
  1472. ::testing::Bool());
  1473. #endif
  1474. // This a test for MostVisitedSites::MergeTiles(...) method, and thus has the
  1475. // same scope as the method itself. This tests merging popular sites with
  1476. // personal tiles.
  1477. // More important things out of the scope of testing presently:
  1478. // - Removing blocked tiles.
  1479. // - Correct host extraction from the URL.
  1480. // - Ensuring personal tiles are not duplicated in popular tiles.
  1481. TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPersonalOnly) {
  1482. std::vector<NTPTile> personal_tiles{
  1483. MakeTile(u"Site 1", "https://www.site1.com/", TileSource::TOP_SITES),
  1484. MakeTile(u"Site 2", "https://www.site2.com/", TileSource::TOP_SITES),
  1485. MakeTile(u"Site 3", "https://www.site3.com/", TileSource::TOP_SITES),
  1486. MakeTile(u"Site 4", "https://www.site4.com/", TileSource::TOP_SITES),
  1487. };
  1488. // Without any popular tiles, the result after merge should be the personal
  1489. // tiles.
  1490. EXPECT_THAT(MostVisitedSites::MergeTiles(std::move(personal_tiles),
  1491. /*popular_tiles=*/NTPTilesVector(),
  1492. /*explore_tile=*/absl::nullopt),
  1493. ElementsAre(MatchesTile(u"Site 1", "https://www.site1.com/",
  1494. TileSource::TOP_SITES),
  1495. MatchesTile(u"Site 2", "https://www.site2.com/",
  1496. TileSource::TOP_SITES),
  1497. MatchesTile(u"Site 3", "https://www.site3.com/",
  1498. TileSource::TOP_SITES),
  1499. MatchesTile(u"Site 4", "https://www.site4.com/",
  1500. TileSource::TOP_SITES)));
  1501. }
  1502. TEST(MostVisitedSitesMergeTest, ShouldMergeTilesWithPopularOnly) {
  1503. std::vector<NTPTile> popular_tiles{
  1504. MakeTile(u"Site 1", "https://www.site1.com/", TileSource::POPULAR),
  1505. MakeTile(u"Site 2", "https://www.site2.com/", TileSource::POPULAR),
  1506. MakeTile(u"Site 3", "https://www.site3.com/", TileSource::POPULAR),
  1507. MakeTile(u"Site 4", "https://www.site4.com/", TileSource::POPULAR),
  1508. };
  1509. // Without any personal tiles, the result after merge should be the popular
  1510. // tiles.
  1511. EXPECT_THAT(
  1512. MostVisitedSites::MergeTiles(/*personal_tiles=*/NTPTilesVector(),
  1513. /*popular_tiles=*/std::move(popular_tiles),
  1514. /*explore_tile=*/absl::nullopt),
  1515. ElementsAre(
  1516. MatchesTile(u"Site 1", "https://www.site1.com/", TileSource::POPULAR),
  1517. MatchesTile(u"Site 2", "https://www.site2.com/", TileSource::POPULAR),
  1518. MatchesTile(u"Site 3", "https://www.site3.com/", TileSource::POPULAR),
  1519. MatchesTile(u"Site 4", "https://www.site4.com/",
  1520. TileSource::POPULAR)));
  1521. }
  1522. TEST(MostVisitedSitesMergeTest, ShouldMergeTilesFavoringPersonalOverPopular) {
  1523. std::vector<NTPTile> popular_tiles{
  1524. MakeTile(u"Site 1", "https://www.site1.com/", TileSource::POPULAR),
  1525. MakeTile(u"Site 2", "https://www.site2.com/", TileSource::POPULAR),
  1526. };
  1527. std::vector<NTPTile> personal_tiles{
  1528. MakeTile(u"Site 3", "https://www.site3.com/", TileSource::TOP_SITES),
  1529. MakeTile(u"Site 4", "https://www.site4.com/", TileSource::TOP_SITES),
  1530. };
  1531. absl::optional<NTPTile> explore_tile{
  1532. MakeTile(u"Explore", "https://explore.example.com/", TileSource::EXPLORE),
  1533. };
  1534. EXPECT_THAT(
  1535. MostVisitedSites::MergeTiles(std::move(personal_tiles),
  1536. /*popular_tiles=*/std::move(popular_tiles),
  1537. /*explore_tiles=*/explore_tile),
  1538. ElementsAre(
  1539. MatchesTile(u"Site 3", "https://www.site3.com/",
  1540. TileSource::TOP_SITES),
  1541. MatchesTile(u"Site 4", "https://www.site4.com/",
  1542. TileSource::TOP_SITES),
  1543. MatchesTile(u"Site 1", "https://www.site1.com/", TileSource::POPULAR),
  1544. MatchesTile(u"Site 2", "https://www.site2.com/", TileSource::POPULAR),
  1545. MatchesTile(u"Explore", "https://explore.example.com/",
  1546. TileSource::EXPLORE)));
  1547. }
  1548. } // namespace ntp_tiles