use std::{
fs,
path::PathBuf,
sync::mpsc::{self, RecvTimeoutError},
thread,
time::Duration,
};
use bumpalo::Bump;
use super::{
construct::{construct_entity_model, ConstructConfig},
identifiers::QualifiedName,
EntityModel, EnumType, EnumTypeMember, EnumUnderlyingType,
};
const SERVICE_URL: &str = "http://services.odata.org/V4/TripPinService";
#[test]
fn trippin_builds() {
construct_from_xml_file("trippin.xml", ConstructConfig::default(), &Bump::new()).unwrap();
}
#[test]
fn enum_no_values_assigned_consecutively() {
let arena = Bump::new();
let model = construct_from_xml_file(
"enum_no_explicit_values.xml",
ConstructConfig::default(),
&arena,
)
.unwrap();
assert_eq!(1, model.schemas.len());
assert_eq!(1, model.schemas[0].enum_types.len());
assert_eq!(
&EnumType {
name: QualifiedName {
qualifier: "Microsoft.OData.SampleService.Models.TripPin",
uq_name: "PersonGender"
},
members: vec![
EnumTypeMember {
name: "Male".to_owned(),
value: 0
},
EnumTypeMember {
name: "Female".to_owned(),
value: 1
},
EnumTypeMember {
name: "Unknown".to_owned(),
value: 2
},
],
is_flags: false,
underlying_type: EnumUnderlyingType::Int32,
},
model.schemas[0].enum_types[0]
)
}
#[test]
fn inheritance_cycle_detected() {
let timeout = Duration::from_secs(2);
let edmx_filepath: PathBuf = [
"src",
"entity_model",
"test",
"inheritance_reference_cycle.xml",
]
.iter()
.collect();
let edmx_str = fs::read_to_string(edmx_filepath).unwrap();
let t_edmx = serde_xml_rs::from_str(&edmx_str).unwrap();
match timeout_action(
move || {
let arena = Bump::new();
let config = ConstructConfig::default();
let entity_model_result =
construct_entity_model(t_edmx, SERVICE_URL.to_owned(), &arena, config);
if !entity_model_result.is_err() {
println!("Fail: entity model construction should have errored");
panic!();
};
},
timeout,
) {
Ok(_) => {}
Err(RecvTimeoutError::Disconnected) => panic!("Construction failed with panic"),
Err(RecvTimeoutError::Timeout) => panic!(
"Construction did not complete within timeout ({:?})",
timeout
),
}
}
#[test]
fn entity_model_debug_output_terminates() {
let timeout = Duration::from_secs(2);
let edmx_filepath: PathBuf = ["src", "entity_model", "test", "type_reference_cycle.xml"]
.iter()
.collect();
let edmx_str = fs::read_to_string(edmx_filepath).unwrap();
let t_edmx = serde_xml_rs::from_str(&edmx_str).unwrap();
match timeout_action(
move || {
let arena = Bump::new();
let config = ConstructConfig::default();
let entity_model =
construct_entity_model(t_edmx, SERVICE_URL.to_owned(), &arena, config).unwrap();
format!("{:?}", entity_model);
},
timeout,
) {
Ok(_) => {}
Err(RecvTimeoutError::Disconnected) => panic!("Debug output failed with panic"),
Err(RecvTimeoutError::Timeout) => {
panic!("Debug did not complete within timeout ({:?})", timeout)
}
}
}
#[test]
fn key_from_base_type_builds() {
construct_from_xml_file(
"inherit_abstract_type.xml",
ConstructConfig::default(),
&Bump::new(),
)
.unwrap();
}
#[test]
fn namespace_and_alias_references_builds() {
construct_from_xml_file(
"namespace_alias.xml",
ConstructConfig::default(),
&Bump::new(),
)
.unwrap();
}
#[test]
fn invalid_nav_prop_binding_ignored_builds() {
construct_from_xml_file(
"invalid_nav_prop_binding_target.xml",
ConstructConfig {
skip_invalid_nav_prop_bindings: true,
..ConstructConfig::default()
},
&Bump::new(),
)
.unwrap();
}
#[test]
fn entity_type_no_key_not_in_collection_builds() {
construct_from_xml_file(
"entity_type_no_key_not_in_collection.xml",
ConstructConfig::default(),
&Bump::new(),
)
.unwrap();
}
#[test]
fn entity_type_no_key_in_collection_nav_prop_errors() {
let arena = Bump::new();
let result = construct_from_xml_file(
"entity_type_no_key_in_collection_nav_prop.xml",
ConstructConfig::default(),
&arena,
);
assert!(result.is_err(), "Construction should have failed");
}
#[test]
fn entity_type_no_key_in_entity_set_errors() {
let arena = Bump::new();
let result = construct_from_xml_file(
"entity_type_no_key_in_entity_set.xml",
ConstructConfig::default(),
&arena,
);
assert!(result.is_err(), "Construction should have failed");
}
#[test]
fn overloaded_identical_key_builds() {
construct_from_xml_file(
"overloaded_identical_key.xml",
ConstructConfig::default(),
&Bump::new(),
)
.unwrap();
}
#[test]
fn overloaded_differing_key_errors() {
let arena = Bump::new();
let result = construct_from_xml_file(
"overloaded_differing_key.xml",
ConstructConfig::default(),
&arena,
);
assert!(result.is_err(), "Construction should have failed");
}
fn construct_from_xml_file<'ar>(
filename: &str,
config: ConstructConfig,
arena: &'ar Bump,
) -> Result<EntityModel<'ar>, anyhow::Error> {
let edmx_filepath: PathBuf = ["src", "entity_model", "test", filename].iter().collect();
let edmx_str = fs::read_to_string(edmx_filepath).unwrap();
let t_edmx = serde_xml_rs::from_str(&edmx_str).unwrap();
construct_entity_model(t_edmx, SERVICE_URL.to_owned(), &arena, config)
}
fn timeout_action<T: Send + 'static>(
action: impl FnOnce() -> T + Send + 'static,
timeout: Duration,
) -> Result<T, RecvTimeoutError> {
let (sender, receiver) = mpsc::channel();
thread::spawn(move || sender.send(action()));
receiver.recv_timeout(timeout)
}