1#![deny(warnings)]
15#![deny(clippy::pedantic, clippy::unwrap_used)]
16#![deny(missing_docs)]
17pub use axum_accept_macros::AcceptExtractor;
18pub use axum_accept_shared::AcceptRejection;
19
20#[cfg(doctest)]
21#[doc = include_str!("../../README.md")]
22pub struct ReadmeDoctests;
23
24#[cfg(test)]
25mod tests {
26 use super::*;
27 use axum::{
28 body::Body,
29 extract::{FromRequest, Request},
30 };
31
32 #[derive(Debug, AcceptExtractor)]
33 enum Accept {
34 #[accept(mediatype = "text/*")]
35 Text,
36 #[accept(mediatype = "text/plain")]
37 TextPlain,
38 #[accept(mediatype = "application/json")]
39 ApplicationJson,
40 #[accept(mediatype = "application/ld+json")]
41 ApplicationLdJson,
42 }
43
44 #[tokio::test]
45 async fn test_accept_extractor_basic() -> Result<(), Box<dyn std::error::Error>> {
46 let req = Request::builder()
47 .header("accept", "application/json,text/plain")
48 .body(Body::from(""))?;
49 let state = ();
50 let media_type = Accept::from_request(req, &state)
51 .await
52 .expect("Expected no rejection");
53 let Accept::ApplicationJson = media_type else {
54 panic!("expected application/json")
55 };
56 Ok(())
57 }
58
59 #[tokio::test]
60 async fn test_accept_extractor_q() -> Result<(), Box<dyn std::error::Error>> {
61 let req = Request::builder()
62 .header("accept", "application/json;q=0.9,text/plain")
63 .body(Body::from(""))?;
64 let state = ();
65 let media_type = Accept::from_request(req, &state)
66 .await
67 .expect("Expected no rejection");
68 let Accept::TextPlain = media_type else {
69 panic!("expected text/plain")
70 };
71 Ok(())
72 }
73
74 #[tokio::test]
75 async fn test_accept_extractor_specifity() -> Result<(), Box<dyn std::error::Error>> {
76 let req = Request::builder()
77 .header("accept", "text/*,text/plain")
78 .body(Body::from(""))?;
79 let state = ();
80 let media_type = Accept::from_request(req, &state)
81 .await
82 .expect("Expected no rejection");
83 let Accept::TextPlain = media_type else {
84 panic!("expected text/plain")
85 };
86 Ok(())
87 }
88
89 #[tokio::test]
90 async fn test_accept_extractor_suffix() -> Result<(), Box<dyn std::error::Error>> {
91 let req = Request::builder()
92 .header("accept", "text/*,application/ld+json,text/plain")
93 .body(Body::from(""))?;
94 let state = ();
95 let media_type = Accept::from_request(req, &state)
96 .await
97 .expect("Expected no rejection");
98 let Accept::ApplicationLdJson = media_type else {
99 panic!("expected application/ldjson")
100 };
101 Ok(())
102 }
103
104 #[tokio::test]
105 async fn test_accept_extractor_no_match() -> Result<(), Box<dyn std::error::Error>> {
106 let req = Request::builder()
107 .header("accept", "text/csv")
108 .body(Body::from(""))?;
109 let state = ();
110 let media_type = Accept::from_request(req, &state).await;
111 let Err(AcceptRejection::NoSupportedMediaTypeFound) = media_type else {
112 panic!("expected no supported media type found")
113 };
114 Ok(())
115 }
116}