chromium/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h"

#import <memory>

#import "base/strings/sys_string_conversions.h"
#import "base/task/sequenced_task_runner.h"
#import "base/task/single_thread_task_runner.h"
#import "base/test/simple_test_clock.h"
#import "components/favicon/core/large_icon_service_impl.h"
#import "components/favicon/core/test/mock_favicon_service.h"
#import "components/favicon_base/favicon_types.h"
#import "components/reading_list/core/fake_reading_list_model_storage.h"
#import "components/reading_list/core/reading_list_model_impl.h"
#import "components/sync/base/storage_type.h"
#import "components/sync/model/wipe_model_upon_sync_disabled_behavior.h"
#import "components/sync/test/test_sync_service.h"
#import "components/url_formatter/url_formatter.h"
#import "ios/chrome/browser/favicon/model/favicon_loader.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_accessibility_delegate.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_custom_action_factory.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_table_view_item.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gmock/include/gmock/gmock.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"

using testing::_;

namespace reading_list {

// ReadingListMediatorTest is parameterized on this enum to test both
// FaviconAttributesProvider and FaviconLoader.
// TODO(crbug.com/41410664): Remove as part of UIRefresh cleanup.
enum class FaviconServiceType {
  FAVICON_LOADER,
  ATTRIBUTES_PROVIDER,
};

class ReadingListMediatorTest
    : public PlatformTest,
      public ::testing::WithParamInterface<FaviconServiceType> {
 public:
  ReadingListMediatorTest() {
    auto storage = std::make_unique<FakeReadingListModelStorage>();
    base::WeakPtr<FakeReadingListModelStorage> storage_ptr =
        storage->AsWeakPtr();
    model_ = std::make_unique<ReadingListModelImpl>(
        std::move(storage), syncer::StorageType::kUnspecified,
        syncer::WipeModelUponSyncDisabledBehavior::kNever, &clock_);
    // Complete the initial model load from storage.
    storage_ptr->TriggerLoadCompletion();
    sync_service_ = std::make_unique<syncer::TestSyncService>();

    EXPECT_CALL(mock_favicon_service_,
                GetLargestRawFaviconForPageURL(_, _, _, _, _))
        .WillRepeatedly([](auto, auto, auto,
                           favicon_base::FaviconRawBitmapCallback callback,
                           base::CancelableTaskTracker* tracker) {
          return tracker->PostTask(
              base::SingleThreadTaskRunner::GetCurrentDefault().get(),
              FROM_HERE,
              base::BindOnce(std::move(callback),
                             favicon_base::FaviconRawBitmapResult()));
        });

    no_title_entry_url_ = GURL("http://chromium.org/unread3");
    // The first 3 have the same update time on purpose.
    model_->AddOrReplaceEntry(GURL("http://chromium.org/unread1"), "unread1",
                              reading_list::ADDED_VIA_CURRENT_APP,
                              /*estimated_read_time=*/base::TimeDelta());
    model_->AddOrReplaceEntry(GURL("http://chromium.org/read1"), "read1",
                              reading_list::ADDED_VIA_CURRENT_APP,
                              /*estimated_read_time=*/base::TimeDelta());
    model_->SetReadStatusIfExists(GURL("http://chromium.org/read1"), true);
    model_->AddOrReplaceEntry(GURL("http://chromium.org/unread2"), "unread2",
                              reading_list::ADDED_VIA_CURRENT_APP,
                              /*estimated_read_time=*/base::TimeDelta());
    clock_.Advance(base::Milliseconds(10));
    model_->AddOrReplaceEntry(no_title_entry_url_, "",
                              reading_list::ADDED_VIA_CURRENT_APP,
                              /*estimated_read_time=*/base::TimeDelta());
    clock_.Advance(base::Milliseconds(10));
    model_->AddOrReplaceEntry(GURL("http://chromium.org/read2"), "read2",
                              reading_list::ADDED_VIA_CURRENT_APP,
                              /*estimated_read_time=*/base::TimeDelta());
    model_->SetReadStatusIfExists(GURL("http://chromium.org/read2"), true);
    large_icon_service_.reset(new favicon::LargeIconServiceImpl(
        &mock_favicon_service_, /*image_fetcher=*/nullptr,
        /*desired_size_in_dip_for_server_requests=*/24,
        /*icon_type_for_server_requests=*/
        favicon_base::IconType::kTouchIcon,
        /*google_server_client_param=*/"test_chrome"));

    favicon_loader.reset(new FaviconLoader(large_icon_service_.get()));
    mediator_ = [[ReadingListMediator alloc]
          initWithModel:model_.get()
            syncService:sync_service_.get()
          faviconLoader:favicon_loader.get()
        listItemFactory:[[ReadingListListItemFactory alloc] init]];
  }

  ~ReadingListMediatorTest() { [mediator_ disconnect]; }

  ReadingListMediatorTest(const ReadingListMediatorTest&) = delete;
  ReadingListMediatorTest& operator=(const ReadingListMediatorTest&) = delete;

 protected:
  testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
  std::unique_ptr<ReadingListModelImpl> model_;
  std::unique_ptr<syncer::TestSyncService> sync_service_;
  ReadingListMediator* mediator_;
  base::SimpleTestClock clock_;
  GURL no_title_entry_url_;
  std::unique_ptr<FaviconLoader> favicon_loader;
  std::unique_ptr<favicon::LargeIconServiceImpl> large_icon_service_;

 private:
  web::WebTaskEnvironment task_environment_;
};

TEST_P(ReadingListMediatorTest, fillItems) {
  // Setup.
  NSMutableArray<id<ReadingListListItem>>* readArray = [NSMutableArray array];
  NSMutableArray<id<ReadingListListItem>>* unreadArray = [NSMutableArray array];

  // Action.
  [mediator_ fillReadItems:readArray unreadItems:unreadArray];

  // Tests.
  EXPECT_EQ(3U, [unreadArray count]);
  EXPECT_EQ(2U, [readArray count]);
  NSArray<ReadingListTableViewItem*>* rlReadArray = [readArray copy];
  NSArray<ReadingListTableViewItem*>* rlUneadArray = [unreadArray copy];
  EXPECT_TRUE([rlUneadArray[0].title isEqualToString:@""]);
  EXPECT_TRUE([rlReadArray[0].title isEqualToString:@"read2"]);
  EXPECT_TRUE([rlReadArray[1].title isEqualToString:@"read1"]);
}

INSTANTIATE_TEST_SUITE_P(
    ,  // Empty instatiation name.
    ReadingListMediatorTest,
    ::testing::Values(FaviconServiceType::FAVICON_LOADER,
                      FaviconServiceType::ATTRIBUTES_PROVIDER));

}  // namespace reading_list