/* * 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 "./blob_db/weather_data_shared.h" #include "applib/event_service_client.h" #include "kernel/events.h" #include "services/common/comm_session/session_remote_version.h" #include "services/normal/blob_db/weather_db.h" #include "services/normal/filesystem/pfs.h" #include "services/normal/weather/weather_service.h" #include "services/normal/weather/weather_service_private.h" #include "services/normal/weather/weather_types.h" #include "util/pstring.h" // Fixture //////////////////////////////////////////////////////////////// // Fakes //////////////////////////////////////////////////////////////// #include "fake_pbl_malloc.h" #include "fake_spi_flash.h" // Stubs //////////////////////////////////////////////////////////////// #include "stubs_analytics.h" #include "stubs_events.h" #include "stubs_logging.h" #include "stubs_mutex.h" #include "stubs_hexdump.h" #include "stubs_passert.h" #include "stubs_prompt.h" #include "stubs_task_watchdog.h" #include "stubs_pebble_tasks.h" #include "stubs_sleep.h" static EventServiceInfo *s_event_info; void event_service_client_subscribe(EventServiceInfo *service_info) { s_event_info = service_info; } void event_service_client_unsubscribe(EventServiceInfo *service_info) {} void bt_persistent_storage_get_cached_system_capabilities( PebbleProtocolCapabilities *capabilities) { capabilities->weather_app_support = 1; } void test_weather_service__initialize(void) { fake_spi_flash_init(0, 0x1000000); pfs_init(false); weather_db_init(); weather_service_init(); weather_shared_data_init(); } void test_weather_service__cleanup(void) { weather_shared_data_cleanup(); } static const WeatherLocationForecast s_forecasts[] = { { .location_name = TEST_WEATHER_DB_LOCATION_PALO_ALTO, .is_current_location = true, .current_temp = 68, .today_high = 68, .today_low = 52, .current_weather_type = WeatherType_Sun, .current_weather_phrase = TEST_WEATHER_DB_SHORT_PHRASE_SUNNY, .tomorrow_high = 70, .tomorrow_low = 60, .tomorrow_weather_type = WeatherType_CloudyDay }, { .location_name = TEST_WEATHER_DB_LOCATION_KITCHENER, .is_current_location = false, .current_temp = -10, .today_high = 0, .today_low = -11, .current_weather_type = WeatherType_PartlyCloudy, .current_weather_phrase = TEST_WEATHER_DB_SHORT_PHRASE_PARTLY_CLOUDY, .tomorrow_high = 2, .tomorrow_low = -3, .tomorrow_weather_type = WeatherType_CloudyDay }, { .location_name = TEST_WEATHER_DB_LOCATION_WATERLOO, .is_current_location = false, .current_temp = -99, .today_high = -98, .today_low = -99, .current_weather_type = WeatherType_HeavySnow, .current_weather_phrase = TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_SNOW, .tomorrow_high = 2, .tomorrow_low = 1, .tomorrow_weather_type = WeatherType_Sun }, { .location_name = TEST_WEATHER_DB_LOCATION_RWC, .is_current_location = true, .current_temp = 60, .today_high = 70, .today_low = 50, .current_weather_type = WeatherType_HeavyRain, .current_weather_phrase = TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_RAIN, .tomorrow_high = 70, .tomorrow_low = 60, .tomorrow_weather_type = WeatherType_PartlyCloudy } }; static void prv_assert_forecast_equal(const WeatherLocationForecast *to_check, const WeatherLocationForecast *original) { cl_assert_equal_s(to_check->location_name, original->location_name); cl_assert_equal_b(to_check->is_current_location, original->is_current_location); cl_assert_equal_i(to_check->current_temp, original->current_temp); cl_assert_equal_i(to_check->today_high, original->today_high); cl_assert_equal_i(to_check->today_low, original->today_low); cl_assert_equal_i(to_check->current_weather_type, original->current_weather_type); cl_assert_equal_s(to_check->current_weather_phrase, original->current_weather_phrase); cl_assert_equal_i(to_check->tomorrow_high, original->tomorrow_high); cl_assert_equal_i(to_check->tomorrow_low, original->tomorrow_low); cl_assert_equal_i(to_check->tomorrow_weather_type, original->tomorrow_weather_type); } void test_weather_service__get_data_for_all_locations(void) { size_t count_out; WeatherDataListNode *head = weather_service_locations_list_create(&count_out); WeatherLocationID id = 0; WeatherDataListNode *current = head; while (current) { cl_assert_equal_i(current->id, id); prv_assert_forecast_equal(¤t->forecast, &s_forecasts[id]); id++; current = (WeatherDataListNode *)current->node.next; } cl_assert_equal_i(count_out, 4); cl_assert_equal_i(id, 4); weather_service_locations_list_destroy(head); } void test_weather_service__get_default_location_forecast_from_weather_db_update(void) { WeatherLocationForecast *forecast = weather_service_create_default_forecast(); // no blob db events were fired during unit test, therefore forecast cache never updated cl_assert(!forecast); const int default_location_index = 0; const WeatherDBKey *default_location_key = weather_shared_data_get_key(default_location_index); PebbleEvent insert_event = (PebbleEvent) { .type = PEBBLE_BLOBDB_EVENT, .blob_db = { .db_id = BlobDBIdWeather, .type = BlobDBEventTypeInsert, .key = (uint8_t *)default_location_key, .key_len = sizeof(WeatherDBKey), } }; s_event_info->handler(&insert_event, s_event_info->context); forecast = weather_service_create_default_forecast(); cl_assert(forecast); prv_assert_forecast_equal(forecast, &s_forecasts[0]); weather_service_destroy_default_forecast(forecast); weather_db_flush(); PebbleEvent flush_event = (PebbleEvent) { .type = PEBBLE_BLOBDB_EVENT, .blob_db = { .db_id = BlobDBIdWeather, .type = BlobDBEventTypeFlush, .key = NULL, .key_len = 0, } }; s_event_info->handler(&flush_event, s_event_info->context); forecast = weather_service_create_default_forecast(); cl_assert(!forecast); } void test_weather_service__get_default_location_forecast_from_watch_app_prefs_db_update(void) { WeatherLocationForecast *forecast = weather_service_create_default_forecast(); // no blob db events were fired during unit test, therefore forecast cache never updated cl_assert(!forecast); const int default_location_index = 0; const WeatherDBKey *default_location_key = weather_shared_data_get_key(0); PebbleEvent insert_event = (PebbleEvent) { .type = PEBBLE_BLOBDB_EVENT, .blob_db = { .db_id = BlobDBIdWatchAppPrefs, .type = BlobDBEventTypeInsert, .key = (uint8_t *)PREF_KEY_WEATHER_APP, .key_len = sizeof(PREF_KEY_WEATHER_APP), } }; s_event_info->handler(&insert_event, s_event_info->context); forecast = weather_service_create_default_forecast(); cl_assert(forecast); prv_assert_forecast_equal(forecast, &s_forecasts[0]); weather_service_destroy_default_forecast(forecast); }