blob: 06fe792cfcb8ef6927b2407a2fa6be5e0149d5e8 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::agent::storage::device_storage::DeviceStorage;
use crate::agent::storage::storage_factory::testing::InMemoryStorageFactory;
use crate::agent::BlueprintHandle;
use crate::base::SettingType;
use crate::config::base::AgentType;
use crate::handler::base::{Context, GenerateHandler};
use crate::handler::setting_handler::persist::ClientProxy;
use crate::handler::setting_handler::{BoxedController, ClientImpl};
use crate::ingress::fidl::Interface;
use crate::input::common::MediaButtonsEventBuilder;
use crate::light::light_controller::LightController;
use crate::light::light_hardware_configuration::{DisableConditions, LightGroupConfiguration};
use crate::light::types::{ColorRgb, LightGroup, LightInfo, LightState, LightType, LightValue};
use crate::tests::fakes::hardware_light_service::HardwareLightService;
use crate::tests::fakes::input_device_registry_service::InputDeviceRegistryService;
use crate::tests::fakes::service_registry::ServiceRegistry;
use crate::{EnvironmentBuilder, LightHardwareConfiguration};
use fidl_fuchsia_settings::{LightError, LightMarker, LightProxy};
use futures::lock::Mutex;
use std::option::Option::Some;
use std::sync::Arc;
type HardwareLightServiceHandle = Arc<Mutex<HardwareLightService>>;
const ENV_NAME: &str = "settings_service_light_test_environment";
const LIGHT_NAME_1: &str = "light_name_1";
const LIGHT_NAME_2: &str = "light_name_2";
const LIGHT_NAME_3: &str = "light_name_3";
fn get_test_light_info() -> LightInfo {
LightInfo {
light_groups: [
(
LIGHT_NAME_1.to_string(),
LightGroup {
name: LIGHT_NAME_1.to_string(),
enabled: true,
light_type: LightType::Brightness,
lights: vec![LightState { value: Some(LightValue::Brightness(0.42)) }],
hardware_index: vec![0],
disable_conditions: vec![],
},
),
(
LIGHT_NAME_2.to_string(),
LightGroup {
name: LIGHT_NAME_2.to_string(),
enabled: true,
light_type: LightType::Simple,
lights: vec![LightState { value: Some(LightValue::Simple(true)) }],
hardware_index: vec![1],
disable_conditions: vec![],
},
),
]
.into(),
}
}
/// Populates the given HardwareLightService fake with the lights from a LightInfo.
///
/// Assumes that each light group has one light, as if the light groups were read from the
/// underlying fuchsia.hardware.light API.
async fn populate_single_test_lights(
hardware_light_service_handle: HardwareLightServiceHandle,
light_info: LightInfo,
) {
for (name, group) in light_info.light_groups.into_iter() {
hardware_light_service_handle
.lock()
.await
.insert_light(
group.hardware_index[0],
name,
group.light_type,
group.lights[0].value.clone().unwrap(),
)
.await;
}
}
/// Populates the given HardwareLightService fake with the lights from a LightInfo.
///
/// For each light group, adds a new light with the light's index in the LightGroup appended to it.
/// For example a light group with name RED and 3 lights would result in RED_1, RED_2, RED_3 being
/// inserted into the fake service.
async fn populate_multiple_test_lights(
hardware_light_service_handle: HardwareLightServiceHandle,
light_info: LightInfo,
) {
for (name, group) in light_info.light_groups.into_iter() {
for i in 0..group.hardware_index.len() {
hardware_light_service_handle
.lock()
.await
.insert_light(
group.hardware_index[i],
format!("{}_{}", name, i),
group.light_type,
group.lights[i].value.clone().unwrap(),
)
.await;
}
}
}
struct TestLightEnvironment {
light_service: LightProxy,
input_service: Arc<Mutex<InputDeviceRegistryService>>,
store: Arc<DeviceStorage>,
}
struct TestLightEnvironmentBuilder {
starting_light_info: Option<LightInfo>,
hardware_light_service_handle: Option<HardwareLightServiceHandle>,
light_hardware_config: Option<LightHardwareConfiguration>,
agents: Vec<AgentType>,
}
impl TestLightEnvironmentBuilder {
fn new() -> Self {
Self {
starting_light_info: None,
hardware_light_service_handle: None,
light_hardware_config: None,
agents: vec![AgentType::Restore],
}
}
/// Sets the initial light info that the fake `HardwareLightService` and device storage will
/// use.
fn set_starting_light_info(mut self, starting_light_info: LightInfo) -> Self {
self.starting_light_info = Some(starting_light_info);
self
}
/// Provides a handle to a custom fake `HardwareLightService`. This only works in conjunction
/// with specifying `starting_light_info`.
fn set_hardware_light_service_handle(
mut self,
hardware_light_service_handle: HardwareLightServiceHandle,
) -> Self {
self.hardware_light_service_handle = Some(hardware_light_service_handle);
self
}
fn set_light_hardware_config(
mut self,
light_hardware_config: LightHardwareConfiguration,
) -> Self {
self.light_hardware_config = Some(light_hardware_config);
self
}
fn add_agent(mut self, agent: AgentType) -> Self {
self.agents.push(agent);
self
}
async fn build(self) -> TestLightEnvironment {
let service_registry = ServiceRegistry::create();
let service_handle = match self.hardware_light_service_handle.clone() {
Some(service) => service,
None => Arc::new(Mutex::new(HardwareLightService::new())),
};
service_registry.lock().await.register_service(service_handle.clone());
// Register fake input device registry service.
let input_service_handle = Arc::new(Mutex::new(InputDeviceRegistryService::new()));
service_registry.lock().await.register_service(input_service_handle.clone());
let storage_factory = Arc::new(if let Some(info) = self.starting_light_info {
let storage_factory = InMemoryStorageFactory::with_initial_data(&info);
if self.hardware_light_service_handle.is_none() {
// If a fake hardware light service wasn't provided for us, populate the initial lights.
populate_single_test_lights(service_handle.clone(), info).await;
}
storage_factory
} else {
InMemoryStorageFactory::new()
});
let mut environment_builder = EnvironmentBuilder::new(Arc::clone(&storage_factory))
.service(Box::new(ServiceRegistry::serve(service_registry)))
.agents(&self.agents.into_iter().map(BlueprintHandle::from).collect::<Vec<_>>())
.fidl_interfaces(&[Interface::Light]);
if let Some(config) = self.light_hardware_config {
// If hardware configuration was specified, we need a generate_handler to include the
// specified configuration. This generate_handler method is a copy-paste of
// persist::controller::spawn from setting_handler.rs, with the innermost controller
// create method replaced with our custome constructor from light controller.
// TODO(fxbug.dev/63832): See if we can reduce this rightward drift.
let generate_handler: GenerateHandler = Box::new(move |context: Context| {
let config = config.clone();
Box::pin(async move {
let setting_type = context.setting_type;
ClientImpl::create(
context,
Box::new(move |proxy| {
let config = config.clone();
Box::pin(async move {
let proxy = ClientProxy::new(proxy, setting_type).await;
let controller_result = LightController::create_with_config(
proxy,
Some(config.clone()),
)
.await;
controller_result
.map(|controller| Box::new(controller) as BoxedController)
})
}),
)
.await
})
});
environment_builder = environment_builder.handler(SettingType::Light, generate_handler);
}
let env = environment_builder.spawn_and_get_nested_environment(ENV_NAME).await.unwrap();
let light_service = env.connect_to_protocol::<LightMarker>().unwrap();
let store = storage_factory.get_device_storage().await;
TestLightEnvironment { light_service, store, input_service: input_service_handle }
}
}
async fn set_light_value(service: &LightProxy, light_group: LightGroup) {
service
.set_light_group_values(
light_group.name.as_str(),
&mut light_group.lights.into_iter().map(LightState::into),
)
.await
.expect("set completed")
.expect("set successful");
}
/// Compares a vector of light group from the settings FIDL API and the light groups from a
/// service-internal LightInfo object for equality.
fn assert_lights_eq(mut groups: Vec<fidl_fuchsia_settings::LightGroup>, info: LightInfo) {
// Watch returns vector, internally we use a HashMap, so convert into a vector for comparison.
let mut expected_value = info
.light_groups
.into_iter()
.map(|(_, value)| fidl_fuchsia_settings::LightGroup::from(value))
.collect::<Vec<_>>();
assert_eq!(groups.len(), expected_value.len());
// Sort by names for stability
groups.sort_by_key(|group: &fidl_fuchsia_settings::LightGroup| group.name.clone());
expected_value.sort_by_key(|group| group.name.clone());
for i in 0..groups.len() {
assert_fidl_light_group_eq(&groups[i], &expected_value[i]);
}
}
fn assert_fidl_light_group_eq(
left: &fidl_fuchsia_settings::LightGroup,
right: &fidl_fuchsia_settings::LightGroup,
) {
assert_eq!(left.name, right.name);
assert_eq!(left.enabled, right.enabled);
assert_eq!(left.type_, right.type_);
assert_eq!(left.lights.as_ref().unwrap().len(), right.lights.as_ref().unwrap().len());
if left.type_ == Some(fidl_fuchsia_settings::LightType::Simple) {
assert_eq!(left.lights, right.lights);
}
}
fn assert_light_group_eq(left: &LightGroup, right: &LightGroup) {
assert_eq!(left.name, right.name);
assert_eq!(left.enabled, right.enabled);
assert_eq!(left.light_type, right.light_type);
assert_eq!(left.lights.len(), right.lights.len());
assert_eq!(left.hardware_index, right.hardware_index);
if left.light_type == LightType::Simple {
assert_eq!(left.lights, right.lights);
}
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_restore() {
// Populate the fake service with the initial lights that will be restored.
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
populate_single_test_lights(hardware_light_service_handle.clone(), get_test_light_info()).await;
let env = TestLightEnvironmentBuilder::new()
.set_hardware_light_service_handle(hardware_light_service_handle)
.build()
.await;
let expected_light_group = get_test_light_info().light_groups.remove(LIGHT_NAME_1).unwrap();
// Verify that the restored value is persisted.
let retrieved_struct = env.store.get::<LightInfo>().await;
assert_light_group_eq(
&expected_light_group.clone(),
retrieved_struct.light_groups.get(LIGHT_NAME_1).unwrap(),
);
// Verify that the restored value is returned on a watch call.
let settings: fidl_fuchsia_settings::LightGroup =
env.light_service.watch_light_group(LIGHT_NAME_1).await.expect("watch completed");
assert_fidl_light_group_eq(
&fidl_fuchsia_settings::LightGroup::from(expected_light_group),
&settings,
);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_restores_on_watch() {
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
let env = TestLightEnvironmentBuilder::new()
.set_hardware_light_service_handle(hardware_light_service_handle.clone())
.build()
.await;
// Don't populate the fake service with lights until after the service starts.
let expected_light_info = get_test_light_info();
populate_single_test_lights(hardware_light_service_handle, expected_light_info.clone()).await;
// Upon a watch call, light controller will read the underlying value from the fake service.
let settings = env.light_service.watch_light_groups().await.expect("watch completed");
assert_lights_eq(settings, expected_light_info);
}
// Tests that when a `LightHardwareConfiguration` is specified, that the service will restore
// lights based on the configuration, while still reading light values from the underlying hardware.
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_restore_from_configuration() {
// Populate the fake service with an initial set of lights.
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
populate_single_test_lights(hardware_light_service_handle.clone(), get_test_light_info()).await;
// Hardware config only includes on light group, basically a renamed version of LIGHT_NAME_1.
let light_hardware_config = LightHardwareConfiguration {
light_groups: vec![LightGroupConfiguration {
name: LIGHT_NAME_3.to_string(),
hardware_index: vec![0],
light_type: LightType::Brightness,
persist: false,
disable_conditions: vec![],
}],
};
let env = TestLightEnvironmentBuilder::new()
.set_hardware_light_service_handle(hardware_light_service_handle)
.set_light_hardware_config(light_hardware_config)
.build()
.await;
// We're expecting LIGHT_NAME_1 except it's been renamed to LIGHT_NAME_3 by the hardware config.
let mut expected_light_group = get_test_light_info().light_groups.remove(LIGHT_NAME_1).unwrap();
expected_light_group.name = LIGHT_NAME_3.to_string();
// Verify that the restored value is persisted.
let retrieved_struct = env.store.get::<LightInfo>().await;
assert_light_group_eq(
&expected_light_group.clone(),
retrieved_struct.light_groups.get(LIGHT_NAME_3).unwrap(),
);
// Verify that the restored value is returned on a watch call.
let settings: fidl_fuchsia_settings::LightGroup =
env.light_service.watch_light_group(LIGHT_NAME_3).await.expect("watch completed");
assert_fidl_light_group_eq(
&fidl_fuchsia_settings::LightGroup::from(expected_light_group),
&settings,
);
// None of the light names provided by in the hardware itself are valid as they're not in the
// configuration.
let _ = env.light_service.watch_light_group(LIGHT_NAME_1).await.expect_err("watch should fail");
let _ = env.light_service.watch_light_group(LIGHT_NAME_2).await.expect_err("watch should fail");
}
// Tests that setting a light that's specified in a `LightHardwareConfiguration` also sets the value
// in the underlying hardware.
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_set_from_configuration() {
// Populate the fake service with an initial set of lights.
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
populate_single_test_lights(hardware_light_service_handle.clone(), get_test_light_info()).await;
// Hardware config only includes on light group, basically a renamed version of LIGHT_NAME_1.
let light_hardware_config = LightHardwareConfiguration {
light_groups: vec![LightGroupConfiguration {
name: LIGHT_NAME_3.to_string(),
hardware_index: vec![0],
light_type: LightType::Brightness,
persist: false,
disable_conditions: vec![],
}],
};
let mut changed_light_group =
get_test_light_info().light_groups.get(LIGHT_NAME_1).unwrap().clone();
// The light hardware configuration basically renames LIGHT_NAME_1 to LIGHT_NAME_3.
changed_light_group.name = LIGHT_NAME_3.to_string();
changed_light_group.lights = vec![LightState { value: Some(LightValue::Brightness(0.99)) }];
let expected_light_info = LightInfo {
light_groups: [(LIGHT_NAME_3.to_string(), changed_light_group.clone())].into(),
};
let env = TestLightEnvironmentBuilder::new()
.set_hardware_light_service_handle(hardware_light_service_handle)
.set_light_hardware_config(light_hardware_config)
.build()
.await;
// Set a light value.
set_light_value(&env.light_service, changed_light_group).await;
// Verify the value we set is persisted in DeviceStorage.
assert_eq!(expected_light_info, env.store.get().await);
// Ensure value from Watch matches set value.
let settings: Vec<fidl_fuchsia_settings::LightGroup> =
env.light_service.watch_light_groups().await.expect("watch completed");
assert_lights_eq(settings, expected_light_info);
}
// Tests that when a `LightHardwareConfiguration` is specified, that light groups configured with
// `DisableConditions::MicSwitch` have their enabled bits set to off when the mic is unmuted.
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_disabled_by_mic_mute_off() {
// Populate the fake service with an initial set of lights.
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
populate_single_test_lights(hardware_light_service_handle.clone(), get_test_light_info()).await;
// Hardware config only includes on light group, basically a renamed version of LIGHT_NAME_1.
let light_hardware_config = LightHardwareConfiguration {
light_groups: vec![LightGroupConfiguration {
name: LIGHT_NAME_3.to_string(),
hardware_index: vec![0],
light_type: LightType::Brightness,
persist: false,
disable_conditions: vec![DisableConditions::MicSwitch],
}],
};
// We're expecting LIGHT_NAME_1 except it's been renamed to LIGHT_NAME_3 by the hardware config,
// and the enabled bit will be set to off.
let mut expected_light_group = get_test_light_info().light_groups.remove(LIGHT_NAME_1).unwrap();
expected_light_group.name = LIGHT_NAME_3.to_string();
expected_light_group.enabled = false;
let env = TestLightEnvironmentBuilder::new()
.set_hardware_light_service_handle(hardware_light_service_handle)
.add_agent(AgentType::MediaButtons)
.set_light_hardware_config(light_hardware_config)
.build()
.await;
// Send mic unmuted, which should disable the light.
let buttons_event = MediaButtonsEventBuilder::new().set_mic_mute(false).build();
env.input_service.lock().await.send_media_button_event(buttons_event).await;
// Verify that the expected value is returned on a watch call.
let settings: fidl_fuchsia_settings::LightGroup =
env.light_service.watch_light_group(LIGHT_NAME_3).await.expect("watch completed");
assert_fidl_light_group_eq(
&fidl_fuchsia_settings::LightGroup::from(expected_light_group),
&settings,
);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_store_and_watch() {
let mut expected_light_info = get_test_light_info();
let mut changed_light_group =
expected_light_info.light_groups.get(LIGHT_NAME_1).unwrap().clone();
changed_light_group.lights = vec![LightState { value: Some(LightValue::Brightness(0.128)) }];
let _ = expected_light_info
.light_groups
.insert(LIGHT_NAME_1.to_string(), changed_light_group.clone());
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
// Set a light value.
set_light_value(&env.light_service, changed_light_group).await;
// Verify the value we set is persisted in DeviceStorage.
assert_eq!(expected_light_info, env.store.get().await);
// Ensure value from Watch matches set value.
let settings: Vec<fidl_fuchsia_settings::LightGroup> =
env.light_service.watch_light_groups().await.expect("watch completed");
assert_lights_eq(settings, expected_light_info);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_set_wrong_size() {
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
// Light group only has one light, attempt to set two lights.
let _ = env
.light_service
.set_light_group_values(
LIGHT_NAME_1,
&mut vec![
LightState { value: Some(LightValue::Brightness(0.128)) },
LightState { value: Some(LightValue::Brightness(0.11)) },
]
.into_iter()
.map(LightState::into),
)
.await
.expect("set completed")
.expect_err("set failed");
}
// Tests that when there are multiple lights, one light can be set at a time.
#[fuchsia_async::run_until_stalled(test)]
async fn test_light_set_single_light() {
const TEST_LIGHT_NAME: &str = "multiple_lights";
const LIGHT_1_VAL: f64 = 0.42;
const LIGHT_2_START_VAL: f64 = 0.24;
const LIGHT_2_CHANGED_VAL: f64 = 0.11;
// For this test, create a light group with two lights to test setting one light at a time.
let original_light_group = LightGroup {
name: TEST_LIGHT_NAME.to_string(),
enabled: true,
light_type: LightType::Brightness,
lights: vec![
LightState { value: Some(LightValue::Brightness(LIGHT_1_VAL)) },
LightState { value: Some(LightValue::Brightness(LIGHT_2_START_VAL)) },
],
hardware_index: vec![0, 1],
disable_conditions: vec![],
};
// When changing the light group, specify None for the first light.
let mut changed_light_group = original_light_group.clone();
changed_light_group.lights = vec![
LightState { value: None },
LightState { value: Some(LightValue::Brightness(LIGHT_2_CHANGED_VAL)) },
];
// Only the second light should change.
let mut expected_light_group = original_light_group.clone();
expected_light_group.lights = vec![
LightState { value: Some(LightValue::Brightness(LIGHT_1_VAL)) },
LightState { value: Some(LightValue::Brightness(LIGHT_2_CHANGED_VAL)) },
];
let starting_light_info =
LightInfo { light_groups: [(TEST_LIGHT_NAME.to_string(), original_light_group)].into() };
let mut expected_light_info = starting_light_info.clone();
let _ = expected_light_info
.light_groups
.insert(TEST_LIGHT_NAME.to_string(), expected_light_group.clone());
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(starting_light_info.clone())
.set_hardware_light_service_handle(hardware_light_service_handle.clone())
.build()
.await;
// Populate the fake service with the initial lights so the set calls aren't rejected.
populate_multiple_test_lights(hardware_light_service_handle, starting_light_info).await;
set_light_value(&env.light_service, changed_light_group).await;
// Verify the value we set is persisted in DeviceStorage.
assert_eq!(expected_light_info, env.store.get().await);
// Ensure value from Watch matches set value.
let mut settings: Vec<fidl_fuchsia_settings::LightGroup> =
env.light_service.watch_light_groups().await.expect("watch completed");
settings.sort_by_key(|group: &fidl_fuchsia_settings::LightGroup| group.name.clone());
let settings =
env.light_service.watch_light_group(TEST_LIGHT_NAME).await.expect("watch completed");
assert_eq!(settings, expected_light_group.into());
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_individual_light_group() {
let test_light_info = get_test_light_info();
let light_group_1 = test_light_info.light_groups.get(LIGHT_NAME_1).unwrap().clone();
let mut light_group_1_updated = light_group_1.clone();
light_group_1_updated.lights = vec![LightState { value: Some(LightValue::Brightness(0.128)) }];
let light_group_2 = test_light_info.light_groups.get(LIGHT_NAME_2).unwrap().clone();
let mut light_group_2_updated = light_group_2.clone();
light_group_2_updated.lights = vec![LightState { value: Some(LightValue::Simple(false)) }];
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
let light_service = env.light_service;
// Ensure values from Watch matches set values.
let settings = light_service.watch_light_group(LIGHT_NAME_1).await.expect("watch completed");
assert_fidl_light_group_eq(&settings, &light_group_1.into());
let settings = light_service.watch_light_group(LIGHT_NAME_2).await.expect("watch completed");
assert_fidl_light_group_eq(&settings, &light_group_2.into());
// Set updated values for the two lights.
set_light_value(&light_service, light_group_1_updated.clone()).await;
let settings = light_service.watch_light_group(LIGHT_NAME_1).await.expect("watch completed");
assert_fidl_light_group_eq(&settings, &light_group_1_updated.into());
set_light_value(&light_service, light_group_2_updated.clone()).await;
let settings = light_service.watch_light_group(LIGHT_NAME_2).await.expect("watch completed");
assert_fidl_light_group_eq(&settings, &light_group_2_updated.into());
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_watch_unknown_light_group_name() {
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
// Unknown name should be rejected.
let _ =
env.light_service.watch_light_group("unknown_name").await.expect_err("watch should fail");
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_set_unknown_light_group_name() {
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
// Unknown name should be rejected.
let result = env
.light_service
.set_light_group_values("unknown_name", &mut vec![].into_iter())
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidName));
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_set_wrong_state_length() {
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(get_test_light_info())
.build()
.await;
// Set with no light state should fail.
let result = env
.light_service
.set_light_group_values(LIGHT_NAME_1, &mut vec![].into_iter())
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
// Set with an extra light state should fail.
let extra_state = vec![
fidl_fuchsia_settings::LightState {
value: None,
..fidl_fuchsia_settings::LightState::EMPTY
},
fidl_fuchsia_settings::LightState {
value: None,
..fidl_fuchsia_settings::LightState::EMPTY
},
];
let result = env
.light_service
.set_light_group_values(LIGHT_NAME_1, &mut extra_state.into_iter())
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_set_wrong_value_type() {
const TEST_LIGHT_NAME: &str = "multiple_lights";
const LIGHT_START_VAL: f64 = 0.24;
const LIGHT_CHANGED_VAL: f64 = 0.11;
let original_light_group = LightGroup {
name: TEST_LIGHT_NAME.to_string(),
enabled: true,
light_type: LightType::Brightness,
lights: vec![
LightState { value: Some(LightValue::Brightness(LIGHT_START_VAL)) },
LightState { value: Some(LightValue::Brightness(LIGHT_START_VAL)) },
],
hardware_index: vec![0, 1],
disable_conditions: vec![],
};
let starting_light_info =
LightInfo { light_groups: [(TEST_LIGHT_NAME.to_string(), original_light_group)].into() };
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(starting_light_info.clone())
.set_hardware_light_service_handle(hardware_light_service_handle)
.build()
.await;
// One of the light values is On instead of brightness, the set should fail.
let result = env
.light_service
.set_light_group_values(
TEST_LIGHT_NAME,
&mut vec![
fidl_fuchsia_settings::LightState {
value: None,
..fidl_fuchsia_settings::LightState::EMPTY
},
fidl_fuchsia_settings::LightState {
value: Some(fidl_fuchsia_settings::LightValue::On(true)),
..fidl_fuchsia_settings::LightState::EMPTY
},
]
.into_iter(),
)
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
// One of the values is the right type, but the other is still wrong, the set should fail.
let result = env
.light_service
.set_light_group_values(
TEST_LIGHT_NAME,
&mut vec![
fidl_fuchsia_settings::LightState {
value: Some(fidl_fuchsia_settings::LightValue::Brightness(LIGHT_CHANGED_VAL)),
..fidl_fuchsia_settings::LightState::EMPTY
},
fidl_fuchsia_settings::LightState {
value: Some(fidl_fuchsia_settings::LightValue::On(true)),
..fidl_fuchsia_settings::LightState::EMPTY
},
]
.into_iter(),
)
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_set_invalid_rgb_values() {
const TEST_LIGHT_NAME: &str = "light";
const LIGHT_START_VAL: f32 = 0.25;
const INVALID_VAL_1: f32 = 1.1;
const INVALID_VAL_2: f32 = -0.1;
let original_light_group = LightGroup {
name: TEST_LIGHT_NAME.to_string(),
enabled: true,
light_type: LightType::Rgb,
lights: vec![LightState {
value: Some(LightValue::Rgb(ColorRgb {
red: LIGHT_START_VAL,
green: LIGHT_START_VAL,
blue: LIGHT_START_VAL,
})),
}],
hardware_index: vec![0],
disable_conditions: vec![],
};
let starting_light_info =
LightInfo { light_groups: [(TEST_LIGHT_NAME.to_string(), original_light_group)].into() };
let hardware_light_service_handle = Arc::new(Mutex::new(HardwareLightService::new()));
let env = TestLightEnvironmentBuilder::new()
.set_starting_light_info(starting_light_info.clone())
.set_hardware_light_service_handle(hardware_light_service_handle)
.build()
.await;
// One of the RGB components is too big, the set should fail.
let result = env
.light_service
.set_light_group_values(
TEST_LIGHT_NAME,
&mut vec![fidl_fuchsia_settings::LightState {
value: Some(fidl_fuchsia_settings::LightValue::Color(
fidl_fuchsia_ui_types::ColorRgb {
red: LIGHT_START_VAL,
green: LIGHT_START_VAL,
blue: INVALID_VAL_1,
},
)),
..fidl_fuchsia_settings::LightState::EMPTY
}]
.into_iter(),
)
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
// One of the RGB components is negative, the set should fail.
let result = env
.light_service
.set_light_group_values(
TEST_LIGHT_NAME,
&mut vec![fidl_fuchsia_settings::LightState {
value: Some(fidl_fuchsia_settings::LightValue::Color(
fidl_fuchsia_ui_types::ColorRgb {
red: LIGHT_START_VAL,
green: INVALID_VAL_2,
blue: LIGHT_START_VAL,
},
)),
..fidl_fuchsia_settings::LightState::EMPTY
}]
.into_iter(),
)
.await
.expect("set returns");
assert_eq!(result, Err(LightError::InvalidValue));
}