blob: dfb9942a45c852cfab01fdfd180c7f0033acdef3 [file] [log] [blame]
// Copyright 2022 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::error::AvailabilityRoutingError,
cm_rust::{Availability, ExposeDeclCommon, ExposeSource, OfferDeclCommon, OfferSource},
};
pub fn advance_with_offer(
current: Availability,
offer: &impl OfferDeclCommon,
) -> Result<Availability, AvailabilityRoutingError> {
let result = advance(current, *offer.availability());
if offer.source() == &OfferSource::Void
&& result == Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
{
return Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget);
}
result
}
pub fn advance_with_expose(
current: Availability,
expose: &impl ExposeDeclCommon,
) -> Result<Availability, AvailabilityRoutingError> {
let result = advance(current, *expose.availability());
if expose.source() == &ExposeSource::Void
&& result == Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
{
return Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget);
}
result
}
impl crate::legacy_router::OfferVisitor for Availability {
fn visit(&mut self, offer: &cm_rust::OfferDecl) -> Result<(), crate::RoutingError> {
*self = advance_with_offer(*self, offer)?;
Ok(())
}
}
impl crate::legacy_router::ExposeVisitor for Availability {
fn visit(&mut self, expose: &cm_rust::ExposeDecl) -> Result<(), crate::RoutingError> {
*self = advance_with_expose(*self, expose)?;
Ok(())
}
}
impl crate::legacy_router::CapabilityVisitor for Availability {
fn visit(&mut self, _: &cm_rust::CapabilityDecl) -> Result<(), crate::RoutingError> {
Ok(())
}
}
pub fn advance(
current: Availability,
next_availability: Availability,
) -> Result<Availability, AvailabilityRoutingError> {
let next = availability::advance(current, next_availability)?;
Ok(next)
}
#[cfg(test)]
mod tests {
use {
super::*,
cm_rust::{
DependencyType, ExposeDecl, ExposeProtocolDecl, ExposeTarget, OfferDecl,
OfferProtocolDecl,
},
cm_rust_testing::*,
test_case::test_case,
};
fn new_offer(availability: Availability) -> OfferDecl {
OfferDecl::Protocol(OfferProtocolDecl {
source: OfferSource::Parent,
source_name: "fuchsia.examples.Echo".parse().unwrap(),
source_dictionary: Default::default(),
target: offer_target_static_child("echo"),
target_name: "fuchsia.examples.Echo".parse().unwrap(),
dependency_type: DependencyType::Weak,
availability,
})
}
fn new_void_offer() -> OfferDecl {
OfferDecl::Protocol(OfferProtocolDecl {
source: OfferSource::Void,
source_name: "fuchsia.examples.Echo".parse().unwrap(),
source_dictionary: Default::default(),
target: offer_target_static_child("echo"),
target_name: "fuchsia.examples.Echo".parse().unwrap(),
dependency_type: DependencyType::Weak,
availability: Availability::Optional,
})
}
#[test_case(Availability::Optional, new_offer(Availability::Optional), Ok(()))]
#[test_case(Availability::Optional, new_offer(Availability::Required), Ok(()))]
#[test_case(Availability::Optional, new_offer(Availability::SameAsTarget), Ok(()))]
#[test_case(
Availability::Optional,
new_offer(Availability::Transitional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(Availability::Optional, new_void_offer(), Ok(()))]
#[test_case(
Availability::Required,
new_offer(Availability::Optional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(Availability::Required, new_offer(Availability::Required), Ok(()))]
#[test_case(Availability::Required, new_offer(Availability::SameAsTarget), Ok(()))]
#[test_case(
Availability::Required,
new_offer(Availability::Transitional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(
Availability::Required,
new_void_offer(),
Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget)
)]
#[test_case(Availability::Transitional, new_offer(Availability::Optional), Ok(()))]
#[test_case(Availability::Transitional, new_offer(Availability::Required), Ok(()))]
#[test_case(Availability::Transitional, new_offer(Availability::SameAsTarget), Ok(()))]
#[test_case(Availability::Transitional, new_offer(Availability::Transitional), Ok(()))]
#[test_case(Availability::Transitional, new_void_offer(), Ok(()))]
fn offer_tests(
availability: Availability,
offer: OfferDecl,
expected: Result<(), AvailabilityRoutingError>,
) {
let actual = advance_with_offer(availability, &offer).map(|_| ());
assert_eq!(actual, expected);
}
fn new_expose(availability: Availability) -> ExposeDecl {
ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Self_,
source_name: "fuchsia.examples.Echo".parse().unwrap(),
source_dictionary: Default::default(),
target: ExposeTarget::Parent,
target_name: "fuchsia.examples.Echo".parse().unwrap(),
availability,
})
}
fn new_void_expose() -> ExposeDecl {
ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Void,
source_name: "fuchsia.examples.Echo".parse().unwrap(),
source_dictionary: Default::default(),
target: ExposeTarget::Parent,
target_name: "fuchsia.examples.Echo".parse().unwrap(),
availability: Availability::Optional,
})
}
#[test_case(Availability::Optional, new_expose(Availability::Optional), Ok(()))]
#[test_case(Availability::Optional, new_expose(Availability::Required), Ok(()))]
#[test_case(Availability::Optional, new_expose(Availability::SameAsTarget), Ok(()))]
#[test_case(
Availability::Optional,
new_expose(Availability::Transitional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(
Availability::Optional,
new_void_expose(),
Ok(())
)]
#[test_case(
Availability::Required,
new_expose(Availability::Optional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(Availability::Required, new_expose(Availability::Required), Ok(()))]
#[test_case(Availability::Required, new_expose(Availability::SameAsTarget), Ok(()))]
#[test_case(
Availability::Required,
new_expose(Availability::Transitional),
Err(AvailabilityRoutingError::TargetHasStrongerAvailability)
)]
#[test_case(
Availability::Required,
new_void_expose(),
Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget)
)]
#[test_case(Availability::Transitional, new_expose(Availability::Optional), Ok(()))]
#[test_case(Availability::Transitional, new_expose(Availability::Required), Ok(()))]
#[test_case(Availability::Transitional, new_expose(Availability::SameAsTarget), Ok(()))]
#[test_case(Availability::Transitional, new_expose(Availability::Transitional), Ok(()))]
#[test_case(
Availability::Transitional,
new_void_expose(),
Ok(())
)]
fn expose_tests(
availability: Availability,
expose: ExposeDecl,
expected: Result<(), AvailabilityRoutingError>,
) {
let actual = advance_with_expose(availability, &expose).map(|_| ());
assert_eq!(actual, expected);
}
}