yaml_test_runner/src/step/match.rs (150 lines of code) (raw):
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use super::Step;
use crate::{
regex::clean_regex,
step::{json_string_from_yaml, Expr},
};
use anyhow::anyhow;
use quote::{ToTokens, Tokens};
use yaml_rust::Yaml;
pub struct Match {
pub expr: Expr,
value: Yaml,
}
impl From<Match> for Step {
fn from(m: Match) -> Self {
Step::Match(m)
}
}
impl Match {
pub fn try_parse(yaml: &Yaml) -> anyhow::Result<Match> {
let hash = yaml
.as_hash()
.ok_or_else(|| anyhow!("expected hash but found {:?}", yaml))?;
let (k, v) = hash.iter().next().unwrap();
let expr = k.as_str().unwrap().trim();
Ok(Match {
expr: expr.into(),
value: v.clone(),
})
}
}
impl ToTokens for Match {
fn to_tokens(&self, tokens: &mut Tokens) {
let expr = self.expr.expression();
match &self.value {
Yaml::String(s) => {
if s.starts_with('/') {
let s = clean_regex(s);
if self.expr.is_body() {
tokens.append(quote! {
assert_regex_match!(&text, #s, true);
});
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_regex_match!(json#ident.as_str().unwrap(), #s, true);
});
}
} else {
let ident = syn::Ident::from(expr.as_str());
// handle set values
if s.starts_with('$') {
let t = {
let s = s
.trim_start_matches('$')
.trim_start_matches('{')
.trim_end_matches('}');
syn::Ident::from(s)
};
tokens.append(quote! {
assert_match!(json#ident, json!(#t));
});
} else {
tokens.append(quote! {
assert_match!(json#ident, json!(#s));
})
};
}
}
Yaml::Integer(i) => {
if self.expr.is_body() {
panic!("match on $body with i64");
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_numeric_match!(json#ident, #i);
});
}
}
Yaml::Real(r) => {
let f = r.parse::<f64>().unwrap();
if self.expr.is_body() {
panic!("match on $body with f64");
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_match!(json#ident, json!(#f));
});
}
}
Yaml::Null => {
if self.expr.is_body() {
tokens.append(quote! {
assert!(text.is_empty(), "expected response to be null (empty) but was {}", &text);
});
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_null!(json#ident);
});
}
}
Yaml::Boolean(b) => {
if self.expr.is_body() {
panic!("match on $body with bool");
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_match!(json#ident, json!(#b));
});
}
}
yaml if yaml.is_array() || yaml.as_hash().is_some() => {
let json = {
let s = json_string_from_yaml(yaml);
syn::Ident::from(s)
};
if self.expr.is_body() {
tokens.append(quote! {
assert_match!(json, json!(#json));
});
} else {
let ident = syn::Ident::from(expr.as_str());
tokens.append(quote! {
assert_match!(json#ident, json!(#json));
});
}
}
yaml => {
panic!("Bad yaml value {:?}", &yaml);
}
}
}
}