mirror of
https://github.com/google/pebble.git
synced 2025-08-10 08:28:10 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
91
tests/fw/services/timeline/test_alarm_layout.c
Normal file
91
tests/fw/services/timeline/test_alarm_layout.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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 "services/common/clock.h"
|
||||
#include "services/normal/alarms/alarm.h"
|
||||
#include "services/normal/timeline/alarm_layout.h"
|
||||
#include "services/normal/timeline/attribute.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stubs_activity.h"
|
||||
#include "stubs_alarm_pin.h"
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_clock.h"
|
||||
#include "stubs_cron.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_i18n.h"
|
||||
#include "stubs_layout_node.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_new_timer.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_rtc.h"
|
||||
#include "stubs_settings_file.h"
|
||||
#include "stubs_system_task.h"
|
||||
#include "stubs_timeline_event.h"
|
||||
#include "stubs_timeline_layout.h"
|
||||
|
||||
// Functions under test
|
||||
/////////////////////////
|
||||
|
||||
void prv_get_subtitle_from_attributes(AttributeList *attributes, char *buffer, size_t buffer_size,
|
||||
const void *i18n_owner);
|
||||
|
||||
// Setup
|
||||
/////////////////////////
|
||||
|
||||
void test_alarm_layout__initialize(void) {
|
||||
|
||||
}
|
||||
|
||||
void test_alarm_layout__cleanup(void) {
|
||||
|
||||
}
|
||||
|
||||
// Tests
|
||||
///////////////////////////
|
||||
|
||||
void test_alarm_layout__get_subtitle_from_attributes(void) {
|
||||
char buffer[TIME_STRING_REQUIRED_LENGTH] = {0};
|
||||
const size_t buffer_size = sizeof(buffer);
|
||||
|
||||
const void *dummy_i18n_owner = (void *)1234;
|
||||
|
||||
AttributeList attribute_list = {0};
|
||||
AttributeList *attribute_list_ref = &attribute_list;
|
||||
|
||||
// For legacy reasons (see PBL-33899), an alarm pin that only has a subtitle attribute should use
|
||||
// that subtitle, manually making it all-caps using toupper_str() on rectangular displays
|
||||
attribute_list_add_cstring(attribute_list_ref, AttributeIdSubtitle, "Weekdays");
|
||||
prv_get_subtitle_from_attributes(attribute_list_ref, buffer, buffer_size, dummy_i18n_owner);
|
||||
cl_assert_equal_s(buffer, PBL_IF_RECT_ELSE("WEEKDAYS", "Weekdays"));
|
||||
|
||||
// An alarm pin that has both a subtitle attribute and an AlarmKind attribute should create the
|
||||
// subtitle using the AlarmKind (ignoring the subtitle attribute), respecting the desire to
|
||||
// all-caps the subtitle on rectangular displays
|
||||
attribute_list = (AttributeList) {0};
|
||||
attribute_list_add_cstring(attribute_list_ref, AttributeIdSubtitle, "Ignore me!");
|
||||
attribute_list_add_uint8(attribute_list_ref, AttributeIdAlarmKind, (uint8_t)ALARM_KIND_JUST_ONCE);
|
||||
prv_get_subtitle_from_attributes(attribute_list_ref, buffer, buffer_size, dummy_i18n_owner);
|
||||
cl_assert_equal_s(buffer, PBL_IF_RECT_ELSE("ONCE", "Once"));
|
||||
attribute_list_destroy_list(attribute_list_ref);
|
||||
}
|
372
tests/fw/services/timeline/test_attribute.c
Normal file
372
tests/fw/services/timeline/test_attribute.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* 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 "services/normal/timeline/attribute.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
static Attribute action1_attributes[] = {
|
||||
{.id = AttributeIdTitle, .cstring = "Dismiss"},
|
||||
};
|
||||
|
||||
static Attribute action2_attributes[] = {
|
||||
{.id = AttributeIdTitle, .cstring = "Like"},
|
||||
{.id = AttributeIdAncsAction, .int8 = 1}
|
||||
};
|
||||
|
||||
static Attribute attributes[] = {
|
||||
{.id = AttributeIdTitle, .cstring = "Test Notification"},
|
||||
{.id = AttributeIdSubtitle, .cstring = "Subtitle"},
|
||||
{.id = AttributeIdBody, .cstring = "This is a test notification. "
|
||||
"Look at it and behold the awesome."},
|
||||
};
|
||||
|
||||
void test_attribute__initialize(void) {
|
||||
}
|
||||
|
||||
void test_attribute__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_attribute__uint32_list(void) {
|
||||
AttributeList attr_list = {};
|
||||
uint8_t metric_buffer[Uint32ListSize(3)];
|
||||
Uint32List *metric_values = (Uint32List *)metric_buffer;
|
||||
metric_values->num_values = 3;
|
||||
metric_values->values[0] = 100;
|
||||
metric_values->values[1] = 200;
|
||||
metric_values->values[2] = 300;
|
||||
attribute_list_add_uint32_list(&attr_list, AttributeIdMetricIcons, metric_values);
|
||||
|
||||
Uint32List *other = attribute_get_uint32_list(&attr_list, AttributeIdMetricIcons);
|
||||
for (int i = 0; i < metric_values->num_values; i++) {
|
||||
cl_assert_equal_i(metric_values->values[i], other->values[i]);
|
||||
}
|
||||
|
||||
const size_t serialized_size = attribute_list_get_serialized_size(&attr_list);
|
||||
cl_assert_equal_i(serialized_size, 19);
|
||||
uint8_t serialized_buffer[serialized_size];
|
||||
attribute_list_serialize(&attr_list, serialized_buffer, &serialized_buffer[serialized_size]);
|
||||
|
||||
const size_t buffer_size = attribute_list_get_string_buffer_size(&attr_list);
|
||||
uint8_t deserialized_buffer[buffer_size];
|
||||
|
||||
AttributeList attr_list_out = {};
|
||||
attribute_list_init_list(attr_list.num_attributes, &attr_list_out);
|
||||
const uint8_t *buffer = (uint8_t *)deserialized_buffer;
|
||||
const uint8_t *cursor = serialized_buffer;
|
||||
attribute_deserialize_list((char **)&buffer, (char *)&deserialized_buffer[buffer_size],
|
||||
&cursor, &serialized_buffer[serialized_size],
|
||||
attr_list_out);
|
||||
other = attribute_get_uint32_list(&attr_list_out, AttributeIdMetricIcons);
|
||||
for (int i = 0; i < metric_values->num_values; i++) {
|
||||
cl_assert_equal_i(metric_values->values[i], other->values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void prv_check_attribute_list_serialize(AttributeList *attr_list_to_serialize,
|
||||
const uint8_t *expected_attr_list_serialized,
|
||||
size_t expected_attr_list_serialized_size) {
|
||||
uint8_t buffer[expected_attr_list_serialized_size];
|
||||
const size_t size = attribute_list_serialize(attr_list_to_serialize, buffer,
|
||||
buffer + expected_attr_list_serialized_size);
|
||||
cl_assert_equal_i(size, expected_attr_list_serialized_size);
|
||||
cl_assert_equal_m(expected_attr_list_serialized, buffer, expected_attr_list_serialized_size);
|
||||
}
|
||||
|
||||
void test_attribute__serialize_attr_list(void) {
|
||||
AttributeList attr_list1 = {
|
||||
.num_attributes = ARRAY_LENGTH(action1_attributes),
|
||||
.attributes = action1_attributes
|
||||
};
|
||||
AttributeList attr_list2 = {
|
||||
.num_attributes = ARRAY_LENGTH(action2_attributes),
|
||||
.attributes = action2_attributes
|
||||
};
|
||||
AttributeList attr_list3 = {
|
||||
.num_attributes = ARRAY_LENGTH(attributes),
|
||||
.attributes = attributes
|
||||
};
|
||||
|
||||
static uint8_t attr_list1_serialized[] = {
|
||||
// Action Attributes
|
||||
0x01, // Attribute ID - Title
|
||||
0x07, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'D', 'i', 's', 'm', 'i', 's', 's',
|
||||
};
|
||||
|
||||
static uint8_t attr_list2_serialized[] = {
|
||||
0x01, // Attribute 1 ID - Title
|
||||
0x04, 0x00, // Attribute 1 Length
|
||||
// Attribute text:
|
||||
'L', 'i', 'k', 'e',
|
||||
0x07, // Attribute 2 ID - ANCS UID
|
||||
0x01, 0x00, // Attribute 2 Length
|
||||
// Attribute text: "Test"
|
||||
0x01
|
||||
};
|
||||
|
||||
static uint8_t attr_list3_serialized[] = {
|
||||
// Attribute 1
|
||||
0x01, // Attribute ID - Title
|
||||
0x11, 0x00, // Attribute Length
|
||||
// Attribute text: "Test Notification"
|
||||
0x54, 0x65, 0x73, 0x74, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e,
|
||||
|
||||
// Attribute 2
|
||||
0x02, // Attribute ID - Subtitle
|
||||
0x08, 0x00, // Attribute Length
|
||||
// Attribute text: "Subtitle"
|
||||
'S', 'u', 'b', 't', 'i', 't', 'l', 'e',
|
||||
|
||||
// Attribute 3
|
||||
0x03, // Attribute ID - Body
|
||||
0x3f, 0x00, // Attribute Length
|
||||
// Attribute text: "This is a test notification. Look at it and behold the awesome."
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x4c, 0x6f, 0x6f,
|
||||
0x6b, 0x20, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x65, 0x68, 0x6f,
|
||||
0x6c, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x2e,
|
||||
};
|
||||
|
||||
prv_check_attribute_list_serialize(&attr_list1, attr_list1_serialized,
|
||||
sizeof(attr_list1_serialized));
|
||||
prv_check_attribute_list_serialize(&attr_list2, attr_list2_serialized,
|
||||
sizeof(attr_list2_serialized));
|
||||
prv_check_attribute_list_serialize(&attr_list3, attr_list3_serialized,
|
||||
sizeof(attr_list3_serialized));
|
||||
}
|
||||
|
||||
void test_attribute__attributes_add_to_list(void) {
|
||||
static const uint32_t value_uint32 = 123123423;
|
||||
static const uint8_t value_uint8 = 17;
|
||||
|
||||
AttributeList list = {0};
|
||||
|
||||
attribute_list_add_cstring(&list, AttributeIdTitle, "Title1");
|
||||
cl_assert_equal_s(attribute_get_string(&list, AttributeIdTitle, ""), "Title1");
|
||||
cl_assert_equal_i(list.num_attributes, 1);
|
||||
|
||||
attribute_list_add_cstring(&list, AttributeIdSubtitle, "Subtitle");
|
||||
cl_assert_equal_s(attribute_get_string(&list, AttributeIdSubtitle, ""), "Subtitle");
|
||||
cl_assert_equal_s(attribute_get_string(&list, AttributeIdTitle, ""), "Title1");
|
||||
cl_assert_equal_i(list.num_attributes, 2);
|
||||
|
||||
attribute_list_add_cstring(&list, AttributeIdTitle, "Title2");
|
||||
cl_assert_equal_s(attribute_get_string(&list, AttributeIdTitle, ""), "Title2");
|
||||
cl_assert_equal_s(attribute_get_string(&list, AttributeIdSubtitle, ""), "Subtitle");
|
||||
cl_assert_equal_i(list.num_attributes, 2);
|
||||
|
||||
attribute_list_add_uint32(&list, AttributeIdLastUpdated, value_uint32);
|
||||
attribute_list_add_uint8(&list, AttributeIdBgColor, value_uint8);
|
||||
cl_assert_equal_i(value_uint32, attribute_get_uint32(&list, AttributeIdLastUpdated, 0));
|
||||
cl_assert_equal_i(value_uint8, attribute_get_uint8(&list, AttributeIdBgColor, 0));
|
||||
cl_assert_equal_i(list.num_attributes, 4);
|
||||
|
||||
attribute_list_destroy_list(&list);
|
||||
}
|
||||
|
||||
void test_attribute__attribute_list_copy(void) {
|
||||
AttributeList list = {0};
|
||||
attribute_list_add_cstring(&list, AttributeIdTitle, "Title");
|
||||
attribute_list_add_cstring(&list, AttributeIdSubtitle, "Subtitle");
|
||||
attribute_list_add_cstring(&list, AttributeIdBody, "Body");
|
||||
|
||||
// title + subtitle + body + 3 * (attributeid + pointer)
|
||||
size_t size_list = attribute_list_get_buffer_size(&list);
|
||||
cl_assert_equal_i(size_list, (5 + 1) + (8 + 1) + (4 + 1) + 3 * sizeof(Attribute));
|
||||
uint8_t *buffer = kernel_malloc_check(size_list);
|
||||
uint8_t *buffer_orig = buffer;
|
||||
AttributeList list2 = {0};
|
||||
cl_assert(attribute_list_copy(&list2, &list, buffer, buffer + size_list));
|
||||
// check that we haven't modified buffer
|
||||
cl_assert(buffer == buffer_orig);
|
||||
cl_assert_equal_s(attribute_get_string(&list2, AttributeIdTitle, ""), "Title");
|
||||
cl_assert_equal_s(attribute_get_string(&list2, AttributeIdSubtitle, ""), "Subtitle");
|
||||
cl_assert_equal_s(attribute_get_string(&list2, AttributeIdBody, ""), "Body");
|
||||
|
||||
// check that the pointers have moved
|
||||
cl_assert(attribute_get_string(&list2, AttributeIdTitle, "") !=
|
||||
attribute_get_string(&list, AttributeIdTitle, ""));
|
||||
cl_assert(attribute_get_string(&list2, AttributeIdSubtitle, "") !=
|
||||
attribute_get_string(&list, AttributeIdSubtitle, ""));
|
||||
cl_assert(attribute_get_string(&list2, AttributeIdBody, "") !=
|
||||
attribute_get_string(&list, AttributeIdBody, ""));
|
||||
attribute_list_destroy_list(&list);
|
||||
kernel_free(buffer);
|
||||
}
|
||||
|
||||
static void prv_check_app_glance_subtitle_in_attribute_list_deserializes(
|
||||
const uint8_t *serialized_attribute_list_to_deserialize,
|
||||
size_t serialized_attribute_list_to_deserialize_size, uint8_t num_attributes,
|
||||
const char *expected_app_glance_subtitle_after_deserializing) {
|
||||
|
||||
// Get the buffer size needed for the attributes we're going to deserialize
|
||||
// We don't have a value to check this against but we implicitly check it because if it's
|
||||
// incorrect then the overall deserialization will fail
|
||||
const uint8_t *end = serialized_attribute_list_to_deserialize +
|
||||
serialized_attribute_list_to_deserialize_size;
|
||||
const uint8_t *buffer_size_cursor = serialized_attribute_list_to_deserialize;
|
||||
const int32_t buffer_size =
|
||||
attribute_get_buffer_size_for_serialized_attributes(num_attributes, &buffer_size_cursor, end);
|
||||
|
||||
// Allocate buffers both for the Attribute structs as well as the data they'll hold
|
||||
Attribute attribute_buffer[num_attributes];
|
||||
char attribute_data_buffer[buffer_size];
|
||||
|
||||
// Setup the arguments for the `attribute_deserialize_list` function
|
||||
char *attribute_data_buffer_pointer = attribute_data_buffer;
|
||||
AttributeList deserialization_result_attribute_list = (AttributeList) {
|
||||
.num_attributes = num_attributes,
|
||||
.attributes = attribute_buffer,
|
||||
};
|
||||
const uint8_t *deserialization_cursor = serialized_attribute_list_to_deserialize;
|
||||
|
||||
// Check that the deserialization completes successfully
|
||||
cl_assert_equal_b(attribute_deserialize_list(&attribute_data_buffer_pointer,
|
||||
attribute_data_buffer + buffer_size,
|
||||
&deserialization_cursor, end,
|
||||
deserialization_result_attribute_list),
|
||||
true);
|
||||
// Check that the app glance subtitle string we deserialized matches the string we expect
|
||||
cl_assert_equal_s(attribute_get_string(&deserialization_result_attribute_list,
|
||||
AttributeIdSubtitleTemplateString, NULL),
|
||||
expected_app_glance_subtitle_after_deserializing);
|
||||
}
|
||||
|
||||
void test_attribute__app_glance_subtitle_in_attribute_list(void) {
|
||||
Attribute app_glance_subtitle_attributes[] = {
|
||||
{
|
||||
.id = AttributeIdSubtitleTemplateString,
|
||||
.cstring = "Your app at a glance!"
|
||||
},
|
||||
};
|
||||
AttributeList app_glance_subtitle_attribute_list = {
|
||||
.num_attributes = ARRAY_LENGTH(app_glance_subtitle_attributes),
|
||||
.attributes = app_glance_subtitle_attributes,
|
||||
};
|
||||
const uint8_t app_glance_subtitle_attribute_list_serialized[] = {
|
||||
0x2F, // Attribute ID - App Glance Subtitle
|
||||
0x15, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'Y', 'o', 'u', 'r', ' ', 'a', 'p', 'p', ' ', 'a', 't', ' ', 'a', ' ',
|
||||
'g', 'l', 'a', 'n', 'c', 'e', '!',
|
||||
};
|
||||
const size_t app_glance_subtitle_attribute_list_serialized_size =
|
||||
sizeof(app_glance_subtitle_attribute_list_serialized);
|
||||
|
||||
// Check that serializing the AttributeList matches the serialized byte array above
|
||||
prv_check_attribute_list_serialize(&app_glance_subtitle_attribute_list,
|
||||
app_glance_subtitle_attribute_list_serialized,
|
||||
app_glance_subtitle_attribute_list_serialized_size);
|
||||
|
||||
// Now let's check that deserializing the serialized byte array above results in the same
|
||||
// attributes as the AttributeList above...
|
||||
|
||||
// It's assumed we know the number of attributes in the serialized list, so just copy it from
|
||||
// the AttributeList we hope to recreate
|
||||
const uint8_t num_attributes = app_glance_subtitle_attribute_list.num_attributes;
|
||||
|
||||
prv_check_app_glance_subtitle_in_attribute_list_deserializes(
|
||||
app_glance_subtitle_attribute_list_serialized,
|
||||
app_glance_subtitle_attribute_list_serialized_size, num_attributes,
|
||||
attribute_get_string(&app_glance_subtitle_attribute_list, AttributeIdSubtitleTemplateString,
|
||||
NULL));
|
||||
}
|
||||
|
||||
void test_attribute__too_long_app_glance_subtitle_in_attribute_list(void) {
|
||||
Attribute app_glance_subtitle_attributes[] = {
|
||||
{
|
||||
.id = AttributeIdSubtitleTemplateString,
|
||||
.cstring = "This is a really really really really really really really really really "
|
||||
"really really really really really really really really really really "
|
||||
"long subtitle!"
|
||||
},
|
||||
};
|
||||
// Check that we're actually using a string longer than the max app glance subtitle length
|
||||
cl_assert(
|
||||
strlen(app_glance_subtitle_attributes->cstring) > ATTRIBUTE_APP_GLANCE_SUBTITLE_MAX_LEN);
|
||||
|
||||
AttributeList app_glance_subtitle_attribute_list = {
|
||||
.num_attributes = ARRAY_LENGTH(app_glance_subtitle_attributes),
|
||||
.attributes = app_glance_subtitle_attributes,
|
||||
};
|
||||
const uint8_t app_glance_subtitle_attribute_list_serialized[] = {
|
||||
0x2F, // Attribute ID - App Glance Subtitle
|
||||
0x9D, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'r', 'e', 'a', 'l', 'l', 'y', ' ',
|
||||
'l', 'o', 'n', 'g', ' ', 's', 'u', 'b', 't', 'i', 't', 'l', 'e', '!',
|
||||
};
|
||||
const size_t app_glance_subtitle_attribute_list_serialized_size =
|
||||
sizeof(app_glance_subtitle_attribute_list_serialized);
|
||||
|
||||
// Check that serializing the AttributeList matches the serialized byte array above
|
||||
// Note that serializing an app glance subtitle that is too long doesn't have any effect; we only
|
||||
// respect the max length when deserializing it!
|
||||
prv_check_attribute_list_serialize(&app_glance_subtitle_attribute_list,
|
||||
app_glance_subtitle_attribute_list_serialized,
|
||||
app_glance_subtitle_attribute_list_serialized_size);
|
||||
|
||||
// Now let's check that deserializing the serialized byte array above results in a truncated
|
||||
// version of the original string because it's longer than the max length
|
||||
|
||||
// It's assumed we know the number of attributes in the serialized list, so just copy it from
|
||||
// the AttributeList we hope to recreate
|
||||
const uint8_t num_attributes = app_glance_subtitle_attribute_list.num_attributes;
|
||||
|
||||
prv_check_app_glance_subtitle_in_attribute_list_deserializes(
|
||||
app_glance_subtitle_attribute_list_serialized,
|
||||
app_glance_subtitle_attribute_list_serialized_size, num_attributes,
|
||||
"This is a really really really really really really really really really really really "
|
||||
"really really really really really really really really long su");
|
||||
}
|
412
tests/fw/services/timeline/test_calendar.c
Normal file
412
tests/fw/services/timeline/test_calendar.c
Normal file
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* 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));
|
||||
}
|
304
tests/fw/services/timeline/test_reminders.c
Normal file
304
tests/fw/services/timeline/test_reminders.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* 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 "services/normal/timeline/reminders.h"
|
||||
|
||||
#include "kernel/events.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fake_new_timer.h"
|
||||
#include "fake_pbl_malloc.h"
|
||||
#include "fake_pebble_tasks.h"
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_system_task.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
static time_t now = 0;
|
||||
static int num_events_put = 0;
|
||||
|
||||
|
||||
time_t rtc_get_time(void) {
|
||||
return now;
|
||||
}
|
||||
|
||||
RtcTicks rtc_get_ticks(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void (*CallbackEventCallback)(void *data);
|
||||
|
||||
void launcher_task_add_callback(CallbackEventCallback callback, void *data) {
|
||||
callback(data);
|
||||
}
|
||||
|
||||
void event_put(PebbleEvent* event) {
|
||||
num_events_put++;
|
||||
}
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
extern TimerID get_reminder_timer_id(void);
|
||||
|
||||
static TimelineItem item1 = {
|
||||
.header = {
|
||||
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4},
|
||||
.timestamp = 0,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
} // don't care about the rest
|
||||
};
|
||||
|
||||
static TimelineItem item2 = {
|
||||
.header = {
|
||||
.id = {0x55, 0xcb, 0x7c, 0x75, 0x8a, 0x35, 0x44, 0x87,
|
||||
0x90, 0xa4, 0x91, 0x3f, 0x1f, 0xa6, 0x76, 0x01},
|
||||
.timestamp = 100,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item3 = {
|
||||
.header = {
|
||||
.id = {0x7c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.timestamp = 300,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item4 = {
|
||||
.header = {
|
||||
.id = {0x8c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.timestamp = 1337,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
}
|
||||
};
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_reminders__initialize(void) {
|
||||
now = 0;
|
||||
num_events_put = 0;
|
||||
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
reminder_db_init();
|
||||
|
||||
// add all four explicitly out of order
|
||||
cl_assert(S_SUCCESS == reminders_insert(&item4));
|
||||
|
||||
cl_assert(S_SUCCESS == reminders_insert(&item2));
|
||||
|
||||
cl_assert(S_SUCCESS == reminders_insert(&item1));
|
||||
|
||||
cl_assert(S_SUCCESS == reminders_insert(&item3));
|
||||
}
|
||||
|
||||
void test_reminders__cleanup(void) {
|
||||
//nada
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_reminders__timer_test(void) {
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 0);
|
||||
cl_assert(memcmp(&item1.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId)) == 0);
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
cl_assert_equal_i(num_events_put, 1);
|
||||
|
||||
// item 2 is now the top reminder...
|
||||
cl_assert_equal_m(&item2.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId));
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 100 * 1000);
|
||||
// ...until we insert item 1 back
|
||||
cl_assert(S_SUCCESS == reminders_insert(&item1));
|
||||
cl_assert_equal_m(&item1.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId));
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 0);
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
cl_assert_equal_i(num_events_put, 2);
|
||||
|
||||
cl_assert_equal_m(&item2.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId));
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 100 * 1000);
|
||||
now = 100;
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
cl_assert_equal_i(num_events_put, 3);
|
||||
|
||||
cl_assert_equal_m(&item3.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId));
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 200 * 1000);
|
||||
now += 200;
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
cl_assert_equal_i(num_events_put, 4);
|
||||
|
||||
cl_assert_equal_m(&item4.header.id, stub_new_timer_callback_data(get_reminder_timer_id()), sizeof(TimelineItemId));
|
||||
cl_assert(stub_new_timer_timeout(get_reminder_timer_id()) == 1037 * 1000);
|
||||
now += 1037;
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
cl_assert_equal_i(num_events_put, 5);
|
||||
|
||||
cl_assert(!new_timer_scheduled(get_reminder_timer_id(), NULL));
|
||||
}
|
||||
|
||||
void test_reminders__first_init_test(void) {
|
||||
cl_assert_equal_i(reminders_init(), 0);
|
||||
test_reminders__timer_test();
|
||||
}
|
||||
|
||||
static TimelineItem s_stale_reminder = {
|
||||
.header = {
|
||||
.id = {0x3C, 0xAF, 0x17, 0xD5, 0xBE, 0x15, 0x4B, 0xFD, 0xAE, 0x2A,
|
||||
0xAE, 0x44, 0xC0, 0x96, 0xCB, 0x7D},
|
||||
.timestamp = 60 * 60,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
}
|
||||
};
|
||||
|
||||
void test_reminders__stale_item_insert(void) {
|
||||
now = 3 * 60 * 60; // 3 hours after stale_reminder
|
||||
cl_assert_equal_i(reminders_insert(&s_stale_reminder), E_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void test_reminders__stale_item_init(void) {
|
||||
cl_assert_equal_i(reminders_insert(&s_stale_reminder), S_SUCCESS);
|
||||
stub_new_timer_stop(get_reminder_timer_id());
|
||||
|
||||
now = 1 * 60 * 60;
|
||||
reminders_init();
|
||||
cl_assert(new_timer_scheduled(get_reminder_timer_id(), NULL));
|
||||
|
||||
now = 3 * 60 * 60;
|
||||
reminders_init();
|
||||
cl_assert(!new_timer_scheduled(get_reminder_timer_id(), NULL));
|
||||
}
|
||||
|
||||
static TimezoneInfo s_tz = {
|
||||
.tm_gmtoff = -8 * 60 * 60, // PST
|
||||
};
|
||||
|
||||
static TimelineItem s_all_day_reminder = {
|
||||
.header = {
|
||||
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x67, 0xb4},
|
||||
.timestamp = 1425511800, // 23:30 UTC March 4
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.all_day = true,
|
||||
} // don't care about the rest
|
||||
};
|
||||
|
||||
// should show up before s_all_day_reminder even though its timestamp is after due to tz adjustment
|
||||
static TimelineItem s_reminder_before_all_day_reminder = {
|
||||
.header = {
|
||||
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8d, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x67, 0xb4},
|
||||
.timestamp = 1425531600, // 21:00 PST March 4
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.all_day = false,
|
||||
}
|
||||
};
|
||||
|
||||
void test_reminders__all_day(void) {
|
||||
time_util_update_timezone(&s_tz);
|
||||
cl_assert_equal_i(reminders_insert(&s_all_day_reminder), S_SUCCESS);
|
||||
cl_assert_equal_i(reminders_insert(&s_reminder_before_all_day_reminder), S_SUCCESS);
|
||||
|
||||
// set time to 16:00 PST March 4
|
||||
now = 1425513600;
|
||||
reminders_init();
|
||||
cl_assert_equal_i(stub_new_timer_timeout(get_reminder_timer_id()), 5 * 60 * 60 * 1000);
|
||||
cl_assert(uuid_equal(&s_reminder_before_all_day_reminder.header.id,
|
||||
(Uuid *)stub_new_timer_callback_data(get_reminder_timer_id())));
|
||||
// set time to 21:00 PST March 4
|
||||
now = 1425531600;
|
||||
stub_pebble_tasks_set_current(PebbleTask_NewTimers);
|
||||
cl_assert(stub_new_timer_fire(get_reminder_timer_id()));
|
||||
stub_pebble_tasks_set_current(PebbleTask_KernelBackground);
|
||||
fake_system_task_callbacks_invoke(1);
|
||||
|
||||
cl_assert_equal_i(stub_new_timer_timeout(get_reminder_timer_id()), (2 * 60 + 30) * 60 * 1000);
|
||||
cl_assert(uuid_equal(&s_all_day_reminder.header.id,
|
||||
(Uuid *)stub_new_timer_callback_data(get_reminder_timer_id())));
|
||||
}
|
||||
|
||||
void test_reminders__stale_all_day(void) {
|
||||
time_util_update_timezone(&s_tz);
|
||||
// set time to 21:00 PST March 5, when s_all_day_reminder should be rejected for being stale
|
||||
now = 1425618000;
|
||||
cl_assert_equal_i(reminders_insert(&s_all_day_reminder), E_INVALID_OPERATION);
|
||||
|
||||
// set time to 21:00 PST March 4
|
||||
now = 1425531600;
|
||||
// if the timestamp of s_all_day_reminder isn't adjusted, it would be rejected for being stale
|
||||
// since it "seems" to be timestamped at 15:30 PST, but it should be accepted
|
||||
cl_assert_equal_i(reminders_insert(&s_all_day_reminder), S_SUCCESS);
|
||||
}
|
||||
|
||||
void test_reminders__calculate_snooze_time(void) {
|
||||
// Test half-time snooze
|
||||
now = 0;
|
||||
cl_assert_equal_i(50, reminders_calculate_snooze_time(&item2));
|
||||
now = 50;
|
||||
cl_assert_equal_i(25, reminders_calculate_snooze_time(&item2));
|
||||
|
||||
// Test constant snooze
|
||||
now = 80;
|
||||
cl_assert_equal_i(600, reminders_calculate_snooze_time(&item2));
|
||||
now = 100 + 48 * 60 * 60;
|
||||
cl_assert_equal_i(600, reminders_calculate_snooze_time(&item2));
|
||||
|
||||
// Test no snooze
|
||||
now = 100 + 48 * 60 * 60 + 1;
|
||||
cl_assert_equal_i(0, reminders_calculate_snooze_time(&item2));
|
||||
}
|
271
tests/fw/services/timeline/test_timeline_layouts.c
Normal file
271
tests/fw/services/timeline/test_timeline_layouts.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* 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 "apps/system_apps/timeline/pin_window.h"
|
||||
#include "services/normal/timeline/weather_layout.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fixtures/load_test_resources.h"
|
||||
|
||||
bool property_animation_init(PropertyAnimation *animation,
|
||||
const PropertyAnimationImplementation *implementation,
|
||||
void *subject, void *from_value, void *to_value) {
|
||||
if (!animation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyAnimationPrivate *animation_private = (PropertyAnimationPrivate *)animation;
|
||||
*animation_private = (PropertyAnimationPrivate){
|
||||
.animation.implementation = (const AnimationImplementation *)implementation,
|
||||
.subject = subject,
|
||||
};
|
||||
|
||||
if (from_value) {
|
||||
animation_private->values.from.int16 = *(int16_t *)from_value;
|
||||
}
|
||||
|
||||
if (to_value) {
|
||||
animation_private->values.to.int16 = *(int16_t *)to_value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clock_get_friendly_date(char *buffer, int buf_size, time_t timestamp) {
|
||||
if (buffer) {
|
||||
strncpy(buffer, "Today", buf_size);
|
||||
buffer[buf_size - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void clock_get_since_time(char *buffer, int buf_size, time_t timestamp) {
|
||||
if (buffer) {
|
||||
strncpy(buffer, "15 minutes ago", buf_size);
|
||||
buffer[buf_size - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Stubs
|
||||
/////////////////////
|
||||
|
||||
#include "stubs_action_menu.h"
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_animation_timing.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_app_timer.h"
|
||||
#include "stubs_app_window_stack.h"
|
||||
#include "stubs_bootbits.h"
|
||||
#include "stubs_click.h"
|
||||
#include "stubs_event_service_client.h"
|
||||
#include "stubs_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_memory_layout.h"
|
||||
#include "stubs_modal_manager.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_pebble_process_info.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_process_manager.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_property_animation.h"
|
||||
#include "stubs_serial.h"
|
||||
#include "stubs_shell_prefs.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_timeline.h"
|
||||
#include "stubs_timeline_actions.h"
|
||||
#include "stubs_timeline_item.h"
|
||||
#include "stubs_timeline_layer.h"
|
||||
#include "stubs_timeline_peek.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "fw/graphics/util.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer *fb = NULL;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_timeline_layouts__initialize(void) {
|
||||
fb = malloc(sizeof(FrameBuffer));
|
||||
framebuffer_init(fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
|
||||
const GContextInitializationMode context_init_mode = GContextInitializationMode_System;
|
||||
graphics_context_init(&s_ctx, fb, context_init_mode);
|
||||
|
||||
framebuffer_clear(fb);
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
|
||||
resource_init();
|
||||
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_timeline_layouts__cleanup(void) {
|
||||
free(fb);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
void prv_handle_down_click(ClickRecognizerRef recognizer, void *context);
|
||||
|
||||
static void prv_render_layout(LayoutId layout_id, const AttributeList *attr_list,
|
||||
size_t num_down_clicks) {
|
||||
PBL_ASSERTN(attr_list);
|
||||
|
||||
TimelineItem item = (TimelineItem) {
|
||||
.header = (CommonTimelineItemHeader) {
|
||||
.layout = layout_id,
|
||||
.type = TimelineItemTypePin,
|
||||
},
|
||||
.attr_list = *attr_list,
|
||||
};
|
||||
|
||||
TimelinePinWindow pin_window = (TimelinePinWindow) {};
|
||||
timeline_pin_window_init(&pin_window, &item, rtc_get_time());
|
||||
Window *window = &pin_window.window;
|
||||
|
||||
window_set_on_screen(window, true, true);
|
||||
|
||||
for (int i = 0; i < num_down_clicks; i++) {
|
||||
prv_handle_down_click(NULL, &pin_window.item_detail_layer);
|
||||
|
||||
// Aint nobody got time for animations; advance the scrolling property animation to completion
|
||||
int16_t to = 0;
|
||||
if (property_animation_get_to_int16(pin_window.item_detail_layer.animation, &to)) {
|
||||
pin_window.item_detail_layer.scroll_offset_pixels = to;
|
||||
}
|
||||
}
|
||||
|
||||
window_render(window, &s_ctx);
|
||||
}
|
||||
|
||||
typedef struct TimelineLayoutTestConfig {
|
||||
LayoutId layout_id;
|
||||
const char *title;
|
||||
const char *subtitle;
|
||||
const char *location_name;
|
||||
const char *body;
|
||||
TimelineResourceId icon_timeline_res_id;
|
||||
WeatherTimeType weather_time_type;
|
||||
} TimelineLayoutTestConfig;
|
||||
|
||||
static void prv_construct_and_render_layout(const TimelineLayoutTestConfig *config,
|
||||
size_t num_down_clicks) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
AttributeList attr_list = (AttributeList) {0};
|
||||
if (config->title) {
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdTitle, config->title);
|
||||
}
|
||||
if (config->subtitle) {
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdSubtitle, config->subtitle);
|
||||
}
|
||||
if (config->location_name) {
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdLocationName, config->location_name);
|
||||
}
|
||||
if (config->body) {
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdBody, config->body);
|
||||
}
|
||||
if (config->icon_timeline_res_id != TIMELINE_RESOURCE_INVALID) {
|
||||
attribute_list_add_resource_id(&attr_list, AttributeIdIconPin, config->icon_timeline_res_id);
|
||||
}
|
||||
attribute_list_add_uint8(&attr_list, AttributeIdDisplayTime, config->weather_time_type);
|
||||
// Just need to put something here so our mocked clock_get_since_time() gets called
|
||||
attribute_list_add_uint32(&attr_list, AttributeIdLastUpdated, 1337);
|
||||
|
||||
prv_render_layout(config->layout_id, &attr_list, num_down_clicks);
|
||||
|
||||
attribute_list_destroy_list(&attr_list);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_timeline_layouts__generic(void) {
|
||||
const TimelineLayoutTestConfig config = (TimelineLayoutTestConfig) {
|
||||
.layout_id = LayoutIdGeneric,
|
||||
.title = "Delfina Pizza",
|
||||
.subtitle = "Open Table Reservation",
|
||||
.location_name = "145 Williams\nJohn Ave, Palo Alto",
|
||||
.body = "Body message",
|
||||
.icon_timeline_res_id = TIMELINE_RESOURCE_DINNER_RESERVATION,
|
||||
};
|
||||
|
||||
prv_construct_and_render_layout(&config, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(peek)));
|
||||
|
||||
prv_construct_and_render_layout(&config, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(details1)));
|
||||
|
||||
// Round only needs to scroll down once to see everything
|
||||
#if !PBL_ROUND
|
||||
prv_construct_and_render_layout(&config, 2);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(details2)));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_timeline_layouts__weather(void) {
|
||||
const TimelineLayoutTestConfig config = (TimelineLayoutTestConfig) {
|
||||
.layout_id = LayoutIdWeather,
|
||||
.title = "The Greatest Sunrise Ever",
|
||||
.subtitle = "90°/60°",
|
||||
.location_name = "Redwood City",
|
||||
.body = "A clear sky. Low around 60F.",
|
||||
.icon_timeline_res_id = TIMELINE_RESOURCE_PARTLY_CLOUDY,
|
||||
.weather_time_type = WeatherTimeType_Pin,
|
||||
};
|
||||
|
||||
prv_construct_and_render_layout(&config, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(peek)));
|
||||
|
||||
prv_construct_and_render_layout(&config, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(details1)));
|
||||
|
||||
// Round needs to scroll down one more time to see everything
|
||||
#if PBL_ROUND
|
||||
prv_construct_and_render_layout(&config, 2);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE_X(details2)));
|
||||
#endif
|
||||
}
|
502
tests/fw/services/timeline/test_timeline_model.c
Normal file
502
tests/fw/services/timeline/test_timeline_model.c
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
786
tests/fw/services/timeline/test_timeline_peek_event.c
Normal file
786
tests/fw/services/timeline/test_timeline_peek_event.c
Normal file
|
@ -0,0 +1,786 @@
|
|||
/*
|
||||
* 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/event.h"
|
||||
#include "services/normal/timeline/peek.h"
|
||||
#include "services/normal/timeline/timeline.h"
|
||||
#include "system/logging.h"
|
||||
|
||||
#include "clar.h"
|
||||
#include "pebble_asserts.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_peek.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 *calendar_get_event_service(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
////////////////////////////////////////////////////////////////
|
||||
typedef struct PeekTestData {
|
||||
PebbleTimelinePeekEvent last_peek_event;
|
||||
unsigned int num_peek_events;
|
||||
} PeekTestData;
|
||||
|
||||
static PeekTestData s_data;
|
||||
|
||||
static PebbleTimelinePeekEvent prv_get_peek_event(void) {
|
||||
return s_data.last_peek_event;
|
||||
}
|
||||
|
||||
static void prv_event_handler(PebbleEvent *event) {
|
||||
if (event->type == PEBBLE_TIMELINE_PEEK_EVENT) {
|
||||
s_data.last_peek_event = event->timeline_peek;
|
||||
s_data.num_peek_events++;
|
||||
}
|
||||
}
|
||||
|
||||
// Fake pins
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
static Attribute title_attr = {
|
||||
.id = AttributeIdTitle,
|
||||
.cstring = "title",
|
||||
};
|
||||
|
||||
static TimelineItem s_item1 = {
|
||||
.header = {
|
||||
.id = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 1 * SECONDS_PER_MINUTE,
|
||||
.duration = 15,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem s_item2 = {
|
||||
.header = {
|
||||
.id = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 5 * SECONDS_PER_MINUTE,
|
||||
.duration = 20,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem s_item3 = {
|
||||
.header = {
|
||||
.id = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 9 * SECONDS_PER_MINUTE,
|
||||
.duration = 5,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem s_future_item = {
|
||||
.header = {
|
||||
.id = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 100 * SECONDS_PER_MINUTE,
|
||||
.duration = 10,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem s_short_future_item = {
|
||||
.header = {
|
||||
.id = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 100 * SECONDS_PER_MINUTE,
|
||||
.duration = 5,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// not a calendar pin
|
||||
static TimelineItem s_weather_item = {
|
||||
.header = {
|
||||
.id = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 10 * SECONDS_PER_MINUTE,
|
||||
.duration = 10,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdWeather,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// add day pin
|
||||
static TimelineItem s_all_day_item = {
|
||||
.header = {
|
||||
.id = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 100 * SECONDS_PER_MINUTE,
|
||||
.duration = 10,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = true,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// 0-duration event
|
||||
static TimelineItem s_point_item = {
|
||||
.header = {
|
||||
.id = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 20 * SECONDS_PER_MINUTE,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdWeather,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// recurring calendar event 1
|
||||
static TimelineItem s_recurring_calendar_item1 = {
|
||||
.header = {
|
||||
.id = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 50 * SECONDS_PER_MINUTE - SECONDS_PER_DAY,
|
||||
.duration = 30,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// recurring calendar event 2
|
||||
static TimelineItem s_recurring_calendar_item2 = {
|
||||
.header = {
|
||||
.id = { 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 50 * SECONDS_PER_MINUTE,
|
||||
.duration = 30,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// recurring calendar event 3
|
||||
static TimelineItem s_recurring_calendar_item3 = {
|
||||
.header = {
|
||||
.id = { 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 50 * SECONDS_PER_MINUTE + SECONDS_PER_DAY,
|
||||
.duration = 30,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// back-to-back calendar event 1
|
||||
static TimelineItem s_back_to_back_calendar_item1 = {
|
||||
.header = {
|
||||
.id = { 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 60 * SECONDS_PER_MINUTE,
|
||||
.duration = 30,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// back-to-back calendar event 2
|
||||
static TimelineItem s_back_to_back_calendar_item2 = {
|
||||
.header = {
|
||||
.id = { 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
.timestamp = 90 * SECONDS_PER_MINUTE,
|
||||
.duration = 30,
|
||||
.type = TimelineItemTypePin,
|
||||
.all_day = false,
|
||||
.layout = LayoutIdCalendar,
|
||||
},
|
||||
.attr_list = {
|
||||
.num_attributes = 1,
|
||||
.attributes = &title_attr,
|
||||
},
|
||||
};
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_timeline_peek_event__initialize(void) {
|
||||
s_data = (PeekTestData){};
|
||||
rtc_set_time(0);
|
||||
fake_event_init();
|
||||
fake_event_set_callback(prv_event_handler);
|
||||
pin_db_init();
|
||||
timeline_event_init();
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__cleanup(void) {
|
||||
timeline_peek_set_show_before_time(TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S);
|
||||
timeline_event_deinit();
|
||||
stub_new_timer_cleanup();
|
||||
fake_settings_file_reset();
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct AddEventParams {
|
||||
TimelineItem *item;
|
||||
} AddEventParams;
|
||||
|
||||
#define ADD_EVENT(...) ({ \
|
||||
AddEventParams params = { __VA_ARGS__ }; \
|
||||
cl_assert(timeline_add(params.item)); \
|
||||
timeline_event_handle_blobdb_event(); \
|
||||
params.item; \
|
||||
})
|
||||
|
||||
typedef struct CreateEventParams {
|
||||
uint8_t id;
|
||||
LayoutId layout;
|
||||
time_t timestamp;
|
||||
uint16_t duration;
|
||||
bool all_day;
|
||||
bool persistent;
|
||||
} CreateEventParams;
|
||||
|
||||
#define DEFINE_EVENT(...) ({ \
|
||||
CreateEventParams params = { __VA_ARGS__ }; \
|
||||
TimelineItem item = { \
|
||||
.header = { \
|
||||
.type = TimelineItemTypePin, \
|
||||
.id = { params.id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, \
|
||||
.layout = params.layout ?: LayoutIdCalendar, \
|
||||
.persistent = params.persistent ? 1 : 0, \
|
||||
.timestamp = params.timestamp, \
|
||||
.all_day = params.all_day, \
|
||||
.duration = params.duration, \
|
||||
}, \
|
||||
.attr_list = { \
|
||||
.num_attributes = 1, \
|
||||
.attributes = &title_attr, \
|
||||
}, \
|
||||
}; \
|
||||
ADD_EVENT( .item = &item ); \
|
||||
item; \
|
||||
})
|
||||
|
||||
typedef struct CheckNoEventsParams {
|
||||
unsigned int count;
|
||||
bool is_future_empty;
|
||||
} CheckNoEventsParams;
|
||||
|
||||
#define CHECK_NO_EVENTS(...) ({ \
|
||||
CheckNoEventsParams params = { __VA_ARGS__ }; \
|
||||
PebbleTimelinePeekEvent peek = prv_get_peek_event(); \
|
||||
cl_assert_equal_i(s_data.num_peek_events, params.count); \
|
||||
cl_assert_equal_uuid(peek.item_id ? *peek.item_id : UUID_INVALID, UUID_INVALID); \
|
||||
cl_assert_equal_i(peek.time_type, TimelinePeekTimeType_None); \
|
||||
cl_assert_equal_i(peek.num_concurrent, 0); \
|
||||
cl_assert_equal_b(peek.is_future_empty, params.is_future_empty); \
|
||||
cl_assert_equal_i(stub_new_timer_get_next(), TIMER_INVALID_ID); \
|
||||
peek; \
|
||||
})
|
||||
|
||||
typedef struct CheckEventParams {
|
||||
unsigned int count;
|
||||
Uuid item_id;
|
||||
unsigned int num_concurrent;
|
||||
unsigned int timeout_ms;
|
||||
TimelinePeekTimeType time_type;
|
||||
bool is_first_event;
|
||||
} CheckEventParams;
|
||||
|
||||
#define CHECK_EVENT(...) ({ \
|
||||
CheckEventParams params = { __VA_ARGS__ }; \
|
||||
PebbleTimelinePeekEvent peek = prv_get_peek_event(); \
|
||||
cl_assert_equal_i(s_data.num_peek_events, params.count); \
|
||||
cl_assert_equal_uuid(peek.item_id ? *peek.item_id : UUID_INVALID, params.item_id); \
|
||||
cl_assert_equal_i(peek.time_type, params.time_type); \
|
||||
cl_assert_equal_i(peek.num_concurrent, params.num_concurrent); \
|
||||
cl_assert_equal_b(peek.is_first_event, params.is_first_event); \
|
||||
cl_assert_equal_b(peek.is_future_empty, false); \
|
||||
const TimerID timer_id = stub_new_timer_get_next(); \
|
||||
cl_assert(timer_id != TIMER_INVALID_ID); \
|
||||
cl_assert_equal_i(stub_new_timer_timeout(timer_id), params.timeout_ms); \
|
||||
peek; \
|
||||
})
|
||||
|
||||
static void prv_invoke_timer(unsigned int timeout_s) {
|
||||
fake_rtc_increment_time(timeout_s);
|
||||
stub_new_timer_invoke(1 /* num_invoke */);
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__no_events(void) {
|
||||
CHECK_NO_EVENTS( .count = 1, .is_future_empty = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__calendar_event(void) {
|
||||
ADD_EVENT( .item = &s_item1 );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_item1.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__calendar_event_all_day(void) {
|
||||
ADD_EVENT( .item = &s_all_day_item );
|
||||
CHECK_NO_EVENTS( .count = 2, .is_future_empty = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__weather_event(void) {
|
||||
ADD_EVENT( .item = &s_weather_item );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_weather_item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = s_weather_item.header.timestamp * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__concurrent_count_and_priority(void) {
|
||||
// Test that num_concurrent increases accordingly
|
||||
// Also test that upcoming items take priority
|
||||
ADD_EVENT( .item = &s_item1 );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_item1.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
ADD_EVENT( .item = &s_item2 );
|
||||
CHECK_EVENT( .count = 3, .item_id = s_item2.header.id, .num_concurrent = 1,
|
||||
.timeout_ms = SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart );
|
||||
ADD_EVENT( .item = &s_item3 );
|
||||
CHECK_EVENT( .count = 4, .item_id = s_item3.header.id, .num_concurrent = 2,
|
||||
.timeout_ms = SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart );
|
||||
// The future item is too far to increase the concurrent count
|
||||
ADD_EVENT( .item = &s_future_item );
|
||||
CHECK_EVENT( .count = 5, .item_id = s_item3.header.id, .num_concurrent = 2,
|
||||
.timeout_ms = SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__before_upcoming_event(void) {
|
||||
// Check that the event is about an upcoming item
|
||||
ADD_EVENT( .item = &s_future_item );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_future_item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms =
|
||||
((s_future_item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S) *
|
||||
MS_PER_SECOND),
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__before_upcoming_event_custom_5min(void) {
|
||||
// Check that the event is about an upcoming item at a custom 5min timeout
|
||||
const unsigned int show_before_time_s = 5 * SECONDS_PER_MINUTE;
|
||||
timeline_peek_set_show_before_time(show_before_time_s);
|
||||
ADD_EVENT( .item = &s_future_item );
|
||||
CHECK_EVENT( .count = 3, .item_id = s_future_item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = ((s_future_item.header.timestamp - show_before_time_s) *
|
||||
MS_PER_SECOND),
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__before_event_starts(void) {
|
||||
// Check that the event is about an item that is about to start
|
||||
rtc_set_time(s_future_item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S / 2);
|
||||
ADD_EVENT( .item = &s_future_item );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_future_item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = (TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S * MS_PER_SECOND) / 2,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__after_event_starts(void) {
|
||||
// Check that the event is about an item about to pass the hide time
|
||||
rtc_set_time(5 * SECONDS_PER_MINUTE);
|
||||
ADD_EVENT( .item = &s_item1 );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_item1.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = ((TIMELINE_PEEK_HIDE_AFTER_TIME_S -
|
||||
(rtc_get_time() - s_item1.header.timestamp)) * MS_PER_SECOND),
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__after_event_starts_short_event(void) {
|
||||
// Check that for a short event, the timeout is the end of the item instead
|
||||
rtc_set_time(10 * SECONDS_PER_MINUTE);
|
||||
ADD_EVENT( .item = &s_item3 );
|
||||
CHECK_EVENT( .count = 2, .item_id = s_item3.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = 4 * SECONDS_PER_MINUTE * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__after_event_passed_hide_time(void) {
|
||||
// Check that there is no event if the last item passed the hide time
|
||||
rtc_set_time(15 * SECONDS_PER_MINUTE);
|
||||
ADD_EVENT( .item = &s_item2 );
|
||||
CHECK_NO_EVENTS( .count = 2 );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__after_event_passed_completely(void) {
|
||||
rtc_set_time(30 * SECONDS_PER_MINUTE);
|
||||
ADD_EVENT( .item = &s_item2 );
|
||||
CHECK_NO_EVENTS( .count = 2, .is_future_empty = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__dismiss_event(void) {
|
||||
// Check that dismissing the last event causes no events to peek
|
||||
TimelineItem *item = &s_future_item;
|
||||
rtc_set_time(item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S / 2);
|
||||
ADD_EVENT( .item = item );
|
||||
CHECK_EVENT( .count = 2, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = (TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S * MS_PER_SECOND) / 2,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
|
||||
// Simulate a timeline peek dismiss
|
||||
cl_must_pass(pin_db_set_status_bits(&item->header.id, TimelineItemStatusDismissed));
|
||||
timeline_event_refresh();
|
||||
|
||||
CHECK_NO_EVENTS( .count = 3 );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__first_event_with_past_event(void) {
|
||||
TimelineItem item =
|
||||
DEFINE_EVENT( .id = 0x01, .timestamp = 20 * SECONDS_PER_MINUTE, .duration = 70 );
|
||||
TimelineItem UNUSED item2 =
|
||||
DEFINE_EVENT( .id = 0x02, .timestamp = -50 * SECONDS_PER_MINUTE, .duration = 30 );
|
||||
unsigned int timeout_s = item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__first_event_with_all_day_event_before(void) {
|
||||
// All day events show up if no timed event has yet passed
|
||||
TimelineItem item =
|
||||
DEFINE_EVENT( .id = 0x01, .timestamp = 20 * SECONDS_PER_MINUTE, .duration = 70 );
|
||||
TimelineItem UNUSED item2 =
|
||||
DEFINE_EVENT( .id = 0x02, .timestamp = 0, .duration = MINUTES_PER_DAY, .all_day = true );
|
||||
unsigned int timeout_s = item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__first_event_with_all_day_event_after(void) {
|
||||
// After a timed event has passed, all day events no longer show up for the day
|
||||
rtc_set_time(SECONDS_PER_HOUR);
|
||||
TimelineItem item =
|
||||
DEFINE_EVENT( .id = 0x01, .timestamp = SECONDS_PER_HOUR + 20 * SECONDS_PER_MINUTE,
|
||||
.duration = 70 );
|
||||
TimelineItem UNUSED item2 =
|
||||
DEFINE_EVENT( .id = 0x02, .timestamp = 0, .duration = MINUTES_PER_DAY, .all_day = true );
|
||||
TimelineItem UNUSED item3 =
|
||||
DEFINE_EVENT( .id = 0x03, .timestamp = 0, .duration = 10 );
|
||||
unsigned int timeout_s = 600;
|
||||
CHECK_EVENT( .count = 4, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__one_event_lifecycle(void) {
|
||||
// Check that one event progresses through SomeTimeNext, WillStart, ShowStarted, None
|
||||
TimelineItem *item = &s_future_item;
|
||||
ADD_EVENT( .item = item );
|
||||
unsigned int timeout_s = item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 2, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 4, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
CHECK_NO_EVENTS( .count = 5 );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__one_short_event_lifecycle(void) {
|
||||
// Check that one event progresses through SomeTimeNext, WillStart, ShowStarted, None
|
||||
TimelineItem *item = &s_short_future_item;
|
||||
ADD_EVENT( .item = item );
|
||||
unsigned int timeout_s = item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 2, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = item->header.duration * SECONDS_PER_MINUTE;
|
||||
CHECK_EVENT( .count = 4, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
CHECK_NO_EVENTS( .count = 5 );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__0_duration_event_lifecycle(void) {
|
||||
// Check that one event progresses through SomeTimeNext, WillStart, ShowStarted, None
|
||||
TimelineItem *item = &s_point_item;
|
||||
ADD_EVENT( .item = item );
|
||||
unsigned int timeout_s = item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 2, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
CHECK_NO_EVENTS( .count = 4 );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__one_recurring_event_lifecycle(void) {
|
||||
// Check that one event progresses through SomeTimeNext, WillStart, ShowStarted
|
||||
TimelineItem *item = &s_recurring_calendar_item2;
|
||||
ADD_EVENT( .item = &s_recurring_calendar_item1 );
|
||||
ADD_EVENT( .item = item );
|
||||
ADD_EVENT( .item = &s_recurring_calendar_item3 );
|
||||
unsigned int timeout_s = item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 4, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 5, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 6, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = (SECONDS_PER_DAY - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S -
|
||||
TIMELINE_PEEK_HIDE_AFTER_TIME_S);
|
||||
CHECK_EVENT( .count = 7, .item_id = s_recurring_calendar_item3.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__two_back_to_back_events(void) {
|
||||
// Check that one event progresses through SomeTimeNext, WillStart, ShowStarted
|
||||
TimelineItem *item = &s_back_to_back_calendar_item1;
|
||||
ADD_EVENT( .item = item );
|
||||
ADD_EVENT( .item = &s_back_to_back_calendar_item2 );
|
||||
unsigned int timeout_s = item->header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 4, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 5, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
item = &s_back_to_back_calendar_item2;
|
||||
CHECK_EVENT( .count = 6, .item_id = item->header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__one_persistent_event_lifecycle(void) {
|
||||
TimelineItem item =
|
||||
DEFINE_EVENT( .id = 0x01, .timestamp = 20 * SECONDS_PER_MINUTE, .duration = 30,
|
||||
.persistent = true );
|
||||
unsigned int timeout_s = item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 2, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 4, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = item.header.duration * SECONDS_PER_MINUTE - TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 5, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
CHECK_NO_EVENTS( .count = 6, .is_future_empty = true );
|
||||
}
|
||||
|
||||
void test_timeline_peek_event__upcoming_priotized_over_persistent_event_lifecycle(void) {
|
||||
TimelineItem item =
|
||||
DEFINE_EVENT( .id = 0x01, .timestamp = 20 * SECONDS_PER_MINUTE, .duration = 70,
|
||||
.persistent = true );
|
||||
TimelineItem item2 =
|
||||
DEFINE_EVENT( .id = 0x02, .timestamp = 50 * SECONDS_PER_MINUTE, .duration = 30 );
|
||||
unsigned int timeout_s = item.header.timestamp - TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 3, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_SomeTimeNext, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 4, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 5, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = 10 * SECONDS_PER_MINUTE; // time until the next event
|
||||
CHECK_EVENT( .count = 6, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_DEFAULT_SHOW_BEFORE_TIME_S;
|
||||
CHECK_EVENT( .count = 7, .item_id = item2.header.id, .num_concurrent = 1,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowWillStart, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = TIMELINE_PEEK_HIDE_AFTER_TIME_S;
|
||||
CHECK_EVENT( .count = 8, .item_id = item2.header.id, .num_concurrent = 1,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted, .is_first_event = true );
|
||||
prv_invoke_timer(timeout_s);
|
||||
timeout_s = 30 * SECONDS_PER_MINUTE; // time until persistent event ends
|
||||
CHECK_EVENT( .count = 9, .item_id = item.header.id, .num_concurrent = 0,
|
||||
.timeout_ms = timeout_s * MS_PER_SECOND,
|
||||
.time_type = TimelinePeekTimeType_ShowStarted );
|
||||
prv_invoke_timer(timeout_s);
|
||||
CHECK_NO_EVENTS( .count = 10, .is_future_empty = true );
|
||||
}
|
359
tests/fw/services/timeline/test_timeline_resources.c
Normal file
359
tests/fw/services/timeline/test_timeline_resources.c
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* 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 "process_management/app_install_manager.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
#include "system/passert.h"
|
||||
#include "util/struct.h"
|
||||
|
||||
// Stubs
|
||||
/////////////////////////
|
||||
|
||||
#include "stubs_kino_reel.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_resources.h"
|
||||
#include "stubs_syscalls.h"
|
||||
|
||||
// Test Data
|
||||
/////////////////////////
|
||||
|
||||
typedef enum TimelineResourceTestAppTimelineId {
|
||||
// We start at 1 because TIMELINE_RESOURCE_INVALID = 0
|
||||
TimelineResourceTestTimelineId_AlarmClock = 1,
|
||||
TimelineResourceTestTimelineId_Basketball,
|
||||
|
||||
TimelineResourceTestTimelineIdCount
|
||||
} TimelineResourceTestTimelineId;
|
||||
|
||||
static const uint32_t s_app_lut[TimelineResourceTestTimelineIdCount][TimelineResourceSizeCount] = {
|
||||
[TIMELINE_RESOURCE_INVALID] = {
|
||||
RESOURCE_ID_INVALID, RESOURCE_ID_INVALID, RESOURCE_ID_INVALID
|
||||
},
|
||||
[TimelineResourceTestTimelineId_AlarmClock] = {
|
||||
RESOURCE_ID_ALARM_CLOCK_TINY, RESOURCE_ID_ALARM_CLOCK_SMALL, RESOURCE_ID_ALARM_CLOCK_LARGE
|
||||
},
|
||||
[TimelineResourceTestTimelineId_Basketball] = {
|
||||
RESOURCE_ID_BASKETBALL_TINY, RESOURCE_ID_BASKETBALL_SMALL, RESOURCE_ID_BASKETBALL_LARGE
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct TimelineResourceTestAppData {
|
||||
AppInstallEntry install_entry;
|
||||
const uint32_t (*resource_lut)[TimelineResourceSizeCount];
|
||||
} TimelineResourceTestAppData;
|
||||
|
||||
typedef enum TimelineResourceTestAppId {
|
||||
// We start from 1 because INSTALL_ID_INVALID = 0
|
||||
TimelineResourceTestAppId_AppWithInvalidLUT = 1,
|
||||
TimelineResourceTestAppId_AppWithInvalidSDKVersion,
|
||||
TimelineResourceTestAppId_ValidApp,
|
||||
|
||||
TimelineResourceTestAppIdInvalid,
|
||||
TimelineResourceTestAppIdCount = TimelineResourceTestAppIdInvalid - 1
|
||||
} TimelineResourceTestAppId;
|
||||
|
||||
static const TimelineResourceTestAppData s_test_apps[TimelineResourceTestAppIdCount] = {
|
||||
{
|
||||
.install_entry = {
|
||||
.install_id = TimelineResourceTestAppId_AppWithInvalidLUT,
|
||||
.uuid = {0x3c, 0x6e, 0x2e, 0x1d, 0x61, 0x7d, 0x4d, 0x17,
|
||||
0x97, 0xa1, 0xbc, 0x43, 0x2d, 0x87, 0x4c, 0xed},
|
||||
.sdk_version = {TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MAJOR,
|
||||
TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MINOR},
|
||||
},
|
||||
// No resource_lut specified because this app has an "invalid" lut
|
||||
},
|
||||
{
|
||||
.install_entry = {
|
||||
.install_id = TimelineResourceTestAppId_AppWithInvalidSDKVersion,
|
||||
.uuid = {0x37, 0xe7, 0x64, 0x5e, 0xd, 0x6a, 0x41, 0xfe,
|
||||
0xb8, 0x80, 0xea, 0x47, 0x5a, 0x5f, 0x34, 0x34},
|
||||
// We set the SDK version to one earlier than the first version supporting timeline resources
|
||||
.sdk_version = {TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MAJOR,
|
||||
TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MINOR - 1},
|
||||
},
|
||||
.resource_lut = s_app_lut,
|
||||
},
|
||||
{
|
||||
.install_entry = {
|
||||
.install_id = TimelineResourceTestAppId_ValidApp,
|
||||
.uuid = {0x9e, 0x95, 0x8b, 0xfe, 0xd, 0xbd, 0x4d, 0xf2,
|
||||
0xbe, 0xbc, 0xf3, 0x77, 0x5d, 0x8d, 0x9f, 0x95},
|
||||
.sdk_version = {TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MAJOR,
|
||||
TIMELINE_RESOURCE_PBW_SUPPORT_FIRST_SDK_VERSION_MINOR},
|
||||
},
|
||||
.resource_lut = s_app_lut,
|
||||
},
|
||||
};
|
||||
|
||||
static const TimelineResourceTestAppData *prv_get_data_for_app_with_id(AppInstallId install_id) {
|
||||
for (int i = 0; i < TimelineResourceTestAppIdCount; i++) {
|
||||
const TimelineResourceTestAppData *data = &s_test_apps[i];
|
||||
if (data->install_entry.install_id == install_id) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const TimelineResourceTestAppData *prv_get_data_for_app_with_uuid(const Uuid *uuid) {
|
||||
for (int i = 0; i < TimelineResourceTestAppIdCount; i++) {
|
||||
const TimelineResourceTestAppData *data = &s_test_apps[i];
|
||||
if (uuid_equal(uuid, &data->install_entry.uuid)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fakes
|
||||
/////////////////////////
|
||||
|
||||
bool prv_validate_lut(ResAppNum res_app_num) {
|
||||
// Just check if the .resource_lut pointer for the provided res_app_num is non-NULL
|
||||
const TimelineResourceTestAppData *data = prv_get_data_for_app_with_id(res_app_num);
|
||||
return data ? (data->resource_lut != NULL) : false;
|
||||
}
|
||||
|
||||
uint32_t prv_get_app_resource_id(ResAppNum res_app_num, TimelineResourceId timeline_id,
|
||||
TimelineResourceSize size) {
|
||||
// Size must be valid
|
||||
if (size >= TimelineResourceSizeCount) {
|
||||
return RESOURCE_ID_INVALID;
|
||||
}
|
||||
|
||||
// This only supports valid non-system apps
|
||||
const TimelineResourceTestAppData *data = prv_get_data_for_app_with_id(res_app_num);
|
||||
if (!data) {
|
||||
return RESOURCE_ID_INVALID;
|
||||
}
|
||||
|
||||
// The app must have a valid LUT
|
||||
if (!data->resource_lut) {
|
||||
return RESOURCE_ID_INVALID;
|
||||
}
|
||||
|
||||
return data->resource_lut[timeline_id][size];
|
||||
}
|
||||
|
||||
static bool s_is_app_published_resource_invalid;
|
||||
|
||||
bool prv_is_app_published_resource_valid(const AppResourceInfo *res_info) {
|
||||
return !s_is_app_published_resource_invalid;
|
||||
}
|
||||
|
||||
AppInstallId app_install_get_id_for_uuid(const Uuid *uuid) {
|
||||
const TimelineResourceTestAppData *data = prv_get_data_for_app_with_uuid(uuid);
|
||||
return NULL_SAFE_FIELD_ACCESS(data, install_entry.install_id, INSTALL_ID_INVALID);
|
||||
}
|
||||
|
||||
bool app_install_get_entry_for_install_id(AppInstallId install_id, AppInstallEntry *entry) {
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const TimelineResourceTestAppData *data = prv_get_data_for_app_with_id(install_id);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
*entry = data->install_entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
ResAppNum app_install_get_app_icon_bank(const AppInstallEntry *entry) {
|
||||
PBL_ASSERTN(entry);
|
||||
if (uuid_equal(&entry->uuid, &(Uuid)UUID_SYSTEM)) {
|
||||
return SYSTEM_APP;
|
||||
} else {
|
||||
return entry->install_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup
|
||||
/////////////////////////
|
||||
|
||||
void test_timeline_resources__initialize(void) {
|
||||
s_is_app_published_resource_invalid = false;
|
||||
}
|
||||
|
||||
// Tests
|
||||
/////////////////////////
|
||||
|
||||
void test_timeline_resources__get_id_system(void) {
|
||||
AppResourceInfo res_info;
|
||||
|
||||
// Calling the function with an invalid TimelineResourceId should return false
|
||||
cl_assert(!timeline_resources_get_id_system(TIMELINE_RESOURCE_INVALID, TimelineResourceSizeTiny,
|
||||
TimelineResourceTestAppId_ValidApp, &res_info));
|
||||
|
||||
// Calling the function with an invalid size should return false
|
||||
cl_assert(!timeline_resources_get_id_system(
|
||||
(TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock, TimelineResourceSizeCount,
|
||||
TimelineResourceTestAppId_ValidApp, &res_info));
|
||||
|
||||
// Calling the function with the ResAppNum of an app with an invalid LUT should return false
|
||||
cl_assert(!timeline_resources_get_id_system(
|
||||
(TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock, TimelineResourceSizeTiny,
|
||||
TimelineResourceTestAppId_AppWithInvalidLUT, &res_info));
|
||||
|
||||
// Calling the function for an invalid resource (e.g. dimensions too large) should return false
|
||||
s_is_app_published_resource_invalid = true;
|
||||
cl_assert(!timeline_resources_get_id_system(
|
||||
(TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock, TimelineResourceSizeTiny,
|
||||
TimelineResourceTestAppId_ValidApp, &res_info));
|
||||
s_is_app_published_resource_invalid = false;
|
||||
|
||||
// Calling the function with valid args should return true and set the correct values in res_info
|
||||
cl_assert(timeline_resources_get_id_system(
|
||||
(TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock, TimelineResourceSizeTiny,
|
||||
TimelineResourceTestAppId_ValidApp, &res_info));
|
||||
cl_assert_equal_i(res_info.res_app_num, TimelineResourceTestAppId_ValidApp);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_ALARM_CLOCK_TINY);
|
||||
|
||||
// Calling the function with valid args should return true even if no AppResourceInfo is provided
|
||||
cl_assert(timeline_resources_get_id_system(
|
||||
(TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock, TimelineResourceSizeTiny,
|
||||
TimelineResourceTestAppId_ValidApp, NULL));
|
||||
|
||||
// Calling the function with a valid system TimelineResourceId should return true and set res_info
|
||||
cl_assert(timeline_resources_get_id_system(TIMELINE_RESOURCE_AUDIO_CASSETTE,
|
||||
TimelineResourceSizeSmall, SYSTEM_APP, &res_info));
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_AUDIO_CASSETTE_SMALL);
|
||||
// Even if the provided ResAppNum != SYSTEM_APP
|
||||
cl_assert(timeline_resources_get_id_system(TIMELINE_RESOURCE_AUDIO_CASSETTE,
|
||||
TimelineResourceSizeSmall, TIMELINE_RESOURCE_INVALID,
|
||||
&res_info));
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_AUDIO_CASSETTE_SMALL);
|
||||
}
|
||||
|
||||
void test_timeline_resources__get_id(void) {
|
||||
TimelineResourceInfo timeline_res_info;
|
||||
AppResourceInfo res_info;
|
||||
|
||||
const TimelineResourceTestAppData *valid_app_data =
|
||||
prv_get_data_for_app_with_id(TimelineResourceTestAppId_ValidApp);
|
||||
PBL_ASSERTN(valid_app_data);
|
||||
|
||||
// Calling the function with an invalid TimelineResourceId should set res_info to the fallback
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &valid_app_data->install_entry.uuid,
|
||||
.res_id = TIMELINE_RESOURCE_INVALID,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeLarge, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_BIRTHDAY_EVENT_LARGE);
|
||||
|
||||
// Set the TimelineResourceInfo to valid values
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &valid_app_data->install_entry.uuid,
|
||||
.res_id = (TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
|
||||
// Calling the function with an invalid size, no TimelineResourceInfo, or no AppResourceInfo
|
||||
// should assert
|
||||
cl_assert_passert(timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeCount,
|
||||
&res_info));
|
||||
cl_assert_passert(timeline_resources_get_id(NULL, TimelineResourceSizeTiny, &res_info));
|
||||
cl_assert_passert(timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeTiny, NULL));
|
||||
|
||||
// Set the TimelineResourceInfo to have the UUID of an app with an invalid LUT
|
||||
const TimelineResourceTestAppData *app_with_invalid_lut_data =
|
||||
prv_get_data_for_app_with_id(TimelineResourceTestAppId_AppWithInvalidLUT);
|
||||
PBL_ASSERTN(app_with_invalid_lut_data);
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &app_with_invalid_lut_data->install_entry.uuid,
|
||||
.res_id = (TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
|
||||
// Calling the function with the UUID of an app with an invalid LUT should set res_info to the
|
||||
// fallback
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeLarge, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_BIRTHDAY_EVENT_LARGE);
|
||||
|
||||
// Set the TimelineResourceInfo to valid values
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &valid_app_data->install_entry.uuid,
|
||||
.res_id = (TimelineResourceId)TimelineResourceTestTimelineId_AlarmClock,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
|
||||
// Calling the function for an invalid resource (e.g. dimensions too large) should set res_info
|
||||
// to the fallback
|
||||
s_is_app_published_resource_invalid = true;
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeLarge, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_BIRTHDAY_EVENT_LARGE);
|
||||
s_is_app_published_resource_invalid = false;
|
||||
|
||||
// Calling the function with valid args should return true and set the correct values in res_info
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeLarge, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, TimelineResourceTestAppId_ValidApp);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_ALARM_CLOCK_LARGE);
|
||||
|
||||
// Set the TimelineResourceInfo to have the UUID of an app with an unsupported SDK version
|
||||
const TimelineResourceTestAppData *app_with_invalid_sdk_version =
|
||||
prv_get_data_for_app_with_id(TimelineResourceTestAppId_AppWithInvalidSDKVersion);
|
||||
PBL_ASSERTN(app_with_invalid_sdk_version);
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &app_with_invalid_sdk_version->install_entry.uuid,
|
||||
.res_id = (TimelineResourceId)TimelineResourceTestTimelineId_Basketball,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
|
||||
// Calling the function with the UUID of an app with an unsupported SDK version should set
|
||||
// res_info to the fallback
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeTiny, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_BIRTHDAY_EVENT_TINY);
|
||||
|
||||
// Set the TimelineResourceInfo to valid values but with a system TimelineResourceId requested
|
||||
timeline_res_info = (TimelineResourceInfo) {
|
||||
.app_id = &(Uuid)UUID_SYSTEM,
|
||||
.res_id = TIMELINE_RESOURCE_HOTEL_RESERVATION,
|
||||
.fallback_id = TIMELINE_RESOURCE_BIRTHDAY_EVENT,
|
||||
};
|
||||
|
||||
// Calling the function with a valid system TimelineResourceId should set the correct values in
|
||||
// res_info
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeSmall, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_HOTEL_RESERVATION_SMALL);
|
||||
// Even if the provided app UUID != UUID_SYSTEM
|
||||
timeline_res_info.app_id = &valid_app_data->install_entry.uuid;
|
||||
timeline_resources_get_id(&timeline_res_info, TimelineResourceSizeSmall, &res_info);
|
||||
cl_assert_equal_i(res_info.res_app_num, SYSTEM_APP);
|
||||
cl_assert_equal_i(res_info.res_id, RESOURCE_ID_HOTEL_RESERVATION_SMALL);
|
||||
}
|
||||
|
||||
void test_timeline_resources__is_system(void) {
|
||||
// System TimelineResourceIds should return true
|
||||
cl_assert(timeline_resources_is_system(TIMELINE_RESOURCE_AUDIO_CASSETTE));
|
||||
|
||||
// Others should return false
|
||||
cl_assert(!timeline_resources_is_system(TIMELINE_RESOURCE_INVALID));
|
||||
cl_assert(!timeline_resources_is_system(NUM_TIMELINE_RESOURCES));
|
||||
}
|
226
tests/fw/services/timeline/wscript
Normal file
226
tests/fw/services/timeline/wscript
Normal file
|
@ -0,0 +1,226 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/services/normal/blob_db/timeline_item_storage.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/blob_db/reminder_db.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/services/normal/timeline/item.c" \
|
||||
" src/fw/services/normal/timeline/attributes_actions.c" \
|
||||
" src/fw/services/normal/timeline/attribute_group.c" \
|
||||
" src/fw/services/normal/timeline/reminders.c",
|
||||
test_sources_ant_glob = "test_reminders.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
def build(ctx):
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
"src/fw/services/normal/blob_db/pin_db.c "
|
||||
"src/fw/services/normal/blob_db/timeline_item_storage.c "
|
||||
"src/fw/services/normal/timeline/attribute.c "
|
||||
"src/fw/services/normal/timeline/attribute_group.c "
|
||||
"src/fw/services/normal/timeline/attributes_actions.c "
|
||||
"src/fw/services/normal/timeline/calendar.c "
|
||||
"src/fw/services/normal/timeline/event.c "
|
||||
"src/fw/services/normal/timeline/item.c "
|
||||
"src/fw/services/normal/timeline/timeline.c "
|
||||
"src/fw/util/crc8.c "
|
||||
"src/fw/util/time/time.c "
|
||||
"tests/fakes/fake_events.c "
|
||||
"tests/fakes/fake_rtc.c "
|
||||
"tests/fakes/fake_settings_file.c "
|
||||
),
|
||||
test_sources_ant_glob="test_calendar.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
"src/fw/services/normal/blob_db/pin_db.c "
|
||||
"src/fw/services/normal/blob_db/timeline_item_storage.c "
|
||||
"src/fw/services/normal/timeline/attribute.c "
|
||||
"src/fw/services/normal/timeline/attribute_group.c "
|
||||
"src/fw/services/normal/timeline/attributes_actions.c "
|
||||
"src/fw/services/normal/timeline/event.c "
|
||||
"src/fw/services/normal/timeline/item.c "
|
||||
"src/fw/services/normal/timeline/peek.c "
|
||||
"src/fw/services/normal/timeline/timeline.c "
|
||||
"src/fw/util/crc8.c "
|
||||
"src/fw/util/time/time.c "
|
||||
"tests/fakes/fake_events.c "
|
||||
"tests/fakes/fake_rtc.c "
|
||||
"tests/fakes/fake_settings_file.c "
|
||||
),
|
||||
test_sources_ant_glob = "test_timeline_peek_event.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/timeline/attribute.c",
|
||||
test_sources_ant_glob = "test_attribute.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/util/time/mktime.c" \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/services/normal/blob_db/timeline_item_storage.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/services/normal/timeline/item.c" \
|
||||
" src/fw/services/normal/timeline/attributes_actions.c" \
|
||||
" src/fw/services/normal/timeline/attribute_group.c" \
|
||||
" src/fw/services/normal/timeline/timeline.c" \
|
||||
" src/fw/services/normal/blob_db/pin_db.c" \
|
||||
" src/fw/apps/system_apps/timeline/timeline_model.c",
|
||||
test_sources_ant_glob = "test_timeline_model.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
" src/fw/process_management/pebble_process_info.c"
|
||||
" src/fw/services/normal/timeline/timeline_resources.c"
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c"
|
||||
),
|
||||
test_sources_ant_glob = "test_timeline_resources.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/alarms/alarm.c" \
|
||||
" src/fw/services/normal/timeline/alarm_layout.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c",
|
||||
test_sources_ant_glob = "test_alarm_layout.c",
|
||||
defines=["CAPABILITY_HAS_HEALTH_TRACKING=0"],
|
||||
override_includes=['dummy_board'],
|
||||
platforms=['snowy', 'spalding'])
|
||||
|
||||
rendering_sources = \
|
||||
" src/fw/applib/fonts/codepoint.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/bitblt_private.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/framebuffer.c" \
|
||||
" src/fw/applib/graphics/bitblt.c" \
|
||||
" src/fw/applib/graphics/framebuffer.c" \
|
||||
" src/fw/applib/graphics/gbitmap.c" \
|
||||
" src/fw/applib/graphics/gbitmap_png.c" \
|
||||
" src/fw/applib/graphics/gbitmap_sequence.c" \
|
||||
" src/fw/applib/graphics/gcolor_definitions.c" \
|
||||
" src/fw/applib/graphics/gdraw_command.c" \
|
||||
" src/fw/applib/graphics/gdraw_command_frame.c" \
|
||||
" src/fw/applib/graphics/gdraw_command_image.c" \
|
||||
" src/fw/applib/graphics/gdraw_command_list.c" \
|
||||
" src/fw/applib/graphics/gdraw_command_sequence.c" \
|
||||
" src/fw/applib/graphics/gpath.c" \
|
||||
" src/fw/applib/graphics/graphics.c" \
|
||||
" src/fw/applib/graphics/graphics_bitmap.c" \
|
||||
" src/fw/applib/graphics/graphics_circle.c" \
|
||||
" src/fw/applib/graphics/graphics_line.c" \
|
||||
" src/fw/applib/graphics/graphics_private.c" \
|
||||
" src/fw/applib/graphics/graphics_private_raw.c" \
|
||||
" src/fw/applib/graphics/gtransform.c" \
|
||||
" src/fw/applib/graphics/gtypes.c" \
|
||||
" src/fw/applib/graphics/perimeter.c" \
|
||||
" src/fw/applib/graphics/text_layout.c" \
|
||||
" src/fw/applib/graphics/text_render.c" \
|
||||
" src/fw/applib/graphics/text_resources.c" \
|
||||
" src/fw/applib/graphics/utf8.c" \
|
||||
" src/fw/applib/ui/action_button.c" \
|
||||
" src/fw/applib/ui/animation_interpolate.c" \
|
||||
" src/fw/applib/ui/content_indicator.c" \
|
||||
" src/fw/applib/ui/inverter_layer.c" \
|
||||
" src/fw/applib/ui/kino/kino_layer.c" \
|
||||
" src/fw/applib/ui/kino/kino_player.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel/transform.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_custom.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_gbitmap.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_gbitmap_sequence.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_pdci.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_pdcs.c" \
|
||||
" src/fw/applib/ui/layer.c" \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/applib/ui/menu_layer_system_cells.c" \
|
||||
" src/fw/applib/ui/scroll_layer.c" \
|
||||
" src/fw/applib/ui/shadows.c" \
|
||||
" src/fw/applib/ui/status_bar_layer.c" \
|
||||
" src/fw/applib/ui/text_layer.c" \
|
||||
" src/fw/applib/ui/text_layer_flow.c" \
|
||||
" src/fw/applib/ui/window.c" \
|
||||
" src/fw/applib/vendor/tinflate/tinflate.c" \
|
||||
" src/fw/applib/vendor/uPNG/upng.c" \
|
||||
" src/fw/apps/system_apps/timeline/text_node.c" \
|
||||
" src/fw/board/displays/display_spalding.c" \
|
||||
" src/fw/drivers/flash/flash_crc.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/resource/resource.c" \
|
||||
" src/fw/resource/resource_storage.c" \
|
||||
" src/fw/resource/resource_storage_builtin.c" \
|
||||
" src/fw/resource/resource_storage_file.c" \
|
||||
" src/fw/resource/resource_storage_flash.c" \
|
||||
" src/fw/services/normal/filesystem/app_file.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/system/hexdump.c" \
|
||||
" src/fw/util/buffer.c" \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" src/fw/util/stringlist.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" tests/fakes/fake_applib_resource.c" \
|
||||
" tests/fakes/fake_clock.c" \
|
||||
" tests/fakes/fake_display.c" \
|
||||
" tests/fakes/fake_fonts.c" \
|
||||
" tests/fakes/fake_gbitmap_get_data_row.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" tests/fixtures/resources/builtin_resources.auto.c" \
|
||||
" tests/fixtures/resources/pfs_resource_table.c" \
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c" \
|
||||
" tests/stubs/stubs_animation.c"
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
rendering_sources +
|
||||
" src/fw/apps/system_apps/timeline/pin_window.c"
|
||||
" src/fw/popups/timeline/timeline_item_layer.c"
|
||||
" src/fw/services/normal/timeline/attribute.c"
|
||||
" src/fw/services/normal/timeline/generic_layout.c"
|
||||
" src/fw/services/normal/timeline/layout_layer.c"
|
||||
" src/fw/services/normal/timeline/layout_node.c"
|
||||
" src/fw/services/normal/timeline/timeline_layout.c"
|
||||
" src/fw/services/normal/timeline/timeline_resources.c"
|
||||
" src/fw/services/normal/timeline/weather_layout.c"
|
||||
" src/fw/services/normal/weather/weather_types.c"
|
||||
" src/fw/shell/system_theme.c"
|
||||
" tests/stubs/stubs_clock.c"
|
||||
" tests/stubs/stubs_timeline_layout.c"
|
||||
),
|
||||
test_sources_ant_glob = "test_timeline_layouts.c",
|
||||
defines=ctx.env.test_image_defines + ["USE_DISPLAY_PERIMETER_ON_FONT_LAYOUT=1"],
|
||||
runtime_deps=ctx.env.test_pngs + ctx.env.test_pbis + ctx.env.test_pfos,
|
||||
override_includes=['dummy_board'],
|
||||
platforms=['snowy', 'spalding', 'silk', 'robert'])
|
||||
|
||||
# vim:filetype=python
|
Loading…
Add table
Add a link
Reference in a new issue