pebble/tests/fw/services/timeline/test_calendar.c
2025-01-27 11:38:16 -08:00

412 lines
12 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "kernel/events.h"
#include "services/normal/blob_db/pin_db.h"
#include "services/normal/timeline/calendar.h"
#include "services/normal/timeline/event.h"
#include "services/normal/timeline/timeline.h"
#include "system/logging.h"
#include "clar.h"
// Stubs
////////////////////////////////////////////////////////////////
#include "stubs_analytics.h"
#include "stubs_ancs.h"
#include "stubs_ancs_notifications.h"
#include "stubs_app_cache.h"
#include "stubs_app_install_manager.h"
#include "stubs_app_manager.h"
#include "stubs_blob_db.h"
#include "stubs_blob_db_sync.h"
#include "stubs_blob_db_sync_util.h"
#include "stubs_event_loop.h"
#include "stubs_event_service_client.h"
#include "stubs_hexdump.h"
#include "stubs_i18n.h"
#include "stubs_layout_layer.h"
#include "stubs_logging.h"
#include "stubs_modal_manager.h"
#include "stubs_mutex.h"
#include "stubs_notification_storage.h"
#include "stubs_notifications.h"
#include "stubs_passert.h"
#include "stubs_phone_call_util.h"
#include "stubs_prompt.h"
#include "stubs_rand_ptr.h"
#include "stubs_regular_timer.h"
#include "stubs_reminder_db.h"
#include "stubs_session.h"
#include "stubs_sleep.h"
#include "stubs_system_task.h"
#include "stubs_task_watchdog.h"
#include "stubs_text_layer_flow.h"
#include "stubs_timeline.h"
#include "stubs_timeline_pin_window.h"
#include "stubs_window_stack.h"
// Fakes
////////////////////////////////////////////////////////////////
#include "fake_new_timer.h"
#include "fake_pbl_malloc.h"
#include "fake_pebble_tasks.h"
#include "fake_rtc.h"
#include "fake_spi_flash.h"
#include "fake_settings_file.h"
#include "fake_events.h"
bool calendar_layout_verify(bool existing_attributes[]) {
return true;
}
bool weather_layout_verify(bool existing_attributes[]) {
return true;
}
const TimelineEventImpl *timeline_peek_get_event_service(void) {
return NULL;
}
// Helpers
////////////////////////////////////////////////////////////////
static bool s_in_calendar_event = false;
static bool prv_get_calendar_ongoing(void) {
PebbleEvent event = fake_event_get_last();
if (event.type == PEBBLE_CALENDAR_EVENT) {
s_in_calendar_event = event.calendar.is_event_ongoing;
}
return s_in_calendar_event;
}
// Fake pins
////////////////////////////////////////////////////////////////
static Attribute title_attr = {
.id = AttributeIdTitle,
.cstring = "title",
};
static TimelineItem item1 = {
.header = {
.id = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 10*60,
.duration = 10,
.type = TimelineItemTypePin,
.all_day = false,
.layout = LayoutIdCalendar,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
static TimelineItem item2 = {
.header = {
.id = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 15*60,
.duration = 20,
.type = TimelineItemTypePin,
.all_day = false,
.layout = LayoutIdCalendar,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
static TimelineItem item3 = {
.header = {
.id = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 25*60,
.duration = 5,
.type = TimelineItemTypePin,
.all_day = false,
.layout = LayoutIdCalendar,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
static TimelineItem item4 = {
.header = {
.id = {0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 100*60,
.duration = 10,
.type = TimelineItemTypePin,
.all_day = false,
.layout = LayoutIdCalendar,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
// NOT A CALENDAR PIN
static TimelineItem item5 = {
.header = {
.id = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 10*60,
.duration = 10,
.type = TimelineItemTypePin,
.all_day = false,
.layout = LayoutIdWeather,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
// ALL DAY PIN
static TimelineItem item6 = {
.header = {
.id = {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.timestamp = 100*60,
.duration = 10,
.type = TimelineItemTypePin,
.all_day = true,
.layout = LayoutIdCalendar,
},
.attr_list = {
.num_attributes = 1,
.attributes = &title_attr,
},
};
// Setup
////////////////////////////////////////////////////////////////
void test_calendar__initialize(void) {
s_in_calendar_event = false;
rtc_set_time(0);
fake_event_init();
pin_db_init();
}
void test_calendar__cleanup(void) {
timeline_event_deinit();
stub_new_timer_cleanup();
fake_settings_file_reset();
}
// Tests
////////////////////////////////////////////////////////////////
void test_calendar__no_events(void) {
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
}
void test_calendar__init_with_future_event(void) {
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 2);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert(timer_id != TIMER_INVALID_ID);
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(10*60, stub_new_timer_timeout(timer_id) / 1000);
}
void test_calendar_handle__future_event_added_and_removed(void) {
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
cl_assert(!stub_new_timer_is_scheduled(timer_id));
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 2);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(10*60, stub_new_timer_timeout(timer_id) / 1000);
cl_assert(timeline_remove(&item1.header.id));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 3);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}
void test_calendar__init_with_ongoing_event(void) {
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
rtc_set_time(15 * 60);
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert(timer_id != TIMER_INVALID_ID);
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(5*60, stub_new_timer_timeout(timer_id) / 1000);
}
void test_calendar_handle__ongoing_event_added_and_removed(void) {
rtc_set_time(15 * 60);
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
cl_assert(!stub_new_timer_is_scheduled(timer_id));
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 2);
cl_assert(prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(5*60, stub_new_timer_timeout(timer_id) / 1000);
cl_assert(timeline_remove(&item1.header.id));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 3);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}
void test_calendar__init_with_past_event(void) {
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
rtc_set_time(30 * 60);
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}
void test_calendar_handle__past_event_added_and_removed(void) {
rtc_set_time(30 * 60);
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
cl_assert(!stub_new_timer_is_scheduled(timer_id));
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 2);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(!stub_new_timer_is_scheduled(timer_id));
cl_assert(timeline_remove(&item1.header.id));
timeline_event_handle_blobdb_event();
cl_assert_equal_i(fake_event_get_count(), 3);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}
void test_calendar__timer_test(void) {
cl_assert(timeline_add(&item1));
timeline_event_handle_blobdb_event();
cl_assert(timeline_add(&item2));
timeline_event_handle_blobdb_event();
cl_assert(timeline_add(&item3));
timeline_event_handle_blobdb_event();
cl_assert(timeline_add(&item4));
timeline_event_handle_blobdb_event();
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert(timer_id != TIMER_INVALID_ID);
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(10*60, stub_new_timer_timeout(timer_id) / 1000);
rtc_set_time(10 * 60);
cl_assert(stub_new_timer_fire(timer_id));
cl_assert_equal_i(fake_event_get_count(), 2);
cl_assert(prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(10*60, stub_new_timer_timeout(timer_id) / 1000);
rtc_set_time(20 * 60);
cl_assert(stub_new_timer_fire(timer_id));
cl_assert_equal_i(fake_event_get_count(), 3);
cl_assert(prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(15*60, stub_new_timer_timeout(timer_id) / 1000);
rtc_set_time(35 * 60);
cl_assert(stub_new_timer_fire(timer_id));
cl_assert_equal_i(fake_event_get_count(), 4);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(65*60, stub_new_timer_timeout(timer_id) / 1000);
rtc_set_time(100 * 60);
cl_assert(stub_new_timer_fire(timer_id));
cl_assert_equal_i(fake_event_get_count(), 5);
cl_assert(prv_get_calendar_ongoing());
cl_assert(stub_new_timer_is_scheduled(timer_id));
cl_assert_equal_i(10*60, stub_new_timer_timeout(timer_id) / 1000);
rtc_set_time(110 * 60);
cl_assert(stub_new_timer_fire(timer_id));
cl_assert_equal_i(fake_event_get_count(), 6);
cl_assert(!prv_get_calendar_ongoing());
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}
void test_calendar__handle_non_calendar_pins(void) {
// Insert a random pin (non calendar event)
cl_assert(timeline_add(&item5));
timeline_event_handle_blobdb_event();
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert_equal_i(timer_id, TIMER_INVALID_ID);
}
void test_calendar__handle_all_day_pins(void) {
// Insert an all day pin
cl_assert(timeline_add(&item6));
timeline_event_handle_blobdb_event();
timeline_event_init();
cl_assert_equal_i(fake_event_get_count(), 1);
cl_assert(!prv_get_calendar_ongoing());
TimerID timer_id = stub_new_timer_get_next();
cl_assert(!stub_new_timer_is_scheduled(timer_id));
}