diff --git a/CHANGELOG.md b/CHANGELOG.md index 27be5bd..5d6eccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.20.1] - 2025-10-01 + +### Changed +- Enriched converter metadata across `multipart`, `redis`, `reqwest`, + `serde_json` and `sqlx` integrations to surface HTTP status details, + retry-after hints and structured failure positions while keeping existing + error categories intact. +- Updated the Teloxide mapping to classify `ApiError::InvalidToken` as + `Unauthorized` and hash potentially sensitive network error details before + emitting telemetry. + +### Tests +- Extended integration tests to assert the new metadata fields, retry hints, + and redaction policies covering the updated converters. + ## [0.20.0] - 2025-09-30 ### Added diff --git a/Cargo.lock b/Cargo.lock index a3abcc5..18742cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1727,7 +1727,7 @@ dependencies = [ [[package]] name = "masterror" -version = "0.20.0" +version = "0.20.1" dependencies = [ "actix-web", "axum 0.8.4", diff --git a/Cargo.toml b/Cargo.toml index 5a58911..b36f3aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "masterror" -version = "0.20.0" +version = "0.20.1" rust-version = "1.90" edition = "2024" license = "MIT OR Apache-2.0" diff --git a/README.md b/README.md index b333634..b5cdc06 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,9 @@ guides, comparisons with `thiserror`/`anyhow`, and troubleshooting recipes. ~~~toml [dependencies] -masterror = { version = "0.20.0", default-features = false } +masterror = { version = "0.20.1", default-features = false } # or with features: -# masterror = { version = "0.20.0", features = [ +# masterror = { version = "0.20.1", features = [ # "axum", "actix", "openapi", "serde_json", # "tracing", "metrics", "backtrace", "sqlx", # "sqlx-migrate", "reqwest", "redis", "validator", @@ -78,10 +78,10 @@ masterror = { version = "0.20.0", default-features = false } ~~~toml [dependencies] # lean core -masterror = { version = "0.20.0", default-features = false } +masterror = { version = "0.20.1", default-features = false } # with Axum/Actix + JSON + integrations -# masterror = { version = "0.20.0", features = [ +# masterror = { version = "0.20.1", features = [ # "axum", "actix", "openapi", "serde_json", # "tracing", "metrics", "backtrace", "sqlx", # "sqlx-migrate", "reqwest", "redis", "validator", @@ -720,13 +720,13 @@ assert_eq!(problem.grpc.expect("grpc").name, "UNAUTHENTICATED"); Minimal core: ~~~toml -masterror = { version = "0.20.0", default-features = false } +masterror = { version = "0.20.1", default-features = false } ~~~ API (Axum + JSON + deps): ~~~toml -masterror = { version = "0.20.0", features = [ +masterror = { version = "0.20.1", features = [ "axum", "serde_json", "openapi", "sqlx", "reqwest", "redis", "validator", "config", "tokio" ] } @@ -735,7 +735,7 @@ masterror = { version = "0.20.0", features = [ API (Actix + JSON + deps): ~~~toml -masterror = { version = "0.20.0", features = [ +masterror = { version = "0.20.1", features = [ "actix", "serde_json", "openapi", "sqlx", "reqwest", "redis", "validator", "config", "tokio" ] } diff --git a/src/convert/config.rs b/src/convert/config.rs index d3ef335..44e7650 100644 --- a/src/convert/config.rs +++ b/src/convert/config.rs @@ -17,10 +17,7 @@ use config::ConfigError; #[cfg(feature = "config")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; #[cfg(feature = "config")] #[cfg_attr(docsrs, doc(cfg(feature = "config")))] diff --git a/src/convert/multipart.rs b/src/convert/multipart.rs index 212db57..890c24e 100644 --- a/src/convert/multipart.rs +++ b/src/convert/multipart.rs @@ -8,16 +8,25 @@ use axum::extract::multipart::MultipartError; -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; impl From for Error { fn from(err: MultipartError) -> Self { - Context::new(AppErrorKind::BadRequest) - .with(field::str("multipart.reason", err.to_string())) - .into_error(err) + let status = err.status(); + let body_text = err.body_text(); + let mut context = Context::new(AppErrorKind::BadRequest) + .with(field::str("multipart.reason", body_text)) + .with(field::u64("http.status", u64::from(status.as_u16()))) + .with(field::bool( + "http.is_client_error", + status.is_client_error() + )); + + if let Some(reason) = status.canonical_reason() { + context = context.with(field::str("http.status_reason", reason)); + } + + context.into_error(err) } } @@ -47,12 +56,29 @@ mod tests { .expect("extractor"); let err = multipart.next_field().await.expect_err("error"); + let status = err.status(); + let body_text = err.body_text(); let app_err: Error = err.into(); assert_eq!(app_err.kind, AppErrorKind::BadRequest); assert_eq!( app_err.metadata().get("multipart.reason"), - Some(&FieldValue::Str(err.to_string().into())) + Some(&FieldValue::Str(body_text.into())) + ); + assert_eq!( + app_err.metadata().get("http.status"), + Some(&FieldValue::U64(u64::from(status.as_u16()))) + ); + assert_eq!( + app_err.metadata().get("http.status_reason"), + status + .canonical_reason() + .map(|reason| FieldValue::Str(reason.into())) + .as_ref() + ); + assert_eq!( + app_err.metadata().get("http.is_client_error"), + Some(&FieldValue::Bool(status.is_client_error())) ); } } diff --git a/src/convert/redis.rs b/src/convert/redis.rs index 05cc4c3..a0fc969 100644 --- a/src/convert/redis.rs +++ b/src/convert/redis.rs @@ -36,10 +36,7 @@ use redis::{RedisError, RetryMethod}; #[cfg(feature = "redis")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; /// Map any [`redis::RedisError`] into an [`AppError`] with kind `Cache`. /// @@ -104,6 +101,10 @@ fn build_context(err: &RedisError) -> (Context, Option) { format!("{:?}", retry_method) )); + if let Some(secs) = retry_after { + context = context.with(field::u64("redis.retry_after_hint_secs", secs)); + } + (context, retry_after) } @@ -144,5 +145,9 @@ mod tests { let app_err: Error = err.into(); assert_eq!(app_err.retry.map(|r| r.after_seconds), Some(2)); assert!(matches!(app_err.kind, AppErrorKind::DependencyUnavailable)); + assert_eq!( + app_err.metadata().get("redis.retry_after_hint_secs"), + Some(&FieldValue::U64(2)) + ); } } diff --git a/src/convert/reqwest.rs b/src/convert/reqwest.rs index 9eeb29f..d79324f 100644 --- a/src/convert/reqwest.rs +++ b/src/convert/reqwest.rs @@ -47,9 +47,7 @@ #[cfg(feature = "reqwest")] use reqwest::{Error as ReqwestError, StatusCode}; -use crate::AppErrorKind; -#[cfg(feature = "reqwest")] -use crate::app_error::{Context, Error, FieldRedaction, field}; +use crate::{AppErrorKind, Context, Error, FieldRedaction, field}; /// Map a [`reqwest::Error`] into an [`Error`] according to its category. /// @@ -116,6 +114,10 @@ fn classify_reqwest_error(err: &ReqwestError) -> (Context, Option) { context = context.with(field::str("http.host", host.to_owned())); } + if let Some(port) = url.port() { + context = context.with(field::u64("http.port", u64::from(port))); + } + let path = url.path(); if !path.is_empty() { context = context.with(field::str("http.path", path.to_owned())); @@ -205,6 +207,10 @@ mod tests { assert_eq!(app_err.retry.map(|r| r.after_seconds), Some(1)); let metadata = app_err.metadata(); assert_eq!(metadata.get("http.status"), Some(&FieldValue::U64(429))); + assert_eq!( + metadata.get("http.port"), + Some(&FieldValue::U64(u64::from(addr.port()))) + ); server.abort(); } diff --git a/src/convert/serde_json.rs b/src/convert/serde_json.rs index f307217..b24ba10 100644 --- a/src/convert/serde_json.rs +++ b/src/convert/serde_json.rs @@ -34,10 +34,7 @@ use serde_json::{Error as SjError, error::Category}; #[cfg(feature = "serde_json")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; /// Map a [`serde_json::Error`] into an [`AppError`]. /// @@ -71,6 +68,12 @@ fn build_context(err: &SjError) -> Context { if column != 0 { context = context.with(field::u64("serde_json.column", u64::from(column))); } + if line != 0 && column != 0 { + context = context.with(field::str( + "serde_json.position", + format!("{line}:{column}") + )); + } context } @@ -117,5 +120,9 @@ mod tests { metadata.get("serde_json.category"), Some(&FieldValue::Str("Syntax".into())) ); + assert_eq!( + metadata.get("serde_json.position"), + Some(&FieldValue::Str("1:1".into())) + ); } } diff --git a/src/convert/sqlx.rs b/src/convert/sqlx.rs index 1fbe506..9710414 100644 --- a/src/convert/sqlx.rs +++ b/src/convert/sqlx.rs @@ -40,10 +40,7 @@ use sqlx::migrate::MigrateError; use sqlx_core::error::{DatabaseError, Error as SqlxError, ErrorKind as SqlxErrorKind}; #[cfg(any(feature = "sqlx", feature = "sqlx-migrate"))] -use crate::{ - AppCode, AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppCode, AppErrorKind, Context, Error, field}; #[cfg(feature = "sqlx")] const SQLSTATE_CODE_OVERRIDES: &[(&str, AppCode)] = &[ @@ -88,7 +85,7 @@ impl From for Error { #[cfg(feature = "sqlx")] fn build_sqlx_context(err: &SqlxError) -> (Context, Option) { - match err { + let (mut context, retry_after) = match err { SqlxError::RowNotFound => ( Context::new(AppErrorKind::NotFound).with(field::str("db.reason", "row_not_found")), None @@ -196,7 +193,13 @@ fn build_sqlx_context(err: &SqlxError) -> (Context, Option) { .with(field::str("db.detail", format!("{:?}", other))), None ) + }; + + if let Some(secs) = retry_after { + context = context.with(field::u64("db.retry_after_hint_secs", secs)); } + + (context, retry_after) } #[cfg(feature = "sqlx")] @@ -346,6 +349,10 @@ mod tests_sqlx { }; let err: Error = SqlxError::Database(Box::new(db_err)).into(); assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + assert_eq!( + err.metadata().get("db.retry_after_hint_secs"), + Some(&FieldValue::U64(1)) + ); } #[derive(Debug)] diff --git a/src/convert/telegram_webapp_sdk.rs b/src/convert/telegram_webapp_sdk.rs index 063eeba..d5529b0 100644 --- a/src/convert/telegram_webapp_sdk.rs +++ b/src/convert/telegram_webapp_sdk.rs @@ -39,10 +39,7 @@ use telegram_webapp_sdk::utils::validate_init_data::ValidationError; #[cfg(feature = "telegram-webapp-sdk")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; /// Map [`ValidationError`] into an [`AppError`] with kind `TelegramAuth`. #[cfg(feature = "telegram-webapp-sdk")] diff --git a/src/convert/teloxide.rs b/src/convert/teloxide.rs index 9686f55..4f29f2b 100644 --- a/src/convert/teloxide.rs +++ b/src/convert/teloxide.rs @@ -4,8 +4,9 @@ //! //! ## Mapping //! -//! - [`RequestError::Api`] or [`RequestError::MigrateToChatId`] → -//! `AppErrorKind::ExternalApi` +//! - [`RequestError::Api`] → `AppErrorKind::ExternalApi` (invalid token → +//! `AppErrorKind::Unauthorized`) +//! - [`RequestError::MigrateToChatId`] → `AppErrorKind::ExternalApi` //! - [`RequestError::RetryAfter`] → `AppErrorKind::RateLimited` //! - [`RequestError::Network`] → `AppErrorKind::Network` //! - [`RequestError::InvalidJson`] → `AppErrorKind::Deserialization` @@ -27,13 +28,10 @@ //! assert!(matches!(app_err.kind, AppErrorKind::RateLimited)); //! ``` #[cfg(feature = "teloxide")] -use teloxide_core::RequestError; +use teloxide_core::{RequestError, errors::ApiError}; #[cfg(feature = "teloxide")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, FieldRedaction, field}; #[cfg(feature = "teloxide")] #[cfg_attr(docsrs, doc(cfg(feature = "teloxide")))] @@ -51,12 +49,21 @@ impl From for Error { #[cfg(feature = "teloxide")] fn build_teloxide_context(err: &RequestError) -> (Context, Option) { match err { - RequestError::Api(api) => ( - Context::new(AppErrorKind::ExternalApi) + RequestError::Api(api) => { + let mut context = Context::new(AppErrorKind::ExternalApi) .with(field::str("telegram.reason", "api")) - .with(field::str("telegram.api_error", api.to_string())), - None - ), + .with(field::str("telegram.api_error", api.to_string())) + .with(field::str( + "telegram.api_error_variant", + format!("{:?}", api) + )); + + if matches!(api, ApiError::InvalidToken) { + context = context.category(AppErrorKind::Unauthorized); + } + + (context, None) + } RequestError::MigrateToChatId(id) => ( Context::new(AppErrorKind::ExternalApi) .with(field::str("telegram.reason", "migrate_to_chat")) @@ -75,7 +82,8 @@ fn build_teloxide_context(err: &RequestError) -> (Context, Option) { RequestError::Network(e) => ( Context::new(AppErrorKind::Network) .with(field::str("telegram.reason", "network")) - .with(field::str("telegram.detail", e.to_string())), + .with(field::str("telegram.detail", e.to_string())) + .redact_field("telegram.detail", FieldRedaction::Hash), None ), RequestError::InvalidJson { @@ -99,12 +107,18 @@ fn build_teloxide_context(err: &RequestError) -> (Context, Option) { #[cfg(all(test, feature = "teloxide"))] mod tests { + #[cfg(feature = "reqwest")] + use std::time::Duration; use std::{io, sync::Arc}; use teloxide_core::{errors::ApiError, types::Seconds}; + #[cfg(feature = "reqwest")] + use tokio::runtime::Builder; use super::*; - use crate::{AppErrorKind, FieldValue}; + #[cfg(feature = "reqwest")] + use crate::FieldRedaction; + use crate::{AppCode, AppErrorKind, FieldValue}; #[test] fn api_maps_to_external_api() { @@ -136,4 +150,43 @@ mod tests { Some(&FieldValue::Str("io".into())) ); } + + #[test] + fn invalid_token_maps_to_unauthorized() { + let err = RequestError::Api(ApiError::InvalidToken); + let app_err: Error = err.into(); + assert_eq!(app_err.kind, AppErrorKind::Unauthorized); + assert_eq!(app_err.code, AppCode::Unauthorized); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("telegram.api_error_variant"), + Some(&FieldValue::Str("InvalidToken".into())) + ); + } + + #[cfg(feature = "reqwest")] + #[test] + fn network_detail_is_hashed() { + let runtime = Builder::new_current_thread() + .enable_all() + .build() + .expect("runtime"); + let reqwest_err = runtime.block_on(async { + reqwest::Client::builder() + .timeout(Duration::from_millis(10)) + .build() + .expect("client") + .get("http://127.0.0.1:65535") + .send() + .await + .expect_err("expected failure") + }); + let err = RequestError::Network(Arc::new(reqwest_err)); + let app_err: Error = err.into(); + let metadata = app_err.metadata(); + assert_eq!( + metadata.redaction("telegram.detail"), + Some(FieldRedaction::Hash) + ); + } } diff --git a/src/convert/tokio.rs b/src/convert/tokio.rs index a2c79e1..f436017 100644 --- a/src/convert/tokio.rs +++ b/src/convert/tokio.rs @@ -36,10 +36,7 @@ use tokio::time::error::Elapsed; #[cfg(feature = "tokio")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; /// Map a [`tokio::time::error::Elapsed`] into an [`AppError`] with kind /// `Timeout`. diff --git a/src/convert/validator.rs b/src/convert/validator.rs index e0fb4e2..fd15b69 100644 --- a/src/convert/validator.rs +++ b/src/convert/validator.rs @@ -42,10 +42,7 @@ use validator::{ValidationErrors, ValidationErrorsKind}; #[cfg(feature = "validator")] -use crate::{ - AppErrorKind, - app_error::{Context, Error, field} -}; +use crate::{AppErrorKind, Context, Error, field}; /// Map [`validator::ValidationErrors`] into an [`AppError`] with kind /// `Validation`. diff --git a/tests/ui/app_error/fail/enum_missing_variant.stderr b/tests/ui/app_error/fail/enum_missing_variant.stderr index d000de1..bbc297c 100644 --- a/tests/ui/app_error/fail/enum_missing_variant.stderr +++ b/tests/ui/app_error/fail/enum_missing_variant.stderr @@ -1,8 +1,9 @@ error: all variants must use #[app_error(...)] to derive AppError conversion --> tests/ui/app_error/fail/enum_missing_variant.rs:8:5 | -8 | #[error("without")] - | ^ +8 | / #[error("without")] +9 | | Without, + | |___________^ warning: unused import: `AppErrorKind` --> tests/ui/app_error/fail/enum_missing_variant.rs:1:17 @@ -10,4 +11,4 @@ warning: unused import: `AppErrorKind` 1 | use masterror::{AppErrorKind, Error}; | ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/app_error/fail/missing_code.stderr b/tests/ui/app_error/fail/missing_code.stderr index 70ccade..4f02301 100644 --- a/tests/ui/app_error/fail/missing_code.stderr +++ b/tests/ui/app_error/fail/missing_code.stderr @@ -2,7 +2,7 @@ error: AppCode conversion requires `code = ...` in #[app_error(...)] --> tests/ui/app_error/fail/missing_code.rs:9:5 | 9 | #[app_error(kind = AppErrorKind::Service)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused imports: `AppCode` and `AppErrorKind` --> tests/ui/app_error/fail/missing_code.rs:1:17 @@ -10,4 +10,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Error}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/app_error/fail/missing_kind.stderr b/tests/ui/app_error/fail/missing_kind.stderr index c615e98..021c135 100644 --- a/tests/ui/app_error/fail/missing_kind.stderr +++ b/tests/ui/app_error/fail/missing_kind.stderr @@ -2,4 +2,4 @@ error: missing `kind = ...` in #[app_error(...)] --> tests/ui/app_error/fail/missing_kind.rs:5:1 | 5 | #[app_error(message)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/formatter/fail/duplicate_fmt.stderr b/tests/ui/formatter/fail/duplicate_fmt.stderr index 5b08225..5b8f363 100644 --- a/tests/ui/formatter/fail/duplicate_fmt.stderr +++ b/tests/ui/formatter/fail/duplicate_fmt.stderr @@ -2,4 +2,4 @@ error: duplicate `fmt` handler specified --> tests/ui/formatter/fail/duplicate_fmt.rs:4:36 | 4 | #[error(fmt = crate::format_error, fmt = crate::format_error)] - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/formatter/fail/implicit_after_named.stderr b/tests/ui/formatter/fail/implicit_after_named.stderr index d416399..be76742 100644 --- a/tests/ui/formatter/fail/implicit_after_named.stderr +++ b/tests/ui/formatter/fail/implicit_after_named.stderr @@ -8,4 +8,5 @@ error: multiple unused formatting arguments | argument never used | argument never used | + = note: consider adding 2 format specifiers = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/formatter/fail/unsupported_flag.stderr b/tests/ui/formatter/fail/unsupported_flag.stderr index d7acdb1..b8bf229 100644 --- a/tests/ui/formatter/fail/unsupported_flag.stderr +++ b/tests/ui/formatter/fail/unsupported_flag.stderr @@ -1,5 +1,5 @@ error: placeholder spanning bytes 0..11 uses an unsupported formatter - --> tests/ui/formatter/fail/unsupported_flag.rs:4:9 + --> tests/ui/formatter/fail/unsupported_flag.rs:4:10 | 4 | #[error("{value:##x}")] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^ diff --git a/tests/ui/formatter/fail/unsupported_formatter.stderr b/tests/ui/formatter/fail/unsupported_formatter.stderr index 5869420..a6a40c2 100644 --- a/tests/ui/formatter/fail/unsupported_formatter.stderr +++ b/tests/ui/formatter/fail/unsupported_formatter.stderr @@ -1,5 +1,5 @@ error: placeholder spanning bytes 0..9 uses an unsupported formatter - --> tests/ui/formatter/fail/unsupported_formatter.rs:4:9 + --> tests/ui/formatter/fail/unsupported_formatter.rs:4:10 | 4 | #[error("{value:y}")] - | ^^^^^^^^^^^ + | ^^^^^^^^^ diff --git a/tests/ui/formatter/fail/uppercase_binary.stderr b/tests/ui/formatter/fail/uppercase_binary.stderr index bbe04b4..3d332c7 100644 --- a/tests/ui/formatter/fail/uppercase_binary.stderr +++ b/tests/ui/formatter/fail/uppercase_binary.stderr @@ -1,5 +1,5 @@ error: placeholder spanning bytes 0..9 uses an unsupported formatter - --> tests/ui/formatter/fail/uppercase_binary.rs:4:9 + --> tests/ui/formatter/fail/uppercase_binary.rs:4:10 | 4 | #[error("{value:B}")] - | ^^^^^^^^^^^ + | ^^^^^^^^^ diff --git a/tests/ui/formatter/fail/uppercase_pointer.stderr b/tests/ui/formatter/fail/uppercase_pointer.stderr index 2c30e71..0bd10fa 100644 --- a/tests/ui/formatter/fail/uppercase_pointer.stderr +++ b/tests/ui/formatter/fail/uppercase_pointer.stderr @@ -1,5 +1,5 @@ error: placeholder spanning bytes 0..9 uses an unsupported formatter - --> tests/ui/formatter/fail/uppercase_pointer.rs:4:9 + --> tests/ui/formatter/fail/uppercase_pointer.rs:4:10 | 4 | #[error("{value:P}")] - | ^^^^^^^^^^^ + | ^^^^^^^^^ diff --git a/tests/ui/masterror/fail/duplicate_attr.stderr b/tests/ui/masterror/fail/duplicate_attr.stderr index c3fb86b..113a10d 100644 --- a/tests/ui/masterror/fail/duplicate_attr.stderr +++ b/tests/ui/masterror/fail/duplicate_attr.stderr @@ -10,4 +10,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Masterror}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/duplicate_telemetry.stderr b/tests/ui/masterror/fail/duplicate_telemetry.stderr index b331baa..9ada290 100644 --- a/tests/ui/masterror/fail/duplicate_telemetry.stderr +++ b/tests/ui/masterror/fail/duplicate_telemetry.stderr @@ -10,4 +10,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Masterror}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/empty_redact.stderr b/tests/ui/masterror/fail/empty_redact.stderr index b2658a1..fd151cc 100644 --- a/tests/ui/masterror/fail/empty_redact.stderr +++ b/tests/ui/masterror/fail/empty_redact.stderr @@ -10,4 +10,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Masterror}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/enum_missing_variant.stderr b/tests/ui/masterror/fail/enum_missing_variant.stderr index 83d517f..5a25e12 100644 --- a/tests/ui/masterror/fail/enum_missing_variant.stderr +++ b/tests/ui/masterror/fail/enum_missing_variant.stderr @@ -1,8 +1,9 @@ error: all variants must use #[masterror(...)] to derive masterror::Error conversion --> tests/ui/masterror/fail/enum_missing_variant.rs:8:5 | -8 | #[error("missing")] - | ^ +8 | / #[error("missing")] +9 | | Missing + | |___________^ warning: unused imports: `AppCode` and `AppErrorKind` --> tests/ui/masterror/fail/enum_missing_variant.rs:1:17 @@ -10,4 +11,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Masterror}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/missing_category.stderr b/tests/ui/masterror/fail/missing_category.stderr index f929951..bdadf45 100644 --- a/tests/ui/masterror/fail/missing_category.stderr +++ b/tests/ui/masterror/fail/missing_category.stderr @@ -2,7 +2,7 @@ error: missing `category = ...` in #[masterror(...)] --> tests/ui/masterror/fail/missing_category.rs:5:1 | 5 | #[masterror(code = AppCode::Internal)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused import: `AppCode` --> tests/ui/masterror/fail/missing_category.rs:1:17 @@ -10,4 +10,4 @@ warning: unused import: `AppCode` 1 | use masterror::{AppCode, Masterror}; | ^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/missing_code.stderr b/tests/ui/masterror/fail/missing_code.stderr index 34abc91..037fac8 100644 --- a/tests/ui/masterror/fail/missing_code.stderr +++ b/tests/ui/masterror/fail/missing_code.stderr @@ -2,7 +2,7 @@ error: missing `code = ...` in #[masterror(...)] --> tests/ui/masterror/fail/missing_code.rs:5:1 | 5 | #[masterror(category = AppErrorKind::Internal)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused import: `AppErrorKind` --> tests/ui/masterror/fail/missing_code.rs:1:17 @@ -10,4 +10,4 @@ warning: unused import: `AppErrorKind` 1 | use masterror::{AppErrorKind, Masterror}; | ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default diff --git a/tests/ui/masterror/fail/unknown_option.stderr b/tests/ui/masterror/fail/unknown_option.stderr index d579838..1822edf 100644 --- a/tests/ui/masterror/fail/unknown_option.stderr +++ b/tests/ui/masterror/fail/unknown_option.stderr @@ -10,4 +10,4 @@ warning: unused imports: `AppCode` and `AppErrorKind` 1 | use masterror::{AppCode, AppErrorKind, Masterror}; | ^^^^^^^ ^^^^^^^^^^^^ | - = note: `#[warn(unused_imports)]` on by default + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default