blob: 7f24dd2d83f966118e135122d2b45e996babcd04 [file] [log] [blame]
// Copyright 2019 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.
#![cfg(test)]
use fidl_table_validation::*;
use std::convert::TryFrom;
macro_rules! dummy_impl_decodable {
($name:ty) => {
impl fidl::encoding::Layout for $name {
fn inline_align(_context: &fidl::encoding::Context) -> usize
where
Self: Sized,
{
0
}
fn inline_size(_context: &fidl::encoding::Context) -> usize
where
Self: Sized,
{
0
}
}
impl fidl::encoding::Decodable for $name {
fn new_empty() -> Self {
Self::default()
}
fn decode(
&mut self,
_decoder: &mut fidl::encoding::Decoder<'_>,
_offset: usize,
) -> fidl::Result<()> {
Ok(())
}
}
};
}
#[test]
fn rejects_missing_fields() {
#[derive(Default)]
struct FidlHello {
required: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
#[fidl_field_type(required)]
required: usize,
}
assert_eq!(
ValidHello::try_from(FidlHello { required: Some(10) }).expect("validation"),
ValidHello { required: 10 },
);
match ValidHello::try_from(FidlHello { required: None }) {
Err(FidlHelloValidationError::MissingField(FidlHelloMissingFieldError::Required)) => {}
_ => panic!("Should have generated an error for missing required field."),
};
}
#[test]
fn sets_default_fields() {
#[derive(Default)]
struct FidlHello {
has_default: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
#[fidl_field_type(default = 22)]
has_default: usize,
}
match ValidHello::try_from(FidlHello { has_default: None }) {
Ok(ValidHello { has_default: 22 }) => {}
_ => panic!("Expected successful validation with default value."),
};
}
#[test]
fn accepts_optional_fields() {
#[derive(Default)]
struct FidlHello {
optional: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
#[fidl_field_type(optional)]
optional: Option<usize>,
}
assert_eq!(
ValidHello::try_from(FidlHello { optional: None }).expect("validation"),
ValidHello { optional: None }
);
assert_eq!(
ValidHello::try_from(FidlHello { optional: Some(15) }).expect("validation"),
ValidHello { optional: Some(15) }
);
}
#[test]
fn invalid_fails_custom_validator() {
#[derive(Default)]
struct FidlHello {
should_not_be_12: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
#[fidl_table_validator(FidlHelloValidator)]
pub struct ValidHello {
#[fidl_field_type(default = 10)]
should_not_be_12: usize,
}
pub struct FidlHelloValidator;
impl Validate<ValidHello> for FidlHelloValidator {
type Error = ();
fn validate(candidate: &ValidHello) -> Result<(), Self::Error> {
match candidate.should_not_be_12 {
12 => Err(()),
_ => Ok(()),
}
}
}
match ValidHello::try_from(FidlHello { should_not_be_12: Some(12) }) {
Err(FidlHelloValidationError::Logical(())) => {}
_ => panic!("Wanted error from custom validator."),
}
}
#[test]
fn valid_passes_custom_validator() {
#[derive(Default)]
struct FidlHello {
should_not_be_12: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
#[fidl_table_validator(FidlHelloValidator)]
pub struct ValidHello {
#[fidl_field_type(default = 10)]
should_not_be_12: usize,
}
pub struct FidlHelloValidator;
impl Validate<ValidHello> for FidlHelloValidator {
type Error = ();
fn validate(candidate: &ValidHello) -> Result<(), Self::Error> {
match candidate.should_not_be_12 {
12 => Err(()),
_ => Ok(()),
}
}
}
assert_eq!(
ValidHello::try_from(FidlHello { should_not_be_12: None }).expect("validation"),
ValidHello { should_not_be_12: 10 }
);
}
#[test]
fn nested_valid_field_accepted() {
#[derive(Default)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default)]
struct FidlHello {
nested: Option<NestedFidl>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
nested: ValidNestedFidl,
}
assert_eq!(
ValidHello::try_from(FidlHello { nested: Some(NestedFidl { required: Some(10) }) })
.expect("validation"),
ValidHello { nested: ValidNestedFidl { required: 10 } },
);
}
#[test]
fn nested_invalid_field_rejected() {
#[derive(Default)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default)]
struct FidlHello {
nested: Option<NestedFidl>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
nested: ValidNestedFidl,
}
match ValidHello::try_from(FidlHello { nested: Some(NestedFidl { required: None }) }) {
Err(FidlHelloValidationError::InvalidField(_)) => {}
r => panic!("Wanted invalid field error for invalid nested field; got {:?}", r),
}
}
#[test]
fn back_into_original_nested() {
#[derive(Default, Debug, PartialEq)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default, Debug, PartialEq)]
struct FidlHello {
nested: Option<NestedFidl>,
}
dummy_impl_decodable!(FidlHello);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(FidlHello)]
struct ValidHello {
nested: ValidNestedFidl,
}
assert_eq!(
FidlHello::from(ValidHello { nested: ValidNestedFidl { required: 10 } }),
FidlHello { nested: Some(NestedFidl { required: Some(10) }) }
);
}
mod nested {
#[derive(Default, Debug, PartialEq)]
pub(crate) struct FidlHello {
pub required: Option<usize>,
}
dummy_impl_decodable!(FidlHello);
}
#[test]
fn works_with_nested_typenames() {
#[derive(Default, ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(nested::FidlHello)]
struct ValidHello {
required: usize,
}
match ValidHello::try_from(nested::FidlHello { required: Some(7) }) {
Ok(valid_hello) => assert_eq!(ValidHello { required: 7 }, valid_hello),
Err(e) => panic!("Did not expect to fail to build ValidHello: got {:?}", e),
};
}
#[test]
fn works_with_option_wrapped_nested_fields() {
#[derive(Default, Debug, PartialEq)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default, Debug, PartialEq)]
struct Fidl {
optional: Option<NestedFidl>,
}
dummy_impl_decodable!(Fidl);
#[derive(Default, ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(Fidl)]
struct ValidFidl {
#[fidl_field_type(optional)]
optional: Option<ValidNestedFidl>,
}
match ValidFidl::try_from(Fidl { optional: Some(NestedFidl { required: Some(5) }) }) {
Ok(valid) => {
assert_eq!(ValidFidl { optional: Some(ValidNestedFidl { required: 5 }) }, valid)
}
Err(e) => panic!("Did not expect to fail to build ValidFidl: got {:?}", e),
};
}
#[test]
fn works_with_vec_wrapped_nested_fields() {
#[derive(Default, Debug, PartialEq)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default, Debug, PartialEq)]
struct Fidl {
vec: Option<Vec<NestedFidl>>,
}
dummy_impl_decodable!(Fidl);
#[derive(Default, ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(Fidl)]
struct ValidFidl {
vec: Vec<ValidNestedFidl>,
}
match ValidFidl::try_from(Fidl {
vec: Some(vec![NestedFidl { required: Some(5) }, NestedFidl { required: Some(6) }]),
}) {
Ok(valid) => assert_eq!(
ValidFidl {
vec: vec![ValidNestedFidl { required: 5 }, ValidNestedFidl { required: 6 }]
},
valid
),
Err(e) => panic!("Did not expect to fail to build ValidFidl: got {:?}", e),
};
}
#[test]
fn works_with_optional_vec_wrapped_nested_fields() {
#[derive(Default, Debug, PartialEq)]
struct NestedFidl {
required: Option<usize>,
}
dummy_impl_decodable!(NestedFidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(NestedFidl)]
struct ValidNestedFidl {
required: usize,
}
#[derive(Default, Debug, PartialEq)]
struct Fidl {
vec: Option<Vec<NestedFidl>>,
}
dummy_impl_decodable!(Fidl);
#[derive(Default, ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(Fidl)]
struct ValidFidl {
#[fidl_field_type(optional)]
vec: Option<Vec<ValidNestedFidl>>,
}
match ValidFidl::try_from(Fidl {
vec: Some(vec![NestedFidl { required: Some(5) }, NestedFidl { required: Some(6) }]),
}) {
Ok(valid) => assert_eq!(
ValidFidl {
vec: Some(vec![ValidNestedFidl { required: 5 }, ValidNestedFidl { required: 6 }])
},
valid
),
Err(e) => panic!("Did not expect to fail to build ValidFidl: got {:?}", e),
};
}
#[test]
fn works_with_identifier_defaults() {
#[derive(Debug, PartialEq)]
enum Cheese {
Cheddar,
Swiss,
}
const DEFAULT_CHEESE: Cheese = Cheese::Cheddar;
impl Default for Cheese {
fn default() -> Self {
DEFAULT_CHEESE
}
}
#[derive(Default, Debug, PartialEq)]
struct Fidl {
cheese: Option<Cheese>,
}
dummy_impl_decodable!(Fidl);
#[derive(ValidFidlTable, Debug, PartialEq)]
#[fidl_table_src(Fidl)]
struct ValidFidl {
#[fidl_field_with_default(DEFAULT_CHEESE)]
cheese: Cheese,
}
match ValidFidl::try_from(Fidl { cheese: None }) {
Ok(valid) => assert_eq!(ValidFidl { cheese: DEFAULT_CHEESE }, valid),
Err(e) => panic!("Did not expect to fail to build ValidFidl: got {:?}", e),
};
match ValidFidl::try_from(Fidl { cheese: Some(Cheese::Swiss) }) {
Ok(valid) => assert_eq!(ValidFidl { cheese: Cheese::Swiss }, valid),
Err(e) => panic!("Did not expect to fail to build ValidFidl: got {:?}", e),
};
}