| Index: ios/chrome/browser/ui/history/history_service_facade_unittest.mm
|
| diff --git a/ios/chrome/browser/ui/history/history_service_facade_unittest.mm b/ios/chrome/browser/ui/history/history_service_facade_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9eb964df7ac08709246c511ceda726d352c41962
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/history/history_service_facade_unittest.mm
|
| @@ -0,0 +1,223 @@
|
| +// Copyright 2016 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 "ios/chrome/browser/ui/history/history_service_facade.h"
|
| +
|
| +#include <memory>
|
| +
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/strings/string16.h"
|
| +#include "components/history/core/browser/history_service.h"
|
| +#include "components/history/core/browser/history_service_observer.h"
|
| +#include "components/keyed_service/core/service_access_type.h"
|
| +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
|
| +#include "ios/chrome/browser/history/history_service_factory.h"
|
| +#import "ios/chrome/browser/ui/history/history_entry.h"
|
| +#import "ios/chrome/browser/ui/history/history_service_facade_delegate.h"
|
| +#include "ios/web/public/test/test_web_thread.h"
|
| +#include "ios/web/public/test/test_web_thread_bundle.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/platform_test.h"
|
| +#import "third_party/ocmock/OCMock/OCMock.h"
|
| +#include "third_party/ocmock/gtest_support.h"
|
| +
|
| +namespace {
|
| +
|
| +struct TestResult {
|
| + GURL url;
|
| + int64_t hour_offset; // Visit time in hours past the baseline time.
|
| +};
|
| +
|
| +// Duplicates on the same day in the local timezone are removed, so set a
|
| +// baseline time in local time.
|
| +const base::Time baseline_time = base::Time::UnixEpoch().LocalMidnight();
|
| +
|
| +// Returns true if |result| matches the test data given by |correct_result|,
|
| +// otherwise returns false.
|
| +bool ResultEquals(const history::HistoryEntry& result,
|
| + const TestResult& correct_result) {
|
| + base::Time correct_time =
|
| + baseline_time + base::TimeDelta::FromHours(correct_result.hour_offset);
|
| +
|
| + return result.time == correct_time && result.url == correct_result.url;
|
| +}
|
| +
|
| +// Returns RemovedEntry using |time_offset|
|
| +HistoryServiceFacade::RemovedEntry EntryForRemoval(const GURL& url,
|
| + int64_t time_offset) {
|
| + return HistoryServiceFacade::RemovedEntry(
|
| + url, baseline_time + base::TimeDelta::FromHours(time_offset));
|
| +}
|
| +} // namespace
|
| +
|
| +// Mock delegate for verifying callback behavior.
|
| +@interface MockHistoryServiceFacadeDelegate
|
| + : NSObject<HistoryServiceFacadeDelegate> {
|
| + std::vector<history::HistoryEntry> _received_entries;
|
| +}
|
| +@property BOOL didCompleteRemoval;
|
| +@property BOOL didReceiveOtherBrowsingHistoryCallback;
|
| +- (BOOL)delegateDidReceiveResult:(const TestResult&)expected_result;
|
| +@end
|
| +
|
| +@implementation MockHistoryServiceFacadeDelegate
|
| +@synthesize didCompleteRemoval = _didCompleteRemoval;
|
| +@synthesize didReceiveOtherBrowsingHistoryCallback =
|
| + _didReceiveOtherBrowsingHistoryCallback;
|
| +
|
| +- (void)historyServiceFacade:(HistoryServiceFacade*)facade
|
| + didReceiveQueryResult:(HistoryServiceFacade::QueryResult)result {
|
| + _received_entries = result.entries;
|
| +}
|
| +
|
| +- (void)historyServiceFacade:(HistoryServiceFacade*)facade
|
| + shouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice {
|
| + _didReceiveOtherBrowsingHistoryCallback = YES;
|
| +}
|
| +
|
| +// Notifies the delegate that history entry deletion has completed.
|
| +- (void)historyServiceFacadeDidCompleteEntryRemoval:
|
| + (HistoryServiceFacade*)facade {
|
| + _didCompleteRemoval = YES;
|
| +}
|
| +
|
| +- (BOOL)delegateDidReceiveResult:(const TestResult&)expected_result {
|
| + for (history::HistoryEntry entry : _received_entries) {
|
| + if (ResultEquals(entry, expected_result))
|
| + return YES;
|
| + }
|
| + return NO;
|
| +}
|
| +
|
| +@end
|
| +
|
| +class HistoryServiceFacadeTest : public PlatformTest,
|
| + public history::HistoryServiceObserver {
|
| + public:
|
| + HistoryServiceFacadeTest() {}
|
| + ~HistoryServiceFacadeTest() override {}
|
| +
|
| + void SetUp() override {
|
| + DCHECK_CURRENTLY_ON(web::WebThread::UI);
|
| + TestChromeBrowserState::Builder builder;
|
| + browser_state_ = builder.Build();
|
| + bool success = browser_state_->CreateHistoryService(true);
|
| + EXPECT_TRUE(success);
|
| +
|
| + mock_delegate_.reset([[MockHistoryServiceFacadeDelegate alloc] init]);
|
| + history_service_facade_.reset(
|
| + new HistoryServiceFacade(browser_state_.get(), mock_delegate_));
|
| + }
|
| +
|
| + // Cycles the runloop until the condition is met (up to 10 seconds).
|
| + typedef base::Callback<bool(void)> WaitCondition;
|
| + bool WaitUntilLoop(WaitCondition condition) {
|
| + DCHECK_CURRENTLY_ON(web::WebThread::UI);
|
| + base::Time maxDate = base::Time::Now() + base::TimeDelta::FromSeconds(10);
|
| + while (!condition.Run()) {
|
| + if (base::Time::Now() > maxDate)
|
| + return false;
|
| + base::RunLoop().RunUntilIdle();
|
| + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + // Adds a visit to history.
|
| + void AddVisit(const GURL& url, int64_t time_offset) {
|
| + history::HistoryService* history_service =
|
| + ios::HistoryServiceFactory::GetForBrowserStateIfExists(
|
| + browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS);
|
| + EXPECT_TRUE(history_service);
|
| +
|
| + history_service->AddObserver(this);
|
| + base::Time time = baseline_time + base::TimeDelta::FromHours(time_offset);
|
| + history_service->AddPage(url, time, history::VisitSource::SOURCE_BROWSED);
|
| +
|
| + // Wait until the data is in the db.
|
| + EXPECT_TRUE(WaitUntilLoop(base::Bind(&HistoryServiceFacadeTest::VerifyVisit,
|
| + base::Unretained(this), url, time)));
|
| +
|
| + history_service->RemoveObserver(this);
|
| + }
|
| +
|
| + // history::HistoryServiceObserver
|
| + void OnURLVisited(history::HistoryService* history_service,
|
| + ui::PageTransition transition,
|
| + const history::URLRow& row,
|
| + const history::RedirectList& redirects,
|
| + base::Time visit_time) override {
|
| + visited_url_ = row.url();
|
| + visited_time_ = row.last_visit();
|
| + }
|
| +
|
| + // Verify visit to |url| at |time| was observed.
|
| + bool VerifyVisit(const GURL& url, const base::Time& time) {
|
| + return visited_url_ == url && visited_time_ == time;
|
| + }
|
| +
|
| + // Verify that a query result was received by delegate callback.
|
| + bool VerifyQueryResult(const TestResult& result) {
|
| + return [mock_delegate_ delegateDidReceiveResult:result];
|
| + }
|
| +
|
| + // Verify that entry removal completion delegate callback was called.
|
| + bool VerifyEntryRemoval() { return [mock_delegate_ didCompleteRemoval]; }
|
| +
|
| + // Verify that the
|
| + // historyServiceFacade:shouldShowNoticeAboutOtherFormsOfBrowsingHistory
|
| + // delegate callback was called.
|
| + bool VerifyOtherHistoryCallback() {
|
| + return [mock_delegate_ didReceiveOtherBrowsingHistoryCallback];
|
| + }
|
| +
|
| + protected:
|
| + web::TestWebThreadBundle thread_bundle_;
|
| + std::unique_ptr<TestChromeBrowserState> browser_state_;
|
| + base::scoped_nsobject<MockHistoryServiceFacadeDelegate> mock_delegate_;
|
| + std::unique_ptr<HistoryServiceFacade> history_service_facade_;
|
| + GURL visited_url_;
|
| + base::Time visited_time_;
|
| + DISALLOW_COPY_AND_ASSIGN(HistoryServiceFacadeTest);
|
| +};
|
| +
|
| +// Tests that invoking QueryHistory results in the delegate receiving an added
|
| +// history entry.
|
| +TEST_F(HistoryServiceFacadeTest, TestQueryHistory) {
|
| + GURL url("http://www.testurl.com");
|
| + AddVisit(url, 0);
|
| +
|
| + base::string16 query = base::string16();
|
| + history::QueryOptions options;
|
| + history_service_facade_->QueryHistory(query, options);
|
| +
|
| + TestResult expected_result = {url, 0};
|
| + EXPECT_TRUE(
|
| + WaitUntilLoop(base::Bind(&HistoryServiceFacadeTest::VerifyQueryResult,
|
| + base::Unretained(this), expected_result)));
|
| +}
|
| +
|
| +// Tests that invoking RemoveHistoryEntries completes with callback to delegate
|
| +// method historyServiceFacadeDidCompleteEntryRemoval.
|
| +TEST_F(HistoryServiceFacadeTest, TestRemoveHistoryEntries) {
|
| + GURL url("http://www.testurl.com");
|
| + AddVisit(url, 0);
|
| +
|
| + std::vector<HistoryServiceFacade::RemovedEntry> entries_to_remove{
|
| + EntryForRemoval(url, 0)};
|
| + history_service_facade_->RemoveHistoryEntries(entries_to_remove);
|
| + EXPECT_TRUE(WaitUntilLoop(base::Bind(
|
| + &HistoryServiceFacadeTest::VerifyEntryRemoval, base::Unretained(this))));
|
| +}
|
| +
|
| +// Tests that invoking QueryOtherFormsOfBrowsingHistory completes with callback
|
| +// to delegate method
|
| +// historyServiceFacade:shouldShowNoticeAboutOtherFormsOfBrowsingHistory:.
|
| +TEST_F(HistoryServiceFacadeTest, TestQueryOtherFormsOfBrowsingHistory) {
|
| + history_service_facade_->QueryOtherFormsOfBrowsingHistory();
|
| + EXPECT_TRUE(WaitUntilLoop(
|
| + base::Bind(&HistoryServiceFacadeTest::VerifyOtherHistoryCallback,
|
| + base::Unretained(this))));
|
| +}
|
|
|