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

502 lines
18 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 "clar.h"
#include "util/uuid.h"
#include "services/normal/filesystem/pfs.h"
#include "services/common/regular_timer.h"
#include "services/normal/blob_db/pin_db.h"
#include "services/normal/timeline/timeline.h"
#include "apps/system_apps/timeline/timeline_model.h"
#include "util/size.h"
// Fixture
////////////////////////////////////////////////////////////////
// Fakes
////////////////////////////////////////////////////////////////
#include "fake_spi_flash.h"
#include "fake_pbl_malloc.h"
#include "fake_rtc.h"
static TimezoneInfo tz = {
.tm_gmtoff = -8 * 60 * 60, // PST
};
// Stubs
////////////////////////////////////////////////////////////////
#include "stubs_analytics.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_calendar.h"
#include "stubs_event_service_client.h"
#include "stubs_events.h"
#include "stubs_fonts.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_passert.h"
#include "stubs_pebble_tasks.h"
#include "stubs_prompt.h"
#include "stubs_rand_ptr.h"
#include "stubs_regular_timer.h"
#include "stubs_resources.h"
#include "stubs_session.h"
#include "stubs_sleep.h"
#include "stubs_syscalls.h"
#include "stubs_task_watchdog.h"
#include "stubs_window_stack.h"
void ancs_notifications_enable_bulk_action_mode(bool enable) {
return;
}
bool ancs_notifications_is_bulk_action_mode_enabled(void) {
return false;
}
status_t reminder_db_delete_with_parent(const TimelineItemId *id) {
return S_SUCCESS;
}
void timeline_action_endpoint_invoke_action(const Uuid *id,
uint8_t action_id, AttributeList *attributes) {
}
void launcher_task_add_callback(void (*callback)(void *data), void *data) {
}
void timeline_pin_window_push_modal(TimelineItem *item) {
}
const PebbleProcessMd *timeline_get_app_info(void) {
return NULL;
}
PebblePhoneCaller* phone_call_util_create_caller(const char *number, const char *name) {
return NULL;
}
void ancs_perform_action(uint32_t notification_uid, uint8_t action_id) {
}
void notifications_handle_notification_action_result(
PebbleSysNotificationActionResult *action_result) {
}
void notification_storage_set_status(const Uuid *id, uint8_t status) {
}
void notifications_handle_notification_acted_upon(Uuid *notification_id) {
return;
}
// Data
/////////////////////////
static TimelineItem s_items[] = {
{
.header = { // [0]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb1},
.parent_id = {0},
.timestamp = 1421178061, // Tue Jan 13 11:41:01 2015 PST
.duration = 1,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}, {
.header = { // [1]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb2},
.parent_id = {0},
.timestamp = 1421183642, // Tue Jan 13 13:14:02 2015 PST
.duration = 10,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}, {
.header = { // [2]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb3},
.parent_id = {0},
.timestamp = 1421183642, // Tue Jan 13 13:14:02 2015 PST
.duration = 2,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}, {
.header = { // [3]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4},
.parent_id = {0},
.timestamp = 1421183642, // Tue Jan 13 13:14:02 2015 PST
.duration = 30,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}, {
.header = { // [4]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb5},
.parent_id = {0},
.timestamp = 1421178061, // Tue Jan 13 11:41:01 2015 PST
.duration = 5,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}, {
.header = { // [5]
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb6},
.parent_id = {0},
.timestamp = 1421183462, // Tue Jan 13 13:11:02 PST 2015
.duration = 4,
.type = TimelineItemTypePin,
.flags = 0,
.layout = LayoutIdTest,
},
.attr_list = {
.num_attributes = 0,
.attributes = NULL,
},
.action_group = {
.num_actions = 0,
.actions = NULL,
},
.allocated_buffer = NULL,
}
};
// Setup
/////////////////////////
void test_timeline_model__initialize(void) {
fake_spi_flash_init(0, 0x1000000);
fake_rtc_init(0, 0);
pfs_init(false);
// Note: creating a settings file is going to result in one malloc for the FD name
pin_db_init();
time_util_update_timezone(&tz);
fake_pbl_malloc_clear_tracking();
for (unsigned int i = 0; i < ARRAY_LENGTH(s_items); ++i) {
cl_assert_equal_i(pin_db_insert_item(&s_items[i]), 0);
}
cl_assert_equal_i(fake_pbl_malloc_num_net_allocs(), 0);
}
void test_timeline_model__cleanup(void) {
}
// Tests
///////////////////////////
static int s_correct_order[] = {0, 4, 5, 2, 1, 3};
void test_timeline_model__future(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[0]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(0));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(1));
int new_idx;
bool has_next;
cl_assert(timeline_model_iter_next(&new_idx, &has_next));
cl_assert(has_next);
cl_assert_equal_i(new_idx, 2);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[0]].header.id,
&timeline_model_get_iter_state(-1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(1));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(2));
cl_assert(timeline_model_iter_next(&new_idx, &has_next));
cl_assert(has_next);
cl_assert_equal_i(new_idx, 3);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(-1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(2));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(3));
cl_assert(timeline_model_iter_next(&new_idx, &has_next));
cl_assert(has_next);
cl_assert_equal_i(new_idx, 4);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(-1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(3));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(4));
cl_assert(timeline_model_iter_next(&new_idx, &has_next));
cl_assert(has_next);
cl_assert_equal_i(new_idx, 5);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(-1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[5]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(4));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(5));
cl_assert(timeline_model_iter_next(&new_idx, &has_next));
cl_assert(!has_next);
cl_assert_equal_i(timeline_model_get_num_items(), 1);
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(-1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[5]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(!timeline_model_iter_next(&new_idx, &has_next));
}
void test_timeline_model__and_back(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
cl_assert(timeline_model_iter_next(NULL, NULL));
cl_assert(timeline_model_iter_next(NULL, NULL));
cl_assert(timeline_model_iter_next(NULL, NULL));
cl_assert(timeline_model_iter_next(NULL, NULL));
cl_assert(timeline_model_iter_next(NULL, NULL));
cl_assert(!timeline_model_iter_next(NULL, NULL));
int new_idx;
cl_assert(timeline_model_iter_prev(&new_idx, NULL));
cl_assert_equal_i(new_idx, 4);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[5]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(4));
cl_assert(timeline_model_iter_prev(&new_idx, NULL));
cl_assert_equal_i(new_idx, 3);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[5]].header.id,
&timeline_model_get_iter_state(2)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(3));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(4));
cl_assert(timeline_model_get_iter_state(2) == timeline_model_get_iter_state_with_timeline_idx(5));
cl_assert(timeline_model_iter_prev(&new_idx, NULL));
cl_assert_equal_i(new_idx, 2);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[4]].header.id,
&timeline_model_get_iter_state(2)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(2));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(3));
cl_assert(timeline_model_get_iter_state(2) == timeline_model_get_iter_state_with_timeline_idx(4));
cl_assert(timeline_model_iter_prev(&new_idx, NULL));
cl_assert_equal_i(new_idx, 1);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[3]].header.id,
&timeline_model_get_iter_state(2)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(1));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(2));
cl_assert(timeline_model_get_iter_state(2) == timeline_model_get_iter_state_with_timeline_idx(3));
cl_assert(timeline_model_iter_prev(&new_idx, NULL));
cl_assert_equal_i(new_idx, 0);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[0]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(2)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(0));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(1));
cl_assert(timeline_model_get_iter_state(2) == timeline_model_get_iter_state_with_timeline_idx(2));
cl_assert(!timeline_model_iter_prev(&new_idx, NULL));
}
void test_timeline_model__graceful_delete_middle(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
timeline_model_remove(&s_items[s_correct_order[1]].header.id);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[0]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(0));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(2));
}
void test_timeline_model__graceful_delete_first(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
timeline_model_remove(&s_items[s_correct_order[0]].header.id);
cl_assert_equal_i(timeline_model_get_num_items(), 2);
cl_assert(uuid_equal(&s_items[s_correct_order[1]].header.id,
&timeline_model_get_iter_state(0)->pin.header.id));
cl_assert(uuid_equal(&s_items[s_correct_order[2]].header.id,
&timeline_model_get_iter_state(1)->pin.header.id));
cl_assert(timeline_model_get_iter_state(0) == timeline_model_get_iter_state_with_timeline_idx(1));
cl_assert(timeline_model_get_iter_state(1) == timeline_model_get_iter_state_with_timeline_idx(2));
}
void test_timeline_model__graceful_delete_all(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
for (int i = 0; i < ARRAY_LENGTH(s_items); i++) {
timeline_model_remove(&s_items[i].header.id);
}
cl_assert_equal_i(timeline_model_get_num_items(), 0);
cl_assert(!timeline_model_iter_next(NULL, NULL));
cl_assert(!timeline_model_iter_prev(NULL, NULL));
}
void test_timeline_model__is_empty(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
timeline_model_init(first_time, &model);
cl_assert(!timeline_model_is_empty());
for (int i = 0; i < ARRAY_LENGTH(s_items); i++) {
timeline_model_remove(&s_items[i].header.id);
}
cl_assert(timeline_model_is_empty());
}
void test_timeline_model__is_empty_immediate(void) {
TimelineModel model = {0};
model.direction = TimelineIterDirectionFuture;
time_t first_time = 1421178000;
// Note: 1421178000 = Tue Jan 13 11:40:00 PST 2015
for (int i = 0; i < ARRAY_LENGTH(s_items); i++) {
pin_db_delete((uint8_t *)&s_items[i].header.id, sizeof(TimelineItemId));
}
timeline_model_init(first_time, &model);
cl_assert(timeline_model_is_empty());
}