pebble/tests/fw/services/test_weather_service.c
2025-01-27 11:38:16 -08:00

225 lines
7.4 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "clar.h"
#include "./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(&current->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);
}