/* * 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 "applib/ui/option_menu_window.h" #include "resource/resource.h" #include "resource/resource_ids.auto.h" #include "services/normal/timeline/timeline_resources.h" #include "clar.h" // Fakes ///////////////////// #include "fake_app_state.h" #include "fake_content_indicator.h" #include "fake_graphics_context.h" #include "fixtures/load_test_resources.h" // Stubs ///////////////////// #include "stubs_analytics.h" #include "stubs_animation_timing.h" #include "stubs_app_install_manager.h" #include "stubs_app_state.h" #include "stubs_app_timer.h" #include "stubs_bootbits.h" #include "stubs_buffer.h" #include "stubs_click.h" #include "stubs_compiled_with_legacy2_sdk.h" #include "stubs_event_service_client.h" #include "stubs_heap.h" #include "stubs_logging.h" #include "stubs_memory_layout.h" #include "stubs_mutex.h" #include "stubs_passert.h" #include "stubs_pbl_malloc.h" #include "stubs_pebble_tasks.h" #include "stubs_print.h" #include "stubs_process_manager.h" #include "stubs_prompt.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_unobstructed_area.h" #include "stubs_window_manager.h" #include "stubs_window_stack.h" // Setup and Teardown //////////////////////////////////// typedef struct OptionMenuTestData { OptionMenu option_menu; } OptionMenuTestData; OptionMenuTestData s_data; void test_option_menu_window__initialize(void) { fake_app_state_init(); load_system_resources_fixture(); s_data = (OptionMenuTestData) {}; rtc_set_time(3 * SECONDS_PER_DAY); } void test_option_menu_window__cleanup(void) { } // Helpers ////////////////////// typedef struct MenuItemConfig { const char *title; const char *subtitle; } MenuItemConfig; typedef struct MenuConfig { OptionMenuCallbacks callbacks; const char *title; size_t num_items; MenuItemConfig *items; OptionMenuContentType content_type; bool icons_enabled; } MenuConfig; static uint16_t prv_menu_get_num_rows(OptionMenu *option_menu, void *context) { return ((MenuConfig *)context)->num_items; } static void prv_menu_draw_row(OptionMenu *option_menu, GContext *ctx, const Layer *cell_layer, const GRect *cell_frame, uint32_t row, bool selected, void *context) { MenuConfig *data = context; option_menu_system_draw_row(option_menu, ctx, cell_layer, cell_frame, data->items[row].title, selected, context); } static void prv_create_menu_and_render(MenuConfig *config) { option_menu_init(&s_data.option_menu); const OptionMenuConfig option_menu_config = { .title = config->title ?: "Option Menu", .content_type = config->content_type, .status_colors = { GColorWhite, GColorBlack }, .highlight_colors = { PBL_IF_COLOR_ELSE(GColorCobaltBlue, GColorBlack), GColorWhite }, .icons_enabled = config->icons_enabled, }; option_menu_configure(&s_data.option_menu, &option_menu_config); const OptionMenuCallbacks callbacks = { .draw_row = config->callbacks.draw_row ?: prv_menu_draw_row, .get_num_rows = config->callbacks.get_num_rows ?: prv_menu_get_num_rows, .get_cell_height = config->callbacks.get_cell_height ?: NULL, }; option_menu_set_callbacks(&s_data.option_menu, &callbacks, config); window_set_on_screen(&s_data.option_menu.window, true, true); window_render(&s_data.option_menu.window, fake_graphics_context_get_context()); } // Tests ////////////////////// // These tests test all permutations on all platforms even if the combination on the particular // platform was not designed and thus does not appear pleasant. Make sure you are looking at the // combination relevant to your use case when examining the unit test output of Option Menu. void prv_create_menu_and_render_long_title(bool icons_enabled, const char *title, bool special_height) { prv_create_menu_and_render(&(MenuConfig) { .title = title, .content_type = special_height ? OptionMenuContentType_DoubleLine : OptionMenuContentType_Default, .num_items = 3, .items = (MenuItemConfig[]) { { .title = "Allow All Notifications", }, { .title = "Allow Phone Calls Only", }, { .title = "Mute All Notifications", } }, .icons_enabled = icons_enabled, }); } void test_option_menu_window__long_title_default_height(void) { prv_create_menu_and_render_long_title(false /* icons_enabled */, "Default Height", false /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__long_title_default_height_icons(void) { prv_create_menu_and_render_long_title(true /* icons_enabled */, "Default Height", false /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__long_title_special_height(void) { prv_create_menu_and_render_long_title(false /* icons_enabled */, "Special Height", true /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__long_title_special_height_icons(void) { prv_create_menu_and_render_long_title(true /* icons_enabled */, "Special Height", true /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void prv_create_menu_and_render_short_title(bool icons_enabled, const char *title, bool special_height) { prv_create_menu_and_render(&(MenuConfig) { .title = title, .content_type = special_height ? OptionMenuContentType_SingleLine : OptionMenuContentType_Default, .num_items = 3, .items = (MenuItemConfig[]) { { .title = "Smaller", }, { .title = "Default", }, { .title = "Larger", } }, .icons_enabled = icons_enabled, }); } void test_option_menu_window__short_title_default_height(void) { prv_create_menu_and_render_short_title(false /* icons_enabled */, "Default Height", false /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__short_title_default_height_icons(void) { prv_create_menu_and_render_short_title(true /* icons_enabled */, "Default Height", false /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__short_title_special_height(void) { prv_create_menu_and_render_short_title(false /* icons_enabled */, "Special Height", true /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); } void test_option_menu_window__short_title_special_height_icons(void) { prv_create_menu_and_render_short_title(true /* icons_enabled */, "Special Height", true /* special_height */); FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE(); }