mirror of
https://github.com/google/pebble.git
synced 2025-03-21 11:21:21 +00:00
298 lines
13 KiB
C
298 lines
13 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 "applib/ui/content_indicator.h"
|
|
#include "applib/ui/content_indicator_private.h"
|
|
#include "util/buffer.h"
|
|
|
|
// Fakes
|
|
////////////////////////////////////
|
|
|
|
#include "fake_app_timer.h"
|
|
#include "fake_content_indicator.h"
|
|
|
|
// Stubs
|
|
////////////////////////////////////
|
|
|
|
#include "stubs_app_state.h"
|
|
#include "stubs_compiled_with_legacy2_sdk.h"
|
|
#include "stubs_gpath.h"
|
|
#include "stubs_graphics.h"
|
|
#include "stubs_graphics_context.h"
|
|
#include "stubs_heap.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_pbl_malloc.h"
|
|
#include "stubs_pebble_tasks.h"
|
|
#include "stubs_ui_window.h"
|
|
#include "stubs_unobstructed_area.h"
|
|
|
|
extern void prv_content_indicator_update_proc(Layer *layer, GContext *ctx);
|
|
|
|
// Helpers
|
|
////////////////////////////////////
|
|
|
|
static Layer s_content_indicator_dummy_layer;
|
|
static LayerUpdateProc s_content_indicator_dummy_layer_update_proc;
|
|
|
|
ContentIndicatorConfig helper_get_dummy_config(void) {
|
|
return (ContentIndicatorConfig) {
|
|
.layer = &s_content_indicator_dummy_layer,
|
|
.times_out = false,
|
|
.alignment = GAlignLeft,
|
|
.colors = {
|
|
.foreground = GColorGreen,
|
|
.background = GColorRed
|
|
}
|
|
};
|
|
}
|
|
|
|
void helper_check_buffer_for_content_indicator(size_t index, ContentIndicator *content_indicator) {
|
|
ContentIndicatorsBuffer *content_indicators_buffer = content_indicator_get_current_buffer();
|
|
Buffer *buffer = &content_indicators_buffer->buffer;
|
|
ContentIndicator **content_indicators = (ContentIndicator**)buffer->data;
|
|
cl_assert_equal_p(content_indicators[index], content_indicator);
|
|
}
|
|
|
|
void helper_check_configs_for_equality(ContentIndicatorConfig a, ContentIndicatorConfig b) {
|
|
cl_assert_equal_p(a.layer, b.layer);
|
|
cl_assert_equal_b(a.times_out, b.times_out);
|
|
cl_assert(a.alignment == b.alignment);
|
|
cl_assert(a.colors.foreground.argb == b.colors.foreground.argb);
|
|
cl_assert(a.colors.background.argb == b.colors.background.argb);
|
|
}
|
|
|
|
// Setup
|
|
/////////////////////////////////
|
|
|
|
void test_content_indicator__initialize(void) {
|
|
// Initialize the static buffer of content indicators
|
|
content_indicator_init_buffer(content_indicator_get_current_buffer());
|
|
// Reset the dummy layer's fields
|
|
memset(&s_content_indicator_dummy_layer, 0, sizeof(Layer));
|
|
}
|
|
|
|
void test_content_indicator__cleanup(void) {
|
|
}
|
|
|
|
// Tests
|
|
////////////////////////////////////
|
|
|
|
void test_content_indicator__create_should_add_to_buffer(void) {
|
|
ContentIndicator *content_indicator;
|
|
for (size_t i = 0; i < CONTENT_INDICATOR_BUFFER_SIZE; i++) {
|
|
content_indicator = content_indicator_create();
|
|
cl_assert(content_indicator);
|
|
helper_check_buffer_for_content_indicator(i, content_indicator);
|
|
}
|
|
|
|
// Creating more content indicators than the buffer can hold should return NULL
|
|
cl_assert_equal_p(content_indicator_create(), NULL);
|
|
}
|
|
|
|
void test_content_indicator__init_should_add_to_buffer(void) {
|
|
ContentIndicator content_indicator;
|
|
for (size_t i = 0; i < CONTENT_INDICATOR_BUFFER_SIZE; i++) {
|
|
content_indicator_init(&content_indicator);
|
|
helper_check_buffer_for_content_indicator(i, &content_indicator);
|
|
}
|
|
|
|
// Initializing more content indicators than the buffer can hold should assert
|
|
cl_assert_passert(content_indicator_init(&content_indicator));
|
|
}
|
|
|
|
void test_content_indicator__deinit_should_remove_from_buffer(void) {
|
|
ContentIndicatorsBuffer *content_indicators_buffer = content_indicator_get_current_buffer();
|
|
Buffer *buffer = &content_indicators_buffer->buffer;
|
|
|
|
ContentIndicator content_indicator;
|
|
size_t bytes_written = 0;
|
|
for (size_t i = 0; i < CONTENT_INDICATOR_BUFFER_SIZE; i++) {
|
|
content_indicator_init(&content_indicator);
|
|
bytes_written += sizeof(ContentIndicator *);
|
|
cl_assert_equal_i(buffer->bytes_written, bytes_written);
|
|
}
|
|
|
|
for (size_t i = 0; i < CONTENT_INDICATOR_BUFFER_SIZE; i++) {
|
|
content_indicator_deinit(&content_indicator);
|
|
bytes_written -= sizeof(ContentIndicator *);
|
|
cl_assert_equal_i(buffer->bytes_written, bytes_written);
|
|
}
|
|
}
|
|
|
|
void test_content_indicator__configuring_should_configure(void) {
|
|
ContentIndicator content_indicator;
|
|
content_indicator_init(&content_indicator);
|
|
ContentIndicatorDirectionData *direction_data = content_indicator.direction_data;
|
|
|
|
// Test setting a dummy configuration for a direction
|
|
const ContentIndicatorConfig dummy_config = helper_get_dummy_config();
|
|
const ContentIndicatorDirection direction = ContentIndicatorDirectionUp;
|
|
dummy_config.layer->update_proc = s_content_indicator_dummy_layer_update_proc;
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, direction, &dummy_config));
|
|
helper_check_configs_for_equality(dummy_config, direction_data[direction].config);
|
|
// Should save a reference to the config layer's update proc
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, direction_data->original_update_proc);
|
|
cl_assert_equal_p(direction_data->original_update_proc,
|
|
s_content_indicator_dummy_layer_update_proc);
|
|
}
|
|
|
|
void test_content_indicator__configuring_different_directions_with_same_layer_should_fail(void) {
|
|
ContentIndicator content_indicator;
|
|
content_indicator_init(&content_indicator);
|
|
|
|
// Setting a dummy configuration for a direction should return true
|
|
const ContentIndicatorConfig dummy_config = helper_get_dummy_config();
|
|
dummy_config.layer->update_proc = s_content_indicator_dummy_layer_update_proc;
|
|
cl_assert(content_indicator_configure_direction(&content_indicator,
|
|
ContentIndicatorDirectionUp,
|
|
&dummy_config));
|
|
|
|
// Using the same dummy configuration (which has the same layer) to configure a different
|
|
// direction should fail
|
|
cl_assert(!content_indicator_configure_direction(&content_indicator,
|
|
ContentIndicatorDirectionDown,
|
|
&dummy_config));
|
|
}
|
|
|
|
void test_content_indicator__setting_content_available_should_update_layer_update_proc(void) {
|
|
ContentIndicator content_indicator;
|
|
content_indicator_init(&content_indicator);
|
|
ContentIndicatorDirectionData *direction_data = content_indicator.direction_data;
|
|
|
|
const ContentIndicatorConfig dummy_config = helper_get_dummy_config();
|
|
const ContentIndicatorDirection direction = ContentIndicatorDirectionUp;
|
|
dummy_config.layer->update_proc = s_content_indicator_dummy_layer_update_proc;
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, direction, &dummy_config));
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, direction_data->original_update_proc);
|
|
cl_assert_equal_p(direction_data->original_update_proc,
|
|
s_content_indicator_dummy_layer_update_proc);
|
|
|
|
// Setting content available should switch the layer's update proc to draw an arrow
|
|
content_indicator_set_content_available(&content_indicator, direction, true);
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, prv_content_indicator_update_proc);
|
|
|
|
// Setting content unavailable should revert the layer's update proc
|
|
content_indicator_set_content_available(&content_indicator, direction, false);
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, direction_data->original_update_proc);
|
|
cl_assert_equal_p(direction_data->original_update_proc,
|
|
s_content_indicator_dummy_layer_update_proc);
|
|
}
|
|
|
|
void test_content_indicator__creating_for_scroll_layer(void) {
|
|
ScrollLayer scroll_layer;
|
|
ContentIndicator *content_indicator = content_indicator_get_or_create_for_scroll_layer(
|
|
&scroll_layer);
|
|
cl_assert(content_indicator);
|
|
// Should save a reference to the scroll layer
|
|
cl_assert_equal_p(content_indicator->scroll_layer, &scroll_layer);
|
|
|
|
// Should retrieve the same content indicator with the same scroll layer
|
|
ContentIndicator *content_indicator2 = content_indicator_get_or_create_for_scroll_layer(
|
|
&scroll_layer);
|
|
cl_assert(content_indicator2);
|
|
// Should save a reference to the scroll layer
|
|
cl_assert_equal_p(content_indicator2->scroll_layer, &scroll_layer);
|
|
cl_assert_equal_p(content_indicator2, content_indicator);
|
|
|
|
// Should retrieve a different content indicator for a different scroll layer
|
|
ScrollLayer scroll_layer2;
|
|
ContentIndicator *content_indicator3 = content_indicator_get_or_create_for_scroll_layer(
|
|
&scroll_layer2);
|
|
cl_assert(content_indicator3);
|
|
// Should save a reference to the scroll layer
|
|
cl_assert_equal_p(content_indicator3->scroll_layer, &scroll_layer2);
|
|
cl_assert(content_indicator3 != content_indicator);
|
|
}
|
|
|
|
void test_content_indicator__should_only_be_created_for_scroll_layer_upon_client_access(void) {
|
|
ContentIndicatorsBuffer *content_indicators_buffer = content_indicator_get_current_buffer();
|
|
Buffer *buffer = &content_indicators_buffer->buffer;
|
|
// At the start of the test, the buffer should be empty
|
|
cl_assert(buffer_is_empty(buffer));
|
|
|
|
ScrollLayer scroll_layer;
|
|
// Trying to access the ContentIndicator for this ScrollLayer should return NULL because we
|
|
// haven't tried to access it as the client yet
|
|
cl_assert_equal_p(content_indicator_get_for_scroll_layer(&scroll_layer), NULL);
|
|
// And the buffer should still be empty
|
|
cl_assert(buffer_is_empty(buffer));
|
|
|
|
// Now we try to access it as the client, which should actually create the ContentIndicator
|
|
ContentIndicator *content_indicator = content_indicator_get_or_create_for_scroll_layer(
|
|
&scroll_layer);
|
|
cl_assert(content_indicator);
|
|
// The ContentIndicator should have a reference to the ScrollLayer
|
|
cl_assert_equal_p(content_indicator->scroll_layer, &scroll_layer);
|
|
// The buffer should now hold the newly created ContentIndicator
|
|
cl_assert(buffer->bytes_written == sizeof(ContentIndicator *));
|
|
|
|
// Finally, calling content_indicator_get_for_scroll_layer() again should return the same
|
|
// ContentIndicator
|
|
ContentIndicator *content_indicator2 = content_indicator_get_for_scroll_layer(&scroll_layer);
|
|
cl_assert(content_indicator2);
|
|
cl_assert_equal_p(content_indicator2, content_indicator);
|
|
// The buffer should still only hold the single ContentIndicator
|
|
cl_assert(buffer->bytes_written == sizeof(ContentIndicator *));
|
|
}
|
|
|
|
void test_content_indicator__pass_null_config_to_reset_direction_data(void) {
|
|
ContentIndicator content_indicator;
|
|
content_indicator_init(&content_indicator);
|
|
ContentIndicatorDirectionData *direction_data = content_indicator.direction_data;
|
|
|
|
const ContentIndicatorConfig dummy_config = helper_get_dummy_config();
|
|
const ContentIndicatorDirection direction = ContentIndicatorDirectionUp;
|
|
dummy_config.layer->update_proc = s_content_indicator_dummy_layer_update_proc;
|
|
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, direction, &dummy_config));
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, direction_data->original_update_proc);
|
|
cl_assert_equal_p(direction_data->original_update_proc,
|
|
s_content_indicator_dummy_layer_update_proc);
|
|
|
|
// Setting content available should switch the layer's update proc
|
|
content_indicator_set_content_available(&content_indicator, direction, true);
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, prv_content_indicator_update_proc);
|
|
|
|
// Direction data should be emptied and layer's update proc should return to original when NULL
|
|
// config is passed
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, direction, NULL));
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, s_content_indicator_dummy_layer_update_proc);
|
|
cl_assert(!direction_data[direction].config.layer);
|
|
|
|
// Setting content available should not change layer update proc without reconfiguring.
|
|
content_indicator_set_content_available(&content_indicator, direction, true);
|
|
cl_assert_equal_p(dummy_config.layer->update_proc, s_content_indicator_dummy_layer_update_proc);
|
|
}
|
|
|
|
void test_content_indicator__re_configure_direction(void) {
|
|
ContentIndicator content_indicator;
|
|
content_indicator_init(&content_indicator);
|
|
|
|
const ContentIndicatorConfig dummy_config = helper_get_dummy_config();
|
|
const ContentIndicatorDirection up = ContentIndicatorDirectionUp;
|
|
const ContentIndicatorDirection down = ContentIndicatorDirectionDown;
|
|
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, up, &dummy_config));
|
|
|
|
// re-configure with the same direction, should be a success
|
|
cl_assert(content_indicator_configure_direction(&content_indicator, up, &dummy_config));
|
|
|
|
// re-configure with a different same direction, should fail
|
|
cl_assert(!content_indicator_configure_direction(&content_indicator, down, &dummy_config));
|
|
}
|