mirror of
https://github.com/google/pebble.git
synced 2025-03-22 19:52:19 +00:00
373 lines
16 KiB
C
373 lines
16 KiB
C
|
/*
|
||
|
* Copyright 2024 Google LLC
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "clar.h"
|
||
|
|
||
|
#include "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");
|
||
|
}
|