api: Replace ruma_api! compile-time path check with a test
This commit is contained in:
parent
9195a5de18
commit
2451f33a64
@ -124,6 +124,13 @@ impl Metadata {
|
|||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for generated `#[test]`s
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _path_parameters(&self) -> Vec<&'static str> {
|
||||||
|
let path = self.history.all_paths().next().unwrap();
|
||||||
|
path.split('/').filter_map(|segment| segment.strip_prefix(':')).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The complete history of this endpoint as far as Ruma knows, together with all variants on
|
/// The complete history of this endpoint as far as Ruma knows, together with all variants on
|
||||||
|
@ -12,12 +12,7 @@ use syn::{
|
|||||||
Attribute, Field, Token, Type,
|
Attribute, Field, Token, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{api_metadata::Metadata, api_request::Request, api_response::Response};
|
||||||
api_metadata::Metadata,
|
|
||||||
api_request::Request,
|
|
||||||
api_response::Response,
|
|
||||||
request::{RequestField, RequestFieldKind},
|
|
||||||
};
|
|
||||||
use crate::util::import_ruma_common;
|
use crate::util::import_ruma_common;
|
||||||
|
|
||||||
mod api_metadata;
|
mod api_metadata;
|
||||||
@ -56,7 +51,6 @@ pub struct Api {
|
|||||||
impl Api {
|
impl Api {
|
||||||
pub fn expand_all(self) -> TokenStream {
|
pub fn expand_all(self) -> TokenStream {
|
||||||
let maybe_feature_error = ensure_feature_presence().map(syn::Error::to_compile_error);
|
let maybe_feature_error = ensure_feature_presence().map(syn::Error::to_compile_error);
|
||||||
let maybe_path_error = self.check_paths().err().map(syn::Error::into_compile_error);
|
|
||||||
|
|
||||||
let ruma_common = import_ruma_common();
|
let ruma_common = import_ruma_common();
|
||||||
|
|
||||||
@ -80,7 +74,6 @@ impl Api {
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#maybe_feature_error
|
#maybe_feature_error
|
||||||
#maybe_path_error
|
|
||||||
|
|
||||||
// For some reason inlining the expression causes issues with macro parsing
|
// For some reason inlining the expression causes issues with macro parsing
|
||||||
const _RUMA_API_VERSION_HISTORY: #ruma_common::api::VersionHistory = #history;
|
const _RUMA_API_VERSION_HISTORY: #ruma_common::api::VersionHistory = #history;
|
||||||
@ -102,39 +95,6 @@ impl Api {
|
|||||||
type _SilenceUnusedError = #error_ty;
|
type _SilenceUnusedError = #error_ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_paths(&self) -> syn::Result<()> {
|
|
||||||
let mut path_iter = self.metadata.history.entries.iter().filter_map(|entry| entry.path());
|
|
||||||
|
|
||||||
let path = path_iter.next().ok_or_else(|| {
|
|
||||||
syn::Error::new(Span::call_site(), "at least one path metadata field must be set")
|
|
||||||
})?;
|
|
||||||
let path_args = path.args();
|
|
||||||
|
|
||||||
if let Some(req) = &self.request {
|
|
||||||
let path_field_names: Vec<_> = req
|
|
||||||
.fields
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.filter_map(|f| match RequestField::try_from(f) {
|
|
||||||
Ok(RequestField { kind: RequestFieldKind::Path, inner }) => {
|
|
||||||
Some(Ok(inner.ident.unwrap().to_string()))
|
|
||||||
}
|
|
||||||
Ok(_) => None,
|
|
||||||
Err(e) => Some(Err(e)),
|
|
||||||
})
|
|
||||||
.collect::<syn::Result<_>>()?;
|
|
||||||
|
|
||||||
if path_args != path_field_names {
|
|
||||||
return Err(syn::Error::new_spanned(
|
|
||||||
req.request_kw,
|
|
||||||
"path fields must be in the same order as they appear in the path segments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Api {
|
impl Parse for Api {
|
||||||
|
@ -389,17 +389,6 @@ pub enum HistoryEntry {
|
|||||||
Removed { version: MatrixVersionLiteral },
|
Removed { version: MatrixVersionLiteral },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HistoryEntry {
|
|
||||||
pub(super) fn path(&self) -> Option<&EndpointPath> {
|
|
||||||
Some(match self {
|
|
||||||
HistoryEntry::Stable { version: _, path } => path,
|
|
||||||
HistoryEntry::Unstable { path } => path,
|
|
||||||
|
|
||||||
_ => return None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct EndpointPath(LitStr);
|
pub struct EndpointPath(LitStr);
|
||||||
|
|
||||||
@ -407,10 +396,6 @@ impl EndpointPath {
|
|||||||
pub fn value(&self) -> String {
|
pub fn value(&self) -> String {
|
||||||
self.0.value()
|
self.0.value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(&self) -> Vec<String> {
|
|
||||||
self.value().split('/').filter_map(|s| s.strip_prefix(':')).map(String::from).collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for EndpointPath {
|
impl Parse for EndpointPath {
|
||||||
|
@ -238,7 +238,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn check(&self, ruma_common: &TokenStream) -> syn::Result<Option<TokenStream>> {
|
pub(super) fn check(&self, ruma_common: &TokenStream) -> syn::Result<TokenStream> {
|
||||||
let http = quote! { #ruma_common::exports::http };
|
let http = quote! { #ruma_common::exports::http };
|
||||||
|
|
||||||
// TODO: highlight problematic fields
|
// TODO: highlight problematic fields
|
||||||
@ -297,8 +297,21 @@ impl Request {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((has_body_fields || has_newtype_body_field).then(|| {
|
let path_fields = self.path_fields().map(|f| f.ident.as_ref().unwrap().to_string());
|
||||||
quote! {
|
let mut tests = quote! {
|
||||||
|
#[::std::prelude::v1::test]
|
||||||
|
fn path_parameters() {
|
||||||
|
let path_params = METADATA._path_parameters();
|
||||||
|
let request_path_fields: &[&::std::primitive::str] = &[#(#path_fields),*];
|
||||||
|
::std::assert_eq!(
|
||||||
|
path_params, request_path_fields,
|
||||||
|
"Path parameters must match the `Request`'s `#[ruma_api(path)]` fields"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if has_body_fields || has_newtype_body_field {
|
||||||
|
tests.extend(quote! {
|
||||||
#[::std::prelude::v1::test]
|
#[::std::prelude::v1::test]
|
||||||
fn request_is_not_get() {
|
fn request_is_not_get() {
|
||||||
::std::assert_ne!(
|
::std::assert_ne!(
|
||||||
@ -306,8 +319,10 @@ impl Request {
|
|||||||
"GET endpoints can't have body fields",
|
"GET endpoints can't have body fields",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
Ok(tests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user