普通文本  |  411行  |  14.76 KB

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

#include "chrome/browser/notifications/welcome_notification.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chrome/test/base/testing_profile.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "sync/api/sync_error_factory_mock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/fake_message_center.h"
#include "ui/message_center/notification.h"

const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";

class MockMessageCenter : public message_center::FakeMessageCenter {
 public:
  MockMessageCenter()
    : add_notification_calls_(0),
      remove_notification_calls_(0),
      notifications_with_shown_as_popup_(0) {};

  int add_notification_calls() { return add_notification_calls_; }
  int remove_notification_calls() { return remove_notification_calls_; }
  int notifications_with_shown_as_popup() {
    return notifications_with_shown_as_popup_;
  }

  // message_center::FakeMessageCenter Overrides
  virtual bool HasNotification(const std::string& id) OVERRIDE {
    return last_notification.get() &&
        (last_notification->id() == id);
  }

  virtual void AddNotification(
      scoped_ptr<message_center::Notification> notification) OVERRIDE {
    EXPECT_FALSE(last_notification.get());
    last_notification.swap(notification);
    add_notification_calls_++;
    if (last_notification->shown_as_popup())
      notifications_with_shown_as_popup_++;
  }

  virtual void RemoveNotification(const std::string& id, bool by_user)
      OVERRIDE {
    EXPECT_TRUE(last_notification.get());
    last_notification.reset();
    remove_notification_calls_++;
  }

  void CloseCurrentNotification() {
    EXPECT_TRUE(last_notification.get());
    last_notification->delegate()->Close(true);
    RemoveNotification(last_notification->id(), true);
  }

 private:
  scoped_ptr<message_center::Notification> last_notification;
  int add_notification_calls_;
  int remove_notification_calls_;
  int notifications_with_shown_as_popup_;
};

class TestSyncProcessor : public syncer::SyncChangeProcessor {
  virtual syncer::SyncError ProcessSyncChanges(
      const tracked_objects::Location& from_here,
      const syncer::SyncChangeList& change_list) OVERRIDE {
    return syncer::SyncError();
  }

  virtual syncer::SyncDataList GetAllSyncData(
      syncer::ModelType type) const OVERRIDE {
    return syncer::SyncDataList();
  }
};

class WelcomeNotificationTest : public testing::Test {
 protected:
  WelcomeNotificationTest() {
    scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry(
        new user_prefs::PrefRegistrySyncable());
    WelcomeNotification::RegisterProfilePrefs(pref_registry.get());
  }

  virtual void SetUp() {
    message_loop_.reset(new base::MessageLoop());
    profile_.reset(new TestingProfile());
    message_center_.reset(new MockMessageCenter());
    welcome_notification_.reset(
        new WelcomeNotification(profile_.get(), message_center_.get()));
  }

  virtual void TearDown() {
    welcome_notification_.reset();
    message_center_.reset();
    profile_.reset();
    message_loop_.reset();
  }

  void StartPreferenceSyncing() {
    PrefServiceSyncable::FromProfile(profile())->GetSyncableService(
        syncer::PREFERENCES)->MergeDataAndStartSyncing(
            syncer::PREFERENCES,
            syncer::SyncDataList(),
            scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessor),
            scoped_ptr<syncer::SyncErrorFactory>(
                new syncer::SyncErrorFactoryMock()));
  }

  void ShowChromeNowNotification() {
    ShowNotification(
        "ChromeNowNotification",
        message_center::NotifierId(
            message_center::NotifierId::APPLICATION,
            kChromeNowExtensionID));
  }

  void ShowRegularNotification() {
    ShowNotification(
        "RegularNotification",
        message_center::NotifierId(
            message_center::NotifierId::APPLICATION,
            "aaaabbbbccccddddeeeeffffggghhhhi"));
  }

  void FlushMessageLoop() {
    message_loop_->RunUntilIdle();
  }

  TestingProfile* profile() { return profile_.get(); }
  MockMessageCenter* message_center() { return message_center_.get(); }

 private:
  class TestNotificationDelegate : public NotificationDelegate {
   public:
    explicit TestNotificationDelegate(const std::string& id)
        : id_(id) {}

    // Overridden from NotificationDelegate:
    virtual void Display() OVERRIDE {}
    virtual void Error() OVERRIDE {}
    virtual void Close(bool by_user) OVERRIDE {}
    virtual void Click() OVERRIDE {}
    virtual void ButtonClick(int index) OVERRIDE {}

    virtual std::string id() const OVERRIDE { return id_; }

    virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
      return NULL;
    }

   private:
    virtual ~TestNotificationDelegate() {}

    const std::string id_;

    DISALLOW_COPY_AND_ASSIGN(TestNotificationDelegate);
  };

  void ShowNotification(
      std::string notification_id,
      const message_center::NotifierId& notifier_id) {
    message_center::RichNotificationData rich_notification_data;
    rich_notification_data.priority = 0;
    Notification notification(
        message_center::NOTIFICATION_TYPE_BASE_FORMAT,
        GURL("http://tests.url"),
        base::UTF8ToUTF16("Title"),
        base::UTF8ToUTF16("Body"),
        gfx::Image(),
        blink::WebTextDirectionDefault,
        notifier_id,
        base::UTF8ToUTF16("Source"),
        base::UTF8ToUTF16(notification_id),
        rich_notification_data,
        new TestNotificationDelegate("TestNotification"));
    welcome_notification_->ShowWelcomeNotificationIfNecessary(notification);
  }

  scoped_ptr<TestingProfile> profile_;
  scoped_ptr<MockMessageCenter> message_center_;
  scoped_ptr<WelcomeNotification> welcome_notification_;
  scoped_ptr<base::MessageLoop> message_loop_;
};

// Show a regular notification. Expect that WelcomeNotification will
// not show a welcome notification.
TEST_F(WelcomeNotificationTest, FirstRunShowRegularNotification) {
  StartPreferenceSyncing();
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowRegularNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 0);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Show a Chrome Now notification. Expect that WelcomeNotification will
// show a welcome notification.
TEST_F(WelcomeNotificationTest, FirstRunChromeNowNotification) {
  StartPreferenceSyncing();
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Show a Chrome Now notification that was already shown before.
TEST_F(WelcomeNotificationTest, ShowWelcomeNotificationAgain) {
  StartPreferenceSyncing();
  profile()->GetPrefs()->SetBoolean(
      prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 1);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Don't show a welcome notification if it was previously dismissed
TEST_F(WelcomeNotificationTest, WelcomeNotificationPreviouslyDismissed) {
  StartPreferenceSyncing();
  profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 0);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Show a Chrome Now notification and dismiss it.
// Expect welcome toast dismissed to be true.
TEST_F(WelcomeNotificationTest, DismissWelcomeNotification) {
  StartPreferenceSyncing();
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();
  message_center()->CloseCurrentNotification();
  FlushMessageLoop();

  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Show a Chrome Now notification and dismiss it via a synced preference change.
// Expect welcome toast dismissed to be true.
TEST_F(WelcomeNotificationTest, SyncedDismissalWelcomeNotification) {
  StartPreferenceSyncing();
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();
  profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);

  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Simulate a delayed preference sync when the welcome notification was
// previously dismissed.
TEST_F(WelcomeNotificationTest, DelayedPreferenceSyncPreviouslyDismissed) {
  // Show a notification while the preference system is not syncing.
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 0);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  // Now start the preference syncing with a previously dismissed welcome.
  profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  StartPreferenceSyncing();

  EXPECT_TRUE(message_center()->add_notification_calls() == 0);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}

// Simulate a delayed preference sync when the welcome notification was
// never shown.
TEST_F(WelcomeNotificationTest, DelayedPreferenceSyncNeverShown) {
  // Show a notification while the preference system is not syncing.
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  ShowChromeNowNotification();

  EXPECT_TRUE(message_center()->add_notification_calls() == 0);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  // Now start the preference syncing with the default preference values.
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));

  StartPreferenceSyncing();

  EXPECT_TRUE(message_center()->add_notification_calls() == 1);
  EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
  EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0);
  EXPECT_FALSE(
      profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
  EXPECT_TRUE(
      profile()->GetPrefs()->GetBoolean(
          prefs::kWelcomeNotificationPreviouslyPoppedUp));
}