#![cfg(all(feature = "macros", feature = "json"))]
use kynos::{
Error, Router,
extract::params::path::Path,
openapi::{Method as OpenApiMethod, PathTemplate, SpecError, Violation},
response::status::NoContent,
router::{endpoint::builder::EndpointBuilder, group::Group},
};
#[derive(kynos::Schema, kynos::PathParams)]
struct FilePath {
path: String,
}
#[derive(kynos::Schema, kynos::PathParams)]
struct ReportPath {
year: u32,
month: u32,
}
async fn a_file(Path(_): Path<FilePath>) -> NoContent {
NoContent
}
async fn a_report(Path(_): Path<ReportPath>) -> NoContent {
NoContent
}
macro_rules! mounting {
($template:expr, $handler:expr) => {
Router::<()>::new()
.mount(EndpointBuilder::<(), _, _>::new(
OpenApiMethod::Get,
PathTemplate::parse($template).expect("a parsable path template"),
$handler,
))
.build(())
.map(|_| ())
};
}
fn opaque_route(result: Result<(), Error>) -> Option<String> {
match result {
Err(Error::Invalid { violations }) => sole_opaque_route(&violations),
_ => None,
}
}
fn sole_opaque_route(violations: &[Violation]) -> Option<String> {
match violations {
[violation] => match &violation.error {
SpecError::OpaqueRoute { pattern } => Some(pattern.clone()),
_ => None,
},
_ => None,
}
}
#[test]
fn a_catch_all_route_is_refused() {
assert_eq!(
opaque_route(mounting!("/files/{*path}", a_file)).as_deref(),
Some("/files/{*path}")
);
}
#[test]
fn a_single_segment_variable_is_accepted() {
assert!(mounting!("/files/{path}", a_file).is_ok());
}
#[test]
fn two_variables_in_one_segment_are_refused() {
assert_eq!(
opaque_route(mounting!("/reports/{year}{month}", a_report)).as_deref(),
Some("/reports/{year}{month}")
);
}
#[test]
fn two_variables_in_two_segments_are_accepted() {
assert!(mounting!("/reports/{year}/{month}", a_report).is_ok());
}
#[test]
fn a_catch_all_reached_through_a_prefix_is_still_refused() {
let refused = Router::<()>::new()
.group(
Group::<()>::new("/v1").mount(EndpointBuilder::<(), _, _>::new(
OpenApiMethod::Get,
PathTemplate::parse("/files/{*path}").expect("a parsable path template"),
a_file,
)),
)
.build(())
.map(|_| ());
assert_eq!(opaque_route(refused).as_deref(), Some("/v1/files/{*path}"));
}
#[test]
fn every_entry_point_reports_an_unroutable_path() {
let router = || {
Router::<()>::new().mount(EndpointBuilder::<(), _, _>::new(
OpenApiMethod::Get,
PathTemplate::parse("/files/{*path}").expect("a parsable path template"),
a_file,
))
};
let reported = router().validate().expect("a validatable router");
assert_eq!(
sole_opaque_route(&reported).as_deref(),
Some("/files/{*path}")
);
assert!(router().openapi().is_err());
assert!(router().build(()).is_err());
}