/* * 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 "test_alarm_common.h" // Stubs #include "stubs_activity.h" #include "stubs_blob_db_sync.h" #include "stubs_blob_db_sync_util.h" #include "stubs_clock.h" #include "stubs_pbl_malloc.h" /////////////////////////////////////////////////////////////////////////////////////////////////// //! Counter variables static int s_num_timer_register_calls = 0; static int s_alarm_timer_timeout_ms = 0; static int s_snooze_timer_timeout_ms = 0; static int s_snooze_timer_id = 0; /////////////////////////////////////////////////////////////////////////////////////////////////// //! Fakes time_t rtc_get_time(void) { return s_current_day + prv_hours_and_minutes_to_seconds(s_current_hour, s_current_minute); } void rtc_get_time_ms(time_t* out_seconds, uint16_t* out_ms) { *out_ms = 0; *out_seconds = rtc_get_time(); } RtcTicks rtc_get_ticks(void) { return 0; } TimerID new_timer_create(void) { static TimerID s_next_timer_id = 0; s_snooze_timer_id = s_next_timer_id + 1; return ++s_next_timer_id; } bool new_timer_start(TimerID timer_id, uint32_t timeout_ms, NewTimerCallback cb, void *cb_data, uint32_t flags) { s_num_timer_register_calls++; s_snooze_timer_timeout_ms = timeout_ms; return true; } bool new_timer_stop(TimerID timer_id) { s_snooze_timer_timeout_ms = 0; return true; } void new_timer_delete(TimerID timer_id) { s_snooze_timer_timeout_ms = 0; } /////////////////////////////////////////////////////////////////////////////////////////////////// //! Setup void test_alarm__initialize(void) { s_num_timer_register_calls = 0; s_num_timeline_adds = 0; s_num_timeline_removes = 0; s_num_alarm_events_put = 0; s_alarm_timer_timeout_ms = 0; s_snooze_timer_timeout_ms = 0; s_num_alarms_fired = 0; s_current_hour = 0; s_current_minute = 0; // Default to Thursday s_current_day = s_thursday; timeline_item_destroy(s_last_timeline_item_added); s_last_timeline_item_added = NULL; s_last_timeline_item_removed_uuid = (Uuid) {}; fake_spi_flash_init(0, 0x1000000); pfs_init(false); pfs_format(false); cron_service_init(); alarm_init(); alarm_service_enable_alarms(true); } void test_alarm__cleanup(void) { cron_service_deinit(); } /////////////////////////////////////////////////////////////////////////////////////////////////// //! Basic Store / Get Tests void test_alarm__alarm_create_recurring_daily(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id = alarm_create(&(AlarmInfo) { .hour = 5, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 5, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id = alarm_create(&(AlarmInfo) { .hour = 6, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 6, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); } void test_alarm__alarm_create_recurring_weekends(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); id = alarm_create(&(AlarmInfo) { .hour = 5, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 5, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); id = alarm_create(&(AlarmInfo) { .hour = 6, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 6, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); } void test_alarm__alarm_create_recurring_weekdays(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); id = alarm_create(&(AlarmInfo) { .hour = 5, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 5, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); id = alarm_create(&(AlarmInfo) { .hour = 6, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 6, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); } void test_alarm__alarm_create_just_once(void) { AlarmId id; // It's currently Thursday @ 00:00 bool just_once_schedule_thursday[7] = {false, false, false, false, true, false, false}; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); id = alarm_create(&(AlarmInfo) { .hour = 5, .minute = 14, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id, 5, 14, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); id = alarm_create(&(AlarmInfo) { .hour = 6, .minute = 14, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id, 6, 14, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); } void test_alarm__alarm_create_recurring_custom(void) { AlarmId id; bool custom_schedule1[7] = {true, false, true, false, false, true, true}; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule1 }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_CUSTOM, custom_schedule1); bool custom_schedule2[7] = {false, false, false, false, false, true, false}; id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule2 }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_CUSTOM, custom_schedule2); bool custom_schedule3[7] = {true, true, true, true, true, true, true}; id = alarm_create(&(AlarmInfo) { .hour = 5, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule3 }); prv_assert_alarm_config(id, 5, 14, false, ALARM_KIND_CUSTOM, custom_schedule3); // FIXME: bool custom_schedule4[7] = {false, false, false, false, false, false, false}; id = alarm_create(&(AlarmInfo) { .hour = 6, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule4 }); prv_assert_alarm_config(id, 6, 14, false, ALARM_KIND_CUSTOM, custom_schedule4); } void test_alarm__alarm_set_time(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id1, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); alarm_set_time(id1, 5, 6); prv_assert_alarm_config(id1, 5, 6, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id2 = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id2, 4, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); alarm_set_time(id2, 23, 56); prv_assert_alarm_config(id2, 23, 56, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); alarm_set_time(id1, 15, 16); prv_assert_alarm_config(id1, 15, 16, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); alarm_set_time(id2, 23, 46); prv_assert_alarm_config(id2, 23, 46, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); } void test_alarm__alarm_set_recurring_daily(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); alarm_set_kind(id, ALARM_KIND_EVERYDAY); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); bool custom_schedule1[7] = {true, false, true, false, false, true, true}; id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule1 }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_CUSTOM, custom_schedule1); alarm_set_kind(id, ALARM_KIND_EVERYDAY); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); } void test_alarm__alarm_set_recurring_weekends(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); alarm_set_kind(id, ALARM_KIND_WEEKENDS); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); bool custom_schedule1[7] = {true, false, true, false, false, true, true}; id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule1 }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_CUSTOM, custom_schedule1); alarm_set_kind(id, ALARM_KIND_WEEKENDS); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); } void test_alarm__alarm_set_recurring_weekdays(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); alarm_set_kind(id, ALARM_KIND_WEEKDAYS); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); bool custom_schedule1[7] = {true, false, true, false, false, true, true}; id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &custom_schedule1 }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_CUSTOM, custom_schedule1); alarm_set_kind(id, ALARM_KIND_WEEKDAYS); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); } void test_alarm__alarm_set_custom(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); bool custom_schedule1[7] = {true, false, true, false, false, true, true}; alarm_set_custom(id, custom_schedule1); prv_assert_alarm_config(id, 3, 14, false, ALARM_KIND_CUSTOM, custom_schedule1); id = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); bool custom_schedule2[7] = {true, false, false, false, false, true, false}; alarm_set_custom(id, custom_schedule2); prv_assert_alarm_config(id, 4, 14, false, ALARM_KIND_CUSTOM, custom_schedule2); } void test_alarm__alarm_get_custom_days(void) { AlarmId id1, id2; bool schedule_1[7] = {true, false, false, false, false, false, true}; bool verify_schedule_1[7] = {false, false, false, false, false, false, false}; id1 = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 3, 14, false, ALARM_KIND_CUSTOM, schedule_1); alarm_get_custom_days(id1, verify_schedule_1); prv_assert_alarm_config(id1, 3, 14, false, ALARM_KIND_CUSTOM, verify_schedule_1); bool schedule_2[7] = {false, false, true, false, false, true, false}; bool verify_schedule_2[7] = {false, false, false, false, false, false, false}; id2 = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); alarm_set_custom(id2, schedule_2); prv_assert_alarm_config(id2, 4, 14, false, ALARM_KIND_CUSTOM, schedule_2); alarm_get_custom_days(id2, verify_schedule_2); prv_assert_alarm_config(id2, 4, 14, false, ALARM_KIND_CUSTOM, verify_schedule_2); } void test_alarm__alarm_get_string_for_custom(void) { bool schedule_1[7] = {true, false, false, false, false, false, true}; char alarm_day_text_1[32] = {0}; alarm_get_string_for_custom(schedule_1, alarm_day_text_1); cl_assert_equal_s(alarm_day_text_1, "Sat,Sun"); bool schedule_2[7] = {true, true, true, true, true, true, true}; char alarm_day_text_2[32] = {0}; alarm_get_string_for_custom(schedule_2, alarm_day_text_2); cl_assert_equal_s(alarm_day_text_2, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); bool schedule_3[7] = {false, true, false, false, false, false, false}; char alarm_day_text_3[32] = {0}; alarm_get_string_for_custom(schedule_3, alarm_day_text_3); cl_assert_equal_s(alarm_day_text_3, "Mondays"); bool schedule_4[7] = {false, false, true, false, false, false, false}; char alarm_day_text_4[32] = {0}; alarm_get_string_for_custom(schedule_4, alarm_day_text_4); cl_assert_equal_s(alarm_day_text_4, "Tuesdays"); bool schedule_5[7] = {false, false, false, true, false, false, false}; char alarm_day_text_5[32] = {0}; alarm_get_string_for_custom(schedule_5, alarm_day_text_5); cl_assert_equal_s(alarm_day_text_5, "Wednesdays"); bool schedule_6[7] = {false, false, false, false, true, false, false}; char alarm_day_text_6[32] = {0}; alarm_get_string_for_custom(schedule_6, alarm_day_text_6); cl_assert_equal_s(alarm_day_text_6, "Thursdays"); bool schedule_7[7] = {false, false, false, false, false, true, false}; char alarm_day_text_7[32] = {0}; alarm_get_string_for_custom(schedule_7, alarm_day_text_7); cl_assert_equal_s(alarm_day_text_7, "Fridays"); bool schedule_8[7] = {false, false, false, false, false, false, true}; char alarm_day_text_8[32] = {0}; alarm_get_string_for_custom(schedule_8, alarm_day_text_8); cl_assert_equal_s(alarm_day_text_8, "Saturdays"); bool schedule_9[7] = {true, false, false, false, false, false, false}; char alarm_day_text_9[32] = {0}; alarm_get_string_for_custom(schedule_9, alarm_day_text_9); cl_assert_equal_s(alarm_day_text_9, "Sundays"); } void test_alarm__alarm_set_get_enabled(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); cl_assert_equal_i(s_num_timeline_adds, 3); cl_assert_equal_i(s_num_timeline_removes, 0); alarm_set_enabled(id1, false); prv_assert_alarm_config(id1, 3, 14, true, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds, 3); cl_assert_equal_i(s_num_timeline_removes, 3); alarm_set_enabled(id1, true); prv_assert_alarm_config(id1, 3, 14, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds, 6); cl_assert_equal_i(s_num_timeline_removes, 3); id2 = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); cl_assert_equal_i(s_num_timeline_adds, 9); cl_assert_equal_i(s_num_timeline_removes, 3); alarm_set_enabled(id2, false); prv_assert_alarm_config(id2, 4, 14, true, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds, 12); cl_assert_equal_i(s_num_timeline_removes, 9); AlarmId invalid_id = 7; alarm_set_enabled(invalid_id, false); cl_assert_equal_i(s_num_timeline_adds, 12); cl_assert_equal_i(s_num_timeline_removes, 9); } void test_alarm__alarm_delete(void) { AlarmId id1, id2, id3, id4, id5, id6, id7; id1 = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); id2 = alarm_create(&(AlarmInfo) { .hour = 4, .minute = 14, .kind = ALARM_KIND_EVERYDAY }); alarm_delete(id1); prv_assert_alarm_config_absent(id1); assert_alarm_pins_absent(id1); alarm_delete(id2); prv_assert_alarm_config_absent(id2); assert_alarm_pins_absent(id2); id3 = alarm_create(&(AlarmInfo) { .hour = 13, .minute = 13, .kind = ALARM_KIND_WEEKDAYS }); id4 = alarm_create(&(AlarmInfo) { .hour = 14, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); id5 = alarm_create(&(AlarmInfo) { .hour = 15, .minute = 15, .kind = ALARM_KIND_WEEKDAYS }); id6 = alarm_create(&(AlarmInfo) { .hour = 16, .minute = 16, .kind = ALARM_KIND_WEEKDAYS }); alarm_delete(id4); prv_assert_alarm_config_absent(id4); assert_alarm_pins_absent(id4); id7 = alarm_create(&(AlarmInfo) { .hour = 17, .minute = 17, .kind = ALARM_KIND_WEEKENDS }); for (int i = 0; i < MAX_CONFIGURED_ALARMS; ++i) { alarm_delete(i); prv_assert_alarm_config_absent(i); assert_alarm_pins_absent(i); } alarm_delete(1); } void test_alarm__snooze_delay(void) { int delay; delay = alarm_get_snooze_delay(); cl_assert_equal_i(delay, 10); alarm_set_snooze_delay(15); delay = alarm_get_snooze_delay(); cl_assert_equal_i(delay, 15); } void test_alarm__set_snooze_alarm() { alarm_set_snooze_alarm(); cl_assert_equal_i(s_snooze_timer_timeout_ms, 10 * 1000); cl_assert_equal_i(s_num_alarm_events_put, 0); s_current_minute = 10; cl_assert_equal_i(s_num_alarm_events_put, 1); } void test_alarm__get_string_for_kind(void) { bool all_caps = false; cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_EVERYDAY, all_caps), "Every Day"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_WEEKDAYS, all_caps), "Weekdays"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_WEEKENDS, all_caps), "Weekends"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_JUST_ONCE, all_caps), "Once"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_CUSTOM, all_caps), "Custom"); all_caps = true; cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_EVERYDAY, all_caps), "EVERY DAY"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_WEEKDAYS, all_caps), "WEEKDAYS"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_WEEKENDS, all_caps), "WEEKENDS"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_JUST_ONCE, all_caps), "ONCE"); cl_assert_equal_s(alarm_get_string_for_kind(ALARM_KIND_CUSTOM, all_caps), "CUSTOM"); } void test_alarm__handle_clock_change(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 3, .minute = 14, .kind = ALARM_KIND_WEEKENDS }); id2 = alarm_create(&(AlarmInfo) { .hour = 13, .minute = 14, .kind = ALARM_KIND_WEEKDAYS }); s_current_hour = 12; s_current_minute = 14; alarm_handle_clock_change(); s_current_hour = 13; s_current_minute = 14; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////// //! Alarm Timeline Pin Tests void test_alarm__pin_add(void) { const AlarmId dummy_alarm_id = 0; const AlarmKind alarm_kind = ALARM_KIND_WEEKENDS; Uuid added_pin_uuid; alarm_pin_add(s_monday, dummy_alarm_id, AlarmType_Basic, alarm_kind, &added_pin_uuid); cl_assert(uuid_equal(&added_pin_uuid, &s_last_timeline_item_added->header.id)); AttributeList *pin_attr_list = &s_last_timeline_item_added->attr_list; const uint32_t pin_icon_tiny = attribute_get_uint32(pin_attr_list, AttributeIdIconTiny, 0); cl_assert_equal_i((int)pin_icon_tiny, TIMELINE_RESOURCE_ALARM_CLOCK); const char *pin_title = attribute_get_string(pin_attr_list, AttributeIdTitle, NULL); cl_assert_equal_s(pin_title, "Alarm"); const char *pin_subtitle = attribute_get_string(pin_attr_list, AttributeIdSubtitle, NULL); cl_assert_equal_s(pin_subtitle, alarm_get_string_for_kind(alarm_kind, false /* all_caps */)); const AlarmKind pin_alarm_kind = (AlarmKind)attribute_get_uint8(pin_attr_list, AttributeIdAlarmKind, 0); cl_assert_equal_i(pin_alarm_kind, alarm_kind); cl_assert_equal_i(s_last_timeline_item_added->action_group.num_actions, 1); const TimelineItemAction *alarm_action = s_last_timeline_item_added->action_group.actions; cl_assert_equal_i(alarm_action->id, dummy_alarm_id); cl_assert_equal_i(alarm_action->type, TimelineItemActionTypeOpenWatchApp); const AttributeList *action_attr_list = &alarm_action->attr_list; const char *action_title = attribute_get_string(action_attr_list, AttributeIdTitle, NULL); cl_assert_equal_s(action_title, "Edit"); } void test_alarm__pin_remove(void) { const AlarmId dummy_alarm_id = 0; Uuid pin_uuid; alarm_pin_add(s_monday, dummy_alarm_id, AlarmType_Basic, ALARM_KIND_WEEKENDS, &pin_uuid); alarm_pin_remove(&pin_uuid); cl_assert(uuid_equal(&pin_uuid, &s_last_timeline_item_removed_uuid)); } //////////////////////////////////////////////////////////////////////////////////////////////////// //! More Advanced Tests void test_alarm__recurring_daily_alarm_timeout_ahead(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds , 3); s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } void test_alarm__recurring_daily_alarm_timeout_behind(void) { AlarmId id; s_current_hour = 11; s_current_minute = 30; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds , 3); // Alarm set for tomorrow, so add 24 hours. s_current_hour = 10 + 24; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } void test_alarm__recurring_daily_alarm(void) { time_t next_alarm_time = 0; alarm_get_next_enabled_alarm(&next_alarm_time); cl_assert_equal_i(next_alarm_time, 0); AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds, 3); alarm_get_next_enabled_alarm(&next_alarm_time); cl_assert_equal_i(next_alarm_time, s_current_day + 10 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); cl_assert_equal_i(s_num_timeline_adds, 6); cl_assert_equal_i(s_num_timeline_removes, 0); alarm_get_next_enabled_alarm(&next_alarm_time); cl_assert_equal_i(next_alarm_time, s_current_day + 10 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); cl_assert_equal_i(s_num_alarm_events_put, 1); cl_assert_equal_i(s_num_timeline_adds, 13); cl_assert_equal_i(s_num_timeline_removes, 6); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); cl_assert_equal_i(s_num_alarm_events_put, 2); cl_assert_equal_i(s_num_timeline_adds, 20); cl_assert_equal_i(s_num_timeline_removes, 12); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_friday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); cl_assert_equal_i(s_num_alarm_events_put, 3); cl_assert_equal_i(s_num_timeline_adds, 27); cl_assert_equal_i(s_num_timeline_removes, 18); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 4); cl_assert_equal_i(s_num_alarm_events_put, 4); cl_assert_equal_i(s_num_timeline_adds, 34); cl_assert_equal_i(s_num_timeline_removes, 24); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 5); cl_assert_equal_i(s_num_alarm_events_put, 5); cl_assert_equal_i(s_num_timeline_adds, 41); cl_assert_equal_i(s_num_timeline_removes, 30); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 6); cl_assert_equal_i(s_num_alarm_events_put, 6); cl_assert_equal_i(s_num_timeline_adds, 48); cl_assert_equal_i(s_num_timeline_removes, 36); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_sunday; // Make sure the wday can wrap properly cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 7); cl_assert_equal_i(s_num_alarm_events_put, 7); cl_assert_equal_i(s_num_timeline_adds, 55); cl_assert_equal_i(s_num_timeline_removes, 42); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); } void test_alarm__recurring_weekends_alarm_timeout_ahead(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); // It's currently Thursday @ 00:00. The alarm shouldn't go off for over 2 days + 10:30 s_current_hour = 10; s_current_minute = 29; s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); // Only 1 pin should be added (for Saturday) cl_assert_equal_i(s_num_timeline_adds, 1); s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); cl_assert_equal_i(s_num_timeline_adds, 3); } void test_alarm__recurring_weekends_alarm_timeout_behind(void) { AlarmId id; s_current_hour = 11; s_current_minute = 30; s_current_day = s_saturday; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); // Only 1 pin should be added (for Sunday) cl_assert_equal_i(s_num_timeline_adds, 1); } void test_alarm__recurring_weekends_alarm(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); // Only 1 pin should be added (for Saturday) cl_assert_equal_i(s_num_timeline_adds, 1); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_WEEKENDS }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_WEEKENDS, s_weekend_schedule); cl_assert_equal_i(s_num_timeline_adds, 2); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); cl_assert_equal_i(s_num_alarm_events_put, 1); cl_assert_equal_i(s_num_timeline_adds, 6); cl_assert_equal_i(s_num_timeline_removes, 2); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); cl_assert_equal_i(s_num_alarm_events_put, 2); cl_assert_equal_i(s_num_timeline_adds, 9); cl_assert_equal_i(s_num_timeline_removes, 5); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_sunday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); cl_assert_equal_i(s_num_alarm_events_put, 3); cl_assert_equal_i(s_num_timeline_adds, 11); cl_assert_equal_i(s_num_timeline_removes, 7); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again, but not until Saturday s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 4); cl_assert_equal_i(s_num_alarm_events_put, 4); cl_assert_equal_i(s_num_timeline_adds, 12); cl_assert_equal_i(s_num_timeline_removes, 8); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); } void test_alarm__recurring_weekday_alarm_timeout_ahead(void) { AlarmId id; s_current_day = s_saturday; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); // Only 1 pin should be added (for Monday) cl_assert_equal_i(s_num_timeline_adds, 1); } void test_alarm__recurring_weekday_alarm_timeout_behind(void) { AlarmId id; s_current_hour = 11; s_current_minute = 30; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); // Only 1 pin should be added (for Friday) cl_assert_equal_i(s_num_timeline_adds, 1); } void test_alarm__recurring_weekday_alarm(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); // 2 pins should be added (for Thursday / Friday) cl_assert_equal_i(s_num_timeline_adds, 2); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); cl_assert_equal_i(s_num_timeline_adds, 4); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); cl_assert_equal_i(s_num_alarm_events_put, 1); cl_assert_equal_i(s_num_timeline_adds, 8); cl_assert_equal_i(s_num_timeline_removes, 4); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); cl_assert_equal_i(s_num_alarm_events_put, 2); cl_assert_equal_i(s_num_timeline_adds, 11); cl_assert_equal_i(s_num_timeline_removes, 7); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_friday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); cl_assert_equal_i(s_num_alarm_events_put, 3); cl_assert_equal_i(s_num_timeline_adds, 14); cl_assert_equal_i(s_num_timeline_removes, 9); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again, but not until Monday s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 4); cl_assert_equal_i(s_num_alarm_events_put, 4); cl_assert_equal_i(s_num_timeline_adds, 17); cl_assert_equal_i(s_num_timeline_removes, 11); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); } void test_alarm__just_once_alarm_timeout_ahead(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_JUST_ONCE }); // It's currently Thursday @ 00:00 bool just_once_schedule_thursday[7] = {false, false, false, false, true, false, false}; prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); // Only 1 pin should be added cl_assert_equal_i(s_num_timeline_adds, 1); } void test_alarm__just_once_alarm_timeout_behind(void) { AlarmId id; s_current_hour = 11; s_current_minute = 30; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_JUST_ONCE }); bool just_once_schedule_friday[7] = {false, false, false, false, false, true, false}; prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_JUST_ONCE, just_once_schedule_friday); // Only 1 pin should be added cl_assert_equal_i(s_num_timeline_adds, 1); } void test_alarm__just_once_alarm(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_JUST_ONCE }); // It's currently Thursday @ 00:00 bool just_once_schedule_thursday[7] = {false, false, false, false, true, false, false}; prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); // Only 1 pin should be added cl_assert_equal_i(s_num_timeline_adds, 1); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); // Only 1 pin should be added cl_assert_equal_i(s_num_timeline_adds, 2); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); prv_assert_alarm_config(id1, 10, 30, true, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); cl_assert_equal_i(s_num_alarm_events_put, 1); cl_assert_equal_i(s_num_timeline_adds, 4); cl_assert_equal_i(s_num_timeline_removes, 2); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. No alarms should be up s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); prv_assert_alarm_config(id2, 11, 30, true, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); cl_assert_equal_i(s_num_alarm_events_put, 2); cl_assert_equal_i(s_num_timeline_adds, 5); cl_assert_equal_i(s_num_timeline_removes, 3); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); } void test_alarm__custom_alarm_everyday(void) { AlarmId id1; bool schedule_1[7] = {true, true, true, true, true, true, true}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_CUSTOM, schedule_1); // It's currently Thursday @ 00:00. s_current_day = s_friday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); s_current_day = s_sunday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); s_current_day = s_monday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 4); s_current_day = s_tuesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 5); s_current_day = s_wednesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 6); } void test_alarm__custom_alarm_weekends_and_weekday(void) { AlarmId id1; bool schedule_1[7] = {true, false, false, true, false, false, true}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_CUSTOM, schedule_1); // It's currently Thursday @ 00:00. s_current_day = s_friday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); s_current_day = s_sunday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_monday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); s_current_day = s_tuesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); s_current_day = s_wednesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); } void test_alarm__custom_alarm_partial_weekdays(void) { AlarmId id1; bool schedule_1[7] = {false, true, true, true, true, false, false}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_CUSTOM, schedule_1); // It's currently Thursday @ 00:00. s_current_day = s_friday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_sunday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_monday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_tuesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); s_current_day = s_wednesday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); } void test_alarm__custom_alarm_weekends(void) { AlarmId id1, id2; bool schedule_1[7] = {true, false, false, false, false, false, true}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_CUSTOM, schedule_1); // Only 1 pin should be added (for Saturday) cl_assert_equal_i(s_num_timeline_adds, 1); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_CUSTOM, schedule_1); cl_assert_equal_i(s_num_timeline_adds, 2); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_saturday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); cl_assert_equal_i(s_num_alarm_events_put, 1); cl_assert_equal_i(s_num_timeline_adds, 6); cl_assert_equal_i(s_num_timeline_removes, 2); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); cl_assert_equal_i(s_num_alarm_events_put, 2); cl_assert_equal_i(s_num_timeline_adds, 9); cl_assert_equal_i(s_num_timeline_removes, 5); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // First alarm goes off. Second one should be up s_current_hour = 10; s_current_minute = 30; s_current_day = s_sunday; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 3); cl_assert_equal_i(s_num_alarm_events_put, 3); cl_assert_equal_i(s_num_timeline_adds, 11); cl_assert_equal_i(s_num_timeline_removes, 7); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); // Second alarm goes off. First one should be up again, but not until Saturday s_current_hour = 11; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 4); cl_assert_equal_i(s_num_alarm_events_put, 4); cl_assert_equal_i(s_num_timeline_adds, 12); cl_assert_equal_i(s_num_timeline_removes, 8); cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time()); } void test_alarm__custom_alarm_no_alarm(void) { AlarmId id1; bool schedule_1[7] = {false, false, false, false, false, false, false}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_CUSTOM, schedule_1); cl_assert_equal_i(s_alarm_timer_timeout_ms, 0); } void test_alarm__custom_alarm_multiple(void) { AlarmId id1, id2; // Alarm set for Tuesday and Saturday bool schedule_1[7] = {false, false, true, false, false, false, true}; id1 = alarm_create(&(AlarmInfo) { .hour = 1, .minute = 30, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_1 }); prv_assert_alarm_config(id1, 1, 30, false, ALARM_KIND_CUSTOM, schedule_1); // It's currently Thursday @ 00:00, 2 days + 1:30 till next alarm /* cl_assert_equal_i(s_alarm_timer_timeout_ms, */ /* (SECONDS_PER_DAY * 2 + prv_hours_and_minutes_to_seconds(1, 30)) * 1000); */ s_current_day = s_sunday; s_current_hour = 12; s_current_minute = 15; cron_service_wakeup(); bool schedule_2[7] = {false, true, false, false, false, false, false}; id2 = alarm_create(&(AlarmInfo) { .hour = 13, .minute = 15, .kind = ALARM_KIND_CUSTOM, .scheduled_days = &schedule_2 }); prv_assert_alarm_config(id2, 13, 15, false, ALARM_KIND_CUSTOM, schedule_2); cl_assert_equal_i(s_num_alarms_fired, 1); s_current_day = s_tuesday; s_current_hour = 1; s_current_minute = 0; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 2); } void test_alarm__disable_upcoming_alarm(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); // Disable the 10:30 alarm alarm_set_enabled(id1, false); // The 10:30 alarm should not have gone off s_current_hour = 11; s_current_minute = 0; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); // Disable the 11:30 alarm alarm_set_enabled(id2, false); // The 11:30 alarm should not go off either s_current_hour = 12; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); // Enable the 11:30 alarm - now it should go off s_current_hour = 11; alarm_set_enabled(id2, true); s_current_hour = 12; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } void test_alarm__delete_upcoming_alarm(void) { AlarmId id1, id2; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id1, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); id2 = alarm_create(&(AlarmInfo) { .hour = 11, .minute = 30, .kind = ALARM_KIND_EVERYDAY }); prv_assert_alarm_config(id2, 11, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule); // Delete the 10:30 alarm alarm_delete(id1); // The 10:30 alarm should not go off s_current_hour = 11; s_current_minute = 0; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); // Delete the 11:30 alarm alarm_delete(id2); // The 11:30 alarm should not go off either s_current_hour = 12; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); } void test_alarm__alarm_type_change_updates_timeout(void) { AlarmId id; id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_WEEKDAYS, s_weekday_schedule); // 2 pins should be added (for Thursday / Friday) cl_assert_equal_i(s_num_timeline_adds, 2); alarm_set_kind(id, ALARM_KIND_WEEKENDS); // Alarm should not go off on Thursday anymore s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 0); // Alarm should go off on the weekend s_current_day = s_saturday; s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } void test_alarm__alarm_get_next_enabled_alarm(void) { // Declarations time_t next_alarm = 0; time_t time_until_alarm = 0; bool at_least_one_alarm_enabled = false; bool alarm_is_scheduled = false; AlarmId id1, id2; // No alarms scheduled at_least_one_alarm_enabled = alarm_get_next_enabled_alarm(&next_alarm); cl_assert_equal_b(at_least_one_alarm_enabled, false); cl_assert_equal_i(next_alarm, 0); // Schedule an alarm, it becomes the next alarm id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); at_least_one_alarm_enabled = alarm_get_next_enabled_alarm(&next_alarm); cl_assert_equal_b(at_least_one_alarm_enabled, true); alarm_is_scheduled = alarm_get_time_until(id1, &time_until_alarm); cl_assert_equal_b(alarm_is_scheduled, true); cl_assert_equal_i(next_alarm, rtc_get_time() + time_until_alarm); // Schedule another alarm before the previous alarm, it becomes the next alarm id2 = alarm_create(&(AlarmInfo) { .hour = 9, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); at_least_one_alarm_enabled = alarm_get_next_enabled_alarm(&next_alarm); cl_assert_equal_b(at_least_one_alarm_enabled, true); alarm_is_scheduled = alarm_get_time_until(id2, &time_until_alarm); cl_assert_equal_b(alarm_is_scheduled, true); cl_assert_equal_i(next_alarm, rtc_get_time() + time_until_alarm); // Disable both alarms, now there is no next alarm alarm_set_enabled(id1, false); alarm_set_enabled(id2, false); at_least_one_alarm_enabled = alarm_get_next_enabled_alarm(&next_alarm); cl_assert_equal_b(at_least_one_alarm_enabled, false); } void test_alarm__alarm_is_next_enabled_alarm_smart(void) { // Declarations AlarmId id1; AlarmId id2; AlarmId id3; // No alarms scheduled, our function should return false cl_assert_equal_b(alarm_is_next_enabled_alarm_smart(), false); // Schedule a basic (non-smart) alarm, our function should return false id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); cl_assert_equal_b(alarm_is_next_enabled_alarm_smart(), false); // Schedule a smart alarm before the basic alarm, our function should return true id2 = alarm_create(&(AlarmInfo) { .hour = 9, .minute = 30, .is_smart = true }); cl_assert_equal_b(alarm_is_next_enabled_alarm_smart(), true); // Schedule another basic alarm before the smart alarm, our function should return false again id3 = alarm_create(&(AlarmInfo) { .hour = 8, .minute = 30, .kind = ALARM_KIND_WEEKDAYS }); cl_assert_equal_b(alarm_is_next_enabled_alarm_smart(), false); // Disable all three alarms, now there is no next alarm and so our function should return false alarm_set_enabled(id1, false); alarm_set_enabled(id2, false); alarm_set_enabled(id3, false); cl_assert_equal_b(alarm_is_next_enabled_alarm_smart(), false); } void test_alarm__skip_two_alarms(void) { AlarmId id1, id2; bool just_once_schedule_thursday[7] = {false, false, false, false, true, false, false}; id1 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 10, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id1, 10, 10, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); id2 = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 20, .kind = ALARM_KIND_JUST_ONCE }); prv_assert_alarm_config(id2, 10, 20, false, ALARM_KIND_JUST_ONCE, just_once_schedule_thursday); // Skip ahead of both alarms // One of the alarms should go off s_current_hour = 10; s_current_minute = 30; cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); // The other alarm should not go off cron_service_wakeup(); cl_assert_equal_i(s_num_alarms_fired, 1); } // TODO: // - Test disable while snoozing // - Test delete while snoozing