mirror of
https://github.com/google/pebble.git
synced 2025-05-29 14:33:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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/health/health_activity_detail_card.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
#include "apps/system_apps/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
#include "apps/system_apps/health/health_progress.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static Window* prv_create_card_and_render(HealthData *health_data) {
|
||||
Window *window = health_activity_detail_card_create(health_data);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
return window;
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_activity_detail_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__render_current_calories_and_distance(void) {
|
||||
HealthData health_data = {
|
||||
.current_calories = 123,
|
||||
.current_distance_meters = 4000,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__render_no_calories(void) {
|
||||
HealthData health_data = {
|
||||
.current_calories = 0,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__render_no_distance(void) {
|
||||
HealthData health_data = {
|
||||
.current_distance_meters = 0,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__render_step_data(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = {600, 900, 700, 1200, 1400, 1300, 1000},
|
||||
.monthly_step_average = 1000,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 3), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_detail_card__render_day_label_no_steps(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = {600, 0, 700},
|
||||
.monthly_step_average = 1000,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 2), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* 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/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
#include "apps/system_apps/health/health_activity_summary_card.h"
|
||||
#include "apps/system_apps/health/health_activity_detail_card.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_card_and_render(HealthData *health_data) {
|
||||
Window window;
|
||||
window_init(&window, WINDOW_NAME("Health"));
|
||||
Layer *window_layer = window_get_root_layer(&window);
|
||||
Layer *card_layer = health_activity_summary_card_create(health_data);
|
||||
layer_set_frame(card_layer, &window_layer->bounds);
|
||||
layer_add_child(window_layer, card_layer);
|
||||
window_set_background_color(&window, health_activity_summary_card_get_bg_color(card_layer));
|
||||
window_set_on_screen(&window, true, true);
|
||||
window_render(&window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_activity_summary_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__no_current_steps(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 0,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 750,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_behind_typical1(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 170,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 340,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_behind_typical2(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 320,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 340,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_behind_typical3(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 460,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 555,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_behind_typical4(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 699,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 840,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_behind_typical5(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 837,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 914,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_equals_typical(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 837,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 837,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_typical1(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 340,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 170,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_typical2(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 400,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 379,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_typical3(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 780,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 480,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_typical4(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 866,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 700,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_typical5(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = 970,
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 900,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_activity_summary_card__render_current_above_expected(void) {
|
||||
HealthData health_data = {
|
||||
.step_data = {2000},
|
||||
.step_averages = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 50}, // 1000
|
||||
.current_step_average = 800,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
64
tests/fw/apps/system_apps/health/test_health_app_includes.h
Normal file
64
tests/fw/apps/system_apps/health/test_health_app_includes.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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/window_private.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fake_rtc.h"
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fixtures/load_test_resources.h"
|
||||
|
||||
// Stubs
|
||||
/////////////////////
|
||||
|
||||
#include "stubs_activity.h"
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_animation_timing.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_app_launch_reason.h"
|
||||
#include "stubs_app_timer.h"
|
||||
#include "stubs_app_window_stack.h"
|
||||
#include "stubs_bootbits.h"
|
||||
#include "stubs_click.h"
|
||||
#include "stubs_health_service.h"
|
||||
#include "stubs_layer.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_process_info.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_serial.h"
|
||||
#include "stubs_shell_prefs.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_status_bar_layer.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "fw/graphics/util.h"
|
86
tests/fw/apps/system_apps/health/test_health_card_view.c
Normal file
86
tests/fw/apps/system_apps/health/test_health_card_view.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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/health/health_card_view.h"
|
||||
#include "apps/system_apps/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
#include "apps/system_apps/health/health_activity_summary_card.h"
|
||||
#include "apps/system_apps/health/health_activity_detail_card.h"
|
||||
#include "apps/system_apps/health/health_hr_summary_card.h"
|
||||
#include "apps/system_apps/health/health_sleep_summary_card.h"
|
||||
#include "apps/system_apps/health/health_sleep_detail_card.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////
|
||||
|
||||
void clock_get_until_time_without_fulltime(char *buffer, int buf_size, time_t timestamp,
|
||||
int max_relative_hrs) {
|
||||
snprintf(buffer, buf_size, "5 MIN AGO");
|
||||
}
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_card_view__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_card_view__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static Window* prv_create_card_and_render(HealthData *health_data) {
|
||||
Window *window = (Window *)health_card_view_create(health_data);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
return window;
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_card_view__render_indicators(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
343
tests/fw/apps/system_apps/health/test_health_detail_card.c
Normal file
343
tests/fw/apps/system_apps/health/test_health_detail_card.c
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* 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/health/health_detail_card.h"
|
||||
#include "apps/system_apps/health/health_progress.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
#define BG_COLOR PBL_IF_COLOR_ELSE(GColorBlueMoon, GColorWhite)
|
||||
#define FILL_COLOR PBL_IF_COLOR_ELSE(GColorKellyGreen, GColorDarkGray)
|
||||
#define TODAY_FILL_COLOR PBL_IF_COLOR_ELSE(GColorMediumAquamarine, GColorDarkGray)
|
||||
|
||||
#define DEFAULT_ZONES { \
|
||||
{ .label = "Today", .progress = 700, .fill_color = TODAY_FILL_COLOR, .hide_typical = true }, \
|
||||
{ .label = "Wed", .progress = 1100, .fill_color = FILL_COLOR }, \
|
||||
{ .label = "Tue", .progress = 400, .fill_color = FILL_COLOR }, \
|
||||
{ .label = "Mon", .progress = 1300, .fill_color = FILL_COLOR }, \
|
||||
{ .label = "Sun", .progress = 800, .fill_color = FILL_COLOR }, \
|
||||
{ .label = "Sat", .progress = 700, .fill_color = FILL_COLOR }, \
|
||||
{ .label = "Fri", .progress = 1200, .fill_color = FILL_COLOR }, \
|
||||
}
|
||||
|
||||
static HealthDetailZone s_zones[] = DEFAULT_ZONES;
|
||||
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_detail_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_detail_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static Window* prv_create_card_and_render(HealthDetailCardConfig *config) {
|
||||
Window *window = (Window *)health_detail_card_create(config);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
return window;
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_detail_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthDetailCardConfig) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_one_heading(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&config);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_two_headings(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.secondary_label = "LABEL2",
|
||||
.secondary_value = "value2",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&config);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_subtitle_text(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.secondary_label = "LABEL2",
|
||||
.secondary_value = "value2",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.num_subtitles = 1,
|
||||
.subtitles = &(HealthDetailSubtitle) {
|
||||
.label = "30 DAY AVG",
|
||||
.fill_color = PBL_IF_COLOR_ELSE(GColorYellow, GColorBlack),
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&config);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_no_subtitle(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(s_zones),
|
||||
.zones = s_zones,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&config);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_zones(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.secondary_label = "LABEL2",
|
||||
.secondary_value = "value2",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.num_subtitles = 1,
|
||||
.subtitles = &(HealthDetailSubtitle) {
|
||||
.label = "30 DAY AVG",
|
||||
.fill_color = PBL_IF_COLOR_ELSE(GColorYellow, GColorBlack),
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(s_zones),
|
||||
.zones = s_zones,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&config);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 3), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_bg_and_zone_colors(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.num_subtitles = 1,
|
||||
.subtitles = &(HealthDetailSubtitle) {
|
||||
.label = "30 DAY AVG",
|
||||
.fill_color = PBL_IF_COLOR_ELSE(GColorYellow, GColorBlack),
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(s_zones),
|
||||
.zones = s_zones,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&config);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 2), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_crown(void) {
|
||||
HealthDetailZone zones[] = DEFAULT_ZONES;
|
||||
zones[1].show_crown = true;
|
||||
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.num_subtitles = 1,
|
||||
.subtitles = &(HealthDetailSubtitle) {
|
||||
.label = "30 DAY AVG",
|
||||
.fill_color = PBL_IF_COLOR_ELSE(GColorYellow, GColorBlack),
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(zones),
|
||||
.zones = zones,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&config);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 2), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__render_zone_hide_typical(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(s_zones),
|
||||
.zones = s_zones,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&config);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 1), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_detail_card__scroll_down(void) {
|
||||
HealthDetailCardConfig config = {
|
||||
.num_headings = 1,
|
||||
.headings = &(HealthDetailHeading) {
|
||||
.primary_label = "LABEL1",
|
||||
.primary_value = "value1",
|
||||
.fill_color = GColorWhite,
|
||||
#if PBL_BW
|
||||
.outline_color = GColorBlack,
|
||||
#endif
|
||||
},
|
||||
.bg_color = BG_COLOR,
|
||||
.daily_avg = 900,
|
||||
.weekly_max = 1300,
|
||||
.num_zones = ARRAY_LENGTH(s_zones),
|
||||
.zones = s_zones,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&config);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 7), MenuRowAlignCenter, false);
|
||||
#else
|
||||
GPoint offset = scroll_layer_get_content_offset(&card->scroll_layer);
|
||||
offset.y -= scroll_layer_get_content_size(&card->scroll_layer).h;
|
||||
|
||||
scroll_layer_set_content_offset(&card->scroll_layer, offset, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
109
tests/fw/apps/system_apps/health/test_health_hr_detail_card.c
Normal file
109
tests/fw/apps/system_apps/health/test_health_hr_detail_card.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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/health/health_hr_detail_card.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
#include "apps/system_apps/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_hr_detail_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_hr_detail_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static Window* prv_create_card_and_render(HealthData *health_data) {
|
||||
Window *window = (Window *)health_hr_detail_card_create(health_data);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
return window;
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_hr_detail_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_hr_detail_card__render_zones(void) {
|
||||
HealthData health_data = {
|
||||
.hr_zone1_minutes = 21,
|
||||
.hr_zone2_minutes = 13,
|
||||
.hr_zone3_minutes = 6,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 2), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_hr_detail_card__render_zones2(void) {
|
||||
HealthData health_data = {
|
||||
.hr_zone1_minutes = 30,
|
||||
.hr_zone2_minutes = 35,
|
||||
.hr_zone3_minutes = 40,
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 2), MenuRowAlignCenter, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
108
tests/fw/apps/system_apps/health/test_health_hr_summary_card.c
Normal file
108
tests/fw/apps/system_apps/health/test_health_hr_summary_card.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
#include "apps/system_apps/health/health_hr_summary_card.h"
|
||||
#include "apps/system_apps/health/health_hr_detail_card.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////
|
||||
|
||||
void clock_get_until_time_without_fulltime(char *buffer, int buf_size, time_t timestamp,
|
||||
int max_relative_hrs) {
|
||||
snprintf(buffer, buf_size, "5 MIN AGO");
|
||||
}
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_hr_summary_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_hr_summary_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_card_and_render(HealthData *health_data) {
|
||||
Window window;
|
||||
window_init(&window, WINDOW_NAME("Health"));
|
||||
Layer *window_layer = window_get_root_layer(&window);
|
||||
Layer *card_layer = health_hr_summary_card_create(health_data);
|
||||
layer_set_frame(card_layer, &window_layer->bounds);
|
||||
layer_add_child(window_layer, card_layer);
|
||||
window_set_background_color(&window, health_hr_summary_card_get_bg_color(card_layer));
|
||||
window_set_on_screen(&window, true, true);
|
||||
window_render(&window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_hr_summary_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_hr_summary_card__render_current_bpm(void) {
|
||||
HealthData health_data = {
|
||||
.current_hr_bpm = 110,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_hr_summary_card__render_timestamp(void) {
|
||||
rtc_set_time(SECONDS_PER_DAY + (SECONDS_PER_HOUR * 12));
|
||||
|
||||
HealthData health_data = {
|
||||
.current_hr_bpm = 110,
|
||||
.hr_last_updated = rtc_get_time() - (SECONDS_PER_MINUTE * 5),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
173
tests/fw/apps/system_apps/health/test_health_sleep_detail_card.c
Normal file
173
tests/fw/apps/system_apps/health/test_health_sleep_detail_card.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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/health/health_sleep_detail_card.h"
|
||||
#include "apps/system_apps/health/health_detail_card.h"
|
||||
#include "apps/system_apps/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
// static void prv_create_card_and_render(HealthData *health_data) {
|
||||
// Window *window = health_sleep_detail_card_create(health_data);
|
||||
// window_set_on_screen(window, true, true);
|
||||
// window_render(window, &s_ctx);
|
||||
// }
|
||||
|
||||
static Window* prv_create_card_and_render(HealthData *health_data) {
|
||||
Window *window = (Window *)health_sleep_detail_card_create(health_data);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
return window;
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_sleep_detail_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_sleep_session(void) {
|
||||
HealthData health_data = {
|
||||
.sleep_start = (23 * SECONDS_PER_HOUR) + (3 * SECONDS_PER_MINUTE),
|
||||
.sleep_end = (7 * SECONDS_PER_HOUR) + (45 * SECONDS_PER_MINUTE),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_sleep_session_same_start_end_time(void) {
|
||||
HealthData health_data = {
|
||||
.sleep_start = (16 * SECONDS_PER_HOUR),
|
||||
.sleep_end = (16 * SECONDS_PER_HOUR),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_30_day_avg(void) {
|
||||
HealthData health_data = {
|
||||
.monthly_sleep_average = (8 * SECONDS_PER_HOUR) + (17 * SECONDS_PER_MINUTE),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_deep_sleep(void) {
|
||||
HealthData health_data = {
|
||||
.deep_sleep = (3 * SECONDS_PER_HOUR) + (23 * SECONDS_PER_MINUTE),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_sleep_data_1(void) {
|
||||
HealthData health_data = {
|
||||
.sleep_data[0] = (7 * SECONDS_PER_HOUR) + (11 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[1] = (6 * SECONDS_PER_HOUR) + (52 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[2] = (7 * SECONDS_PER_HOUR) + (13 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[3] = (9 * SECONDS_PER_HOUR) + (21 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[4] = (9 * SECONDS_PER_HOUR) + (18 * SECONDS_PER_MINUTE),
|
||||
.monthly_sleep_average = (8 * SECONDS_PER_HOUR) + (17 * SECONDS_PER_MINUTE),
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 1), MenuRowAlignCenter, false);
|
||||
#else
|
||||
GPoint offset = scroll_layer_get_content_offset(&card->scroll_layer);
|
||||
|
||||
// scroll past sleep session, deep sleep and avg
|
||||
offset.y -= 114;
|
||||
|
||||
scroll_layer_set_content_offset(&card->scroll_layer, offset, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_detail_card__render_sleep_data_2(void) {
|
||||
HealthData health_data = {
|
||||
.sleep_data[0] = (7 * SECONDS_PER_HOUR) + (14 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[1] = (4 * SECONDS_PER_HOUR) + (59 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[2] = (8 * SECONDS_PER_HOUR) + (17 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[3] = (5 * SECONDS_PER_HOUR) + (34 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[4] = (7 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[5] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.sleep_data[6] = (10 * SECONDS_PER_HOUR) + (11 * SECONDS_PER_MINUTE),
|
||||
.monthly_sleep_average = (8 * SECONDS_PER_HOUR) + (36 * SECONDS_PER_MINUTE),
|
||||
};
|
||||
|
||||
HealthDetailCard *card = (HealthDetailCard *)prv_create_card_and_render(&health_data);
|
||||
|
||||
#if PBL_ROUND
|
||||
menu_layer_set_selected_index(&card->menu_layer, MenuIndex(0, 7), MenuRowAlignCenter, false);
|
||||
#else
|
||||
GPoint offset = scroll_layer_get_content_offset(&card->scroll_layer);
|
||||
offset.y -= scroll_layer_get_content_size(&card->scroll_layer).h;
|
||||
|
||||
scroll_layer_set_content_offset(&card->scroll_layer, offset, false);
|
||||
#endif
|
||||
|
||||
window_render(&card->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* 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/health/health_data.h"
|
||||
#include "apps/system_apps/health/health_data_private.h"
|
||||
#include "apps/system_apps/health/health_sleep_summary_card.h"
|
||||
|
||||
#include "test_health_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
const int s_now_utc = 1467763200; // July 6, 2016
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_card_and_render(HealthData *health_data) {
|
||||
Window window;
|
||||
window_init(&window, WINDOW_NAME("Health"));
|
||||
Layer *window_layer = window_get_root_layer(&window);
|
||||
Layer *card_layer = health_sleep_summary_card_create(health_data);
|
||||
layer_set_frame(card_layer, &window_layer->bounds);
|
||||
layer_add_child(window_layer, card_layer);
|
||||
window_set_background_color(&window, health_sleep_summary_card_get_bg_color(card_layer));
|
||||
window_set_on_screen(&window, true, true);
|
||||
window_render(&window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_health_sleep_summary_card__render_no_data(void) {
|
||||
prv_create_card_and_render(&(HealthData) {});
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_no_typical(void) {
|
||||
HealthData health_data = {
|
||||
.monthly_sleep_average = (9 * SECONDS_PER_HOUR),
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_no_sleep_last_night(void) {
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.typical_sleep_start = -4 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 7 * SECONDS_PER_HOUR,
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_sleep_late_start_early_end1(void) {
|
||||
const time_t start_of_today = time_util_get_midnight_of(s_now_utc);
|
||||
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.sleep_data[0] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.sleep_start = -3 * SECONDS_PER_HOUR,
|
||||
.sleep_end = 5 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_start = -4 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 7 * SECONDS_PER_HOUR,
|
||||
|
||||
// The sleep ring are filled by sleep sessions
|
||||
.num_activity_sessions = 3,
|
||||
.activity_sessions[0] = {
|
||||
.start_utc = start_of_today - (3 * SECONDS_PER_HOUR), // 9pm
|
||||
.length_min = (3 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
.activity_sessions[1] = {
|
||||
.start_utc = start_of_today + (1 * SECONDS_PER_HOUR), // 1am
|
||||
.length_min = (4 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
.activity_sessions[2] = {
|
||||
.start_utc = start_of_today + (2 * SECONDS_PER_HOUR), // 2am
|
||||
.length_min = (1 * MINUTES_PER_HOUR) + 30,
|
||||
.type = ActivitySessionType_RestfulSleep,
|
||||
},
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_sleep_late_start_early_end2(void) {
|
||||
const time_t start_of_today = time_util_get_midnight_of(s_now_utc);
|
||||
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.sleep_data[0] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.sleep_start = 0 * SECONDS_PER_HOUR,
|
||||
.sleep_end = 7 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_start = -1 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 8 * SECONDS_PER_HOUR,
|
||||
|
||||
// The sleep ring are filled by sleep sessions
|
||||
.num_activity_sessions = 3,
|
||||
.activity_sessions[0] = {
|
||||
.start_utc = start_of_today - (0 * SECONDS_PER_HOUR), // 12am
|
||||
.length_min = (7 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
.activity_sessions[1] = {
|
||||
.start_utc = start_of_today + (2 * SECONDS_PER_HOUR), // 2am
|
||||
.length_min = (1 * MINUTES_PER_HOUR) + 40,
|
||||
.type = ActivitySessionType_RestfulSleep,
|
||||
},
|
||||
.activity_sessions[2] = {
|
||||
.start_utc = start_of_today + (4 * SECONDS_PER_HOUR), // 4am
|
||||
.length_min = (2 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_RestfulSleep,
|
||||
},
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_sleep_early_start_early_end1(void) {
|
||||
const time_t start_of_today = time_util_get_midnight_of(s_now_utc);
|
||||
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.sleep_data[0] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.sleep_start = -3 * SECONDS_PER_HOUR,
|
||||
.sleep_end = 7 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_start = -1 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 8 * SECONDS_PER_HOUR,
|
||||
|
||||
// The sleep ring are filled by sleep sessions
|
||||
.num_activity_sessions = 3,
|
||||
.activity_sessions[0] = {
|
||||
.start_utc = start_of_today - (3 * SECONDS_PER_HOUR), // 9pm
|
||||
.length_min = (10 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
.activity_sessions[1] = {
|
||||
.start_utc = start_of_today - (2 * SECONDS_PER_HOUR), // 10pm
|
||||
.length_min = (1 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_RestfulSleep,
|
||||
},
|
||||
.activity_sessions[2] = {
|
||||
.start_utc = start_of_today + (3 * SECONDS_PER_HOUR), // 3am
|
||||
.length_min = (1 * MINUTES_PER_HOUR) + 15,
|
||||
.type = ActivitySessionType_RestfulSleep,
|
||||
},
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_health_sleep_summary_card__render_sleep_early_start_late_end1(void) {
|
||||
const time_t start_of_today = time_util_get_midnight_of(s_now_utc);
|
||||
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.sleep_data[0] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.sleep_start = -3 * SECONDS_PER_HOUR,
|
||||
.sleep_end = 7 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_start = -4 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 5 * SECONDS_PER_HOUR,
|
||||
|
||||
// The sleep ring are filled by sleep sessions
|
||||
.num_activity_sessions = 2,
|
||||
.activity_sessions[0] = {
|
||||
.start_utc = start_of_today - (3 * SECONDS_PER_HOUR),
|
||||
.length_min = (3 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
.activity_sessions[1] = {
|
||||
.start_utc = start_of_today + (1 * SECONDS_PER_HOUR),
|
||||
.length_min = (6 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
},
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
|
||||
void test_health_sleep_summary_card__render_sleep_late_start_late_end1(void) {
|
||||
const time_t start_of_today = time_util_get_midnight_of(s_now_utc);
|
||||
|
||||
HealthData health_data = {
|
||||
// Used for text
|
||||
.sleep_data[0] = (8 * SECONDS_PER_HOUR) + (12 * SECONDS_PER_MINUTE),
|
||||
.typical_sleep = (10 * SECONDS_PER_HOUR),
|
||||
.monthly_sleep_average = (300 * SECONDS_PER_HOUR),
|
||||
|
||||
// Used for typical
|
||||
.sleep_start = -4 * SECONDS_PER_HOUR,
|
||||
.sleep_end = 4 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_start = -3 * SECONDS_PER_HOUR,
|
||||
.typical_sleep_end = 3 * SECONDS_PER_HOUR,
|
||||
|
||||
// The sleep ring are filled by sleep sessions
|
||||
.num_activity_sessions = 1,
|
||||
.activity_sessions[0] = {
|
||||
.start_utc = start_of_today - (4 * SECONDS_PER_HOUR),
|
||||
.length_min = (8 * MINUTES_PER_HOUR),
|
||||
.type = ActivitySessionType_Sleep,
|
||||
}
|
||||
};
|
||||
|
||||
prv_create_card_and_render(&health_data);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
193
tests/fw/apps/system_apps/health/wscript
Normal file
193
tests/fw/apps/system_apps/health/wscript
Normal file
|
@ -0,0 +1,193 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
rendering_sources = \
|
||||
" src/fw/applib/fonts/codepoint.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/framebuffer.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/bitblt_private.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/kino/kino_reel.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_system_cells.c" \
|
||||
" src/fw/applib/vendor/tinflate/tinflate.c" \
|
||||
" src/fw/applib/vendor/uPNG/upng.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/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_applib_resource.c" \
|
||||
" tests/fakes/fake_display.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/stubs/stubs_animation.c" \
|
||||
" tests/stubs/stubs_system_theme.c"
|
||||
|
||||
health_app_sources = \
|
||||
" src/fw/applib/graphics/gpath_builder.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/transform.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_custom.c" \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/applib/ui/scroll_layer.c" \
|
||||
" src/fw/applib/ui/shadows.c" \
|
||||
" src/fw/applib/ui/text_layer.c" \
|
||||
" src/fw/applib/ui/text_layer_flow.c" \
|
||||
" src/fw/applib/ui/window.c" \
|
||||
" src/fw/apps/system_apps/health/health_data.c" \
|
||||
" src/fw/apps/system_apps/health/health_progress.c" \
|
||||
" src/fw/apps/system_apps/health/health_ui.c" \
|
||||
" src/fw/apps/system_apps/timeline/text_node.c" \
|
||||
" src/fw/services/normal/activity/health_util.c" \
|
||||
" src/fw/services/normal/timeline/timeline_resources.c" \
|
||||
" src/fw/util/buffer.c" \
|
||||
" src/fw/util/stats.c" \
|
||||
" src/fw/util/time/mktime.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" tests/fakes/fake_clock.c" \
|
||||
" tests/fakes/fake_fonts.c" \
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c"
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_activity_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_activity_summary_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_hr_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_hr_summary_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_sleep_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_sleep_summary_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_card_view.c",
|
||||
test_sources_ant_glob = "test_health_card_view.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_activity_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_activity_summary_card.c",
|
||||
test_sources_ant_glob = "test_health_activity_summary_card.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_sleep_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_sleep_summary_card.c",
|
||||
test_sources_ant_glob = "test_health_sleep_summary_card.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_hr_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_hr_summary_card.c",
|
||||
test_sources_ant_glob = "test_health_hr_summary_card.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=['silk'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_activity_detail_card.c",
|
||||
test_sources_ant_glob = "test_health_activity_detail_card.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_sleep_detail_card.c",
|
||||
test_sources_ant_glob = "test_health_sleep_detail_card.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c" \
|
||||
" src/fw/apps/system_apps/health/health_hr_detail_card.c",
|
||||
test_sources_ant_glob = "test_health_hr_detail_card.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
health_app_sources + \
|
||||
" src/fw/apps/system_apps/health/health_detail_card.c",
|
||||
test_sources_ant_glob = "test_health_detail_card.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'])
|
||||
|
||||
# vim:filetype=python
|
442
tests/fw/apps/system_apps/launcher/test_launcher_menu_layer.c
Normal file
442
tests/fw/apps/system_apps/launcher/test_launcher_menu_layer.c
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* 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/window_private.h"
|
||||
#include "apps/system_apps/launcher/default/launcher_menu_layer.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/app_glances/app_glance_service.h"
|
||||
#include "services/normal/blob_db/app_glance_db.h"
|
||||
#include "util/size.h"
|
||||
|
||||
static GContext s_ctx;
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fake_settings_file.h"
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fixtures/load_test_resources.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
|
||||
extern const uint16_t g_timeline_resources[][TimelineResourceSizeCount];
|
||||
#define TIMELINE_RESOURCE_TEST_FAKE_PNG (9999 | 0x80000000)
|
||||
|
||||
//! Add more values to this enum and the array below to add new apps to the launcher in these
|
||||
//! unit tests.
|
||||
typedef enum LauncherMenuLayerTestApp {
|
||||
LauncherMenuLayerTestApp_Watchfaces,
|
||||
LauncherMenuLayerTestApp_LongTitle,
|
||||
LauncherMenuLayerTestApp_InteriorApp,
|
||||
LauncherMenuLayerTestApp_Travel,
|
||||
LauncherMenuLayerTestApp_NoIcon,
|
||||
|
||||
LauncherMenuLayerTestAppCount
|
||||
} LauncherMenuLayerTestApp;
|
||||
|
||||
typedef struct LauncherMenuLayerTestAppNode {
|
||||
AppMenuNode node;
|
||||
uint32_t bitmap_icon_resource_id;
|
||||
uint32_t pdc_icon_resource_id;
|
||||
uint32_t bitmap_slice_icon_resource_id;
|
||||
uint32_t pdc_slice_icon_resource_id;
|
||||
} LauncherMenuLayerTestAppNode;
|
||||
|
||||
static bool s_use_pdc_icons;
|
||||
|
||||
static const LauncherMenuLayerTestAppNode s_fake_app_nodes[LauncherMenuLayerTestAppCount] = {
|
||||
[LauncherMenuLayerTestApp_Watchfaces] = {
|
||||
.node = {
|
||||
.name = "Watchfaces",
|
||||
.uuid = (Uuid) {0xc3, 0xcf, 0xda, 0xa9, 0x76, 0x1f, 0x49, 0x89,
|
||||
0x99, 0x4c, 0x30, 0x13, 0xcd, 0xc3, 0xef, 0xb9},
|
||||
},
|
||||
.bitmap_icon_resource_id = RESOURCE_ID_MENU_LAYER_GENERIC_WATCHFACE_ICON,
|
||||
.pdc_icon_resource_id = RESOURCE_ID_ALARM_CLOCK_TINY,
|
||||
.bitmap_slice_icon_resource_id = TIMELINE_RESOURCE_TEST_FAKE_PNG,
|
||||
.pdc_slice_icon_resource_id = TIMELINE_RESOURCE_BASKETBALL,
|
||||
},
|
||||
[LauncherMenuLayerTestApp_LongTitle] = {
|
||||
.node = {
|
||||
.name = "Really really long title",
|
||||
.uuid = (Uuid) {0xd4, 0x17, 0x61, 0x3c, 0x43, 0x31, 0x44, 0x90,
|
||||
0xa1, 0x68, 0xf2, 0x46, 0x53, 0xd3, 0x76, 0x3a},
|
||||
},
|
||||
// these icons are too big and will be replaced with the generic app icon
|
||||
.bitmap_icon_resource_id = RESOURCE_ID_SETTINGS_ICON_BLUETOOTH,
|
||||
.pdc_icon_resource_id = RESOURCE_ID_AMERICAN_FOOTBALL_SMALL,
|
||||
.bitmap_slice_icon_resource_id = TIMELINE_RESOURCE_TEST_FAKE_PNG,
|
||||
.pdc_slice_icon_resource_id = TIMELINE_RESOURCE_BASKETBALL,
|
||||
},
|
||||
[LauncherMenuLayerTestApp_InteriorApp] = {
|
||||
.node = {
|
||||
.name = "Interior App",
|
||||
.uuid = (Uuid) {0x11, 0xcf, 0xac, 0x66, 0x29, 0x9c, 0x4a, 0xa6,
|
||||
0x94, 0x5d, 0xf0, 0x53, 0x6e, 0xd1, 0x4e, 0xe8},
|
||||
},
|
||||
// these icons are too big and will be replaced with the generic app icon
|
||||
.bitmap_icon_resource_id = RESOURCE_ID_SETTINGS_ICON_BLUETOOTH_ALT,
|
||||
.pdc_icon_resource_id = RESOURCE_ID_BASEBALL_GAME_SMALL,
|
||||
.bitmap_slice_icon_resource_id = TIMELINE_RESOURCE_TEST_FAKE_PNG,
|
||||
.pdc_slice_icon_resource_id = TIMELINE_RESOURCE_BASKETBALL,
|
||||
},
|
||||
[LauncherMenuLayerTestApp_Travel] = {
|
||||
.node = {
|
||||
.name = "Travel",
|
||||
.uuid = (Uuid) {0x27, 0x53, 0xd0, 0xc, 0x65, 0xbb, 0x41, 0x83,
|
||||
0x9c, 0xf1, 0x17, 0x3e, 0x6, 0xdf, 0xda, 0xde},
|
||||
},
|
||||
.bitmap_icon_resource_id = RESOURCE_ID_SETTINGS_ICON_AIRPLANE,
|
||||
.pdc_icon_resource_id = RESOURCE_ID_SCHEDULED_FLIGHT_TINY,
|
||||
.bitmap_slice_icon_resource_id = TIMELINE_RESOURCE_TEST_FAKE_PNG,
|
||||
.pdc_slice_icon_resource_id = TIMELINE_RESOURCE_BASKETBALL,
|
||||
},
|
||||
[LauncherMenuLayerTestApp_NoIcon] = {
|
||||
.node = {
|
||||
.name = "No Icon",
|
||||
.uuid = (Uuid) {0x7f, 0x4f, 0xc1, 0x32, 0x32, 0x78, 0x47, 0xec,
|
||||
0x91, 0x64, 0xf1, 0x76, 0xf9, 0xea, 0x1f, 0xc2},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
AppMenuNode* app_menu_data_source_get_node_at_index(AppMenuDataSource *source,
|
||||
uint16_t row_index) {
|
||||
cl_assert(source);
|
||||
cl_assert(row_index < ARRAY_LENGTH(s_fake_app_nodes));
|
||||
const LauncherMenuLayerTestAppNode *test_node = &s_fake_app_nodes[row_index];
|
||||
static AppMenuNode node_copy;
|
||||
node_copy = test_node->node;
|
||||
node_copy.icon_resource_id =
|
||||
s_use_pdc_icons ? test_node->pdc_icon_resource_id : test_node->bitmap_icon_resource_id;
|
||||
return &node_copy;
|
||||
}
|
||||
|
||||
uint16_t app_menu_data_source_get_count(AppMenuDataSource *source) {
|
||||
cl_assert(source);
|
||||
return ARRAY_LENGTH(s_fake_app_nodes);
|
||||
}
|
||||
|
||||
static GBitmap s_default_app_icon_bitmap;
|
||||
void app_menu_data_source_enable_icons(AppMenuDataSource *source, uint32_t fallback_icon_id) {
|
||||
cl_assert(source);
|
||||
source->show_icons = true;
|
||||
gbitmap_deinit(&s_default_app_icon_bitmap);
|
||||
gbitmap_init_with_resource_system(&s_default_app_icon_bitmap, SYSTEM_APP, fallback_icon_id);
|
||||
source->default_icon = &s_default_app_icon_bitmap;
|
||||
}
|
||||
|
||||
static GBitmap s_app_icon_bitmap;
|
||||
GBitmap *app_menu_data_source_get_node_icon(AppMenuDataSource *source, AppMenuNode *node) {
|
||||
cl_assert(source);
|
||||
cl_assert(node);
|
||||
|
||||
if (!node->icon_resource_id) {
|
||||
return &s_default_app_icon_bitmap;
|
||||
}
|
||||
|
||||
gbitmap_deinit(&s_app_icon_bitmap);
|
||||
gbitmap_init_with_resource(&s_app_icon_bitmap, node->icon_resource_id);
|
||||
return &s_app_icon_bitmap;
|
||||
}
|
||||
|
||||
//! We use this function in the app glance service to create a key (the install ID) for an app
|
||||
//! glance cache entry; just fake it by constructing a 32-bit number from the first 4 bytes of the
|
||||
//! app's UUID
|
||||
AppInstallId app_install_get_id_for_uuid(const Uuid *uuid) {
|
||||
if (!uuid) {
|
||||
return INSTALL_ID_INVALID;
|
||||
}
|
||||
return ((uuid->byte3 << 24) | (uuid->byte2 << 16) | (uuid->byte1 << 8) | uuid->byte0);
|
||||
}
|
||||
|
||||
bool timeline_resources_get_id_system(TimelineResourceId timeline_id, TimelineResourceSize size,
|
||||
ResAppNum res_app_num, AppResourceInfo *res_info_out) {
|
||||
if (timeline_id == TIMELINE_RESOURCE_TEST_FAKE_PNG) {
|
||||
// random PNG resource for testing since no timeline resources use PNGs
|
||||
res_info_out->res_id = RESOURCE_ID_MUSIC_APP_GLANCE_PLAY;
|
||||
} else {
|
||||
res_info_out->res_id = g_timeline_resources[timeline_id & 0x7FFFFFFF][size];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timeline_resources_is_system(TimelineResourceId timeline_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stubs
|
||||
/////////////////////
|
||||
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_alarm.h"
|
||||
#include "stubs_alerts.h"
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_manager.h"
|
||||
#include "stubs_app_window_stack.h"
|
||||
#include "stubs_app_timer.h"
|
||||
#include "stubs_battery_state_service.h"
|
||||
#include "stubs_bluetooth_ctl.h"
|
||||
#include "stubs_bootbits.h"
|
||||
#include "stubs_click.h"
|
||||
#include "stubs_clock.h"
|
||||
#include "stubs_do_not_disturb.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_event_service_client.h"
|
||||
#include "stubs_health_util.h"
|
||||
#include "stubs_i18n.h"
|
||||
#include "stubs_kino_player.h"
|
||||
#include "stubs_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_memory_layout.h"
|
||||
#include "stubs_music.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_notification_storage.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pebble_process_info.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_serial.h"
|
||||
#include "stubs_session.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_status_bar_layer.h"
|
||||
#include "stubs_system_theme.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_tick.h"
|
||||
#include "stubs_time.h"
|
||||
#include "stubs_watchface.h"
|
||||
#include "stubs_weather_service.h"
|
||||
#include "stubs_weather_types.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
#include "stubs_workout_service.h"
|
||||
#include "stubs_workout_utils.h"
|
||||
|
||||
// We can't include stubs_process_manager.h because it conflicts with the two helper includes below
|
||||
void process_manager_send_callback_event_to_process(PebbleTask task, void (*callback)(void *),
|
||||
void *data) {}
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "../../../graphics/test_graphics.h"
|
||||
#include "../../../graphics/util.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static FrameBuffer *fb = NULL;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__initialize(void) {
|
||||
// Setup framebuffer and graphics context
|
||||
fb = malloc(sizeof(FrameBuffer));
|
||||
framebuffer_init(fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
test_graphics_context_init(&s_ctx, fb);
|
||||
graphics_context_set_antialiased(&s_ctx, true);
|
||||
|
||||
// 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();
|
||||
|
||||
// Setup content indicators buffer
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
|
||||
// Setup AppGlanceDB
|
||||
fake_settings_file_reset();
|
||||
app_glance_db_init();
|
||||
|
||||
// Setup AppGlanceService
|
||||
app_glance_service_init();
|
||||
|
||||
// Default to showing bitmap icons
|
||||
s_use_pdc_icons = false;
|
||||
}
|
||||
|
||||
void app_glance_db_deinit(void);
|
||||
|
||||
void test_launcher_menu_layer__cleanup(void) {
|
||||
app_glance_db_deinit();
|
||||
gbitmap_deinit(&s_app_icon_bitmap);
|
||||
gbitmap_deinit(&s_default_app_icon_bitmap);
|
||||
free(fb);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
//! Declared T_STATIC in launcher_menu_layer.c so we can easily change the launcher's selected index
|
||||
//! from unit tests without also specifying the y offset for the scroll layer that is required by
|
||||
//! `launcher_menu_layer_set_selection_state()`.
|
||||
void prv_launcher_menu_layer_set_selection_index(LauncherMenuLayer *launcher_menu_layer,
|
||||
uint16_t index, MenuRowAlign row_align,
|
||||
bool animated);
|
||||
|
||||
void prv_render_launcher_menu_layer(uint16_t selected_index) {
|
||||
AppMenuDataSource data_source = {};
|
||||
app_menu_data_source_init(&data_source, NULL, NULL);
|
||||
app_menu_data_source_enable_icons(&data_source, RESOURCE_ID_MENU_LAYER_GENERIC_WATCHAPP_ICON);
|
||||
|
||||
LauncherMenuLayer launcher_menu_layer = {};
|
||||
launcher_menu_layer_init(&launcher_menu_layer, &data_source);
|
||||
const bool animated = false;
|
||||
// If we used MenuRowAlignCenter on rect then the test images would show the top and bottom
|
||||
// rows being clipped by the edge of the screen
|
||||
const MenuRowAlign row_align = PBL_IF_RECT_ELSE(MenuRowAlignTop, MenuRowAlignCenter);
|
||||
prv_launcher_menu_layer_set_selection_index(&launcher_menu_layer, selected_index,
|
||||
row_align, animated);
|
||||
|
||||
layer_render_tree(launcher_menu_layer_get_layer(&launcher_menu_layer), &s_ctx);
|
||||
|
||||
launcher_menu_layer_deinit(&launcher_menu_layer);
|
||||
app_menu_data_source_deinit(&data_source);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_launcher_menu_layer__long_title(void) {
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_LongTitle);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__no_icon(void) {
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_NoIcon);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__interior_app(void) {
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_InteriorApp);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__no_icon_app_with_glance(void) {
|
||||
// Insert a glance with a slice for the app that doesn't have a default icon
|
||||
const AppGlance glance = (AppGlance) {
|
||||
.num_slices = 1,
|
||||
.slices = {
|
||||
{
|
||||
.expiration_time = 1464734484, // (Tue, 31 May 2016 22:41:24 GMT)
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle = {
|
||||
.icon_resource_id = TIMELINE_RESOURCE_SCHEDULED_FLIGHT,
|
||||
.template_string = "Glances baby!",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(
|
||||
&s_fake_app_nodes[LauncherMenuLayerTestApp_NoIcon].node.uuid, &glance), S_SUCCESS);
|
||||
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_NoIcon);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
static void prv_insert_glances_for_app_selected_and_apps_above_and_below_with_glances_test(void) {
|
||||
// Insert glances with 1 slice for the app above the interior app, the interior app, and the app
|
||||
// below the interior app so we can see that the subtitle is positioned properly in all 3 cases
|
||||
cl_assert(LauncherMenuLayerTestApp_InteriorApp > 0);
|
||||
for (LauncherMenuLayerTestApp i = LauncherMenuLayerTestApp_InteriorApp - 1;
|
||||
i <= LauncherMenuLayerTestApp_InteriorApp + 1; i++) {
|
||||
const LauncherMenuLayerTestAppNode *test_node = &s_fake_app_nodes[i];
|
||||
const uint32_t icon_resource_id = s_use_pdc_icons ? test_node->pdc_slice_icon_resource_id :
|
||||
test_node->bitmap_slice_icon_resource_id;
|
||||
AppGlance glance = (AppGlance) {
|
||||
.num_slices = 1,
|
||||
.slices = {
|
||||
{
|
||||
.expiration_time = 1464734484, // (Tue, 31 May 2016 22:41:24 GMT)
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle = {
|
||||
// Just continue using their default icon, we care more about the subtitle in this test
|
||||
.icon_resource_id = icon_resource_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
snprintf(glance.slices[0].icon_and_subtitle.template_string,
|
||||
sizeof(glance.slices[0].icon_and_subtitle.template_string),
|
||||
"%s glance", s_fake_app_nodes[i].node.name);
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&s_fake_app_nodes[i].node.uuid, &glance),
|
||||
S_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__app_selected_and_apps_above_and_below_with_glances(void) {
|
||||
prv_insert_glances_for_app_selected_and_apps_above_and_below_with_glances_test();
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_InteriorApp);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__long_title_pdc(void) {
|
||||
s_use_pdc_icons = true;
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_LongTitle);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__no_icon_pdc(void) {
|
||||
s_use_pdc_icons = true;
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_NoIcon);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__interior_app_pdc(void) {
|
||||
s_use_pdc_icons = true;
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_InteriorApp);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__no_icon_app_with_glance_pdc(void) {
|
||||
s_use_pdc_icons = true;
|
||||
// Insert a glance with a slice for the app that doesn't have a default icon
|
||||
const AppGlance glance = (AppGlance) {
|
||||
.num_slices = 1,
|
||||
.slices = {
|
||||
{
|
||||
.expiration_time = 1464734484, // (Tue, 31 May 2016 22:41:24 GMT)
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle = {
|
||||
.icon_resource_id = TIMELINE_RESOURCE_SCHEDULED_FLIGHT,
|
||||
.template_string = "Glances baby!",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(
|
||||
&s_fake_app_nodes[LauncherMenuLayerTestApp_NoIcon].node.uuid, &glance), S_SUCCESS);
|
||||
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_NoIcon);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_launcher_menu_layer__app_selected_and_apps_above_and_below_with_glances_pdc(void) {
|
||||
s_use_pdc_icons = true;
|
||||
prv_insert_glances_for_app_selected_and_apps_above_and_below_with_glances_test();
|
||||
prv_render_launcher_menu_layer(LauncherMenuLayerTestApp_InteriorApp);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
109
tests/fw/apps/system_apps/launcher/wscript
Normal file
109
tests/fw/apps/system_apps/launcher/wscript
Normal file
|
@ -0,0 +1,109 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
common_sources_ant_glob = (
|
||||
" src/fw/applib/fonts/codepoint.c"
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/framebuffer.c"
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/bitblt_private.c"
|
||||
" src/fw/applib/graphics/bitblt.c"
|
||||
" src/fw/applib/graphics/gbitmap.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/gdraw_command_transforms.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/gtypes.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/animation_interpolate.c"
|
||||
" src/fw/applib/ui/animation_timing.c"
|
||||
" src/fw/applib/ui/inverter_layer.c"
|
||||
" src/fw/applib/ui/layer.c"
|
||||
" src/fw/applib/ui/menu_layer.c"
|
||||
" src/fw/applib/ui/scroll_layer.c"
|
||||
" src/fw/applib/ui/shadows.c"
|
||||
" src/fw/applib/ui/window.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/flash_translation.c"
|
||||
" src/fw/services/normal/filesystem/pfs.c"
|
||||
" src/fw/system/hexdump.c"
|
||||
" src/fw/util/crc8.c"
|
||||
" src/fw/util/legacy_checksum.c"
|
||||
" tests/fakes/fake_display.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"
|
||||
)
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
common_sources_ant_glob +
|
||||
" src/fw/applib/graphics/framebuffer.c"
|
||||
" src/fw/applib/graphics/gbitmap_png.c"
|
||||
" src/fw/applib/graphics/gbitmap_sequence.c"
|
||||
" src/fw/applib/template_string.c"
|
||||
" src/fw/applib/ui/content_indicator.c"
|
||||
" src/fw/applib/ui/kino/kino_reel.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/menu_layer_system_cells.c"
|
||||
" src/fw/applib/vendor/tinflate/tinflate.c"
|
||||
" src/fw/applib/vendor/uPNG/upng.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_alarms.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_generic.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_music.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_notifications.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_private.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_service.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_settings.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_structured.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_watchfaces.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_weather.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_app_glance_workout.c"
|
||||
" src/fw/apps/system_apps/launcher/default/launcher_menu_layer.c"
|
||||
" src/fw/apps/system_apps/timeline/text_node.c"
|
||||
" src/fw/board/displays/display_spalding.c"
|
||||
" src/fw/services/normal/app_glances/app_glance_service.c"
|
||||
" src/fw/services/normal/blob_db/app_glance_db.c"
|
||||
" src/fw/services/normal/filesystem/app_file.c"
|
||||
" src/fw/services/normal/timeline/attribute.c"
|
||||
" src/fw/util/buffer.c"
|
||||
" src/fw/util/lru_cache.c"
|
||||
" tests/fakes/fake_applib_resource.c"
|
||||
" tests/fakes/fake_fonts.c"
|
||||
" tests/fakes/fake_settings_file.c"
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c"
|
||||
" tests/stubs/stubs_animation.c"
|
||||
" tests/stubs/stubs_app_install_manager.c"
|
||||
" tests/stubs/stubs_app_menu_data_source.c"
|
||||
),
|
||||
test_sources_ant_glob="test_launcher_menu_layer.c",
|
||||
defines=ctx.env.test_image_defines,
|
||||
runtime_deps=(ctx.env.test_pngs + ctx.env.test_pbis + ctx.env.test_pfos),
|
||||
override_includes=["dummy_board"],
|
||||
platforms=["silk", "snowy", "spalding", "robert"])
|
||||
|
||||
# vim:filetype=python
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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/window_private.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_animation.h"
|
||||
#include "fake_app_state.h"
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fake_evented_timer.h"
|
||||
#include "fake_graphics_context.h"
|
||||
#include "fake_rtc.h"
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fixtures/load_test_resources.h"
|
||||
|
||||
// Stubs
|
||||
/////////////////////
|
||||
|
||||
#include "stubs_action_menu.h"
|
||||
#include "stubs_activity.h"
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_ancs.h"
|
||||
#include "stubs_animation_timing.h"
|
||||
#include "stubs_animation_timing.h"
|
||||
#include "stubs_app.h"
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_app_launch_reason.h"
|
||||
#include "stubs_app_manager.h"
|
||||
#include "stubs_app_timer.h"
|
||||
#include "stubs_app_window_stack.h"
|
||||
#include "stubs_blob_db.h"
|
||||
#include "stubs_blob_db_sync.h"
|
||||
#include "stubs_blob_db_sync_util.h"
|
||||
#include "stubs_bootbits.h"
|
||||
#include "stubs_click.h"
|
||||
#include "stubs_compositor_transitions.h"
|
||||
#include "stubs_event_loop.h"
|
||||
#include "stubs_event_service_client.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_i18n.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_notification_storage.h"
|
||||
#include "stubs_notifications.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_pebble_process_info.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_phone_call_util.h"
|
||||
#include "stubs_process_manager.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_property_animation.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
#include "stubs_reminder_db.h"
|
||||
#include "stubs_serial.h"
|
||||
#include "stubs_session.h"
|
||||
#include "stubs_shell_prefs.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_system_theme.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_timeline.h"
|
||||
#include "stubs_timeline_actions.h"
|
||||
#include "stubs_timeline_layout.h"
|
||||
#include "stubs_timeline_layout_animations.h"
|
||||
#include "stubs_timeline_peek.h"
|
||||
#include "stubs_timezone_database.h"
|
||||
#include "stubs_wakeup.h"
|
||||
#include "stubs_watchface.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "fw/graphics/util.h"
|
271
tests/fw/apps/system_apps/timeline/test_timeline_list_view.c
Normal file
271
tests/fw/apps/system_apps/timeline/test_timeline_list_view.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/timeline.h"
|
||||
#include "resource/resource.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
|
||||
#include "test_timeline_app_includes.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
typedef struct TimelineTestData {
|
||||
TimelineModel model;
|
||||
} TimelineTestData;
|
||||
|
||||
TimelineTestData s_data;
|
||||
|
||||
void test_timeline_list_view__initialize(void) {
|
||||
fake_app_state_init();
|
||||
load_system_resources_fixture();
|
||||
|
||||
s_data = (TimelineTestData) {};
|
||||
rtc_set_time(3 * SECONDS_PER_DAY);
|
||||
}
|
||||
|
||||
void test_timeline_list_view__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
typedef struct TimelineItemConfig {
|
||||
time_t relative_timestamp;
|
||||
uint16_t duration;
|
||||
const char *title;
|
||||
const char *subtitle;
|
||||
TimelineResourceId icon;
|
||||
} TimelineItemConfig;
|
||||
|
||||
typedef struct ListViewConfig {
|
||||
TimelineItemConfig *pins[2];
|
||||
bool past;
|
||||
bool day_separator;
|
||||
} ListViewConfig;
|
||||
|
||||
static void prv_add_timeline_item(const TimelineItemConfig *config, bool past) {
|
||||
PBL_ASSERTN(config);
|
||||
TimelineItem *item = NULL;
|
||||
const time_t now = rtc_get_time();
|
||||
const time_t timestamp = now + ((past ? -1 : 1) * config->relative_timestamp);
|
||||
if (config) {
|
||||
AttributeList list;
|
||||
attribute_list_init_list(0 /* num_attributes */, &list);
|
||||
attribute_list_add_cstring(&list, AttributeIdTitle, config->title);
|
||||
if (config->subtitle) {
|
||||
attribute_list_add_cstring(&list, AttributeIdSubtitle, config->subtitle);
|
||||
}
|
||||
attribute_list_add_uint32(&list, AttributeIdIconPin, config->icon);
|
||||
item = timeline_item_create_with_attributes(timestamp, config->duration,
|
||||
TimelineItemTypePin, LayoutIdGeneric,
|
||||
&list, NULL);
|
||||
attribute_list_destroy_list(&list);
|
||||
PBL_ASSERTN(item);
|
||||
}
|
||||
if (item) {
|
||||
pin_db_insert_item(item);
|
||||
timeline_item_destroy(item);
|
||||
}
|
||||
}
|
||||
|
||||
static void prv_create_list_view_and_render(ListViewConfig *config) {
|
||||
pin_db_init();
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_LENGTH(config->pins); i++) {
|
||||
if (config->pins[i]) {
|
||||
prv_add_timeline_item(config->pins[i], config->past);
|
||||
}
|
||||
}
|
||||
|
||||
s_data.model = (TimelineModel) {};
|
||||
s_data.model.direction = config->past ? TimelineIterDirectionPast : TimelineIterDirectionFuture;
|
||||
timeline_model_init(rtc_get_time(), &s_data.model);
|
||||
|
||||
Window window;
|
||||
window_init(&window, "Timeline");
|
||||
|
||||
TimelineLayer timeline_layer = {};
|
||||
const TimelineScrollDirection scroll_direction =
|
||||
config->past ? TimelineScrollDirectionUp : TimelineScrollDirectionDown;
|
||||
timeline_layer_init(&timeline_layer, &window.layer.frame, scroll_direction);
|
||||
const GColor color = config->past ? TIMELINE_PAST_COLOR : TIMELINE_FUTURE_COLOR;
|
||||
timeline_layer_set_sidebar_color(&timeline_layer, color);
|
||||
timeline_layer_set_sidebar_width(&timeline_layer, timeline_layer_get_ideal_sidebar_width());
|
||||
layer_add_child(&window.layer, &timeline_layer.layer);
|
||||
timeline_layer_reset(&timeline_layer);
|
||||
|
||||
if (config->day_separator) {
|
||||
// Simulate showing the day separator
|
||||
int new_idx;
|
||||
bool has_new;
|
||||
cl_assert(timeline_model_iter_next(&new_idx, &has_new));
|
||||
if (has_new) {
|
||||
timeline_layer_set_next_item(&timeline_layer, new_idx);
|
||||
}
|
||||
timeline_layer_move_data(&timeline_layer, 1);
|
||||
cl_assert(timeline_layer_should_animate_day_separator(&timeline_layer));
|
||||
fake_animation_complete(timeline_layer_create_day_sep_show(&timeline_layer));
|
||||
fake_animation_complete(timeline_layer.day_separator.kino_layer.player.animation);
|
||||
timeline_layer_set_layouts_hidden(&timeline_layer, true);
|
||||
}
|
||||
|
||||
window_set_on_screen(&window, true, true);
|
||||
window_render(&window, fake_graphics_context_get_context());
|
||||
|
||||
timeline_layer_deinit(&timeline_layer);
|
||||
timeline_model_deinit();
|
||||
pin_db_flush();
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_and_render_title_and_subtitle(bool past, uint16_t first_duration_m) {
|
||||
prv_create_list_view_and_render(&(ListViewConfig) {
|
||||
.pins = {
|
||||
&(TimelineItemConfig) {
|
||||
.relative_timestamp = (11 * SECONDS_PER_HOUR) + (30 * SECONDS_PER_MINUTE),
|
||||
.duration = first_duration_m,
|
||||
.title = "Jon Byrd birthday party",
|
||||
.subtitle = "Kaboom, Redwood City",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}, &(TimelineItemConfig) {
|
||||
.relative_timestamp = 12 * SECONDS_PER_HOUR,
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.title = "Design Review Meeting",
|
||||
.subtitle = "Batavia, Palo Alto",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}
|
||||
},
|
||||
.past = past,
|
||||
});
|
||||
}
|
||||
|
||||
void test_timeline_list_view__title_and_subtitle_overlap_future(void) {
|
||||
#if !PLATFORM_SPALDING
|
||||
prv_create_and_render_title_and_subtitle(false /* past */, MINUTES_PER_HOUR);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_timeline_list_view__title_and_subtitle_back_to_back_future(void) {
|
||||
#if !PLATFORM_SPALDING
|
||||
prv_create_and_render_title_and_subtitle(false /* past */, MINUTES_PER_HOUR / 2);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_timeline_list_view__title_and_subtitle_free_time_future(void) {
|
||||
prv_create_and_render_title_and_subtitle(false /* past */, 5 /* first_duration_m */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void test_timeline_list_view__title_and_subtitle_free_time_past(void) {
|
||||
prv_create_and_render_title_and_subtitle(true /* past */, 5 /* first_duration_m */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP(TEST_PBI_FILE);
|
||||
}
|
||||
|
||||
void prv_create_and_render_pin_and_dot(bool past) {
|
||||
prv_create_list_view_and_render(&(ListViewConfig) {
|
||||
.pins = {
|
||||
&(TimelineItemConfig) {
|
||||
.relative_timestamp = (11 * SECONDS_PER_HOUR) + (30 * SECONDS_PER_MINUTE),
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.title = "Jon Byrd birthday party",
|
||||
.subtitle = "Kaboom, Redwood City",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}, &(TimelineItemConfig) {
|
||||
.relative_timestamp = SECONDS_PER_DAY + SECONDS_PER_HOUR,
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.title = "Design Review Meeting",
|
||||
.subtitle = "Batavia, Palo Alto",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}
|
||||
},
|
||||
.past = past,
|
||||
});
|
||||
}
|
||||
|
||||
void test_timeline_list_view__pin_and_dot_future(void) {
|
||||
prv_create_and_render_pin_and_dot(false /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void test_timeline_list_view__pin_and_dot_past(void) {
|
||||
prv_create_and_render_pin_and_dot(true /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void prv_create_and_render_day_sep_tomorrow(bool past) {
|
||||
prv_create_list_view_and_render(&(ListViewConfig) {
|
||||
.pins = {
|
||||
&(TimelineItemConfig) {
|
||||
.relative_timestamp = (11 * SECONDS_PER_HOUR) + (30 * SECONDS_PER_MINUTE),
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.title = "Jon Byrd birthday party",
|
||||
.subtitle = "Kaboom, Redwood City",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}, &(TimelineItemConfig) {
|
||||
.relative_timestamp = ((11 * SECONDS_PER_HOUR) + (30 * SECONDS_PER_MINUTE) +
|
||||
SECONDS_PER_DAY),
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.title = "Design Review Meeting",
|
||||
.subtitle = "Batavia, Palo Alto",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}
|
||||
},
|
||||
.past = past,
|
||||
.day_separator = true,
|
||||
});
|
||||
}
|
||||
|
||||
void test_timeline_list_view__day_sep_tomorrow_future(void) {
|
||||
prv_create_and_render_day_sep_tomorrow(false /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void test_timeline_list_view__day_sep_tomorrow_past(void) {
|
||||
prv_create_and_render_day_sep_tomorrow(true /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void prv_create_and_render_pin_and_fin(bool past) {
|
||||
prv_create_list_view_and_render(&(ListViewConfig) {
|
||||
.pins = {
|
||||
&(TimelineItemConfig) {
|
||||
.relative_timestamp = (11 * SECONDS_PER_HOUR) + (30 * SECONDS_PER_MINUTE),
|
||||
.title = "Jon Byrd birthday party",
|
||||
.duration = MINUTES_PER_HOUR,
|
||||
.subtitle = "Kaboom, Redwood City",
|
||||
.icon = TIMELINE_RESOURCE_TIMELINE_CALENDAR,
|
||||
}
|
||||
},
|
||||
.past = past,
|
||||
});
|
||||
}
|
||||
|
||||
void test_timeline_list_view__pin_and_fin_future(void) {
|
||||
prv_create_and_render_pin_and_fin(false /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void test_timeline_list_view__pin_and_fin_past(void) {
|
||||
prv_create_and_render_pin_and_fin(true /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
77
tests/fw/apps/system_apps/timeline/test_timeline_no_events.c
Normal file
77
tests/fw/apps/system_apps/timeline/test_timeline_no_events.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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/timeline.h"
|
||||
#include "resource/resource.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
|
||||
#include "test_timeline_app_includes.h"
|
||||
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
typedef struct TimelineTestData {
|
||||
TimelineAppData app;
|
||||
} TimelineTestData;
|
||||
|
||||
TimelineTestData s_data;
|
||||
|
||||
void test_timeline_no_events__initialize(void) {
|
||||
fake_app_state_init();
|
||||
load_system_resources_fixture();
|
||||
|
||||
s_data = (TimelineTestData) {};
|
||||
}
|
||||
|
||||
void test_timeline_no_events__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
void prv_init_peek_layer(TimelineAppData *data);
|
||||
void prv_setup_no_events_peek(TimelineAppData *data);
|
||||
|
||||
static void prv_create_no_events_and_render(bool past) {
|
||||
Window *window = &s_data.app.timeline_window;
|
||||
window_init(window, "Timeline");
|
||||
const GColor color = past ? TIMELINE_PAST_COLOR : TIMELINE_FUTURE_COLOR;
|
||||
window_set_background_color(window, color);
|
||||
|
||||
prv_init_peek_layer(&s_data.app);
|
||||
prv_setup_no_events_peek(&s_data.app);
|
||||
peek_layer_play(&s_data.app.peek_layer);
|
||||
fake_animation_complete(s_data.app.peek_layer.kino_layer.player.animation);
|
||||
fake_evented_timer_trigger(s_data.app.peek_layer.hidden_fields_timer);
|
||||
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, fake_graphics_context_get_context());
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_timeline_no_events__future(void) {
|
||||
prv_create_no_events_and_render(false /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
||||
|
||||
void test_timeline_no_events__past(void) {
|
||||
prv_create_no_events_and_render(true /* past */);
|
||||
FAKE_GRAPHICS_CONTEXT_CHECK_DEST_BITMAP_FILE();
|
||||
}
|
148
tests/fw/apps/system_apps/timeline/wscript
Normal file
148
tests/fw/apps/system_apps/timeline/wscript
Normal file
|
@ -0,0 +1,148 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
|
||||
def build(ctx):
|
||||
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/kino/kino_reel.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_system_cells.c "
|
||||
"src/fw/applib/vendor/tinflate/tinflate.c "
|
||||
"src/fw/applib/vendor/uPNG/upng.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/crc8.c "
|
||||
"src/fw/util/legacy_checksum.c "
|
||||
"tests/fakes/fake_animation.c "
|
||||
"tests/fakes/fake_applib_resource.c "
|
||||
"tests/fakes/fake_display.c "
|
||||
"tests/fakes/fake_gbitmap_get_data_row.c "
|
||||
"tests/fakes/fake_graphics_context.c "
|
||||
"tests/fakes/fake_property_animation.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/stubs/stubs_animation.c "
|
||||
)
|
||||
|
||||
timeline_app_sources = (
|
||||
"src/fw/applib/graphics/gdraw_command_transforms.c "
|
||||
"src/fw/applib/graphics/gpath_builder.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/scale_segmented.c "
|
||||
"src/fw/applib/ui/kino/kino_reel/transform.c "
|
||||
"src/fw/applib/ui/kino/kino_reel/unfold.c "
|
||||
"src/fw/applib/ui/kino/kino_reel_custom.c "
|
||||
"src/fw/applib/ui/menu_layer.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/apps/system_apps/timeline/peek_layer.c "
|
||||
"src/fw/apps/system_apps/timeline/pin_window.c "
|
||||
"src/fw/apps/system_apps/timeline/text_node.c "
|
||||
"src/fw/apps/system_apps/timeline/timeline.c "
|
||||
"src/fw/apps/system_apps/timeline/timeline_animations.c "
|
||||
"src/fw/apps/system_apps/timeline/timeline_layer.c "
|
||||
"src/fw/apps/system_apps/timeline/timeline_model.c "
|
||||
"src/fw/apps/system_apps/timeline/timeline_relbar.c "
|
||||
"src/fw/popups/timeline/timeline_item_layer.c "
|
||||
"src/fw/services/common/clock.c "
|
||||
"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/generic_layout.c "
|
||||
"src/fw/services/normal/timeline/item.c "
|
||||
"src/fw/services/normal/timeline/layout_layer.c "
|
||||
"src/fw/services/normal/timeline/layout_node.c "
|
||||
"src/fw/services/normal/timeline/timeline.c "
|
||||
"src/fw/services/normal/timeline/timeline_layout.c "
|
||||
"src/fw/services/normal/timeline/timeline_resources.c "
|
||||
"src/fw/shell/system_theme.c "
|
||||
"src/fw/util/buffer.c "
|
||||
"src/fw/util/stats.c "
|
||||
"src/fw/util/stringlist.c "
|
||||
"src/fw/util/time/mktime.c "
|
||||
"src/fw/util/time/time.c "
|
||||
"tests/fakes/fake_fonts.c "
|
||||
"tests/fakes/fake_settings_file.c "
|
||||
"tests/fixtures/resources/timeline_resource_table.auto.c "
|
||||
"tests/stubs/stubs_evented_timer.c "
|
||||
)
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
rendering_sources +
|
||||
timeline_app_sources
|
||||
),
|
||||
test_sources_ant_glob="test_timeline_list_view.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
rendering_sources +
|
||||
timeline_app_sources
|
||||
),
|
||||
test_sources_ant_glob="test_timeline_no_events.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'],
|
||||
# The no events is a builtin on silk and thus cannot be used in a unit test currently
|
||||
platforms=['snowy', 'spalding', 'robert'])
|
||||
|
||||
# vim:filetype=python
|
377
tests/fw/apps/system_apps/weather/test_weather_app_layout.c
Normal file
377
tests/fw/apps/system_apps/weather/test_weather_app_layout.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* 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/graphics/framebuffer.h"
|
||||
#include "applib/graphics/graphics.h"
|
||||
#include "apps/system_apps/weather/weather_app_layout.h"
|
||||
#include "applib/ui/app_window_stack.h"
|
||||
#include "applib/ui/content_indicator.h"
|
||||
#include "applib/ui/content_indicator_private.h"
|
||||
#include "applib/ui/dialogs/simple_dialog.h"
|
||||
#include "applib/ui/text_layer.h"
|
||||
#include "applib/ui/window_private.h"
|
||||
#include "resource/resource.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
#include "shell/system_theme.h"
|
||||
#include "util/buffer.h"
|
||||
#include "util/graphics.h"
|
||||
#include "util/hash.h"
|
||||
#include "util/math.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fake_spi_flash.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_click.h"
|
||||
#include "stubs_i18n.h"
|
||||
#include "stubs_layer.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_process_info.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_serial.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_status_bar_layer.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_system_theme.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "fw/graphics/test_graphics.h"
|
||||
#include "fw/graphics/util.h"
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer *fb = NULL;
|
||||
|
||||
KinoReel *kino_reel_morph_square_create(KinoReel *from_reel, bool take_ownership) {
|
||||
return from_reel;
|
||||
}
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_weather_app_layout__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_weather_app_layout__cleanup(void) {
|
||||
free(fb);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_layout_for_forecast(const WeatherLocationForecast *forecast,
|
||||
WeatherAppLayout *layout, Window *window) {
|
||||
window_init(window, WINDOW_NAME("Weather"));
|
||||
weather_app_layout_init(layout, &s_ctx.dest_bitmap.bounds);
|
||||
weather_app_layout_set_data(layout, forecast);
|
||||
window_set_user_data(window, layout);
|
||||
|
||||
Layer *window_root_layer = window_get_root_layer(window);
|
||||
layer_add_child(window_root_layer, &layout->root_layer);
|
||||
window_set_on_screen(window, true, true);
|
||||
}
|
||||
|
||||
static void prv_create_layout_for_forecast_and_render(const WeatherLocationForecast *forecast) {
|
||||
Window window;
|
||||
WeatherAppLayout layout = {};
|
||||
prv_create_layout_for_forecast(forecast, &layout, &window);
|
||||
window_render(&window, &s_ctx);
|
||||
}
|
||||
|
||||
static void prv_create_layout_for_forecast_and_render_with_down_arrow_indicator(
|
||||
const WeatherLocationForecast *forecast) {
|
||||
Window window;
|
||||
WeatherAppLayout layout = {};
|
||||
prv_create_layout_for_forecast(forecast, &layout, &window);
|
||||
weather_app_layout_set_down_arrow_visible(&layout, true);
|
||||
window_render(&window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_weather_app_layout__render_palo_alto(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = 68,
|
||||
.today_high = 68,
|
||||
.today_low = 58,
|
||||
.current_weather_type = WeatherType_Sun,
|
||||
.current_weather_phrase = "Sunny",
|
||||
.tomorrow_high = 62,
|
||||
.tomorrow_low = 52,
|
||||
.tomorrow_weather_type = WeatherType_PartlyCloudy,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
static void prv_render_long_strings_test(bool is_current_location) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "QWERTYUIO ASEDDFFGHHJ",
|
||||
.is_current_location = is_current_location,
|
||||
.current_temp = 68,
|
||||
.today_high = 68,
|
||||
.today_low = 58,
|
||||
.current_weather_type = WeatherType_PartlyCloudy,
|
||||
.current_weather_phrase = "Cloudy with 90% chance of meatballs",
|
||||
.tomorrow_high = 62,
|
||||
.tomorrow_low = 52,
|
||||
.tomorrow_weather_type = WeatherType_Sun,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_longer_strings(void) {
|
||||
const bool is_current_location = false;
|
||||
prv_render_long_strings_test(is_current_location);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_longer_strings_for_current_location(void) {
|
||||
const bool is_current_location = true;
|
||||
prv_render_long_strings_test(is_current_location);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_large_numbers(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = -88,
|
||||
.today_high = -88,
|
||||
.today_low = -88,
|
||||
.current_weather_type = WeatherType_Sun,
|
||||
.current_weather_phrase = "Sunny",
|
||||
.tomorrow_high = -99,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_PartlyCloudy,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_cloudy_light_snow(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = -88,
|
||||
.today_high = -88,
|
||||
.today_low = -88,
|
||||
.current_weather_type = WeatherType_CloudyDay,
|
||||
.current_weather_phrase = "Cloudy",
|
||||
.tomorrow_high = -99,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_LightSnow,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_light_rain_heavy_rain(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = -88,
|
||||
.today_high = -88,
|
||||
.today_low = -88,
|
||||
.current_weather_type = WeatherType_LightRain,
|
||||
.current_weather_phrase = "Light Rain",
|
||||
.tomorrow_high = -99,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_HeavyRain,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_generic_generic(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "HOUSTON",
|
||||
.current_temp = 110,
|
||||
.today_high = 120,
|
||||
.today_low = 85,
|
||||
.current_weather_type = WeatherType_Generic,
|
||||
.current_weather_phrase = "Humid AF",
|
||||
.tomorrow_high = 500,
|
||||
.tomorrow_low = 100,
|
||||
.tomorrow_weather_type = WeatherType_Generic,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_heavy_snow_rain_snow(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = -88,
|
||||
.today_high = -88,
|
||||
.today_low = -88,
|
||||
.current_weather_type = WeatherType_HeavySnow,
|
||||
.current_weather_phrase = "Heavy Snow",
|
||||
.tomorrow_high = -99,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_RainAndSnow,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_down_arrow(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = -88,
|
||||
.today_high = -88,
|
||||
.today_low = -88,
|
||||
.current_weather_type = WeatherType_HeavySnow,
|
||||
.current_weather_phrase = "Heavy Snow",
|
||||
.tomorrow_high = -99,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_RainAndSnow,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render_with_down_arrow_indicator(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_all_unknown_values(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.today_high = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.today_low = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.current_weather_type = WeatherType_Unknown,
|
||||
.current_weather_phrase = "",
|
||||
.tomorrow_high = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.tomorrow_low = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.tomorrow_weather_type = WeatherType_Unknown,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_some_unknown_values(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PALO ALTO",
|
||||
.current_temp = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.today_high = 99,
|
||||
.today_low = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.current_weather_type = WeatherType_Sun,
|
||||
.current_weather_phrase = "",
|
||||
.tomorrow_high = WEATHER_SERVICE_LOCATION_FORECAST_UNKNOWN_TEMP,
|
||||
.tomorrow_low = -99,
|
||||
.tomorrow_weather_type = WeatherType_Unknown,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_current_location(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "PHILADELPHIA",
|
||||
.is_current_location = true,
|
||||
.current_temp = 13,
|
||||
.today_high = 15,
|
||||
.today_low = -2,
|
||||
.current_weather_type = WeatherType_HeavySnow,
|
||||
.current_weather_phrase = "Heavy Snow",
|
||||
.tomorrow_high = 26,
|
||||
.tomorrow_low = 3,
|
||||
.tomorrow_weather_type = WeatherType_RainAndSnow,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render_with_down_arrow_indicator(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_weather_app_layout__render_long_current_location_name_pbl_38049(void) {
|
||||
const WeatherLocationForecast forecast = {
|
||||
.location_name = "DA'AN DISTRICT",
|
||||
.is_current_location = true,
|
||||
.current_temp = 30,
|
||||
.today_high = 33,
|
||||
.today_low = 26,
|
||||
.current_weather_type = WeatherType_CloudyDay,
|
||||
.current_weather_phrase = "M Cloudy",
|
||||
.tomorrow_high = 34,
|
||||
.tomorrow_low = 26,
|
||||
.tomorrow_weather_type = WeatherType_HeavyRain,
|
||||
};
|
||||
|
||||
prv_create_layout_for_forecast_and_render_with_down_arrow_indicator(&forecast);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
// renders a blank image
|
||||
void test_weather_app_layout__render_empty_view(void) {
|
||||
prv_create_layout_for_forecast_and_render(NULL);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
92
tests/fw/apps/system_apps/weather/wscript
Normal file
92
tests/fw/apps/system_apps/weather/wscript
Normal file
|
@ -0,0 +1,92 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
rendering_sources = \
|
||||
" src/fw/applib/fonts/codepoint.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/framebuffer.c" \
|
||||
" src/fw/applib/graphics/8_bit/bitblt_private.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/kino/kino_reel.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/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/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" src/fw/applib/vendor/tinflate/tinflate.c" \
|
||||
" src/fw/applib/vendor/uPNG/upng.c" \
|
||||
" tests/fakes/fake_applib_resource.c" \
|
||||
" tests/fakes/fake_display.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/stubs/stubs_animation.c"
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
" src/fw/applib/ui/animation_interpolate.c" \
|
||||
" src/fw/applib/ui/kino/kino_layer.c" \
|
||||
" src/fw/applib/ui/kino/kino_player.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_custom.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel/transform.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/ui/scroll_layer.c" \
|
||||
" src/fw/applib/ui/inverter_layer.c" \
|
||||
" src/fw/applib/ui/content_indicator.c" \
|
||||
" tests/fakes/fake_fonts.c" \
|
||||
" src/fw/applib/ui/shadows.c" \
|
||||
" src/fw/apps/system_apps/weather/weather_app_layout.c" \
|
||||
" src/fw/services/normal/timeline/timeline_resources.c" \
|
||||
" src/fw/services/normal/weather/weather_types.c" \
|
||||
" src/fw/util/buffer.c" \
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c",
|
||||
test_sources_ant_glob = "test_weather_app_layout.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'])
|
||||
|
||||
# vim:filetype=python
|
595
tests/fw/apps/system_apps/workout/test_workout_active.c
Normal file
595
tests/fw/apps/system_apps/workout/test_workout_active.c
Normal file
|
@ -0,0 +1,595 @@
|
|||
/*
|
||||
* 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/workout/workout.h"
|
||||
#include "apps/system_apps/workout/workout_active.h"
|
||||
#include "apps/system_apps/workout/workout_data.h"
|
||||
#include "apps/system_apps/workout/workout_dialog.h"
|
||||
|
||||
#include "services/normal/activity/health_util.h"
|
||||
|
||||
#include "test_workout_app_includes.h"
|
||||
|
||||
#include "stubs_window_manager.h"
|
||||
|
||||
bool s_hrm_is_present;
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
extern void prv_cycle_scrollable_metrics(WorkoutActiveWindow *active_window);
|
||||
|
||||
bool activity_is_hrm_present(void) {
|
||||
return s_hrm_is_present;
|
||||
}
|
||||
|
||||
uint16_t time_ms(time_t *tloc, uint16_t *out_ms) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void workout_push_summary_window(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static WorkoutData s_workout_data;
|
||||
|
||||
static WorkoutController s_workout_controller = {
|
||||
.is_paused = workout_service_is_paused,
|
||||
.pause = workout_service_pause_workout,
|
||||
.stop = workout_service_stop_workout,
|
||||
.update_data = workout_data_update,
|
||||
.metric_to_string = workout_data_fill_metric_value,
|
||||
.get_metric_value = workout_data_get_metric_value,
|
||||
.get_distance_string = health_util_get_distance_string,
|
||||
};
|
||||
|
||||
typedef struct SportsData {
|
||||
int32_t current_bpm;
|
||||
char *duration_string;
|
||||
char *distance_string;
|
||||
char *pace_string;
|
||||
char *custom_label_string;
|
||||
char *custom_value_string;
|
||||
} SportsData;
|
||||
|
||||
static SportsData s_sports_data;
|
||||
|
||||
static bool prv_is_sports_paused(void) { return false; }
|
||||
static bool prv_sports_pause(bool should_be_paused) { return false; }
|
||||
static void prv_metric_to_string(WorkoutMetricType type, char *buffer, size_t buffer_size,
|
||||
void *i18n_owner, void *sports_data) {
|
||||
SportsData *data = sports_data;
|
||||
|
||||
switch (type) {
|
||||
case WorkoutMetricType_Hr:
|
||||
{
|
||||
snprintf(buffer, buffer_size, "%d", data->current_bpm);
|
||||
break;
|
||||
}
|
||||
case WorkoutMetricType_Speed:
|
||||
case WorkoutMetricType_Pace:
|
||||
{
|
||||
strncpy(buffer, data->pace_string, buffer_size);
|
||||
break;
|
||||
}
|
||||
case WorkoutMetricType_Distance:
|
||||
{
|
||||
strncpy(buffer, data->distance_string, buffer_size);
|
||||
break;
|
||||
}
|
||||
case WorkoutMetricType_Duration:
|
||||
{
|
||||
strncpy(buffer, data->duration_string, buffer_size);
|
||||
break;
|
||||
}
|
||||
case WorkoutMetricType_Custom:
|
||||
{
|
||||
strncpy(buffer, data->custom_value_string, buffer_size);
|
||||
break;
|
||||
}
|
||||
// Not supported by the sports API
|
||||
case WorkoutMetricType_Steps:
|
||||
case WorkoutMetricType_AvgPace:
|
||||
case WorkoutMetricType_None:
|
||||
case WorkoutMetricTypeCount:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t prv_sports_get_value(WorkoutMetricType type, void *sports_data) {
|
||||
SportsData *data = sports_data;
|
||||
switch (type) {
|
||||
case WorkoutMetricType_Hr:
|
||||
return data->current_bpm;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *prv_get_custom_metric_label_string(void) {
|
||||
return s_sports_data.custom_label_string;
|
||||
}
|
||||
|
||||
static WorkoutController s_sports_controller = {
|
||||
.is_paused = prv_is_sports_paused,
|
||||
.pause = prv_sports_pause,
|
||||
.stop = NULL,
|
||||
.update_data = NULL,
|
||||
.metric_to_string = prv_metric_to_string,
|
||||
.get_metric_value = prv_sports_get_value,
|
||||
.get_distance_string = health_util_get_distance_string,
|
||||
.get_custom_metric_label_string = prv_get_custom_metric_label_string,
|
||||
};
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_workout_active__initialize(void) {
|
||||
s_hrm_is_present = true;
|
||||
|
||||
s_workout_data = (WorkoutData) {};
|
||||
s_sports_data = (SportsData) {};
|
||||
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_workout_active__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_create_window_and_render(WorkoutActiveWindow *active_window,
|
||||
int seconday_metric_idx) {
|
||||
for (int i = 0; i < seconday_metric_idx; i++) {
|
||||
prv_cycle_scrollable_metrics(active_window);
|
||||
}
|
||||
|
||||
Window *window = (Window *)active_window;
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
}
|
||||
|
||||
// Workout Tests
|
||||
//////////////////////
|
||||
|
||||
void test_workout_active__workout_render_no_data(void) {
|
||||
s_workout_data = (WorkoutData) {};
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_walk(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 84,
|
||||
.distance_m = 1234,
|
||||
.avg_pace = health_util_get_pace(84, 1234),
|
||||
.bpm = 71,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Walk, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_walk_no_hrm(void) {
|
||||
s_hrm_is_present = false;
|
||||
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 84,
|
||||
.distance_m = 1234,
|
||||
.avg_pace = health_util_get_pace(84, 1234),
|
||||
.bpm = 71,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Walk, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_run(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 84,
|
||||
.distance_m = 1234,
|
||||
.avg_pace = health_util_get_pace(84, 1234),
|
||||
.bpm = 71,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_run_no_hrm(void) {
|
||||
s_hrm_is_present = false;
|
||||
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 84,
|
||||
.distance_m = 1234,
|
||||
.avg_pace = health_util_get_pace(84, 1234),
|
||||
.bpm = 71,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_open_workout(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 0,
|
||||
.duration_s = 84,
|
||||
.distance_m = 0,
|
||||
.avg_pace = health_util_get_pace(84, 0),
|
||||
.bpm = 92,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Open, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_open_workout_no_hrm(void) {
|
||||
s_hrm_is_present = false;
|
||||
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 0,
|
||||
.duration_s = 84,
|
||||
.distance_m = 0,
|
||||
.avg_pace = health_util_get_pace(84, 0),
|
||||
.bpm = 92,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Open, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_hr_zone_1(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 789,
|
||||
.distance_m = 234,
|
||||
.avg_pace = health_util_get_pace(789, 234),
|
||||
.bpm = 148,
|
||||
.hr_zone = 1,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_hr_zone_2(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 789,
|
||||
.distance_m = 234,
|
||||
.avg_pace = health_util_get_pace(789, 234),
|
||||
.bpm = 167,
|
||||
.hr_zone = 2,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_hr_zone_3(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 567,
|
||||
.duration_s = 789,
|
||||
.distance_m = 234,
|
||||
.avg_pace = health_util_get_pace(789, 234),
|
||||
.bpm = 197,
|
||||
.hr_zone = 3,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Run, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__workout_render_very_slow_pace(void) {
|
||||
s_workout_data = (WorkoutData) {
|
||||
.steps = 0,
|
||||
.duration_s = SECONDS_PER_HOUR,
|
||||
.distance_m = 1609,
|
||||
.avg_pace = health_util_get_pace(SECONDS_PER_HOUR, 1609),
|
||||
.bpm = 0,
|
||||
.hr_zone = 0,
|
||||
};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_for_activity_type(
|
||||
ActivitySessionType_Walk, &s_workout_data, &s_workout_controller);
|
||||
prv_create_window_and_render(active_window, 2);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Workout Tests
|
||||
//////////////////////
|
||||
|
||||
void test_workout_active__sports_pace(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_pace_long_values(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "04:20:39",
|
||||
.distance_string = "115.12",
|
||||
.pace_string = "12:34",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_speed(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "20:00",
|
||||
.distance_string = "18.9",
|
||||
.pace_string = "35.3",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Speed,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_no_hrm(void) {
|
||||
s_hrm_is_present = false;
|
||||
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_hr_z0(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_hr_z1(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 135,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_hr_z2(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 165,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_hr_z3(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 180,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Hr};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_custom_field(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
.custom_label_string = "CUSTOM",
|
||||
.custom_value_string = "000000",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Custom};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_custom_long_values(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
.custom_label_string = "CUSTOM FIELD LABEL",
|
||||
.custom_value_string = "0000000000000000000",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Custom};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_active__sports_custom_hanging_label(void) {
|
||||
s_sports_data = (SportsData) {
|
||||
.current_bpm = 71,
|
||||
.duration_string = "30:00",
|
||||
.distance_string = "5.0",
|
||||
.pace_string = "6:00",
|
||||
.custom_label_string = "Hanging Field",
|
||||
.custom_value_string = "000000",
|
||||
};
|
||||
|
||||
WorkoutMetricType top_metric = WorkoutMetricType_Duration;
|
||||
WorkoutMetricType middle_metric = WorkoutMetricType_Distance;
|
||||
WorkoutMetricType scrollable_metrics[] = {WorkoutMetricType_Pace,
|
||||
WorkoutMetricType_Custom};
|
||||
|
||||
WorkoutActiveWindow *active_window = workout_active_create_tripple_layout(
|
||||
top_metric, middle_metric, ARRAY_LENGTH(scrollable_metrics), scrollable_metrics,
|
||||
&s_sports_data, &s_sports_controller);
|
||||
prv_create_window_and_render(active_window, 1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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/window_private.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
#include "fake_content_indicator.h"
|
||||
#include "fake_rtc.h"
|
||||
#include "fake_pbl_std.h"
|
||||
#include "fake_regular_timer.h"
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_workout_service.h"
|
||||
#include "fixtures/load_test_resources.h"
|
||||
|
||||
// Stubs
|
||||
/////////////////////
|
||||
|
||||
#include "stubs_activity.h"
|
||||
#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_attribute.h"
|
||||
#include "stubs_bootbits.h"
|
||||
#include "stubs_click.h"
|
||||
#include "stubs_event_service_client.h"
|
||||
#include "stubs_health_service.h"
|
||||
#include "stubs_i18n.h"
|
||||
#include "stubs_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_memory_layout.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_notifications.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_serial.h"
|
||||
#include "stubs_shell_prefs.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_syscalls.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_timeline_item.h"
|
||||
#include "stubs_vibes.h"
|
||||
#include "stubs_window_manager.h"
|
||||
#include "stubs_window_stack.h"
|
||||
|
||||
typedef struct KinoReel KinoReel;
|
||||
|
||||
KinoReel *kino_reel_scale_segmented_create(KinoReel *from_reel, bool take_ownership,
|
||||
GRect screen_frame) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kino_reel_scale_segmented_set_deflate_effect(KinoReel *reel, int16_t expand) {}
|
||||
|
||||
bool kino_reel_scale_segmented_set_delay_by_distance(KinoReel *reel, GPoint target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper Functions
|
||||
/////////////////////
|
||||
|
||||
#include "fw/graphics/util.h"
|
122
tests/fw/apps/system_apps/workout/test_workout_dialog.c
Normal file
122
tests/fw/apps/system_apps/workout/test_workout_dialog.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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/workout/workout_dialog.h"
|
||||
|
||||
#include "resource/resource_ids.auto.h"
|
||||
|
||||
#include "test_workout_app_includes.h"
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
uint16_t time_ms(time_t *tloc, uint16_t *out_ms) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_workout_dialog__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_workout_dialog__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_workout_dialog__render_end_workout(void) {
|
||||
WorkoutDialog *workout_dialog = workout_dialog_create("Workout End");
|
||||
Dialog *dialog = workout_dialog_get_dialog(workout_dialog);
|
||||
|
||||
dialog_show_status_bar_layer(dialog, true);
|
||||
dialog_set_fullscreen(dialog, true);
|
||||
dialog_set_text(dialog, "End Workout?");
|
||||
dialog_set_background_color(dialog, PBL_IF_COLOR_ELSE(GColorYellow, GColorWhite));
|
||||
dialog_set_text_color(dialog, GColorBlack);
|
||||
dialog_set_icon(dialog, RESOURCE_ID_WORKOUT_APP_END);
|
||||
dialog_set_icon_animate_direction(dialog, DialogIconAnimateNone);
|
||||
|
||||
window_set_on_screen(&dialog->window, true, true);
|
||||
window_render(&dialog->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_dialog__render_detected_workout(void) {
|
||||
WorkoutDialog *workout_dialog = workout_dialog_create("Workout Detected");
|
||||
Dialog *dialog = workout_dialog_get_dialog(workout_dialog);
|
||||
|
||||
dialog_show_status_bar_layer(dialog, true);
|
||||
dialog_set_fullscreen(dialog, true);
|
||||
dialog_set_background_color(dialog, PBL_IF_COLOR_ELSE(GColorYellow, GColorWhite));
|
||||
dialog_set_text_color(dialog, GColorBlack);
|
||||
dialog_set_icon(dialog, RESOURCE_ID_WORKOUT_APP_DETECTED);
|
||||
dialog_set_icon_animate_direction(dialog, DialogIconAnimateNone);
|
||||
|
||||
workout_dialog_set_text(workout_dialog, "Run\nDetected");
|
||||
workout_dialog_set_subtext(workout_dialog, "03:42");
|
||||
|
||||
window_set_on_screen(&dialog->window, true, true);
|
||||
window_render(&dialog->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_dialog__render_workout_ended(void) {
|
||||
WorkoutDialog *workout_dialog = workout_dialog_create("Workout Ended");
|
||||
Dialog *dialog = workout_dialog_get_dialog(workout_dialog);
|
||||
|
||||
dialog_show_status_bar_layer(dialog, true);
|
||||
dialog_set_fullscreen(dialog, true);
|
||||
dialog_set_background_color(dialog, PBL_IF_COLOR_ELSE(GColorYellow, GColorWhite));
|
||||
dialog_set_text_color(dialog, GColorBlack);
|
||||
dialog_set_icon(dialog, RESOURCE_ID_WORKOUT_APP_DETECTED);
|
||||
dialog_set_icon_animate_direction(dialog, DialogIconAnimateNone);
|
||||
|
||||
workout_dialog_set_text(workout_dialog, "Workout\nEnded");
|
||||
workout_dialog_set_action_bar_hidden(workout_dialog, true);
|
||||
|
||||
window_set_on_screen(&dialog->window, true, true);
|
||||
window_render(&dialog->window, &s_ctx);
|
||||
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
102
tests/fw/apps/system_apps/workout/test_workout_selection.c
Normal file
102
tests/fw/apps/system_apps/workout/test_workout_selection.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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/workout/workout_selection.h"
|
||||
|
||||
#include "test_workout_app_includes.h"
|
||||
|
||||
typedef struct WorkoutSelectionWindow {
|
||||
Window window;
|
||||
MenuLayer menu_layer;
|
||||
} WorkoutSelectionWindow;
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
uint16_t time_ms(time_t *tloc, uint16_t *out_ms) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool workout_service_is_workout_type_supported(ActivitySessionType type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_workout_selection__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_workout_selection__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_select_workout_cb(ActivitySessionType type) { }
|
||||
|
||||
static void prv_create_window_and_render(uint16_t row) {
|
||||
WorkoutSelectionWindow *selection_window = workout_selection_push(prv_select_workout_cb);
|
||||
Window *window = &selection_window->window;
|
||||
MenuLayer *menu_layer = &selection_window->menu_layer;
|
||||
|
||||
menu_layer_set_selected_index(menu_layer, MenuIndex(0, row), MenuRowAlignCenter, false);
|
||||
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_workout_selection__render_run_selected(void) {
|
||||
prv_create_window_and_render(0);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_selection__render_walk_selected(void) {
|
||||
prv_create_window_and_render(1);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_selection__render_workout_selected(void) {
|
||||
prv_create_window_and_render(2);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
96
tests/fw/apps/system_apps/workout/test_workout_summary.c
Normal file
96
tests/fw/apps/system_apps/workout/test_workout_summary.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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/workout/workout_summary.h"
|
||||
#include "apps/system_apps/workout/workout_utils.h"
|
||||
|
||||
#include "test_workout_app_includes.h"
|
||||
|
||||
// Fakes
|
||||
/////////////////////
|
||||
|
||||
uint16_t time_ms(time_t *tloc, uint16_t *out_ms) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool workout_service_is_workout_type_supported(ActivitySessionType type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Setup and Teardown
|
||||
////////////////////////////////////
|
||||
|
||||
static GContext s_ctx;
|
||||
static FrameBuffer s_fb;
|
||||
|
||||
GContext *graphics_context_get_current_context(void) {
|
||||
return &s_ctx;
|
||||
}
|
||||
|
||||
void test_workout_summary__initialize(void) {
|
||||
// Setup graphics context
|
||||
framebuffer_init(&s_fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
||||
framebuffer_clear(&s_fb);
|
||||
graphics_context_init(&s_ctx, &s_fb, GContextInitializationMode_App);
|
||||
s_app_state_get_graphics_context = &s_ctx;
|
||||
|
||||
// Setup resources
|
||||
fake_spi_flash_init(0 /* offset */, 0x1000000 /* length */);
|
||||
pfs_init(false /* run filesystem check */);
|
||||
pfs_format(true /* write erase headers */);
|
||||
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
||||
false /* is_next */);
|
||||
resource_init();
|
||||
|
||||
// Setup content indicator
|
||||
ContentIndicatorsBuffer *buffer = content_indicator_get_current_buffer();
|
||||
content_indicator_init_buffer(buffer);
|
||||
}
|
||||
|
||||
void test_workout_summary__cleanup(void) {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
//////////////////////
|
||||
|
||||
static void prv_start_workout_cb(ActivitySessionType type) { }
|
||||
static void prv_select_workout_cb(ActivitySessionType type) { }
|
||||
|
||||
static void prv_create_window_and_render(ActivitySessionType activity_type) {
|
||||
Window *window = (Window *)workout_summary_window_create(activity_type,
|
||||
prv_start_workout_cb,
|
||||
prv_select_workout_cb);
|
||||
window_set_on_screen(window, true, true);
|
||||
window_render(window, &s_ctx);
|
||||
}
|
||||
|
||||
// Tests
|
||||
//////////////////////
|
||||
|
||||
void test_workout_summary__render_open_workout(void) {
|
||||
prv_create_window_and_render(ActivitySessionType_Open);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_summary__render_walk(void) {
|
||||
prv_create_window_and_render(ActivitySessionType_Walk);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
||||
|
||||
void test_workout_summary__render_run(void) {
|
||||
prv_create_window_and_render(ActivitySessionType_Run);
|
||||
cl_check(gbitmap_pbi_eq(&s_ctx.dest_bitmap, TEST_PBI_FILE));
|
||||
}
|
109
tests/fw/apps/system_apps/workout/test_workout_utils.c
Normal file
109
tests/fw/apps/system_apps/workout/test_workout_utils.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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/workout/workout_utils.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include "services/normal/activity/activity.h"
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
#include "stubs_attribute.h"
|
||||
#include "stubs_i18n.h"
|
||||
#include "stubs_notifications.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_rtc.h"
|
||||
#include "stubs_timeline_item.h"
|
||||
|
||||
// Stubs
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
bool workout_service_is_workout_type_supported(ActivitySessionType type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fakes
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
static ActivitySession s_sessions[ACTIVITY_MAX_ACTIVITY_SESSIONS_COUNT];
|
||||
static uint32_t s_num_sessions = 0;
|
||||
|
||||
static void prv_add_session(ActivitySession *session) {
|
||||
memcpy(&s_sessions[s_num_sessions++], session, sizeof(ActivitySession));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
bool activity_get_sessions(uint32_t *session_entries, ActivitySession *sessions) {
|
||||
memcpy(sessions, s_sessions, s_num_sessions * sizeof(ActivitySession));
|
||||
*session_entries = s_num_sessions;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
void test_workout_utils__initialize(void) {
|
||||
s_num_sessions = 0;
|
||||
}
|
||||
|
||||
void test_workout_utils__cleanup(void) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------------------
|
||||
void test_workout_utils__find_ongoing_activity_session(void) {
|
||||
bool found_session;
|
||||
|
||||
// Check if it can handle NULL session
|
||||
found_session = workout_utils_find_ongoing_activity_session(NULL);
|
||||
cl_assert_equal_b(found_session, false);
|
||||
|
||||
// Make sure there are no sessions
|
||||
cl_assert_equal_i(s_num_sessions, 0);
|
||||
|
||||
// Add a non-ongoing walk session
|
||||
prv_add_session(&(ActivitySession){
|
||||
.type = ActivitySessionType_Walk,
|
||||
.ongoing = false,
|
||||
});
|
||||
|
||||
// Make sure the session was added
|
||||
cl_assert_equal_i(s_num_sessions, 1);
|
||||
|
||||
// Find the session we just added
|
||||
ActivitySession walk_session = {};
|
||||
found_session = workout_utils_find_ongoing_activity_session(&walk_session);
|
||||
|
||||
// Made sure non-ongoing sessions are not returned
|
||||
cl_assert_equal_b(found_session, false);
|
||||
|
||||
// Add an ongoing run session
|
||||
prv_add_session(&(ActivitySession){
|
||||
.type = ActivitySessionType_Run,
|
||||
.ongoing = true,
|
||||
});
|
||||
|
||||
// Make sure the session was added
|
||||
cl_assert_equal_i(s_num_sessions, 2);
|
||||
|
||||
// Find the session we just added
|
||||
ActivitySession run_session = {};
|
||||
found_session = workout_utils_find_ongoing_activity_session(&run_session);
|
||||
|
||||
// Make sure the function returned true and the returned session is of type run
|
||||
cl_assert_equal_b(found_session, true);
|
||||
cl_assert_equal_i(run_session.type, ActivitySessionType_Run);
|
||||
}
|
155
tests/fw/apps/system_apps/workout/wscript
Normal file
155
tests/fw/apps/system_apps/workout/wscript
Normal file
|
@ -0,0 +1,155 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
rendering_sources = \
|
||||
" src/fw/applib/fonts/codepoint.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/framebuffer.c" \
|
||||
" src/fw/applib/graphics/${BITDEPTH}_bit/bitblt_private.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_bar_layer.c" \
|
||||
" src/fw/applib/ui/status_bar_layer.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel.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_system_cells.c" \
|
||||
" src/fw/applib/vendor/tinflate/tinflate.c" \
|
||||
" src/fw/applib/vendor/uPNG/upng.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/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_applib_resource.c" \
|
||||
" tests/fakes/fake_display.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/stubs/stubs_animation.c" \
|
||||
" tests/stubs/stubs_system_theme.c"
|
||||
|
||||
workout_app_sources = \
|
||||
" src/fw/applib/graphics/gpath_builder.c" \
|
||||
" src/fw/applib/ui/animation_interpolate.c" \
|
||||
" src/fw/applib/ui/content_indicator.c" \
|
||||
" src/fw/applib/ui/dialogs/dialog.c" \
|
||||
" src/fw/applib/ui/dialogs/dialog_private.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/transform.c" \
|
||||
" src/fw/applib/ui/kino/kino_reel_custom.c" \
|
||||
" src/fw/applib/ui/scroll_layer.c" \
|
||||
" src/fw/applib/ui/shadows.c" \
|
||||
" src/fw/applib/ui/text_layer.c" \
|
||||
" src/fw/applib/ui/text_layer_flow.c" \
|
||||
" src/fw/applib/ui/window.c" \
|
||||
" src/fw/apps/system_apps/timeline/text_node.c" \
|
||||
" src/fw/services/normal/activity/health_util.c" \
|
||||
" src/fw/services/normal/activity/hr_util.c" \
|
||||
" src/fw/services/normal/timeline/timeline_resources.c" \
|
||||
" src/fw/util/buffer.c" \
|
||||
" src/fw/util/stats.c" \
|
||||
" src/fw/util/time/mktime.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" tests/fakes/fake_clock.c" \
|
||||
" tests/fakes/fake_fonts.c" \
|
||||
" tests/fakes/fake_workout_service.c" \
|
||||
" tests/fixtures/resources/timeline_resource_table.auto.c"
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
workout_app_sources + \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/apps/system_apps/workout/workout_countdown.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_selection.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_dialog.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_utils.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_summary.c",
|
||||
test_sources_ant_glob = "test_workout_summary.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
workout_app_sources + \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/apps/system_apps/workout/workout_data.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_dialog.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_active.c",
|
||||
test_sources_ant_glob = "test_workout_active.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
workout_app_sources + \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/apps/system_apps/workout/workout_data.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_dialog.c",
|
||||
test_sources_ant_glob = "test_workout_dialog.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = rendering_sources + \
|
||||
workout_app_sources + \
|
||||
" src/fw/applib/ui/menu_layer.c" \
|
||||
" src/fw/apps/system_apps/workout/workout_utils.c" + \
|
||||
" src/fw/apps/system_apps/workout/workout_selection.c",
|
||||
test_sources_ant_glob = "test_workout_selection.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'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = " src/fw/apps/system_apps/workout/workout_utils.c",
|
||||
test_sources_ant_glob = "test_workout_utils.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
# vim:filetype=python
|
Loading…
Add table
Add a link
Reference in a new issue