use crate::engine::schema::{rel_name_variants, type_name_variants};
use crate::Error;
use log::trace;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fs::File;
use std::io::BufReader;
use std::slice::Iter;
const LATEST_CONFIG_VERSION: i32 = 2;
fn get_false() -> bool {
false
}
fn get_true() -> bool {
true
}
fn get_none() -> Option<String> {
None
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Configuration {
version: i32,
#[serde(default)]
pub model: Vec<Type>,
#[serde(default)]
endpoints: Vec<Endpoint>,
}
impl Configuration {
pub fn new(version: i32, model: Vec<Type>, endpoints: Vec<Endpoint>) -> Configuration {
Configuration {
version,
model,
endpoints,
}
}
pub fn endpoints(&self) -> Iter<Endpoint> {
self.endpoints.iter()
}
pub fn types(&self) -> Iter<Type> {
self.model.iter()
}
pub fn validate(&self) -> Result<(), Error> {
trace!("Config::validate called");
let scalar_names = ["Int", "Float", "Boolean", "String", "ID"];
self.model
.iter()
.map(|t| {
if self.model.iter().filter(|t2| t2.name == t.name).count() > 1 {
return Err(Error::ConfigItemDuplicated {
type_name: t.name.to_string(),
});
}
let name_variants = type_name_variants(t);
self.model.iter().try_for_each(|t2| {
if name_variants.contains(t2.name()) {
Err(Error::ConfigItemDuplicated {
type_name: t2.name().to_string(),
})
} else {
Ok(())
}
})?;
if scalar_names.iter().any(|s| s == &t.name) {
return Err(Error::ConfigItemReserved {
type_name: t.name.clone(),
});
}
if t.props.iter().any(|p| p.name().to_uppercase() == "ID") {
return Err(Error::ConfigItemReserved {
type_name: "ID".to_string(),
});
}
if t.props.iter().any(|p| p.name().to_uppercase() == "LABEL") {
return Err(Error::ConfigItemReserved {
type_name: "label".to_string(),
});
}
if t.rels
.iter()
.any(|r| r.props.iter().any(|p| p.name().to_uppercase() == "ID"))
{
return Err(Error::ConfigItemReserved {
type_name: "ID".to_string(),
});
}
if t.rels
.iter()
.any(|r| r.props.iter().any(|p| p.name().to_uppercase() == "LABEL"))
{
return Err(Error::ConfigItemReserved {
type_name: "label".to_string(),
});
}
if t.rels
.iter()
.any(|r| r.props.iter().any(|p| p.name().to_uppercase() == "SRC"))
{
return Err(Error::ConfigItemReserved {
type_name: "src".to_string(),
});
}
if t.rels
.iter()
.any(|r| r.props.iter().any(|p| p.name().to_uppercase() == "DST"))
{
return Err(Error::ConfigItemReserved {
type_name: "dst".to_string(),
});
}
t.rels.iter().try_for_each(|r| {
let rel_name_variants = rel_name_variants(t, r);
self.model.iter().try_for_each(|t2| {
if rel_name_variants.contains(t2.name()) {
Err(Error::ConfigItemDuplicated {
type_name: t2.name().to_string(),
})
} else {
Ok(())
}
})
})?;
Ok(())
})
.collect::<Result<Vec<_>, Error>>()?;
self.endpoints
.iter()
.map(|ep| {
if self.endpoints.iter().filter(|e| e.name == ep.name).count() > 1 {
return Err(Error::ConfigItemDuplicated {
type_name: ep.name.to_string(),
});
}
if let Some(input) = &ep.input {
if let TypeDef::Custom(t) = &input.type_def {
if scalar_names.iter().any(|s| s == &t.name) {
return Err(Error::ConfigItemReserved {
type_name: t.name.to_string(),
});
}
}
}
if let TypeDef::Custom(t) = &ep.output.type_def {
if scalar_names.iter().any(|s| s == &t.name) {
return Err(Error::ConfigItemReserved {
type_name: t.name.to_string(),
});
}
}
Ok(())
})
.collect::<Result<Vec<_>, Error>>()?;
Ok(())
}
pub fn version(&self) -> i32 {
self.version
}
}
impl Default for Configuration {
fn default() -> Configuration {
Configuration {
version: 1,
model: vec![],
endpoints: vec![],
}
}
}
impl TryFrom<File> for Configuration {
type Error = Error;
fn try_from(f: File) -> Result<Configuration, Error> {
let r = BufReader::new(f);
Ok(serde_yaml::from_reader(r)?)
}
}
impl TryFrom<String> for Configuration {
type Error = Error;
fn try_from(s: String) -> Result<Configuration, Error> {
Ok(serde_yaml::from_str(&s)?)
}
}
impl TryFrom<&str> for Configuration {
type Error = Error;
fn try_from(s: &str) -> Result<Configuration, Error> {
Ok(serde_yaml::from_str(s)?)
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Endpoint {
name: String,
class: EndpointClass,
input: Option<EndpointType>,
output: EndpointType,
}
impl Endpoint {
pub fn new(
name: String,
class: EndpointClass,
input: Option<EndpointType>,
output: EndpointType,
) -> Endpoint {
Endpoint {
name,
class,
input,
output,
}
}
pub fn class(&self) -> &EndpointClass {
&self.class
}
pub fn name(&self) -> &str {
&self.name
}
pub fn input(&self) -> Option<&EndpointType> {
self.input.as_ref()
}
pub fn output(&self) -> &EndpointType {
&self.output
}
}
impl TryFrom<&str> for Endpoint {
type Error = Error;
fn try_from(yaml: &str) -> Result<Endpoint, Error> {
serde_yaml::from_str(yaml).map_err(|e| Error::YamlDeserializationFailed { source: e })
}
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum EndpointClass {
Query,
Mutation,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct EndpointsFilter {
#[serde(default = "get_true")]
read: bool,
#[serde(default = "get_true")]
create: bool,
#[serde(default = "get_true")]
update: bool,
#[serde(default = "get_true")]
delete: bool,
}
impl EndpointsFilter {
pub fn new(read: bool, create: bool, update: bool, delete: bool) -> EndpointsFilter {
EndpointsFilter {
read,
create,
update,
delete,
}
}
pub fn all() -> EndpointsFilter {
EndpointsFilter {
read: true,
create: true,
update: true,
delete: true,
}
}
pub fn create(self) -> bool {
self.create
}
pub fn delete(self) -> bool {
self.delete
}
pub fn none() -> EndpointsFilter {
EndpointsFilter {
read: false,
create: false,
update: false,
delete: false,
}
}
pub fn read(self) -> bool {
self.read
}
pub fn update(self) -> bool {
self.update
}
}
impl Default for EndpointsFilter {
fn default() -> EndpointsFilter {
EndpointsFilter {
read: true,
create: true,
update: true,
delete: true,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EndpointType {
#[serde(rename = "type")]
type_def: TypeDef,
#[serde(default = "get_false")]
list: bool,
#[serde(default = "get_false")]
required: bool,
}
impl EndpointType {
pub fn new(type_def: TypeDef, list: bool, required: bool) -> EndpointType {
EndpointType {
type_def,
list,
required,
}
}
pub fn list(&self) -> bool {
self.list
}
pub fn required(&self) -> bool {
self.required
}
pub fn type_def(&self) -> &TypeDef {
&self.type_def
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum GraphqlType {
Int,
Float,
String,
Boolean,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Property {
name: String,
#[serde(default)]
uses: UsesFilter,
#[serde(rename = "type")]
type_name: String,
#[serde(default = "get_true")]
required: bool,
#[serde(default = "get_false")]
list: bool,
#[serde(default = "get_none")]
resolver: Option<String>,
#[serde(default = "get_none")]
validator: Option<String>,
}
impl Property {
pub fn new(
name: String,
uses: UsesFilter,
type_name: String,
required: bool,
list: bool,
resolver: Option<String>,
validator: Option<String>,
) -> Property {
Property {
name,
uses,
type_name,
required,
list,
resolver,
validator,
}
}
pub fn list(&self) -> bool {
self.list
}
pub fn name(&self) -> &str {
&self.name
}
pub fn uses(&self) -> UsesFilter {
self.uses
}
pub fn resolver(&self) -> Option<&String> {
self.resolver.as_ref()
}
pub fn required(&self) -> bool {
self.required
}
pub fn type_name(&self) -> &str {
&self.type_name
}
pub fn validator(&self) -> Option<&String> {
self.validator.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Relationship {
name: String,
#[serde(default = "get_false")]
list: bool,
nodes: Vec<String>,
#[serde(default)]
props: Vec<Property>,
#[serde(default)]
endpoints: EndpointsFilter,
#[serde(default = "get_none")]
resolver: Option<String>,
}
impl Relationship {
pub fn new(
name: String,
list: bool,
nodes: Vec<String>,
props: Vec<Property>,
endpoints: EndpointsFilter,
resolver: Option<String>,
) -> Relationship {
Relationship {
name,
list,
nodes,
props,
endpoints,
resolver,
}
}
pub fn endpoints(&self) -> &EndpointsFilter {
&self.endpoints
}
pub fn list(&self) -> bool {
self.list
}
pub fn name(&self) -> &str {
&self.name
}
pub fn nodes(&self) -> Iter<String> {
self.nodes.iter()
}
pub fn props_as_slice(&self) -> &[Property] {
&self.props
}
pub fn resolver(&self) -> Option<&String> {
self.resolver.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Type {
name: String,
#[serde(default)]
props: Vec<Property>,
#[serde(default)]
rels: Vec<Relationship>,
#[serde(default)]
endpoints: EndpointsFilter,
}
impl Type {
pub fn new(
name: String,
props: Vec<Property>,
rels: Vec<Relationship>,
endpoints: EndpointsFilter,
) -> Type {
Type {
name,
props,
rels,
endpoints,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn endpoints(&self) -> &EndpointsFilter {
&self.endpoints
}
pub fn props(&self) -> Iter<Property> {
self.props.iter()
}
pub fn mut_props(&mut self) -> &mut Vec<Property> {
&mut self.props
}
pub fn props_as_slice(&self) -> &[Property] {
&self.props
}
pub fn rels(&self) -> Iter<Relationship> {
self.rels.iter()
}
}
impl TryFrom<&str> for Type {
type Error = Error;
fn try_from(yaml: &str) -> Result<Type, Error> {
serde_yaml::from_str(yaml).map_err(|e| Error::YamlDeserializationFailed { source: e })
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(untagged)]
pub enum TypeDef {
Scalar(GraphqlType),
Existing(String),
Custom(Type),
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct UsesFilter {
#[serde(default = "get_true")]
create: bool,
#[serde(default = "get_true")]
query: bool,
#[serde(default = "get_true")]
update: bool,
#[serde(default = "get_true")]
output: bool,
}
impl UsesFilter {
pub fn new(create: bool, query: bool, update: bool, output: bool) -> UsesFilter {
UsesFilter {
create,
query,
update,
output,
}
}
pub fn all() -> UsesFilter {
UsesFilter {
create: true,
query: true,
update: true,
output: true,
}
}
pub fn create(self) -> bool {
self.create
}
pub fn query(self) -> bool {
self.query
}
pub fn none() -> UsesFilter {
UsesFilter {
create: false,
query: false,
update: false,
output: false,
}
}
pub fn output(self) -> bool {
self.output
}
pub fn update(self) -> bool {
self.update
}
}
impl Default for UsesFilter {
fn default() -> UsesFilter {
UsesFilter {
create: true,
query: true,
update: true,
output: true,
}
}
}
pub fn compose(configs: Vec<Configuration>) -> Result<Configuration, Error> {
let mut version: Option<i32> = None;
let mut model: Vec<Type> = Vec::new();
let mut endpoints: Vec<Endpoint> = Vec::new();
configs
.into_iter()
.map(|mut c| {
match version {
None => version = Some(c.version()),
Some(v) => {
if v != c.version {
return Err(Error::ConfigVersionMismatched {
expected: v,
found: c.version,
});
}
}
}
model.append(&mut c.model);
endpoints.append(&mut c.endpoints);
Ok(())
})
.collect::<Result<Vec<_>, Error>>()?;
Ok(Configuration::new(
version.unwrap_or(LATEST_CONFIG_VERSION),
model,
endpoints,
))
}
#[cfg(test)]
pub(crate) fn mock_project_config() -> Configuration {
Configuration::new(1, vec![mock_project_type()], vec![])
}
#[cfg(test)]
pub(crate) fn mock_project_type() -> Type {
Type::new(
"Project".to_string(),
vec![
Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
),
Property::new(
"tags".to_string(),
UsesFilter::all(),
"String".to_string(),
false,
true,
None,
None,
),
Property::new(
"public".to_string(),
UsesFilter::all(),
"Boolean".to_string(),
true,
false,
None,
None,
),
],
vec![
Relationship::new(
"owner".to_string(),
false,
vec!["User".to_string()],
vec![Property::new(
"since".to_string(),
UsesFilter::all(),
"String".to_string(),
false,
false,
None,
None,
)],
EndpointsFilter::all(),
None,
),
Relationship::new(
"board".to_string(),
false,
vec!["ScrumBoard".to_string(), "KanbanBoard".to_string()],
vec![],
EndpointsFilter::all(),
None,
),
Relationship::new(
"commits".to_string(),
true,
vec!["Commit".to_string()],
vec![],
EndpointsFilter::all(),
None,
),
Relationship::new(
"issues".to_string(),
true,
vec!["Feature".to_string(), "Bug".to_string()],
vec![],
EndpointsFilter::all(),
None,
),
],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_user_type() -> Type {
Type::new(
"User".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_kanbanboard_type() -> Type {
Type::new(
"KanbanBoard".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_scrumboard_type() -> Type {
Type::new(
"ScrumBoard".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_feature_type() -> Type {
Type::new(
"Feature".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_bug_type() -> Type {
Type::new(
"Bug".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
fn mock_commit_type() -> Type {
Type::new(
"Commit".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)
}
#[cfg(test)]
pub(crate) fn mock_endpoint_one() -> Endpoint {
Endpoint::new(
"RegisterUsers".to_string(),
EndpointClass::Mutation,
Some(EndpointType::new(
TypeDef::Existing("UserCreateMutationInput".to_string()),
true,
true,
)),
EndpointType::new(TypeDef::Existing("User".to_string()), true, true),
)
}
#[cfg(test)]
pub(crate) fn mock_endpoint_two() -> Endpoint {
Endpoint::new(
"DisableUser".to_string(),
EndpointClass::Mutation,
Some(EndpointType::new(
TypeDef::Existing("UserQueryInput".to_string()),
false,
true,
)),
EndpointType::new(TypeDef::Existing("User".to_string()), false, true),
)
}
#[cfg(test)]
pub(crate) fn mock_endpoint_three() -> Endpoint {
Endpoint::new(
"ComputeBurndown".to_string(),
EndpointClass::Query,
Some(EndpointType::new(
TypeDef::Custom(Type::new(
"BurndownFilter".to_string(),
vec![Property::new(
"ticket_types".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)),
false,
false,
)),
EndpointType::new(
TypeDef::Custom(Type::new(
"BurndownMetrics".to_string(),
vec![Property::new(
"points".to_string(),
UsesFilter::all(),
"Int".to_string(),
false,
false,
None,
None,
)],
vec![],
EndpointsFilter::all(),
)),
false,
true,
),
)
}
#[cfg(test)]
pub(crate) fn mock_config() -> Configuration {
Configuration::new(
1,
vec![
mock_project_type(),
mock_user_type(),
mock_kanbanboard_type(),
mock_scrumboard_type(),
mock_feature_type(),
mock_bug_type(),
mock_commit_type(),
],
vec![
mock_endpoint_one(),
mock_endpoint_two(),
mock_endpoint_three(),
],
)
}
#[cfg(test)]
pub(crate) fn mock_endpoints_filter() -> Configuration {
Configuration::new(
1,
vec![Type::new(
"User".to_string(),
vec![Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
)],
vec![],
EndpointsFilter::new(false, true, false, false),
)],
Vec::new(),
)
}
#[cfg(test)]
mod tests {
use super::{
compose, Configuration, Endpoint, EndpointType, EndpointsFilter, Property, Relationship,
Type, UsesFilter,
};
use crate::Error;
use std::convert::TryInto;
use std::fs::File;
#[test]
fn warpgrapher_book_config() {
let config = Configuration::new(
1,
vec![
Type::new(
"User".to_string(),
vec![
Property::new(
"username".to_string(),
UsesFilter::all(),
"String".to_string(),
false,
false,
None,
None,
),
Property::new(
"email".to_string(),
UsesFilter::all(),
"String".to_string(),
false,
false,
None,
None,
),
],
Vec::new(),
EndpointsFilter::all(),
),
Type::new(
"Team".to_string(),
vec![Property::new(
"teamname".to_string(),
UsesFilter::all(),
"String".to_string(),
false,
false,
None,
None,
)],
vec![Relationship::new(
"members".to_string(),
true,
vec!["User".to_string()],
Vec::new(),
EndpointsFilter::default(),
None,
)],
EndpointsFilter::all(),
),
],
vec![],
);
assert!(!config.model.is_empty());
}
#[test]
fn new_warpgrapher_config() {
let c = Configuration::new(1, Vec::new(), Vec::new());
assert!(c.version == 1);
assert!(c.model.is_empty());
}
#[test]
fn new_property() {
let p = Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
);
assert!(p.name == "name");
assert!(p.type_name == "String");
}
#[test]
fn new_node_type() {
let t = Type::new(
"User".to_string(),
vec![
Property::new(
"name".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
),
Property::new(
"role".to_string(),
UsesFilter::all(),
"String".to_string(),
true,
false,
None,
None,
),
],
vec![],
EndpointsFilter::all(),
);
assert!(t.name == "User");
assert!(t.props.get(0).unwrap().name == "name");
assert!(t.props.get(1).unwrap().name == "role");
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn test_validate() {
let valid_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_ok.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
assert!(valid_config.validate().is_ok());
let mut config_vec: Vec<Configuration> = Vec::new();
let valid_config_0: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_0.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
let valid_config_1: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_1.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
let valid_config_2: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_2.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
config_vec.push(valid_config_0);
config_vec.push(valid_config_1);
config_vec.push(valid_config_2);
let composed_config: Configuration = match compose(config_vec) {
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
assert!(composed_config.validate().is_ok());
let duplicate_type_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_duplicate_type.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match duplicate_type_config.validate() {
Err(Error::ConfigItemDuplicated { type_name: _ }) => (),
_ => panic!(),
}
let duplicate_endpoint_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_duplicate_endpoint.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match duplicate_endpoint_config.validate() {
Err(Error::ConfigItemDuplicated { type_name: _ }) => (),
_ => panic!(),
}
let duplicate_derived_name_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_duplicate_derived_name.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match duplicate_derived_name_config.validate() {
Err(Error::ConfigItemDuplicated { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_prop_name_id_test() {
let node_prop_name_id_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_node_prop_name_id.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match node_prop_name_id_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let rel_prop_name_id_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_rel_prop_name_id.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match rel_prop_name_id_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_prop_name_src_test() {
let rel_prop_name_src_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_rel_prop_name_src.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match rel_prop_name_src_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_prop_name_dst_test() {
let rel_prop_name_dst_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_rel_prop_name_dst.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match rel_prop_name_dst_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_scalar_name_int_test() {
let scalar_type_name_int_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_type_name_int.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_type_name_int_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_input_type_name_int_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_input_type_name_int.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_input_type_name_int_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_output_type_name_int_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_output_type_name_int.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_output_type_name_int_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_scalar_name_float_test() {
let scalar_type_name_float_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_type_name_float.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_type_name_float_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_input_type_name_float_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_input_type_name_float.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_input_type_name_float_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_output_type_name_float_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_output_type_name_float.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_output_type_name_float_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_scalar_name_string_test() {
let scalar_type_name_string_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_type_name_string.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_type_name_string_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_input_type_name_string_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_input_type_name_string.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_input_type_name_string_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_output_type_name_string_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_output_type_name_string.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_output_type_name_string_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_scalar_name_id_test() {
let scalar_type_name_id_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_type_name_id.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_type_name_id_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_input_type_name_id_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_input_type_name_id.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_input_type_name_id_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_output_type_name_id_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_output_type_name_id.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_output_type_name_id_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn config_scalar_name_boolean_test() {
let scalar_type_name_boolean_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_type_name_boolean.yml",
)
.expect("Coudln't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_type_name_boolean_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_input_type_name_boolean_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_input_type_name_boolean.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_input_type_name_boolean_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
let scalar_endpoint_output_type_name_boolean_config: Configuration = match File::open(
"tests/fixtures/config-validation/test_config_scalar_endpoint_output_type_name_boolean.yml",
)
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
match scalar_endpoint_output_type_name_boolean_config.validate() {
Err(Error::ConfigItemReserved { type_name: _ }) => (),
_ => panic!(),
}
}
#[allow(clippy::match_wild_err_arm)]
#[test]
fn test_compose() {
assert!(TryInto::<Configuration>::try_into(
File::open("tests/fixtures/config-validation/test_config_err.yml")
.expect("Couldn't open file")
)
.is_err());
assert!(TryInto::<Configuration>::try_into(
File::open("tests/fixtures/config-validation/test_config_ok.yml")
.expect("Couldn't open file")
)
.is_ok());
let mut config_vec: Vec<Configuration> = Vec::new();
assert!(compose(config_vec.clone()).is_ok());
let valid_config_0: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_0.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
let valid_config_1: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_1.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
let valid_config_2: Configuration =
match File::open("tests/fixtures/config-validation/test_config_compose_2.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
let mismatch_version_config: Configuration =
match File::open("tests/fixtures/config-validation/test_config_with_version_100.yml")
.expect("Couldn't open file")
.try_into()
{
Err(e) => panic!("{}", e),
Ok(wgc) => wgc,
};
config_vec.push(valid_config_0);
config_vec.push(valid_config_1);
config_vec.push(valid_config_2);
assert!(compose(config_vec.clone()).is_ok());
config_vec.push(mismatch_version_config);
assert!(compose(config_vec).is_err());
}
#[test]
fn test_config_send() {
fn assert_send<T: Send>() {}
assert_send::<Configuration>();
}
#[test]
fn test_config_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Configuration>();
}
#[test]
fn test_endpoint_send() {
fn assert_send<T: Send>() {}
assert_send::<Endpoint>();
}
#[test]
fn test_endpoint_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Endpoint>();
}
#[test]
fn test_endpoints_filter_send() {
fn assert_send<T: Send>() {}
assert_send::<EndpointsFilter>();
}
#[test]
fn test_endpoints_filter_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<EndpointsFilter>();
}
#[test]
fn test_endpoints_type_send() {
fn assert_send<T: Send>() {}
assert_send::<EndpointType>();
}
#[test]
fn test_endpoints_type_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<EndpointType>();
}
#[test]
fn test_property_send() {
fn assert_send<T: Send>() {}
assert_send::<Property>();
}
#[test]
fn test_property_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Property>();
}
#[test]
fn test_relationship_send() {
fn assert_send<T: Send>() {}
assert_send::<Relationship>();
}
#[test]
fn test_relationship_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Relationship>();
}
#[test]
fn test_type_send() {
fn assert_send<T: Send>() {}
assert_send::<Type>();
}
#[test]
fn test_type_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Type>();
}
}