diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index b735be9c..5c0ce828 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2020-xx-xx +* Added compile success and failure testing. [#1677] + +[#1677]: https://github.com/actix/actix-web/pull/1677 ## 0.3.0 - 2020-09-11 diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml index 05b52c9d..1bf78f99 100644 --- a/actix-web-codegen/Cargo.toml +++ b/actix-web-codegen/Cargo.toml @@ -22,3 +22,4 @@ proc-macro2 = "1" actix-rt = "1.0.0" actix-web = "3.0.0" futures-util = { version = "0.3.5", default-features = false } +trybuild = "1" diff --git a/actix-web-codegen/README.md b/actix-web-codegen/README.md index 45eb82c2..6eca847b 100644 --- a/actix-web-codegen/README.md +++ b/actix-web-codegen/README.md @@ -1,8 +1,22 @@ -# Helper and convenience macros for Actix-web. [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-web-codegen)](https://crates.io/crates/actix-web-codegen) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# actix-web-codegen + +> Helper and convenience macros for Actix Web + +[![crates.io](https://meritbadge.herokuapp.com/actix-web-codegen)](https://crates.io/crates/actix-web-codegen) +[![Documentation](https://docs.rs/actix-web-codegen/badge.svg)](https://docs.rs/actix-web) +[![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html) +[![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) +[![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) +[![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Documentation & Resources -* [API Documentation](https://docs.rs/actix-web-codegen/) -* [Chat on gitter](https://gitter.im/actix/actix) -* Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen) -* Minimum supported Rust version: 1.40 or later +- [API Documentation](https://docs.rs/actix-web-codegen) +- [Chat on Gitter](https://gitter.im/actix/actix-web) +- Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen) +- Minimum supported Rust version: 1.42 or later. + +## Compile Testing +Uses the [`trybuild`] crate. All compile fail tests should include a stderr file generated by `trybuild`. See the [workflow section](https://github.com/dtolnay/trybuild#workflow) of the trybuild docs for info on how to do this. + +[`trybuild`]: https://github.com/dtolnay/trybuild diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index b6df3f0d..445fe924 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -49,13 +49,13 @@ use proc_macro::TokenStream; /// Creates route handler with `GET` method guard. /// -/// Syntax: `#[get("path"[, attributes])]` +/// Syntax: `#[get("path" [, attributes])]` /// /// ## Attributes: /// /// - `"path"` - Raw literal string with path for which to register handler. Mandatory. -/// - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard` -/// - `wrap="Middleware"` - Registers a resource middleware. +/// - `guard = "function_name"` - Registers function as guard using `actix_web::guard::fn_guard` +/// - `wrap = "Middleware"` - Registers a resource middleware. #[proc_macro_attribute] pub fn get(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Get) @@ -63,7 +63,7 @@ pub fn get(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `POST` method guard. /// -/// Syntax: `#[post("path"[, attributes])]` +/// Syntax: `#[post("path" [, attributes])]` /// /// Attributes are the same as in [get](attr.get.html) #[proc_macro_attribute] @@ -73,7 +73,7 @@ pub fn post(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `PUT` method guard. /// -/// Syntax: `#[put("path"[, attributes])]` +/// Syntax: `#[put("path" [, attributes])]` /// /// Attributes are the same as in [get](attr.get.html) #[proc_macro_attribute] @@ -83,9 +83,9 @@ pub fn put(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `DELETE` method guard. /// -/// Syntax: `#[delete("path"[, attributes])]` +/// Syntax: `#[delete("path" [, attributes])]` /// -/// Attributes are the same as in [get](attr.get.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Delete) @@ -93,9 +93,9 @@ pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `HEAD` method guard. /// -/// Syntax: `#[head("path"[, attributes])]` +/// Syntax: `#[head("path" [, attributes])]` /// -/// Attributes are the same as in [head](attr.head.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn head(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Head) @@ -103,9 +103,9 @@ pub fn head(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `CONNECT` method guard. /// -/// Syntax: `#[connect("path"[, attributes])]` +/// Syntax: `#[connect("path" [, attributes])]` /// -/// Attributes are the same as in [connect](attr.connect.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Connect) @@ -113,9 +113,9 @@ pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `OPTIONS` method guard. /// -/// Syntax: `#[options("path"[, attributes])]` +/// Syntax: `#[options("path" [, attributes])]` /// -/// Attributes are the same as in [options](attr.options.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn options(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Options) @@ -123,9 +123,9 @@ pub fn options(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `TRACE` method guard. /// -/// Syntax: `#[trace("path"[, attributes])]` +/// Syntax: `#[trace("path" [, attributes])]` /// -/// Attributes are the same as in [trace](attr.trace.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Trace) @@ -133,9 +133,9 @@ pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `PATCH` method guard. /// -/// Syntax: `#[patch("path"[, attributes])]` +/// Syntax: `#[patch("path" [, attributes])]` /// -/// Attributes are the same as in [patch](attr.patch.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Patch) diff --git a/actix-web-codegen/tests/trybuild.rs b/actix-web-codegen/tests/trybuild.rs new file mode 100644 index 00000000..b675947d --- /dev/null +++ b/actix-web-codegen/tests/trybuild.rs @@ -0,0 +1,7 @@ +#[test] +fn compile_macros() { + let t = trybuild::TestCases::new(); + + t.pass("tests/trybuild/simple.rs"); + t.compile_fail("tests/trybuild/simple-fail.rs"); +} diff --git a/actix-web-codegen/tests/trybuild/simple-fail.rs b/actix-web-codegen/tests/trybuild/simple-fail.rs new file mode 100644 index 00000000..14049768 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple-fail.rs @@ -0,0 +1,25 @@ +use actix_web::*; + +#[get("/one", other)] +async fn one() -> impl Responder { + HttpResponse::Ok() +} + +#[post(/two)] +async fn two() -> impl Responder { + HttpResponse::Ok() +} + +static PATCH_PATH: &str = "/three"; + +#[patch(PATCH_PATH)] +async fn three() -> impl Responder { + HttpResponse::Ok() +} + +#[delete("/four", "/five")] +async fn four() -> impl Responder { + HttpResponse::Ok() +} + +fn main() {} diff --git a/actix-web-codegen/tests/trybuild/simple-fail.stderr b/actix-web-codegen/tests/trybuild/simple-fail.stderr new file mode 100644 index 00000000..12c32c00 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple-fail.stderr @@ -0,0 +1,23 @@ +error: Unknown attribute. + --> $DIR/simple-fail.rs:3:15 + | +3 | #[get("/one", other)] + | ^^^^^ + +error: expected identifier or literal + --> $DIR/simple-fail.rs:8:8 + | +8 | #[post(/two)] + | ^ + +error: Unknown attribute. + --> $DIR/simple-fail.rs:15:9 + | +15 | #[patch(PATCH_PATH)] + | ^^^^^^^^^^ + +error: Multiple paths specified! Should be only one! + --> $DIR/simple-fail.rs:20:19 + | +20 | #[delete("/four", "/five")] + | ^^^^^^^ diff --git a/actix-web-codegen/tests/trybuild/simple.rs b/actix-web-codegen/tests/trybuild/simple.rs new file mode 100644 index 00000000..6b1e6744 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple.rs @@ -0,0 +1,15 @@ +use actix_web::*; + +#[get("/config")] +async fn config() -> impl Responder { + HttpResponse::Ok() +} + +#[actix_web::main] +async fn main() { + let srv = test::start(|| App::new().service(config)); + + let request = srv.get("/config"); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +}