// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/time/calendar_model.h"
#include <cstddef>
#include <iterator>
#include <list>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "ash/calendar/calendar_client.h"
#include "ash/calendar/calendar_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/session/session_controller.h"
#include "ash/public/cpp/session/session_types.h"
#include "ash/public/cpp/session/user_info.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/time/calendar_list_model.h"
#include "ash/system/time/calendar_unittest_utils.h"
#include "ash/system/time/calendar_utils.h"
#include "ash/test/ash_test_base.h"
#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chromeos/ash/components/settings/scoped_timezone_settings.h"
#include "components/user_manager/user_type.h"
#include "google_apis/calendar/calendar_api_response_types.h"
#include "google_apis/common/api_error_codes.h"
namespace ash {
namespace {
using ::google_apis::calendar::CalendarEvent;
using ::google_apis::calendar::EventList;
using ::google_apis::calendar::SingleCalendar;
const char* kStartTime0 = "23 Oct 2009 11:30 GMT";
const char* kEndTime0 = "23 Oct 2009 12:30 GMT";
const char* kId0 = "id_0";
const char* kSummary0 = "summary_0";
const char* kStartTime1 = "19 Oct 2009 07:30 GMT";
const char* kEndTime1 = "19 Oct 2009 08:30 GMT";
const char* kId1 = "id_1";
const char* kSummary1 = "summary_1";
const char* kStartTime2 = "15 Oct 2009 11:30 GMT";
const char* kEndTime2 = "15 Oct 2009 12:30 GMT";
const char* kId2 = "id_2";
const char* kSummary2 = "summary_2";
const char* kStartTime3 = "14 Oct 2009 11:30 GMT";
const char* kEndTime3 = "14 Oct 2009 12:30 GMT";
const char* kId3 = "id_3";
const char* kSummary3 = "summary_3";
const char* kStartTime4 = "23 Feb 2010 11:30 GMT";
const char* kEndTime4 = "23 Feb 2010 12:30 GMT";
const char* kId4 = "id_4";
const char* kSummary4 = "summary_4";
const char* kStartTime5 = "23 Mar 2010 11:30 GMT";
const char* kEndTime5 = "23 Mar 2010 12:30 GMT";
const char* kId5 = "id_5";
const char* kSummary5 = "summary_5";
const char* kStartTime12 = "24 Oct 2009 07:10 GMT";
const char* kEndTime12 = "24 Oct 2009 08:00 GMT";
const char* kId12 = "id_12";
const char* kSummary12 = "summary_12";
const char* kStartTime13 = "24 Oct 2009 07:30 GMT";
const char* kEndTime13 = "25 Oct 2009 08:30 GMT";
const char* kId13 = "id_13";
const char* kSummary13 = "summary_13";
const char* kBaseStartTime = "01 Oct 2009 00:00 GMT";
const char* kCalendarId1 = "[email protected]";
const char* kCalendarSummary1 = "[email protected]";
const char* kCalendarColorId1 = "12";
bool kCalendarSelected1 = true;
bool kCalendarPrimary1 = true;
} // namespace
class CalendarModelUtilsTest : public AshTestBase {
public:
CalendarModelUtilsTest() = default;
CalendarModelUtilsTest(const CalendarModelUtilsTest& other) = delete;
CalendarModelUtilsTest& operator=(const CalendarModelUtilsTest& other) =
delete;
~CalendarModelUtilsTest() override = default;
static void SetFakeNow(base::Time fake_now) { fake_time_ = fake_now; }
static base::Time FakeTimeNow() { return fake_time_; }
static base::Time fake_time_;
};
base::Time CalendarModelUtilsTest::fake_time_;
TEST_F(CalendarModelUtilsTest, SurroundingMonths) {
std::set<base::Time> months;
// Set current date.
base::Time current_date, start_of_month;
current_date =
calendar_test_utils::GetTimeFromString("23 Oct 2009 11:30 GMT");
start_of_month =
calendar_test_utils::GetTimeFromString("01 Oct 2009 00:00 GMT");
CalendarModelUtilsTest::SetFakeNow(current_date);
base::subtle::ScopedTimeClockOverrides time_override(
&CalendarModelUtilsTest::FakeTimeNow,
/*time_ticks_override=*/nullptr,
/*thread_ticks_override=*/nullptr);
// 0 months out.
months = calendar_utils::GetSurroundingMonthsUTC(current_date, 0);
EXPECT_EQ(1UL, months.size());
EXPECT_TRUE(base::Contains(months, start_of_month));
// 1 month out.
base::Time start_of_previous_month =
calendar_test_utils::GetTimeFromString("01 Sep 2009 00:00 GMT");
base::Time start_of_next_month =
calendar_test_utils::GetTimeFromString("01 Nov 2009 00:00 GMT");
months = calendar_utils::GetSurroundingMonthsUTC(current_date, 1);
EXPECT_EQ(3UL, months.size());
EXPECT_TRUE(base::Contains(months, start_of_month));
EXPECT_TRUE(base::Contains(months, start_of_previous_month));
EXPECT_TRUE(base::Contains(months, start_of_next_month));
// 2 months out.
base::Time start_of_previous_month_2 =
calendar_test_utils::GetTimeFromString("01 Aug 2009 00:00 GMT");
base::Time start_of_next_month_2 =
calendar_test_utils::GetTimeFromString("01 Dec 2009 00:00 GMT");
months = calendar_utils::GetSurroundingMonthsUTC(current_date, 2);
EXPECT_EQ(5UL, months.size());
EXPECT_TRUE(base::Contains(months, start_of_month));
EXPECT_TRUE(base::Contains(months, start_of_previous_month));
EXPECT_TRUE(base::Contains(months, start_of_next_month));
EXPECT_TRUE(base::Contains(months, start_of_previous_month_2));
EXPECT_TRUE(base::Contains(months, start_of_next_month_2));
// 3 months out, which takes us into the next year.
base::Time start_of_previous_month_3 =
calendar_test_utils::GetTimeFromString("01 Jul 2009 00:00 GMT");
base::Time start_of_next_month_3 =
calendar_test_utils::GetTimeFromString("01 Jan 2010 00:00 GMT");
months = calendar_utils::GetSurroundingMonthsUTC(current_date, 3);
EXPECT_EQ(7UL, months.size());
EXPECT_TRUE(base::Contains(months, start_of_month));
EXPECT_TRUE(base::Contains(months, start_of_previous_month));
EXPECT_TRUE(base::Contains(months, start_of_next_month));
EXPECT_TRUE(base::Contains(months, start_of_previous_month_2));
EXPECT_TRUE(base::Contains(months, start_of_next_month_2));
EXPECT_TRUE(base::Contains(months, start_of_previous_month_3));
EXPECT_TRUE(base::Contains(months, start_of_next_month_3));
}
class CalendarModelTest
: public AshTestBase,
public testing::WithParamInterface</*multi_calendar_enabled=*/bool> {
public:
CalendarModelTest()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
scoped_feature_list_.InitWithFeatureState(
ash::features::kMultiCalendarSupport, IsMultiCalendarEnabled());
}
CalendarModelTest(const CalendarModelTest& other) = delete;
CalendarModelTest& operator=(const CalendarModelTest& other) = delete;
~CalendarModelTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
// Register a mock `CalendarClient` to the `CalendarController`.
const std::string email = "[email protected]";
AccountId account_id = AccountId::FromUserEmail(email);
Shell::Get()->calendar_controller()->SetActiveUserAccountIdForTesting(
account_id);
calendar_model_ = std::make_unique<CalendarModel>();
calendar_client_ =
std::make_unique<calendar_test_utils::CalendarClientTestImpl>();
Shell::Get()->calendar_controller()->RegisterClientForUser(
account_id, calendar_client_.get());
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
ash::prefs::kCalendarIntegrationEnabled, true);
if (IsMultiCalendarEnabled()) {
FetchCalendars();
}
}
void TearDown() override {
time_overrides_.reset();
calendar_model_.reset();
scoped_feature_list_.Reset();
AshTestBase::TearDown();
}
bool IsMultiCalendarEnabled() { return GetParam(); }
void FetchCalendars() {
// Set a mock calendar list.
std::list<std::unique_ptr<google_apis::calendar::SingleCalendar>> calendars;
calendars.push_back(calendar_test_utils::CreateCalendar(
kCalendarId1, kCalendarSummary1, kCalendarColorId1, kCalendarSelected1,
kCalendarPrimary1));
calendar_client_->SetCalendarList(
calendar_test_utils::CreateMockCalendarList(std::move(calendars)));
// Start the calendar list fetch and fast forward until it is complete.
calendar_list_model()->FetchCalendars();
WaitUntilFetched();
}
int EventsNumberOfDay(const char* day, SingleDayEventList* events) {
base::Time day_base = calendar_test_utils::GetTimeFromString(day);
if (events) {
events->clear();
}
return calendar_model_->EventsNumberOfDay(day_base, events);
}
int EventsNumberOfDay(base::Time day, SingleDayEventList* events) {
if (events) {
events->clear();
}
return calendar_model_->EventsNumberOfDay(day, events);
}
int EventsNumberOfDayInternal(const char* day,
SingleDayEventList* events) const {
base::Time day_base = calendar_test_utils::GetTimeFromString(day);
if (events) {
events->clear();
}
return calendar_model_->EventsNumberOfDay(day_base, events);
}
base::Time GetStartTimeMidnightAdjusted(
const google_apis::calendar::CalendarEvent* event) {
return calendar_utils::GetStartTimeMidnightAdjusted(event);
}
bool EventsPresentAtIndex(std::vector<base::Time>& months, int index) {
DCHECK_GE(index, 0);
DCHECK_LT(index, static_cast<int>(months.size()));
return base::Contains(calendar_model_->event_months_, months[index]);
}
bool EventsPresentInRange(std::vector<base::Time>& months,
int start_index,
int end_index) {
DCHECK_GE(start_index, 0);
DCHECK_GE(end_index, start_index);
for (int i = start_index; i < end_index; ++i) {
if (!EventsPresentAtIndex(months, i)) {
return false;
}
}
return true;
}
bool NoEventsPresentInRange(std::vector<base::Time>& months,
int start_index,
int end_index) {
DCHECK_GE(start_index, 0);
DCHECK_GE(end_index, start_index);
for (int i = start_index; i < end_index; ++i) {
const base::Time& start_of_month =
calendar_utils::GetFirstDayOfMonth(months[i]).UTCMidnight();
if (base::Contains(non_prunable_months(), start_of_month)) {
continue;
}
if (EventsPresentAtIndex(months, i)) {
return false;
}
}
return true;
}
void UpdateSession(uint32_t session_id,
const std::string& email,
bool is_child = false) {
UserSession session;
session.session_id = session_id;
session.user_info.type = is_child ? user_manager::UserType::kChild
: user_manager::UserType::kRegular;
session.user_info.account_id = AccountId::FromUserEmail(email);
session.user_info.display_name = email;
session.user_info.display_email = email;
session.user_info.is_new_profile = false;
SessionController::Get()->UpdateUserSession(session);
}
void TestMultiDayEvent(SingleDayEventList events,
const char* start_date_str,
const char* end_date_str) {
base::Time start_time_midnight =
calendar_test_utils::GetTimeFromString(start_date_str).UTCMidnight();
base::Time end_time_midnight =
calendar_test_utils::GetTimeFromString(end_date_str).UTCMidnight();
// Each day inside the event's time range should have an event.
while (start_time_midnight <= end_time_midnight) {
EXPECT_EQ(1, EventsNumberOfDay(start_time_midnight, &events));
// Add more than 24 hours to consider daylight savings.
start_time_midnight =
(start_time_midnight + base::Hours(30)).UTCMidnight();
}
}
// Wait until the response is back. Since we used `PostDelayedTask` with 1
// second to mimic the behavior of fetching, duration of 1 minute should be
// enough.
void WaitUntilFetched() {
task_environment()->FastForwardBy(base::Minutes(1));
base::RunLoop().RunUntilIdle();
}
// Set today's date to add non-prunable months in the model.
void SetTodayFromStr(const char* date_str) {
bool result = base::Time::FromString(date_str, &now_);
DCHECK(result);
SetTodayFromTime(now_);
}
void SetTodayFromTime(base::Time date) {
now_ = date;
std::set<base::Time> months = calendar_utils::GetSurroundingMonthsUTC(
now_, calendar_utils::kNumSurroundingMonthsCached);
calendar_model_->non_prunable_months_.clear();
// Non-prunable months are today's date and the two surrounding months.
calendar_model()->AddNonPrunableMonths(months);
}
void SetEventList(std::unique_ptr<google_apis::calendar::EventList> events) {
calendar_client_->SetEventList(std::move(events));
}
void SetError(google_apis::ApiErrorCode error) {
calendar_client_->SetError(error);
}
void MockOnEventsFetched(base::Time start_of_month,
google_apis::ApiErrorCode error,
const google_apis::calendar::EventList* events) {
calendar_model_->OnEventsFetched(start_of_month,
google_apis::calendar::kPrimaryCalendarId,
error, events);
}
base::Time now() { return now_; }
std::set<base::Time> non_prunable_months() {
return calendar_model_->non_prunable_months_;
}
CalendarModel::MonthToEventsMap& event_months() {
return calendar_model_->event_months_;
}
CalendarListModel* calendar_list_model() {
return Shell::Get()->system_tray_model()->calendar_list_model();
}
CalendarModel* calendar_model() { return calendar_model_.get(); }
std::unique_ptr<base::subtle::ScopedTimeClockOverrides> time_overrides_;
std::unique_ptr<CalendarModel> calendar_model_;
std::unique_ptr<calendar_test_utils::CalendarClientTestImpl> calendar_client_;
base::Time now_;
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(MultiCalendar, CalendarModelTest, testing::Bool());
TEST_P(CalendarModelTest, FetchingSuccessfullyWithOneEvent) {
// All events will be distributed by the system timezone. If no timezone is
// set, the test will run with the local default timezone which might cause a
// test failure. So here sets the timezone to "GMT", and the same for all the
// tests in this file.
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Set current date to `kStartTime0`.
SetTodayFromStr(kStartTime0);
base::Time start_of_month = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime0));
std::unique_ptr<google_apis::calendar::CalendarEvent> event =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
// Set up list of events as the mock response.
auto event_list = std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event));
// Haven't fetched anything yet, so no events on `kStartTime0`.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month));
// Set this event list as the response;
SetEventList(std::move(event_list));
// Now fetch the events, the status changes to `kFetching` before the events
// are fetched.
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_EQ(CalendarModel::kFetching,
calendar_model()->FindFetchingStatus(start_of_month));
WaitUntilFetched();
// Now we have an event on kStartTime0.
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
EXPECT_FALSE(events.empty());
EXPECT_TRUE(events.size() == 1);
// Set an empty event list as the mock response.
auto event_list2 = std::make_unique<google_apis::calendar::EventList>();
// Set the event list as the response;
SetEventList(std::move(event_list2));
// Now we do a refetch.
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_EQ(CalendarModel::kRefetching,
calendar_model()->FindFetchingStatus(start_of_month));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
WaitUntilFetched();
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month));
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
std::unique_ptr<google_apis::calendar::CalendarEvent> event2 =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
// Set up list of events as the mock response.
auto event_list3 = std::make_unique<google_apis::calendar::EventList>();
event_list3->InjectItemForTesting(std::move(event2));
// Set the event list as the response;
SetEventList(std::move(event_list3));
// Now we do a refetch.
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_EQ(CalendarModel::kRefetching,
calendar_model()->FindFetchingStatus(start_of_month));
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
WaitUntilFetched();
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
}
TEST_P(CalendarModelTest, FetchingSuccessfullyWithMultiEvents) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Set current date to `kStartTime0`.
SetTodayFromStr(kStartTime0);
// Set up list of events from the same month as the mock response.
std::unique_ptr<google_apis::calendar::CalendarEvent> event0 =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
std::unique_ptr<google_apis::calendar::CalendarEvent> event1 =
calendar_test_utils::CreateEvent(kId1, kSummary1, kStartTime1, kEndTime1);
std::unique_ptr<google_apis::calendar::CalendarEvent> event2 =
calendar_test_utils::CreateEvent(kId2, kSummary2, kStartTime2, kEndTime2);
std::unique_ptr<google_apis::calendar::CalendarEvent> event3 =
calendar_test_utils::CreateEvent(kId3, kSummary3, kStartTime3, kEndTime3);
std::unique_ptr<google_apis::calendar::CalendarEvent> event13 =
calendar_test_utils::CreateEvent(kId13, kSummary13, kStartTime13,
kEndTime13);
auto event_list = std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event0));
event_list->InjectItemForTesting(std::move(event1));
event_list->InjectItemForTesting(std::move(event2));
event_list->InjectItemForTesting(std::move(event3));
event_list->InjectItemForTesting(std::move(event13));
base::Time start_of_month0 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime0));
base::Time start_of_month1 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime1));
base::Time start_of_month2 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime2));
base::Time start_of_month3 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime3));
base::Time start_of_month13 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime13));
// Haven't fetch anything yet, so no events are fetched.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month0));
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month1));
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month2));
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month3));
EXPECT_EQ(CalendarModel::kNever,
calendar_model()->FindFetchingStatus(start_of_month13));
// Set this event list as the response;
SetEventList(std::move(event_list));
// Now fetch the events, the status changes to `kFetching` before the events
// are fetched. We put all events in one mock response list with one fetch. So
// here we only call `FetchEvents` one time.
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_EQ(CalendarModel::kFetching,
calendar_model()->FindFetchingStatus(start_of_month0));
WaitUntilFetched();
// Now we have an event on kStartTime0.
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month0));
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month1));
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month2));
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month3));
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month13));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime1, &events));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime2, &events));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime3, &events));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime13, &events));
// Set up an empty event list.
auto event_list2 = std::make_unique<google_apis::calendar::EventList>();
// Set this event list as the response;
SetEventList(std::move(event_list2));
// Now we do a refetch.
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_EQ(CalendarModel::kRefetching,
calendar_model()->FindFetchingStatus(start_of_month0));
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
WaitUntilFetched();
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(start_of_month0));
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
}
TEST_P(CalendarModelTest, ChangeTimeDifference) {
// Sets the timezone to "America/Los_Angeles".
ash::system::ScopedTimezoneSettings timezone_settings(u"America/Los_Angeles");
calendar_test_utils::ScopedLibcTimeZone scoped_libc_timezone(
"America/Los_Angeles");
ASSERT_TRUE(scoped_libc_timezone.is_success());
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Set today to`kStartTime0`.
SetTodayFromStr(kStartTime0);
// Creates 3 events:
// (1) kStartTime0 = "23 Oct 2009 11:30 GMT";
// kEndTime0 = "23 Oct 2009 12:30 GMT";
//
// (2) kStartTime12 = "24 Oct 2009 07:10 GMT";
// kEndTime12 = "24 Oct 2009 08:00 GMT";
//
// (3) kStartTime13 = "24 Oct 2009 07:30 GMT";
// kEndTime13 = "25 Oct 2009 08:30 GMT";
std::unique_ptr<google_apis::calendar::CalendarEvent> event0 =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
std::unique_ptr<google_apis::calendar::CalendarEvent> event12 =
calendar_test_utils::CreateEvent(kId12, kSummary12, kStartTime12,
kEndTime12);
std::unique_ptr<google_apis::calendar::CalendarEvent> event13 =
calendar_test_utils::CreateEvent(kId13, kSummary13, kStartTime13,
kEndTime13);
// Prepare mock events.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event0));
event_list->InjectItemForTesting(std::move(event12));
event_list->InjectItemForTesting(std::move(event13));
// Set this event list as the mock response;
SetEventList(std::move(event_list));
calendar_model()->FetchEvents(calendar_utils::GetStartOfMonthUTC(now()));
WaitUntilFetched();
// Based on the tesing timezone "America/Los_Angeles" (-7hrs) these 3 events
// are distributed into 3 days, since one of them is a multi day event. See
// details as below:
//
// (1) kStartTime0 = "23 Oct 2009 11:30 GMT";
// kEndTime0 = "23 Oct 2009 12:30 GMT";
// => event1 23 Oct 2009 4:30 ~5:30
//
// (2) kStartTime12 = "24 Oct 2009 07:10 GMT";
// kEndTime12 = "24 Oct 2009 08:00 GMT";
// => event2 24 Oct 2009 00:10 ~1:00
//
// (3) kStartTime13 = "24 Oct 2009 07:30 GMT";
// kEndTime13 = "25 Oct 2009 08:30 GMT";
// => event3 24 Oct 2009 00:30 ~23:59
// event4 25 Oct 2009 00:00 ~1:30
SingleDayEventList events;
EXPECT_EQ(1, EventsNumberOfDay("23 Oct 2009 00:00", &events));
EXPECT_EQ(2, EventsNumberOfDay("24 Oct 2009 00:00", &events));
EXPECT_EQ(1, EventsNumberOfDay("25 Oct 2009 00:00", &events));
EXPECT_EQ(0, EventsNumberOfDay("26 Oct 2009 00:00", &events));
// Sets the timezone to "Pacific/Honolulu" which has -10 hours time
// difference.
timezone_settings.SetTimezoneFromID(u"Pacific/Honolulu");
// (1) kStartTime0 = "23 Oct 2009 11:30 GMT";
// kEndTime0 = "23 Oct 2009 12:30 GMT";
// => event1 23 Oct 2009 1:30 ~2:30
//
// (2) kStartTime12 = "24 Oct 2009 07:10 GMT";
// kEndTime12 = "24 Oct 2009 08:00 GMT";
// => event2 23 Oct 2009 21:10 ~22:00
//
// (3) kStartTime13 = "24 Oct 2009 07:30 GMT";
// kEndTime13 = "25 Oct 2009 08:30 GMT";
// => event3 23 Oct 2009 21:30 ~23:59
// event4 24 Oct 2009 00:00 ~22:30
calendar_model()->RedistributeEvents();
EXPECT_EQ(3, EventsNumberOfDay("23 Oct 2009 00:00", &events));
EXPECT_EQ(1, EventsNumberOfDay("24 Oct 2009 00:00", &events));
EXPECT_EQ(0, EventsNumberOfDay("25 Oct 2009 00:00", &events));
EXPECT_EQ(0, EventsNumberOfDay("26 Oct 2009 00:00", &events));
// Sets the timezone to "Pacific/Kiritimatis" which has +14 hours time
// difference;
timezone_settings.SetTimezoneFromID(u"Pacific/Kiritimati");
// (1) kStartTime0 = "23 Oct 2009 11:30 GMT";
// kEndTime0 = "23 Oct 2009 12:30 GMT";
// => event1 24 Oct 2009 1:30 ~2:30
//
// (2) kStartTime12 = "24 Oct 2009 07:10 GMT";
// kEndTime12 = "24 Oct 2009 08:00 GMT";
// => event2 24 Oct 2009 21:10 ~22:00
//
// (3) kStartTime13 = "24 Oct 2009 07:30 GMT";
// kEndTime13 = "25 Oct 2009 08:30 GMT";
// => event4 24 Oct 2009 21:30 ~23:59
// event5 25 Oct 2009 00:00 ~22:30
calendar_model()->RedistributeEvents();
EXPECT_EQ(0, EventsNumberOfDay("23 Oct 2009 00:00", &events));
EXPECT_EQ(3, EventsNumberOfDay("24 Oct 2009 00:00", &events));
EXPECT_EQ(1, EventsNumberOfDay("25 Oct 2009 00:00", &events));
EXPECT_EQ(0, EventsNumberOfDay("26 Oct 2009 00:00", &events));
}
// Test for pruning of events.
TEST_P(CalendarModelTest, PruneEvents) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// The number of event is exactly the max cached capacity. No events should be
// removed when init the mock response.
constexpr int kNumEvents = calendar_utils::kMaxNumPrunableMonths +
calendar_utils::kMaxNumNonPrunableMonths; // 25
// Loop from base start time to mock the initial cached months.
base::Time current_month =
calendar_test_utils::GetTimeFromString(kBaseStartTime);
// Set the next next month as today. The default surrounding months number is
// 2. This sets the first 5 months as the non_prunable months.
// NOTE: We must set today before injecting any events because if we set it
// at the i == 2 loop, the first two months will be added to mru_months_ and
// will be prunable.
base::Time next_month = calendar_utils::GetStartOfNextMonthUTC(current_month);
SetTodayFromTime(calendar_utils::GetStartOfNextMonthUTC(next_month));
for (int i = 0; i < kNumEvents; ++i) {
// Inject events.
MockOnEventsFetched(current_month, google_apis::ApiErrorCode::HTTP_SUCCESS,
nullptr);
current_month = calendar_utils::GetStartOfNextMonthUTC(current_month);
}
std::vector<base::Time> init_prunable_months;
for (auto& month : event_months()) {
if (!base::Contains(non_prunable_months(), month.first)) {
init_prunable_months.push_back(month.first);
}
}
EXPECT_EQ((int)init_prunable_months.size(),
calendar_utils::kMaxNumPrunableMonths);
// Loop from start time reversely to mock scroll up form the current month to
// the previous months.
base::Time on_screen_month =
calendar_test_utils::GetTimeFromString(kBaseStartTime);
for (int i = 0; i < calendar_utils::kMaxNumPrunableMonths; ++i) {
auto months = calendar_utils::GetSurroundingMonthsUTC(on_screen_month, 1);
// Fetch events.
for (auto& month : months) {
calendar_model()->FetchEvents(month);
}
WaitUntilFetched();
if (i > 1) {
EXPECT_LE((int)event_months().size(), kNumEvents + 1);
EXPECT_TRUE(EventsPresentInRange(
init_prunable_months, i, calendar_utils::kMaxNumPrunableMonths - 1));
EXPECT_TRUE(NoEventsPresentInRange(init_prunable_months, 0, i));
}
on_screen_month =
calendar_utils::GetStartOfPreviousMonthUTC(on_screen_month);
}
// No `non_prunable_months` is delected.
for (auto month : non_prunable_months()) {
EXPECT_TRUE(base::Contains(event_months(), month));
}
EXPECT_EQ((int)event_months().size(), kNumEvents + 1);
}
TEST_P(CalendarModelTest, RecordFetchResultHistogram_Success) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
base::HistogramTester histogram_tester;
// Current date is just `kStartTime0`.
SetTodayFromStr(kStartTime0);
histogram_tester.ExpectBucketCount("Ash.Calendar.FetchEvents.Result",
google_apis::HTTP_SUCCESS,
/*expected_count=*/0);
// Now fetch the events, which will get all events from the current month,
// as well as next/prev months.
for (auto& month : non_prunable_months()) {
calendar_model()->FetchEvents(month);
}
WaitUntilFetched();
// We should have recorded "success" for all fetches.
histogram_tester.ExpectBucketCount(
"Ash.Calendar.FetchEvents.Result", google_apis::HTTP_SUCCESS,
/*expected_count=*/calendar_utils::kMaxNumNonPrunableMonths);
}
TEST_P(CalendarModelTest, RecordFetchResultHistogram_Failure) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
base::HistogramTester histogram_tester;
// Current date is just `kStartTime0`.
base::Time current_date = calendar_test_utils::GetTimeFromString(kStartTime0);
SetTodayFromTime(current_date);
// Now fetch the events.
google_apis::ApiErrorCode error;
int i = 0;
for (auto month : non_prunable_months()) {
switch (i) {
case 0:
error = google_apis::HTTP_UNAUTHORIZED;
break;
case 1:
case 2:
error = google_apis::NO_CONNECTION;
break;
default:
error = google_apis::PARSE_ERROR;
break;
}
SetError(error);
calendar_model()->FetchEvents(month);
WaitUntilFetched();
++i;
}
// We should have recorded "success" for no fetches.
histogram_tester.ExpectBucketCount("Ash.Calendar.FetchEvents.Result",
google_apis::HTTP_SUCCESS,
/*expected_count=*/0);
histogram_tester.ExpectBucketCount("Ash.Calendar.FetchEvents.Result",
google_apis::HTTP_UNAUTHORIZED,
/*expected_count=*/1);
histogram_tester.ExpectBucketCount("Ash.Calendar.FetchEvents.Result",
google_apis::NO_CONNECTION,
/*expected_count=*/2);
histogram_tester.ExpectBucketCount("Ash.Calendar.FetchEvents.Result",
google_apis::PARSE_ERROR,
/*expected_count=*/2);
}
TEST_P(CalendarModelTest, SessionStateChange) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Current date is just `kStartTime0`.
SetTodayFromStr(kStartTime0);
std::unique_ptr<google_apis::calendar::CalendarEvent> event =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
// Haven't injected anything yet, so no events on `kStartTime0`.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
// Set up list of events as the mock response and fetch the event list.
auto event_list = std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event));
SetEventList(std::move(event_list));
calendar_model()->FetchEvents(now());
WaitUntilFetched();
// Now we have an event on kStartTime0.
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
EXPECT_FALSE(events.empty());
EXPECT_TRUE(events.size() == 1);
// Lets pretend the user locked the screen, which should clear all cached
// events.
SessionInfo session_info;
session_info.state = session_manager::SessionState::LOCKED;
SessionController::Get()->SetSessionInfo(session_info);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
}
TEST_P(CalendarModelTest, ActiveUserChange) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Set up two users, user1 is the active user.
UpdateSession(1u, "[email protected]");
UpdateSession(2u, "[email protected]");
std::vector<uint32_t> order = {1u, 2u};
SessionController::Get()->SetUserSessionOrder(order);
base::RunLoop().RunUntilIdle();
// Current date is just `kStartTime0`.
SetTodayFromStr(kStartTime0);
std::set<base::Time> months =
calendar_utils::GetSurroundingMonthsUTC(base::Time::Now(), 1);
// Haven't injected anything yet, so no events on `kStartTime0`.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
// Set up list of events.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
std::unique_ptr<google_apis::calendar::CalendarEvent> event =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
event_list->InjectItemForTesting(std::move(event));
SetEventList(std::move(event_list));
// Now fetch the events.
calendar_model()->FetchEvents(now());
WaitUntilFetched();
// Now we have an event on kStartTime0.
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
EXPECT_FALSE(events.empty());
EXPECT_TRUE(events.size() == 1);
// Make user2 the active user, and we should clear the cached events.
order = {2u, 1u};
SessionController::Get()->SetUserSessionOrder(order);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
EXPECT_TRUE(event_months().empty());
}
TEST_P(CalendarModelTest, ActiveChildUserChange) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
// Set up two users, user1 is the active user.
UpdateSession(1u, "[email protected]", /*is_child*/ true);
UpdateSession(2u, "[email protected]", /*is_child*/ true);
std::vector<uint32_t> order = {1u, 2u};
SessionController::Get()->SetUserSessionOrder(order);
base::RunLoop().RunUntilIdle();
// Current date is just `kStartTime0`.
SetTodayFromStr(kStartTime0);
std::set<base::Time> months =
calendar_utils::GetSurroundingMonthsUTC(base::Time::Now(), 1);
// Haven't injected anything yet, so no events on `kStartTime0`.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
// Set up list of events.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
std::unique_ptr<google_apis::calendar::CalendarEvent> event =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
event_list->InjectItemForTesting(std::move(event));
SetEventList(std::move(event_list));
// Now fetch the events.
calendar_model()->FetchEvents(now());
WaitUntilFetched();
// Now we have an event on kStartTime0 for chlid user1.
EXPECT_EQ(1, EventsNumberOfDay(kStartTime0, &events));
EXPECT_FALSE(events.empty());
EXPECT_TRUE(events.size() == 1);
// Make user2 the active user, and we should clear the cached events.
order = {2u, 1u};
SessionController::Get()->SetUserSessionOrder(order);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
EXPECT_TRUE(event_months().empty());
}
TEST_P(CalendarModelTest, ClearEvents) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
std::unique_ptr<google_apis::calendar::CalendarEvent> event0 =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
std::unique_ptr<google_apis::calendar::CalendarEvent> event1 =
calendar_test_utils::CreateEvent(kId1, kSummary1, kStartTime1, kEndTime1);
std::unique_ptr<google_apis::calendar::CalendarEvent> event2 =
calendar_test_utils::CreateEvent(kId2, kSummary2, kStartTime2, kEndTime2);
std::unique_ptr<google_apis::calendar::CalendarEvent> event3 =
calendar_test_utils::CreateEvent(kId3, kSummary3, kStartTime3, kEndTime3);
std::unique_ptr<google_apis::calendar::CalendarEvent> event4 =
calendar_test_utils::CreateEvent(kId4, kSummary4, kStartTime4, kEndTime4);
std::unique_ptr<google_apis::calendar::CalendarEvent> event5 =
calendar_test_utils::CreateEvent(kId5, kSummary5, kStartTime5, kEndTime5);
auto event_list = std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event0));
event_list->InjectItemForTesting(std::move(event1));
event_list->InjectItemForTesting(std::move(event2));
event_list->InjectItemForTesting(std::move(event3));
event_list->InjectItemForTesting(std::move(event4));
event_list->InjectItemForTesting(std::move(event5));
// Current time is `kStartTime1`.
SetTodayFromStr(kStartTime1);
// Events from no months should now be present.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime0, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime1, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime2, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime3, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime4, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime5, &events));
MockOnEventsFetched(now(), google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
// Events from all months should now be present.
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime0, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime1, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime2, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime3, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime4, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime5, &events));
// Clear out all non-prunable months.
calendar_model()->ClearAllPrunableEvents();
// Events from all non-prunable months should be present, but others not
// present.
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime0, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime1, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime2, &events));
EXPECT_EQ(1, EventsNumberOfDayInternal(kStartTime3, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime4, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime5, &events));
// Now clear out all events.
calendar_model()->ClearAllCachedEvents();
// Events from all months prunable and non-prunable should not be present.
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime0, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime1, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime2, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime3, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime4, &events));
EXPECT_EQ(0, EventsNumberOfDayInternal(kStartTime5, &events));
}
// Test for filtering of events based on their statuses. Cancelled or declined
// events shouldn't be inserted in a month.
TEST_P(CalendarModelTest, ShouldFilterEvents) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kStartTime0);
// Haven't injected anything yet, so no events on `kStartTime0`.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
EXPECT_TRUE(events.empty());
// Inject events.
std::vector<std::tuple<const char*, CalendarEvent::EventStatus,
CalendarEvent::ResponseStatus>>
events_to_create = {
std::make_tuple("cancelled+accepted",
CalendarEvent::EventStatus::kCancelled,
CalendarEvent::ResponseStatus::kAccepted),
std::make_tuple("confirmed+accepted",
CalendarEvent::EventStatus::kConfirmed,
CalendarEvent::ResponseStatus::kAccepted),
std::make_tuple("tentative+accepted",
CalendarEvent::EventStatus::kTentative,
CalendarEvent::ResponseStatus::kAccepted),
std::make_tuple("unknown+accepted",
CalendarEvent::EventStatus::kUnknown,
CalendarEvent::ResponseStatus::kAccepted),
std::make_tuple("confirmed+declined",
CalendarEvent::EventStatus::kConfirmed,
CalendarEvent::ResponseStatus::kDeclined),
std::make_tuple("confirmed+needs_action",
CalendarEvent::EventStatus::kConfirmed,
CalendarEvent::ResponseStatus::kNeedsAction),
std::make_tuple("confirmed+tentative",
CalendarEvent::EventStatus::kConfirmed,
CalendarEvent::ResponseStatus::kTentative),
std::make_tuple("confirmed+unknown",
CalendarEvent::EventStatus::kConfirmed,
CalendarEvent::ResponseStatus::kUnknown)};
std::unique_ptr<EventList> event_list = std::make_unique<EventList>();
for (auto& event_to_create : events_to_create) {
event_list->InjectItemForTesting(calendar_test_utils::CreateEvent(
std::get<0>(event_to_create), std::get<0>(event_to_create), kStartTime0,
kEndTime0, std::get<1>(event_to_create), std::get<2>(event_to_create)));
}
MockOnEventsFetched(now(), google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
// Verify that events were filtered by their statuses.
EXPECT_EQ(4, EventsNumberOfDay(kStartTime0, &events));
EXPECT_FALSE(events.empty());
std::vector<std::string> filtered_event_ids;
base::ranges::transform(events, std::back_inserter(filtered_event_ids),
&CalendarEvent::id);
EXPECT_THAT(filtered_event_ids,
testing::UnorderedElementsAreArray(std::vector<std::string>{
"confirmed+accepted", "tentative+accepted",
"confirmed+needs_action", "confirmed+tentative"}));
}
TEST_P(CalendarModelTest, EdgeOfMonthEvent) {
// Will add event that's in the same month as kNow using PDT (UTC-7),
// so the times will translate to next day (and month) on UTC.
ash::system::ScopedTimezoneSettings timezone_settings(u"America/Los_Angeles");
const char* kId = "id";
const char* kSummary = "summary";
const char* kNow = "10 May 2022 13:00 PDT";
const char* kEdgeOfMonthEventStartTime = "31 May 2022 22:00 PDT";
const char* kEdgeOfMonthEventEndTime = "31 May 2022 23:00 PDT";
// Set current date and get surrounding months.
SetTodayFromStr(kNow);
// Insert an event in the edge of the month.
std::unique_ptr<google_apis::calendar::CalendarEvent> end_of_month_event =
calendar_test_utils::CreateEvent(
kId, kSummary, kEdgeOfMonthEventStartTime, kEdgeOfMonthEventEndTime);
// Haven't injected anything yet, so no events on the start time.
SingleDayEventList events;
base::Time start_time_adjusted =
GetStartTimeMidnightAdjusted(end_of_month_event.get());
EXPECT_EQ(0, EventsNumberOfDay(start_time_adjusted, &events));
// Get ready to inject an event in the edge of the month.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(end_of_month_event));
MockOnEventsFetched(now(), google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
// Now the day where the event started should have an event.
EXPECT_EQ(1, EventsNumberOfDay(start_time_adjusted, &events));
// The month to events map should insert the event in the current month.
auto cur_month_map =
event_months().find(calendar_utils::GetStartOfMonthUTC(now()));
EXPECT_FALSE(cur_month_map->second.empty());
// The month to events map should not insert the event in the next month.
auto next_month_map =
event_months().find(calendar_utils::GetStartOfNextMonthUTC(now()));
EXPECT_TRUE(next_month_map->second.empty());
}
TEST_P(CalendarModelTest, MultiDayEvents) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
// Generic event id and summary.
const char* kId = "id";
const char* kSummary = "summary";
// Multi-day event ranges in the two surrounding months.
const char* kMultiDayStartTime = "20 Nov 2022 22:00 GMT";
const char* kMultiDayEndTime = "25 Nov 2022 10:00 GMT";
const char* kMultiMonthStartTime = "10 Sep 2022 22:00 GMT";
const char* kMultiMonthEndTime = "2 Nov 2022 10:00 GMT";
const char* kMultiYearStartTime = "10 Dec 2022 22:00 GMT";
const char* kMultiYearEndTime = "10 Jan 2023 10:00 GMT";
// Create multi-day events.
std::unique_ptr<google_apis::calendar::CalendarEvent> multi_day_event =
calendar_test_utils::CreateEvent(kId, kSummary, kMultiDayStartTime,
kMultiDayEndTime);
std::unique_ptr<google_apis::calendar::CalendarEvent> multi_month_event =
calendar_test_utils::CreateEvent(kId, kSummary, kMultiMonthStartTime,
kMultiMonthEndTime);
std::unique_ptr<google_apis::calendar::CalendarEvent> multi_year_event =
calendar_test_utils::CreateEvent(kId, kSummary, kMultiYearStartTime,
kMultiYearEndTime);
// Haven't injected anything yet, so no events on the start times.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kMultiDayStartTime, &events));
EXPECT_EQ(0, EventsNumberOfDay(kMultiMonthStartTime, &events));
EXPECT_EQ(0, EventsNumberOfDay(kMultiYearStartTime, &events));
// Prepare mock events list.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(multi_day_event));
event_list->InjectItemForTesting(std::move(multi_month_event));
event_list->InjectItemForTesting(std::move(multi_year_event));
// Mock the events are fech by each related month.
MockOnEventsFetched(
calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString("10 Sep 2022 22:00 GMT")),
google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
MockOnEventsFetched(
calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString("10 Oct 2022 22:00 GMT")),
google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
MockOnEventsFetched(
calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString("10 Nov 2022 22:00 GMT")),
google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
MockOnEventsFetched(
calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString("10 Dec 2022 22:00 GMT")),
google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
MockOnEventsFetched(
calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString("10 Jan 2023 22:00 GMT")),
google_apis::ApiErrorCode::HTTP_SUCCESS, event_list.get());
// Test a multi-day event whose start and end are in the same month.
TestMultiDayEvent(events, kMultiDayStartTime, kMultiDayEndTime);
// Test a multi-day event whose start and end are in different months.
TestMultiDayEvent(events, kMultiMonthStartTime, kMultiMonthEndTime);
// Test a multi-day event whose start and end are in different years.
TestMultiDayEvent(events, kMultiYearStartTime, kMultiYearEndTime);
}
TEST_P(CalendarModelTest, MultiAllDayEvents) {
// Set timezone and fake now. We set this to be GMT+n as we previously
// had a bug where all day events overflowed into the day after they were set
// to end for GMT+ timezones.
const char* kNow = "10 Nov 2022 13:00 GMT+5";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT+5");
SetTodayFromStr(kNow);
// Generic event id and summary.
const char* kId = "id";
const char* kSummary = "summary";
// Create 2 day "all day" event. "All day" events technically don't have
// start and end times but we set them to start and end at 00:00 local time in
// the API response.
const char* kMultiAllDayEventPreviousDayTime = "19 Nov 2022 00:00 GMT";
const char* kMultiAllDayEventDayOneStartTime = "20 Nov 2022 00:00 GMT";
const char* kMultiAllDayEventDayTwoStartTime = "21 Nov 2022 00:00 GMT";
const char* kMultiAllDayEventEndTime = "22 Nov 2022 00:00 GMT";
std::unique_ptr<google_apis::calendar::CalendarEvent> multi_all_day_event =
calendar_test_utils::CreateEvent(
kId, kSummary, kMultiAllDayEventDayOneStartTime,
kMultiAllDayEventEndTime,
google_apis::calendar::CalendarEvent::EventStatus::kConfirmed,
google_apis::calendar::CalendarEvent::ResponseStatus::kAccepted,
true);
// Haven't injected anything yet, so no events on the start times.
SingleDayEventList events;
EXPECT_EQ(0, EventsNumberOfDay(kMultiAllDayEventDayOneStartTime, &events));
// Prepare mock events list.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(multi_all_day_event));
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
// Assert that the correct number of all day events are stored. We should not
// have events on days surrounding the all day events.
EXPECT_EQ(0, EventsNumberOfDay(kMultiAllDayEventPreviousDayTime, &events));
EXPECT_EQ(1, EventsNumberOfDay(kMultiAllDayEventDayOneStartTime, &events));
EXPECT_EQ(1, EventsNumberOfDay(kMultiAllDayEventDayTwoStartTime, &events));
EXPECT_EQ(0, EventsNumberOfDay(kMultiAllDayEventEndTime, &events));
}
TEST_P(CalendarModelTest, FindFetchingStatus) {
// Sets the timezone to "GMT".
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
if (IsMultiCalendarEnabled()) {
EXPECT_TRUE(calendar_list_model()->get_is_cached());
EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
}
std::unique_ptr<google_apis::calendar::CalendarEvent> event0 =
calendar_test_utils::CreateEvent(kId0, kSummary0, kStartTime0, kEndTime0);
std::unique_ptr<google_apis::calendar::CalendarEvent> event1 =
calendar_test_utils::CreateEvent(kId1, kSummary1, kStartTime1, kEndTime1);
std::unique_ptr<google_apis::calendar::CalendarEvent> event2 =
calendar_test_utils::CreateEvent(kId2, kSummary2, kStartTime2, kEndTime2);
std::unique_ptr<google_apis::calendar::CalendarEvent> event3 =
calendar_test_utils::CreateEvent(kId3, kSummary3, kStartTime3, kEndTime3);
auto event_list = std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event0));
event_list->InjectItemForTesting(std::move(event1));
event_list->InjectItemForTesting(std::move(event2));
event_list->InjectItemForTesting(std::move(event3));
SetTodayFromStr(kStartTime0);
base::Time start_of_month0 = calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime0));
// Mock that events 0~3 has fetched.
MockOnEventsFetched(start_of_month0, google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
// Starts fetching a date that is not in the cache.
base::Time fetching_date =
calendar_test_utils::GetTimeFromString("1 Apr 2022 00:00 GMT");
calendar_model()->FetchEvents(fetching_date);
// The request for `fetching_date` is just sent out.
EXPECT_EQ(CalendarModel::kFetching,
calendar_model()->FindFetchingStatus(
calendar_utils::GetStartOfMonthUTC(fetching_date)));
// The request for kStartTime 0,1,2,3 are already finished (since
// `OnEventsFetched` is called).
EXPECT_EQ(
CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime0))));
EXPECT_EQ(
CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime1))));
EXPECT_EQ(
CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime2))));
EXPECT_EQ(
CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime3))));
// The result of `kStartTime4` has never been fetched. And the request has
// never been sent either.
EXPECT_EQ(
CalendarModel::kNever,
calendar_model()->FindFetchingStatus(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kStartTime4))));
WaitUntilFetched();
EXPECT_EQ(CalendarModel::kSuccess,
calendar_model()->FindFetchingStatus(
calendar_utils::GetStartOfMonthUTC(fetching_date)));
}
TEST_P(CalendarModelTest, FindEventsSplitByMultiDayAndSameDay) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT+5";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT+5");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kMultiDayId = "multi-day";
const char* kMultiDayEventStartTime = "10 Nov 2022 12:00 GMT";
const char* kMultiDayEventEndTime = "12 Nov 2022 10:00 GMT";
const char* kSameDayId = "same-day";
const char* kSameDayEventStartTime = "10 Nov 2022 09:00 GMT";
const char* kSameDayEventEndTime = "10 Nov 2022 10:00 GMT";
auto multi_day_event = calendar_test_utils::CreateEvent(
kMultiDayId, kSummary, kMultiDayEventStartTime, kMultiDayEventEndTime);
auto same_day_event = calendar_test_utils::CreateEvent(
kSameDayId, kSummary, kSameDayEventStartTime, kSameDayEventEndTime);
// Prepare mock events list.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(multi_day_event));
event_list->InjectItemForTesting(std::move(same_day_event));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto [multi_day_events, same_day_events] =
calendar_model_->FindEventsSplitByMultiDayAndSameDay(now_);
EXPECT_EQ(multi_day_events.size(), size_t(1));
EXPECT_EQ(multi_day_events.back().id(), kMultiDayId);
EXPECT_EQ(same_day_events.size(), size_t(1));
EXPECT_EQ(same_day_events.back().id(), kSameDayId);
}
TEST_P(CalendarModelTest, FindUpcomingEvents_SameDay) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kEventStartingInTenMinsId = "event_starting_in_ten_mins";
const char* kEventStartingInThirtyMinsId = "event_starting_in_thirty_mins";
const char* kEventStartingInTwoHoursId = "event_starting_in_two_hours";
const char* kEventInProgressStartedLessThanOneHourAgoId =
"event_in_progress_started_less_than_one_hour_ago";
const char* kEventInProgressStartedMoreThanOneHourAgoId =
"event_in_progress_started_more_than_one_hour_ago";
const char* kEventFinishedId = "event_finished";
auto event_starting_in_ten_mins = calendar_test_utils::CreateEvent(
kEventStartingInTenMinsId, kSummary, "10 Nov 2022 13:10 GMT",
"10 Nov 2022 15:00 GMT");
auto event_starting_in_thirty_mins = calendar_test_utils::CreateEvent(
kEventStartingInThirtyMinsId, kSummary, "10 Nov 2022 13:30 GMT",
"10 Nov 2022 15:00 GMT");
auto event_starting_in_two_hours = calendar_test_utils::CreateEvent(
kEventStartingInTwoHoursId, kSummary, "10 Nov 2022 15:00 GMT",
"10 Nov 2022 16:00 GMT");
auto event_in_progress_started_less_than_one_hour_ago =
calendar_test_utils::CreateEvent(
kEventInProgressStartedLessThanOneHourAgoId, kSummary,
"10 Nov 2022 12:01:00 GMT", "10 Nov 2022 17:00 GMT");
auto event_in_progress_started_more_than_one_hour_ago =
calendar_test_utils::CreateEvent(
kEventInProgressStartedMoreThanOneHourAgoId, kSummary,
"10 Nov 2022 11:00 GMT", "10 Nov 2022 17:00 GMT");
auto event_finished = calendar_test_utils::CreateEvent(
kEventFinishedId, kSummary, "10 Nov 2022 12:30 GMT",
"10 Nov 2022 12:59 GMT");
// Prepare mock events list.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event_starting_in_ten_mins));
event_list->InjectItemForTesting(std::move(event_starting_in_thirty_mins));
event_list->InjectItemForTesting(std::move(event_starting_in_two_hours));
event_list->InjectItemForTesting(
std::move(event_in_progress_started_less_than_one_hour_ago));
event_list->InjectItemForTesting(
std::move(event_in_progress_started_more_than_one_hour_ago));
event_list->InjectItemForTesting(std::move(event_finished));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
// We should only get the 2 events back that start in 10 mins or were ongoing
// with < 60 mins passed.
EXPECT_EQ(events.size(), size_t(2));
EXPECT_TRUE(event_list_contains(events, kEventStartingInTenMinsId));
EXPECT_FALSE(event_list_contains(events, kEventStartingInThirtyMinsId));
EXPECT_FALSE(event_list_contains(events, kEventStartingInTwoHoursId));
EXPECT_TRUE(
event_list_contains(events, kEventInProgressStartedLessThanOneHourAgoId));
EXPECT_FALSE(
event_list_contains(events, kEventInProgressStartedMoreThanOneHourAgoId));
EXPECT_FALSE(event_list_contains(events, kEventFinishedId));
}
// If time now is 23:55 and we have an upcoming event starting at 00:05 the
// following day, we should only show today's events. This test is needed after
// we made the change to the logic of showing the up next view. Before the
// change, we would show the events starting in 10 mins even if it's in the next
// day. Now it shouldn't be shown.
TEST_P(CalendarModelTest, FindUpcomingEvents_NextDay) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 23:55 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kEventStartingInTenMinsTomorrowId =
"event_starting_in_ten_mins_tomorrow";
auto event_starting_in_ten_mins_tomorrow = calendar_test_utils::CreateEvent(
kEventStartingInTenMinsTomorrowId, kSummary, "11 Nov 2022 00:05 GMT",
"10 Nov 2022 15:00 GMT");
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(
std::move(event_starting_in_ten_mins_tomorrow));
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
EXPECT_EQ(events.size(), size_t(0));
EXPECT_FALSE(event_list_contains(events, kEventStartingInTenMinsTomorrowId));
}
// If time now is 00:10 and we have an event that started <1 hour ago, then we
// should get in progress events from the previous day back.
TEST_P(CalendarModelTest, FindUpcomingEvents_PreviousDay) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 00:10 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kEventInProgressStartedYesterdayId =
"event_in_progress_started_yesterday_id";
auto event_in_progress_started_yesterday = calendar_test_utils::CreateEvent(
kEventInProgressStartedYesterdayId, kSummary, "09 Nov 2022 23:15 GMT",
"10 Nov 2022 00:15 GMT");
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(
std::move(event_in_progress_started_yesterday));
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
EXPECT_EQ(events.size(), size_t(1));
EXPECT_TRUE(event_list_contains(events, kEventInProgressStartedYesterdayId));
}
// If the next event doesn't start in the next 10 mins, we'll still show it.
// This is needed after we changed the logic of showing the up next view.
TEST_P(CalendarModelTest, FindUpcomingEvents_ShowTheNextEvent) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kEventStartingInThirtyMinsId = "event_starting_in_thirty_mins";
auto event_starting_in_thirty_mins = calendar_test_utils::CreateEvent(
kEventStartingInThirtyMinsId, kSummary, "10 Nov 2022 13:30 GMT",
"10 Nov 2022 15:00 GMT");
// Prepare mock events list.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(event_starting_in_thirty_mins));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
EXPECT_EQ(events.size(), size_t(1));
EXPECT_TRUE(event_list_contains(events, kEventStartingInThirtyMinsId));
}
// If two events start at the same time, show the one finishing earlier first.
// Returns:
// First event: 13:00 - 13:45
// Second event: 13:00 - 14:00
TEST_P(CalendarModelTest, EventsSortingWithSameStartTime) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kFirstEventId = "first_event";
const char* kSecondEventId = "second_event";
auto first_event = calendar_test_utils::CreateEvent(kFirstEventId, kSummary,
"10 Nov 2022 13:00 GMT",
"10 Nov 2022 13:45 GMT");
auto second_event = calendar_test_utils::CreateEvent(kSecondEventId, kSummary,
"10 Nov 2022 13:00 GMT",
"10 Nov 2022 14:00 GMT");
// Prepare mock events list. Note we add the second event first, which should
// later be sorted differently.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(second_event));
event_list->InjectItemForTesting(std::move(first_event));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
EXPECT_EQ(events.size(), size_t(2));
EXPECT_EQ(kFirstEventId, events.front().id());
EXPECT_EQ(kSecondEventId, events.back().id());
}
// Shows all events that start in 10 mins.
TEST_P(CalendarModelTest, ShowEventsStartIn10MinsAsUpNext) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kFirstEventId = "first_event";
const char* kSecondEventId = "second_event";
auto first_event = calendar_test_utils::CreateEvent(kFirstEventId, kSummary,
"10 Nov 2022 13:05 GMT",
"10 Nov 2022 13:45 GMT");
auto second_event = calendar_test_utils::CreateEvent(kSecondEventId, kSummary,
"10 Nov 2022 13:00 GMT",
"10 Nov 2022 14:00 GMT");
// Prepare mock events list. Note we add the first event first, which should
// later be sorted differently.
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(first_event));
event_list->InjectItemForTesting(std::move(second_event));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
EXPECT_EQ(events.size(), size_t(2));
EXPECT_TRUE(event_list_contains(events, kSecondEventId));
}
// Shows the first event if there's no events that start in 10 mins.
TEST_P(CalendarModelTest, ShowTheFirstEventAsUpNext) {
// Set timezone and fake now.
const char* kNow = "10 Nov 2022 13:00 GMT";
ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
SetTodayFromStr(kNow);
const char* kSummary = "summary";
const char* kFirstEventId = "first_event";
const char* kSecondEventId = "second_event";
auto first_event = calendar_test_utils::CreateEvent(kFirstEventId, kSummary,
"10 Nov 2022 15:05 GMT",
"10 Nov 2022 15:45 GMT");
auto second_event = calendar_test_utils::CreateEvent(kSecondEventId, kSummary,
"10 Nov 2022 16:00 GMT",
"10 Nov 2022 17:00 GMT");
std::unique_ptr<google_apis::calendar::EventList> event_list =
std::make_unique<google_apis::calendar::EventList>();
event_list->InjectItemForTesting(std::move(first_event));
event_list->InjectItemForTesting(std::move(second_event));
// Mock the events are fetched.
MockOnEventsFetched(calendar_utils::GetStartOfMonthUTC(
calendar_test_utils::GetTimeFromString(kNow)),
google_apis::ApiErrorCode::HTTP_SUCCESS,
event_list.get());
auto events = calendar_model_->FindUpcomingEvents(now_);
auto event_list_contains = [](auto& event_list, auto& id) {
return base::Contains(event_list, id, &CalendarEvent::id);
};
EXPECT_EQ(events.size(), size_t(1));
EXPECT_TRUE(event_list_contains(events, kFirstEventId));
EXPECT_FALSE(event_list_contains(events, kSecondEventId));
}
} // namespace ash