Vastly improve testing
- simplify some examples - add macrotest for expanding/snapshotting macro expansion & add tests - add workaround to enable referencing relative dirs from macrotest files - ensure workaround doesn't get built in release - add trybuild for testing error messages & add tests - fix indeterministic macro output - sort routes after collecting - use BTreeMap instead of HashMap to preserve insertion order - fix compile_error syntax error
This commit is contained in:
parent
f0ce2b2737
commit
daf793eb06
20 changed files with 357 additions and 25 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.direnv/
|
.direnv/
|
||||||
target/
|
target/
|
||||||
|
wip/
|
||||||
|
|
91
Cargo.lock
generated
91
Cargo.lock
generated
|
@ -17,6 +17,15 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
|
@ -93,8 +102,10 @@ dependencies = [
|
||||||
"macrotest",
|
"macrotest",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
"regex",
|
||||||
"syn",
|
"syn",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"trybuild",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -481,6 +492,35 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
|
@ -610,6 +650,21 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "target-triple"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.44.2"
|
version = "1.44.2"
|
||||||
|
@ -639,6 +694,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
@ -709,6 +776,21 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trybuild"
|
||||||
|
version = "1.0.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ae08be68c056db96f0e6c6dd820727cca756ced9e1f4cc7fdd20e2a55e23898"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"target-triple",
|
||||||
|
"termcolor",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -721,6 +803,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
|
@ -21,11 +21,14 @@ quote = "1.0"
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
macrotest = "1.1.0"
|
macrotest = "1.1.0"
|
||||||
|
regex = "1.11.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.98"
|
anyhow = "1.0.98"
|
||||||
axum = "0.8.3"
|
axum = "0.8.3"
|
||||||
tokio = { version = "1.44.2", features = ["full"] }
|
tokio = { version = "1.44.2", features = ["full"] }
|
||||||
|
trybuild = "1.0.104"
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
pedantic = "warn"
|
pedantic = { level = "warn", priority = -1 }
|
||||||
|
unused-async = { level = "allow", priority = 0 } # required for examples without unecessary noise
|
||||||
|
|
|
@ -5,4 +5,3 @@ async fn main() -> anyhow::Result<()> {
|
||||||
server::server().await?;
|
server::server().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ struct AppState {
|
||||||
_foo: String,
|
_foo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imports route.rs files & generates an init fn
|
// Imports route.rs files & generates an ::into_router() fn
|
||||||
#[folder_router("examples/advanced/api", AppState)]
|
#[folder_router("examples/advanced/api", AppState)]
|
||||||
struct MyFolderRouter();
|
struct MyFolderRouter();
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use axum_folder_router::folder_router;
|
use axum_folder_router::folder_router;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
struct AppState {
|
struct AppState;
|
||||||
_foo: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Imports route.rs files & generates an init fn
|
// Imports route.rs files & generates an ::into_router() fn
|
||||||
#[folder_router("./examples/simple/api", AppState)]
|
#[folder_router("./examples/simple/api", AppState)]
|
||||||
struct MyFolderRouter();
|
struct MyFolderRouter();
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
// Create app state
|
// Create app state
|
||||||
let app_state = AppState {
|
let app_state = AppState;
|
||||||
_foo: String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use the init fn generated above
|
// Use the init fn generated above
|
||||||
let folder_router: Router<AppState> = MyFolderRouter::into_router();
|
let folder_router: Router<AppState> = MyFolderRouter::into_router();
|
||||||
|
|
42
src/lib.rs
42
src/lib.rs
|
@ -123,7 +123,7 @@
|
||||||
//! - **Expects seperate directory**: To make rust-analyzer & co work correctly the macro imports all route.rs files inside the given directory tree.
|
//! - **Expects seperate directory**: To make rust-analyzer & co work correctly the macro imports all route.rs files inside the given directory tree.
|
||||||
//! It is highly recommended to keep the route directory seperate from the rest of your module-tree.
|
//! It is highly recommended to keep the route directory seperate from the rest of your module-tree.
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::BTreeMap,
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -131,6 +131,7 @@ use std::{
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
use regex::Regex;
|
||||||
use syn::{
|
use syn::{
|
||||||
Ident,
|
Ident,
|
||||||
Item,
|
Item,
|
||||||
|
@ -143,6 +144,7 @@ use syn::{
|
||||||
parse_macro_input,
|
parse_macro_input,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct FolderRouterArgs {
|
struct FolderRouterArgs {
|
||||||
path: String,
|
path: String,
|
||||||
state_type: Ident,
|
state_type: Ident,
|
||||||
|
@ -166,7 +168,7 @@ impl Parse for FolderRouterArgs {
|
||||||
struct ModuleDir {
|
struct ModuleDir {
|
||||||
name: String,
|
name: String,
|
||||||
has_route: bool,
|
has_route: bool,
|
||||||
children: HashMap<String, ModuleDir>,
|
children: BTreeMap<String, ModuleDir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleDir {
|
impl ModuleDir {
|
||||||
|
@ -174,7 +176,7 @@ impl ModuleDir {
|
||||||
ModuleDir {
|
ModuleDir {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
has_route: false,
|
has_route: false,
|
||||||
children: HashMap::new(),
|
children: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +194,7 @@ impl ModuleDir {
|
||||||
/// This will scan all `route.rs` files in the `./src/api` directory and its
|
/// This will scan all `route.rs` files in the `./src/api` directory and its
|
||||||
/// subdirectories, automatically mapping their path structure to URL routes
|
/// subdirectories, automatically mapping their path structure to URL routes
|
||||||
/// with the specified state type.
|
/// with the specified state type.
|
||||||
|
#[allow(clippy::missing_panics_doc)]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn folder_router(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn folder_router(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = parse_macro_input!(attr as FolderRouterArgs);
|
let args = parse_macro_input!(attr as FolderRouterArgs);
|
||||||
|
@ -201,19 +204,42 @@ pub fn folder_router(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let base_path = args.path;
|
let base_path = args.path;
|
||||||
let state_type = args.state_type;
|
let state_type = args.state_type;
|
||||||
|
|
||||||
|
let manifest_dir = {
|
||||||
// Get the project root directory
|
// Get the project root directory
|
||||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or("./".to_string());
|
let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or("./".to_string());
|
||||||
|
|
||||||
|
// Create regex to match macrotest pattern with exactly 42 alphanumeric chars
|
||||||
|
// This is the only way to enable us to reference the example route folders in
|
||||||
|
// our macrotest::expand tests
|
||||||
|
let re = Regex::new(r"^(.+)/target/tests/axum-folder-router/[A-Za-z0-9]{42}$").unwrap();
|
||||||
|
|
||||||
|
// If the pattern matches, extract the real project root
|
||||||
|
// Being extra caucious to warn any users about this unexpected Workaround
|
||||||
|
if let Some(captures) = re.captures(&dir) {
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
return TokenStream::from(quote! {
|
||||||
|
compile_error!("axum-folder-router: MACROTEST_WORKAROUND compiled in non-debug env, something is likely wrong!");
|
||||||
|
});
|
||||||
|
captures.get(1).unwrap().as_str().to_string()
|
||||||
|
} else {
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let base_dir = Path::new(&manifest_dir).join(&base_path);
|
let base_dir = Path::new(&manifest_dir).join(&base_path);
|
||||||
|
|
||||||
// Collect route files
|
// Collect route files
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
collect_route_files(&base_dir, &base_dir, &mut routes);
|
collect_route_files(&base_dir, &base_dir, &mut routes);
|
||||||
|
|
||||||
|
// ensures deterministic macro output
|
||||||
|
routes.sort();
|
||||||
|
|
||||||
if routes.is_empty() {
|
if routes.is_empty() {
|
||||||
return TokenStream::from(quote! {
|
return TokenStream::from(quote! {
|
||||||
compile_error!(concat!("No route.rs files found in the specified directory: ",
|
compile_error!(concat!("No route.rs files found in the specified directory: '",
|
||||||
#base_path,
|
#base_path,
|
||||||
". Make sure the path is correct and contains route.rs files."
|
"'. Make sure the path is correct and contains route.rs files."
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -258,8 +284,8 @@ pub fn folder_router(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
if method_registrations.is_empty() {
|
if method_registrations.is_empty() {
|
||||||
return TokenStream::from(quote! {
|
return TokenStream::from(quote! {
|
||||||
compile_error!(concat!("No routes defined in '",
|
compile_error!(concat!("No routes defined in '",
|
||||||
#base_path
|
#base_path,
|
||||||
"', make sure to define at least one `pub async fn` named after an method. (E.g. get, post, put, delete)"
|
"', make sure to define at least one `pub async fn` named after an method. (e.g. get, post, put, delete)"
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
4
tests/expand.rs
Normal file
4
tests/expand.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#[test]
|
||||||
|
pub fn expand_snapshot_pass() {
|
||||||
|
macrotest::expand("tests/expand/*.rs");
|
||||||
|
}
|
131
tests/expand/advanced.expanded.rs
Normal file
131
tests/expand/advanced.expanded.rs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
struct AppState {
|
||||||
|
_foo: String,
|
||||||
|
}
|
||||||
|
#[automatically_derived]
|
||||||
|
impl ::core::clone::Clone for AppState {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> AppState {
|
||||||
|
AppState {
|
||||||
|
_foo: ::core::clone::Clone::clone(&self._foo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "/home/tristand/code/axum-folder-router/examples/advanced/api"]
|
||||||
|
mod __folder_router__myfolderrouter__examples_advanced_api {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::response::{Html, IntoResponse};
|
||||||
|
pub async fn get() -> impl IntoResponse {
|
||||||
|
Html("<h1>Hello World!</h1>").into_response()
|
||||||
|
}
|
||||||
|
pub async fn post() -> impl IntoResponse {
|
||||||
|
"Posted successfully".into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "files"]
|
||||||
|
pub mod files {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::response::{Html, IntoResponse};
|
||||||
|
pub async fn get() -> impl IntoResponse {
|
||||||
|
Html("<h1>Hello World!</h1>").into_response()
|
||||||
|
}
|
||||||
|
pub async fn post() -> impl IntoResponse {
|
||||||
|
"Posted successfully".into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "[...path]"]
|
||||||
|
pub mod ___path {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::{extract::Path, response::IntoResponse};
|
||||||
|
pub async fn get(Path(path): Path<String>) -> impl IntoResponse {
|
||||||
|
::alloc::__export::must_use({
|
||||||
|
let res = ::alloc::fmt::format(
|
||||||
|
format_args!("Requested file path: {0}", path),
|
||||||
|
);
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "users"]
|
||||||
|
pub mod users {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::response::{Html, IntoResponse};
|
||||||
|
pub async fn get() -> impl IntoResponse {
|
||||||
|
Html("<h1>Hello World!</h1>").into_response()
|
||||||
|
}
|
||||||
|
pub async fn post() -> impl IntoResponse {
|
||||||
|
"Posted successfully".into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "[id]"]
|
||||||
|
pub mod __id {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::{extract::Path, response::IntoResponse};
|
||||||
|
pub async fn get(Path(id): Path<String>) -> impl IntoResponse {
|
||||||
|
::alloc::__export::must_use({
|
||||||
|
let res = ::alloc::fmt::format(format_args!("User ID: {0}", id));
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct MyFolderRouter();
|
||||||
|
impl MyFolderRouter {
|
||||||
|
pub fn into_router() -> axum::Router<AppState> {
|
||||||
|
let mut router = axum::Router::new();
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/files/{*path}",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::files::___path::route::get,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/files",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::files::route::get,
|
||||||
|
)
|
||||||
|
.post(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::files::route::post,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::route::get,
|
||||||
|
)
|
||||||
|
.post(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::route::post,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/users/{:id}",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::users::__id::route::get,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/users",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::users::route::get,
|
||||||
|
)
|
||||||
|
.post(
|
||||||
|
__folder_router__myfolderrouter__examples_advanced_api::users::route::post,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router
|
||||||
|
}
|
||||||
|
}
|
9
tests/expand/advanced.rs
Normal file
9
tests/expand/advanced.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AppState {
|
||||||
|
_foo: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[folder_router("examples/advanced/api", AppState)]
|
||||||
|
struct MyFolderRouter();
|
|
@ -1 +0,0 @@
|
||||||
../../examples
|
|
33
tests/expand/simple.expanded.rs
Normal file
33
tests/expand/simple.expanded.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
struct AppState;
|
||||||
|
#[automatically_derived]
|
||||||
|
impl ::core::clone::Clone for AppState {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> AppState {
|
||||||
|
AppState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[path = "/home/tristand/code/axum-folder-router/examples/simple/api"]
|
||||||
|
mod __folder_router__myfolderrouter__examples_simple_api {
|
||||||
|
#[path = "route.rs"]
|
||||||
|
pub mod route {
|
||||||
|
use axum::response::{Html, IntoResponse};
|
||||||
|
pub async fn get() -> impl IntoResponse {
|
||||||
|
Html("<h1>Hello World!</h1>").into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct MyFolderRouter();
|
||||||
|
impl MyFolderRouter {
|
||||||
|
pub fn into_router() -> axum::Router<AppState> {
|
||||||
|
let mut router = axum::Router::new();
|
||||||
|
router = router
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
axum::routing::get(
|
||||||
|
__folder_router__myfolderrouter__examples_simple_api::route::get,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
router
|
||||||
|
}
|
||||||
|
}
|
7
tests/expand/simple.rs
Normal file
7
tests/expand/simple.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AppState;
|
||||||
|
|
||||||
|
#[folder_router("examples/simple/api", AppState)]
|
||||||
|
struct MyFolderRouter();
|
5
tests/failures.rs
Normal file
5
tests/failures.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#[test]
|
||||||
|
fn ui() {
|
||||||
|
let t = trybuild::TestCases::new();
|
||||||
|
t.compile_fail("tests/failures/*.rs");
|
||||||
|
}
|
9
tests/failures/no_files.rs
Normal file
9
tests/failures/no_files.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AppState;
|
||||||
|
|
||||||
|
#[folder_router("some/non/existing/directory", AppState)]
|
||||||
|
struct MyFolderRouter();
|
||||||
|
|
||||||
|
fn main() {}
|
7
tests/failures/no_files.stderr
Normal file
7
tests/failures/no_files.stderr
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
error: No route.rs files found in the specified directory: 'some/non/existing/directory'. Make sure the path is correct and contains route.rs files.
|
||||||
|
--> tests/failures/no_files.rs:6:1
|
||||||
|
|
|
||||||
|
6 | #[folder_router("some/non/existing/directory", AppState)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in the attribute macro `folder_router` (in Nightly builds, run with -Z macro-backtrace for more info)
|
9
tests/failures/no_routes.rs
Normal file
9
tests/failures/no_routes.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use axum_folder_router::folder_router;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AppState;
|
||||||
|
|
||||||
|
#[folder_router("../../../../tests/failures/no_routes", AppState)]
|
||||||
|
struct MyFolderRouter();
|
||||||
|
|
||||||
|
fn main() {}
|
7
tests/failures/no_routes.stderr
Normal file
7
tests/failures/no_routes.stderr
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
error: No routes defined in '../../../../tests/failures/no_routes', make sure to define at least one `pub async fn` named after an method. (e.g. get, post, put, delete)
|
||||||
|
--> tests/failures/no_routes.rs:6:1
|
||||||
|
|
|
||||||
|
6 | #[folder_router("../../../../tests/failures/no_routes", AppState)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in the attribute macro `folder_router` (in Nightly builds, run with -Z macro-backtrace for more info)
|
0
tests/failures/no_routes/route.rs
Normal file
0
tests/failures/no_routes/route.rs
Normal file
|
@ -1,4 +0,0 @@
|
||||||
#[test]
|
|
||||||
pub fn expand_examples_pass() {
|
|
||||||
macrotest::expand("test/expand/**/*.rs");
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue