blob: fbd1bb422ad8682fe46af7ab1a2cd2fce8dfc709 [file] [log] [blame]
// Copyright 2015 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 <stddef.h>
#include <stdint.h>
#include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/nullable_string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/notifications/notification_database_conversions.h"
#include "content/browser/notifications/notification_database_data.pb.h"
#include "content/browser/notifications/notification_database_resources.pb.h"
#include "content/public/browser/notification_database_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/notifications/notification_resources.h"
#include "third_party/blink/public/platform/modules/notifications/web_notification_constants.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace content {
namespace {
SkBitmap CreateBitmap(int width, int height, SkColor color) {
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height);
bitmap.eraseColor(color);
return bitmap;
}
} // namespace
const char kNotificationId[] = "my-notification";
const int64_t kServiceWorkerRegistrationId = 9001;
const bool kReplacedExistingNotification = true;
const int kNumClicks = 8;
const int kNumActionButtonClicks = 9;
const double kInitTimeMillis = 12345;
const int kTimeUntilFirstClickMillis = 11111;
const int kTimeUntilLastClickMillis = 22222;
const int kTimeUntilCloseMillis = 33333;
const blink::PlatformNotificationActionType kNotificationActionType =
blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
const char kOrigin[] = "https://example.com/";
const char kNotificationTitle[] = "My Notification";
const char kNotificationLang[] = "nl";
const char kNotificationBody[] = "Hello, world!";
const char kNotificationTag[] = "my_tag";
const char kNotificationImageUrl[] = "https://example.com/image.jpg";
const char kNotificationIconUrl[] = "https://example.com/icon.png";
const char kNotificationBadgeUrl[] = "https://example.com/badge.png";
const char kNotificationActionIconUrl[] = "https://example.com/action_icon.png";
const int kNotificationVibrationPattern[] = {100, 200, 300};
const double kNotificationTimestamp = 621046800.;
const unsigned char kNotificationData[] = {0xdf, 0xff, 0x0, 0x0, 0xff, 0xdf};
const double kShowTriggerTimestamp = 621086800.;
const bool kHasTriggered = true;
TEST(NotificationDatabaseConversionsTest, SerializeAndDeserializeData) {
std::vector<int> vibration_pattern(
kNotificationVibrationPattern,
kNotificationVibrationPattern +
base::size(kNotificationVibrationPattern));
std::vector<char> developer_data(
kNotificationData, kNotificationData + base::size(kNotificationData));
blink::PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16(kNotificationTitle);
notification_data.direction =
blink::mojom::NotificationDirection::RIGHT_TO_LEFT;
notification_data.lang = kNotificationLang;
notification_data.body = base::ASCIIToUTF16(kNotificationBody);
notification_data.tag = kNotificationTag;
notification_data.image = GURL(kNotificationImageUrl);
notification_data.icon = GURL(kNotificationIconUrl);
notification_data.badge = GURL(kNotificationBadgeUrl);
notification_data.vibration_pattern = vibration_pattern;
notification_data.timestamp = base::Time::FromJsTime(kNotificationTimestamp);
notification_data.renotify = true;
notification_data.silent = true;
notification_data.require_interaction = true;
notification_data.show_trigger_timestamp =
base::Time::FromJsTime(kShowTriggerTimestamp);
notification_data.data = developer_data;
for (size_t i = 0; i < blink::kWebNotificationMaxActions; i++) {
blink::PlatformNotificationAction notification_action;
notification_action.type = kNotificationActionType;
notification_action.action = base::NumberToString(i);
notification_action.title = base::NumberToString16(i);
notification_action.icon = GURL(kNotificationActionIconUrl);
notification_action.placeholder =
base::NullableString16(base::NumberToString16(i), false);
notification_data.actions.push_back(notification_action);
}
NotificationDatabaseData database_data;
database_data.notification_id = kNotificationId;
database_data.origin = GURL(kOrigin);
database_data.service_worker_registration_id = kServiceWorkerRegistrationId;
database_data.notification_data = notification_data;
database_data.replaced_existing_notification = kReplacedExistingNotification;
database_data.num_clicks = kNumClicks;
database_data.num_action_button_clicks = kNumActionButtonClicks;
database_data.creation_time_millis = base::Time::FromDoubleT(kInitTimeMillis);
database_data.time_until_first_click_millis =
base::TimeDelta::FromMilliseconds(kTimeUntilFirstClickMillis);
database_data.time_until_last_click_millis =
base::TimeDelta::FromMilliseconds(kTimeUntilLastClickMillis);
database_data.time_until_close_millis =
base::TimeDelta::FromMilliseconds(kTimeUntilCloseMillis);
database_data.closed_reason = NotificationDatabaseData::ClosedReason::USER;
database_data.has_triggered = kHasTriggered;
std::string serialized_data;
// Serialize the data in |notification_data| to the string |serialized_data|.
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
// Deserialize the data in |serialized_data| to |copied_data|.
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_EQ(database_data.notification_id, copied_data.notification_id);
EXPECT_EQ(database_data.origin, copied_data.origin);
EXPECT_EQ(database_data.service_worker_registration_id,
copied_data.service_worker_registration_id);
EXPECT_EQ(database_data.num_clicks, copied_data.num_clicks);
EXPECT_EQ(database_data.num_action_button_clicks,
copied_data.num_action_button_clicks);
EXPECT_EQ(database_data.replaced_existing_notification,
copied_data.replaced_existing_notification);
EXPECT_EQ(database_data.creation_time_millis,
copied_data.creation_time_millis);
EXPECT_EQ(database_data.time_until_first_click_millis,
copied_data.time_until_first_click_millis);
EXPECT_EQ(database_data.time_until_last_click_millis,
copied_data.time_until_last_click_millis);
EXPECT_EQ(database_data.time_until_close_millis,
copied_data.time_until_close_millis);
EXPECT_EQ(database_data.closed_reason, copied_data.closed_reason);
EXPECT_EQ(database_data.has_triggered, copied_data.has_triggered);
const blink::PlatformNotificationData& copied_notification_data =
copied_data.notification_data;
EXPECT_EQ(notification_data.title, copied_notification_data.title);
EXPECT_EQ(notification_data.direction, copied_notification_data.direction);
EXPECT_EQ(notification_data.lang, copied_notification_data.lang);
EXPECT_EQ(notification_data.body, copied_notification_data.body);
EXPECT_EQ(notification_data.tag, copied_notification_data.tag);
EXPECT_EQ(notification_data.image, copied_notification_data.image);
EXPECT_EQ(notification_data.icon, copied_notification_data.icon);
EXPECT_EQ(notification_data.badge, copied_notification_data.badge);
EXPECT_THAT(copied_notification_data.vibration_pattern,
testing::ElementsAreArray(kNotificationVibrationPattern));
EXPECT_EQ(notification_data.timestamp, copied_notification_data.timestamp);
EXPECT_EQ(notification_data.renotify, copied_notification_data.renotify);
EXPECT_EQ(notification_data.silent, copied_notification_data.silent);
EXPECT_EQ(notification_data.require_interaction,
copied_notification_data.require_interaction);
EXPECT_EQ(notification_data.show_trigger_timestamp,
copied_notification_data.show_trigger_timestamp);
ASSERT_EQ(developer_data.size(), copied_notification_data.data.size());
for (size_t i = 0; i < developer_data.size(); ++i)
EXPECT_EQ(developer_data[i], copied_notification_data.data[i]);
ASSERT_EQ(notification_data.actions.size(),
copied_notification_data.actions.size());
for (size_t i = 0; i < notification_data.actions.size(); ++i) {
EXPECT_EQ(notification_data.actions[i].type,
copied_notification_data.actions[i].type);
EXPECT_EQ(notification_data.actions[i].action,
copied_notification_data.actions[i].action);
EXPECT_EQ(notification_data.actions[i].title,
copied_notification_data.actions[i].title);
EXPECT_EQ(notification_data.actions[i].icon,
copied_notification_data.actions[i].icon);
EXPECT_EQ(notification_data.actions[i].placeholder,
copied_notification_data.actions[i].placeholder);
EXPECT_FALSE(copied_notification_data.actions[i].placeholder.is_null());
}
}
TEST(NotificationDatabaseConversionsTest, ActionDeserializationIsNotAdditive) {
NotificationDatabaseData database_data;
for (size_t i = 0; i < blink::kWebNotificationMaxActions; ++i)
database_data.notification_data.actions.emplace_back();
std::string serialized_data;
NotificationDatabaseData copied_database_data;
// Serialize the data in |notification_data| to the string |serialized_data|,
// and then deserialize it again immediately to |copied_database_data|.
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
ASSERT_TRUE(DeserializeNotificationDatabaseData(serialized_data,
&copied_database_data));
EXPECT_EQ(copied_database_data.notification_data.actions.size(),
blink::kWebNotificationMaxActions);
// Deserialize it again in the same |copied_database_data|. The number of
// actions in the structure should not be affected.
ASSERT_TRUE(DeserializeNotificationDatabaseData(serialized_data,
&copied_database_data));
EXPECT_EQ(copied_database_data.notification_data.actions.size(),
blink::kWebNotificationMaxActions);
}
TEST(NotificationDatabaseConversionsTest, SerializeAndDeserializeActionTypes) {
blink::PlatformNotificationActionType action_types[] = {
blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON,
blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT};
for (blink::PlatformNotificationActionType action_type : action_types) {
blink::PlatformNotificationData notification_data;
blink::PlatformNotificationAction action;
action.type = action_type;
notification_data.actions.push_back(action);
NotificationDatabaseData database_data;
database_data.notification_data = notification_data;
std::string serialized_data;
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_EQ(action_type, copied_data.notification_data.actions[0].type);
}
}
TEST(NotificationDatabaseConversionsTest, SerializeAndDeserializeDirections) {
blink::mojom::NotificationDirection directions[] = {
blink::mojom::NotificationDirection::LEFT_TO_RIGHT,
blink::mojom::NotificationDirection::RIGHT_TO_LEFT,
blink::mojom::NotificationDirection::AUTO};
for (size_t i = 0; i < base::size(directions); ++i) {
blink::PlatformNotificationData notification_data;
notification_data.direction = directions[i];
NotificationDatabaseData database_data;
database_data.notification_data = notification_data;
std::string serialized_data;
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_EQ(directions[i], copied_data.notification_data.direction);
}
}
TEST(NotificationDatabaseConversionsTest,
SerializeAndDeserializeClosedReasons) {
NotificationDatabaseData::ClosedReason closed_reasons[] = {
NotificationDatabaseData::ClosedReason::USER,
NotificationDatabaseData::ClosedReason::DEVELOPER,
NotificationDatabaseData::ClosedReason::UNKNOWN};
for (size_t i = 0; i < base::size(closed_reasons); ++i) {
NotificationDatabaseData database_data;
database_data.closed_reason = closed_reasons[i];
std::string serialized_data;
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_EQ(closed_reasons[i], copied_data.closed_reason);
}
}
TEST(NotificationDatabaseConversionsTest,
SerializeAndDeserializeNullPlaceholder) {
blink::PlatformNotificationAction action;
action.type = kNotificationActionType;
action.placeholder = base::NullableString16(); // null string.
blink::PlatformNotificationData notification_data;
notification_data.actions.push_back(action);
NotificationDatabaseData database_data;
database_data.notification_data = notification_data;
std::string serialized_data;
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_TRUE(copied_data.notification_data.actions[0].placeholder.is_null());
}
TEST(NotificationDatabaseConversionsTest,
SerializeAndDeserializeNullShowTriggerTimestamp) {
blink::PlatformNotificationData notification_data;
// explicitly empty timestamp
notification_data.show_trigger_timestamp = base::nullopt;
NotificationDatabaseData database_data;
database_data.notification_data = notification_data;
std::string serialized_data;
ASSERT_TRUE(
SerializeNotificationDatabaseData(database_data, &serialized_data));
NotificationDatabaseData copied_data;
ASSERT_TRUE(
DeserializeNotificationDatabaseData(serialized_data, &copied_data));
EXPECT_FALSE(
copied_data.notification_data.show_trigger_timestamp.has_value());
}
TEST(NotificationDatabaseConversionsTest, OptionalFieldsGetCleared) {
NotificationDatabaseData data_without_fields;
NotificationDatabaseData data_with_fields;
data_with_fields.time_until_close_millis = base::TimeDelta::FromSeconds(1);
data_with_fields.time_until_first_click_millis =
base::TimeDelta::FromSeconds(2);
data_with_fields.time_until_last_click_millis =
base::TimeDelta::FromSeconds(3);
data_with_fields.notification_resources = blink::NotificationResources();
std::string serialized_data;
NotificationDatabaseData copied_database_data;
// Serialize the |data_with_fields| to the string |serialized_data|,
// and then deserialize it again immediately to |copied_database_data|.
ASSERT_TRUE(
SerializeNotificationDatabaseData(data_with_fields, &serialized_data));
ASSERT_TRUE(DeserializeNotificationDatabaseData(serialized_data,
&copied_database_data));
EXPECT_EQ(base::TimeDelta::FromSeconds(1),
copied_database_data.time_until_close_millis);
EXPECT_EQ(base::TimeDelta::FromSeconds(2),
copied_database_data.time_until_first_click_millis);
EXPECT_EQ(base::TimeDelta::FromSeconds(3),
copied_database_data.time_until_last_click_millis);
EXPECT_FALSE(copied_database_data.notification_resources.has_value());
// Deserialize the |data_without_fields| in the same |copied_database_data|.
// The optional fields should now be gone.
ASSERT_TRUE(
SerializeNotificationDatabaseData(data_without_fields, &serialized_data));
ASSERT_TRUE(DeserializeNotificationDatabaseData(serialized_data,
&copied_database_data));
EXPECT_FALSE(copied_database_data.time_until_close_millis.has_value());
EXPECT_FALSE(copied_database_data.time_until_first_click_millis.has_value());
EXPECT_FALSE(copied_database_data.time_until_last_click_millis.has_value());
EXPECT_FALSE(copied_database_data.notification_resources.has_value());
}
TEST(NotificationDatabaseConversionsTest,
SerializeAndDeserializeNotificationResources) {
blink::NotificationResources notification_resources;
notification_resources.notification_icon = CreateBitmap(10, 10, SK_ColorBLUE);
notification_resources.image = CreateBitmap(20, 20, SK_ColorGREEN);
notification_resources.badge = CreateBitmap(30, 30, SK_ColorRED);
notification_resources.action_icons.push_back(
CreateBitmap(40, 40, SK_ColorYELLOW));
notification_resources.action_icons.push_back(
CreateBitmap(41, 41, SK_ColorCYAN));
notification_resources.action_icons.push_back(
CreateBitmap(42, 42, SK_ColorMAGENTA));
std::string serialized_resources;
ASSERT_TRUE(SerializeNotificationDatabaseResources(notification_resources,
&serialized_resources));
blink::NotificationResources copied_resources;
ASSERT_TRUE(DeserializeNotificationDatabaseResources(serialized_resources,
&copied_resources));
EXPECT_EQ(10, copied_resources.notification_icon.width());
EXPECT_EQ(20, copied_resources.image.width());
EXPECT_EQ(30, copied_resources.badge.width());
EXPECT_EQ(3u, copied_resources.action_icons.size());
EXPECT_EQ(40, copied_resources.action_icons[0].width());
EXPECT_EQ(41, copied_resources.action_icons[1].width());
EXPECT_EQ(42, copied_resources.action_icons[2].width());
}
} // namespace content