/* * 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/text_layer.h" // Stubs ///////////////////// #include "stubs_app_state.h" #include "stubs_graphics.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_process_manager.h" #include "stubs_system_theme.h" #include "stubs_ui_window.h" #include "stubs_unobstructed_area.h" GFont fonts_get_system_font(const char *font_key) { return NULL; } void graphics_context_set_fill_color(GContext* ctx, GColor color){} void graphics_context_set_text_color(GContext* ctx, GColor color){} // Fakes //////////////////////// #define MOCKED_CREATED_LAYOUT (GTextLayoutCacheRef)123456 void graphics_text_layout_cache_init(GTextLayoutCacheRef *layout_cache) { *layout_cache = MOCKED_CREATED_LAYOUT; } void graphics_text_layout_cache_deinit(GTextLayoutCacheRef *layout_cache) {} void graphics_text_layout_set_line_spacing_delta(GTextLayoutCacheRef layout, int16_t delta) {} int16_t graphics_text_layout_get_line_spacing_delta(const GTextLayoutCacheRef layout) { return 0; } GSize graphics_text_layout_get_max_used_size(GContext *ctx, const char *text, GFont const font, const GRect box, const GTextOverflowMode overflow_mode, const GTextAlignment alignment, GTextLayoutCacheRef layout) { return GSizeZero; } typedef struct { struct { GTextLayoutCacheRef layout; } disable_text_flow; struct { GTextLayoutCacheRef layout; uint8_t inset; } enable_text_flow; struct { GTextLayoutCacheRef layout; } disable_paging; struct { GTextLayoutCacheRef layout; GPoint origin; GRect paging; } enable_paging; } MockValues; static MockValues s_actual; void graphics_text_attributes_restore_default_text_flow(GTextLayoutCacheRef layout) { s_actual.disable_text_flow.layout = layout; } void graphics_text_attributes_enable_screen_text_flow(GTextLayoutCacheRef layout, uint8_t inset) { s_actual.enable_text_flow.layout = layout; s_actual.enable_text_flow.inset = inset; } void graphics_text_attributes_restore_default_paging(GTextLayoutCacheRef layout) { s_actual.disable_paging.layout = layout; } void graphics_text_attributes_enable_paging(GTextLayoutCacheRef layout, GPoint content_origin_on_screen, GRect paging_on_screen) { s_actual.enable_paging.layout = layout; s_actual.enable_paging.origin = content_origin_on_screen; s_actual.enable_paging.paging = paging_on_screen; } #define MOCKED_PAGING_ORIGIN GPoint(1 ,2) #define MOCKED_PAGING_PAGE GRect(3, 4, 5, 6) bool s_text_layer_calc_text_flow_paging_values_result; bool text_layer_calc_text_flow_paging_values(const TextLayer *text_layer, GPoint *content_origin_on_screen, GRect *page_rect_on_screen) { *content_origin_on_screen = MOCKED_PAGING_ORIGIN; *page_rect_on_screen = MOCKED_PAGING_PAGE; return s_text_layer_calc_text_flow_paging_values_result; } // Tests ////////////////////// #define cl_assert_mocks_called(expected) \ do { \ cl_assert_equal_p((expected).disable_text_flow.layout, s_actual.disable_text_flow.layout); \ cl_assert_equal_p((expected).enable_text_flow.layout, s_actual.enable_text_flow.layout); \ cl_assert_equal_i((expected).enable_text_flow.inset, s_actual.enable_text_flow.inset); \ cl_assert_equal_p((expected).disable_paging.layout, s_actual.disable_paging.layout); \ cl_assert_equal_p((expected).enable_paging.layout, s_actual.enable_paging.layout); \ cl_assert_equal_i((expected).enable_paging.origin.x, s_actual.enable_paging.origin.x); \ cl_assert_equal_i((expected).enable_paging.origin.y, s_actual.enable_paging.origin.y); \ cl_assert_equal_i((expected).enable_paging.paging.origin.x, s_actual.enable_paging.paging.origin.x); \ cl_assert_equal_i((expected).enable_paging.paging.origin.y, s_actual.enable_paging.paging.origin.y); \ cl_assert_equal_i((expected).enable_paging.paging.size.w, s_actual.enable_paging.paging.size.w); \ cl_assert_equal_i((expected).enable_paging.paging.size.h, s_actual.enable_paging.paging.size.h); \ } while(0) Window window; TextLayer text_layer; void test_text_layer__initialize(void) { s_actual = (MockValues){}; window = (Window){}; text_layer_init(&text_layer, &GRect(10, 20, 30, 40)); s_text_layer_calc_text_flow_paging_values_result = true; } void test_text_layer__cleanup(void) { } void test_text_layer__enable_text_flow_does_nothing_outside_view_hierarchy(void) { text_layer_enable_screen_text_flow_and_paging(&text_layer, 8); // nothing called cl_assert_mocks_called((MockValues){}); cl_assert(text_layer.layout_cache == NULL); } void test_text_layer__enable_text_flow(void) { text_layer.layer.window = &window; text_layer_enable_screen_text_flow_and_paging(&text_layer, 8); cl_assert_mocks_called(((MockValues){ .enable_text_flow.layout = text_layer.layout_cache, .enable_text_flow.inset = 8, .enable_paging.layout = text_layer.layout_cache, .enable_paging.origin = MOCKED_PAGING_ORIGIN, .enable_paging.paging = MOCKED_PAGING_PAGE, })); cl_assert(text_layer.layout_cache == MOCKED_CREATED_LAYOUT); } void test_text_layer__enable_text_flow_requires_successful_calc_for_paging(void) { text_layer.layer.window = &window; s_text_layer_calc_text_flow_paging_values_result = false; text_layer_enable_screen_text_flow_and_paging(&text_layer, 8); cl_assert_mocks_called(((MockValues){ .enable_text_flow.layout = text_layer.layout_cache, .enable_text_flow.inset = 8, })); cl_assert(text_layer.layout_cache == MOCKED_CREATED_LAYOUT); } void test_text_layer__disable_text_flow(void) { text_layer.layout_cache = MOCKED_CREATED_LAYOUT; text_layer_restore_default_text_flow_and_paging(&text_layer); cl_assert_mocks_called(((MockValues){ .disable_paging.layout = text_layer.layout_cache, .disable_text_flow.layout = text_layer.layout_cache, })); }