diff --git a/CHANGELOG.md b/CHANGELOG.md index 791f336d..747695a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Router display now uses different characters to represent root and matchable nodes. - Successful matches now return a flattened representation of node data. +### Fixed + +- Be consistent with the use of terms "path" and "route". + ## [0.2.1] - 2024-09-04 ### Changed diff --git a/src/decode.rs b/src/decode.rs index 9de9d33c..24f85a06 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -1,9 +1,9 @@ -use crate::errors::PathError; +use crate::errors::EncodingError; use std::borrow::Cow; /// Try and percent-decode input bytes. /// Does not do any sort of normalization, simply decodes hex characters. -pub fn percent_decode(input: &[u8]) -> Result, PathError> { +pub fn percent_decode(input: &[u8]) -> Result, EncodingError> { if !input.contains(&b'%') { return Ok(Cow::Borrowed(input)); } @@ -20,7 +20,7 @@ pub fn percent_decode(input: &[u8]) -> Result, PathError> { if let Some(decoded) = decode_hex(a, b) { output.push(decoded); } else { - return Err(PathError::InvalidEncoding { + return Err(EncodingError::InvalidEncoding { input: String::from_utf8_lossy(input).to_string(), position: i, character: [b'%', a, b], diff --git a/src/errors.rs b/src/errors.rs index 08b66dab..c77df918 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -8,6 +8,9 @@ pub use constraint::ConstraintError; pub(crate) mod delete; pub use delete::DeleteError; +pub(crate) mod encoding; +pub use encoding::EncodingError; + pub(crate) mod insert; pub use insert::InsertError; diff --git a/src/errors/delete.rs b/src/errors/delete.rs index c3b546b4..205d1cb1 100644 --- a/src/errors/delete.rs +++ b/src/errors/delete.rs @@ -7,7 +7,7 @@ pub enum DeleteError { /// A [`RouteError`] that occurred during the delete. RouteError(RouteError), - /// Path to be deleted was not found in the router. + /// Route to be deleted was not found in the router. /// /// # Examples /// @@ -15,22 +15,22 @@ pub enum DeleteError { /// use wayfind::errors::DeleteError; /// /// let error = DeleteError::NotFound { - /// path: "/not_found".to_string(), + /// route: "/not_found".to_string(), /// }; /// /// let display = " /// not found /// - /// Path: /not_found + /// Route: /not_found /// - /// The specified path does not exist in the router + /// The specified route does not exist in the router /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` NotFound { - /// The path that was not found in the router. - path: String, + /// The route that was not found in the router. + route: String, }, } @@ -40,13 +40,13 @@ impl Display for DeleteError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::RouteError(error) => error.fmt(f), - Self::NotFound { path } => write!( + Self::NotFound { route } => write!( f, r#"not found - Path: {path} + Route: {route} -The specified path does not exist in the router"# +The specified route does not exist in the router"# ), } } diff --git a/src/errors/encoding.rs b/src/errors/encoding.rs new file mode 100644 index 00000000..fbbc37d4 --- /dev/null +++ b/src/errors/encoding.rs @@ -0,0 +1,67 @@ +use std::{error::Error, fmt::Display}; + +/// Errors relating to attempting to decode percent-encoded strings. +#[derive(Debug, PartialEq, Eq)] +pub enum EncodingError { + /// Invalid percent-encoding sequence encountered. + /// + /// # Examples + /// + /// ```rust + /// use wayfind::errors::EncodingError; + /// + /// let error = EncodingError::InvalidEncoding { + /// input: "/hello%GGworld".to_string(), + /// position: 6, + /// character: [b'%', b'G', b'G'], + /// }; + /// + /// let display = " + /// invalid percent-encoding + /// + /// Input: /hello%GGworld + /// ^^^ + /// + /// Expected: '%' followed by two hexadecimal digits (a-F, 0-9) + /// Found: '%GG' + /// "; + /// + /// assert_eq!(error.to_string(), display.trim()); + /// ``` + InvalidEncoding { + /// The unaltered input string. + input: String, + /// The position in the input where the invalid encoding was found. + position: usize, + /// The invalid character sequence. + character: [u8; 3], + }, +} + +impl Error for EncodingError {} + +impl Display for EncodingError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidEncoding { + input, + position, + character, + } => { + let character = String::from_utf8_lossy(character); + let arrow = " ".repeat(*position) + "^^^"; + + write!( + f, + "invalid percent-encoding + + Input: {input} + {arrow} + +Expected: '%' followed by two hexadecimal digits (a-F, 0-9) + Found: '{character}'", + ) + } + } + } +} diff --git a/src/errors/insert.rs b/src/errors/insert.rs index 80d44b4c..9b0af88c 100644 --- a/src/errors/insert.rs +++ b/src/errors/insert.rs @@ -1,67 +1,67 @@ -use super::{route::RouteError, PathError}; +use super::{route::RouteError, EncodingError}; use std::{error::Error, fmt::Display}; /// Errors relating to attempting to insert a route into a [`Router`](crate::Router). #[derive(Debug, PartialEq, Eq)] pub enum InsertError { - /// A [`PathError`] that occurred at the start of the insert operation. - PathError(PathError), + /// A [`EncodingError`] that occurred during the decoding. + EncodingError(EncodingError), /// A [`RouteError`] that occurred during the insert operation. RouteError(RouteError), - /// The path provided was percent-encoded. + /// The route provided was percent-encoded. /// /// # Examples /// /// ```rust /// use wayfind::errors::InsertError; /// - /// let error = InsertError::EncodedPath { + /// let error = InsertError::EncodedRoute { /// input: "/hello%20world".to_string(), /// decoded: "/hello world".to_string(), /// }; /// /// let display = " - /// encoded path + /// encoded route /// /// Input: /hello%20world /// Decoded: /hello world /// - /// The router expects paths to be in their decoded form + /// The router expects routes to be in their decoded form /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` - EncodedPath { - /// The original encoded input path. + EncodedRoute { + /// The original encoded input route. input: String, - /// The decoded version of the path. + /// The decoded version of the route. decoded: String, }, - /// The path being inserted already exists in the router. + /// The route being inserted already exists in the router. /// /// # Examples /// /// ```rust /// use wayfind::errors::InsertError; /// - /// let error = InsertError::DuplicatePath { - /// path: "/existing/path".to_string(), + /// let error = InsertError::DuplicateRoute { + /// route: "/existing/route".to_string(), /// }; /// /// let display = " - /// duplicate path + /// duplicate route /// - /// Path: /existing/path + /// Route: /existing/route /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` - DuplicatePath { - /// The path that already exists in the router. - path: String, + DuplicateRoute { + /// The route that already exists in the router. + route: String, }, /// The constraint specified in the route is not recognized by the router. @@ -96,22 +96,22 @@ impl Error for InsertError {} impl Display for InsertError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::PathError(error) => error.fmt(f), + Self::EncodingError(error) => error.fmt(f), Self::RouteError(error) => error.fmt(f), - Self::EncodedPath { input, decoded } => write!( + Self::EncodedRoute { input, decoded } => write!( f, - r#"encoded path + r#"encoded route Input: {input} Decoded: {decoded} -The router expects paths to be in their decoded form"# +The router expects routes to be in their decoded form"# ), - Self::DuplicatePath { path } => write!( + Self::DuplicateRoute { route } => write!( f, - r#"duplicate path + r#"duplicate route - Path: {path}"# + Route: {route}"# ), Self::UnknownConstraint { constraint } => write!( f, @@ -125,9 +125,9 @@ The router doesn't recognize this constraint"# } } -impl From for InsertError { - fn from(error: PathError) -> Self { - Self::PathError(error) +impl From for InsertError { + fn from(error: EncodingError) -> Self { + Self::EncodingError(error) } } diff --git a/src/errors/path.rs b/src/errors/path.rs index 605e0a36..ba37f472 100644 --- a/src/errors/path.rs +++ b/src/errors/path.rs @@ -1,41 +1,12 @@ use std::{error::Error, fmt::Display}; -/// Errors relating to attempting to decode and validate path. +use super::EncodingError; + +/// Errors relating to attempting to decode and validate path. #[derive(Debug, PartialEq, Eq)] pub enum PathError { - /// Invalid percent-encoding sequence encountered. - /// - /// # Examples - /// - /// ```rust - /// use wayfind::errors::PathError; - /// - /// let error = PathError::InvalidEncoding { - /// input: "/hello%GGworld".to_string(), - /// position: 6, - /// character: [b'%', b'G', b'G'], - /// }; - /// - /// let display = " - /// invalid percent-encoding - /// - /// Input: /hello%GGworld - /// ^^^ - /// - /// Expected: '%' followed by two hexadecimal digits (a-F, 0-9) - /// Found: '%GG' - /// "; - /// - /// assert_eq!(error.to_string(), display.trim()); - /// ``` - InvalidEncoding { - /// The unaltered input string. - input: String, - /// The position in the input where the invalid encoding was found. - position: usize, - /// The invalid character sequence. - character: [u8; 3], - }, + /// A [`EncodingError`] that occurred during the decoding. + EncodingError(EncodingError), } impl Error for PathError {} @@ -43,25 +14,13 @@ impl Error for PathError {} impl Display for PathError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::InvalidEncoding { - input, - position, - character, - } => { - let character = String::from_utf8_lossy(character); - let arrow = " ".repeat(*position) + "^^^"; - - write!( - f, - "invalid percent-encoding - - Input: {input} - {arrow} - -Expected: '%' followed by two hexadecimal digits (a-F, 0-9) - Found: '{character}'", - ) - } + Self::EncodingError(error) => error.fmt(f), } } } + +impl From for PathError { + fn from(error: EncodingError) -> Self { + Self::EncodingError(error) + } +} diff --git a/src/errors/route.rs b/src/errors/route.rs index 9011d7ef..5b867b22 100644 --- a/src/errors/route.rs +++ b/src/errors/route.rs @@ -1,12 +1,12 @@ use std::{error::Error, fmt::Display}; -/// Errors relating to malformed paths. +/// Errors relating to malformed routes. #[derive(Debug, PartialEq, Eq)] pub enum RouteError { - /// The path is empty. - EmptyPath, + /// The route is empty. + EmptyRoute, - /// Empty braces were found in the path. + /// Empty braces were found in the route. /// /// # Examples /// @@ -14,27 +14,27 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::EmptyBraces { - /// path: "/{}".to_string(), + /// route: "/{}".to_string(), /// position: 1, /// }; /// /// let display = " /// empty braces /// - /// Path: /{} + /// Route: /{} /// ^^ /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` EmptyBraces { - /// The path containing empty braces. - path: String, + /// The route containing empty braces. + route: String, /// The position of the empty brace. position: usize, }, - /// An unescaped brace was found in the path. + /// An unescaped brace was found in the route. /// /// # Examples /// @@ -42,29 +42,29 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::UnescapedBrace { - /// path: "/{".to_string(), + /// route: "/{".to_string(), /// position: 1, /// }; /// /// let display = " /// unescaped brace /// - /// Path: /{ + /// Route: /{ /// ^ /// - /// tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path + /// tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` UnescapedBrace { - /// The path containing an unescaped brace. - path: String, + /// The route containing an unescaped brace. + route: String, /// The position of the unescaped brace. position: usize, }, - /// An empty parameter name was found in the path. + /// An empty parameter name was found in the route. /// /// # Examples /// @@ -72,7 +72,7 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::EmptyParameter { - /// path: "/{:}".to_string(), + /// route: "/{:}".to_string(), /// start: 1, /// length: 3, /// }; @@ -80,22 +80,22 @@ pub enum RouteError { /// let display = " /// empty parameter name /// - /// Path: /{:} + /// Route: /{:} /// ^^^ /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` EmptyParameter { - /// The path containing an empty parameter. - path: String, + /// The route containing an empty parameter. + route: String, /// The position of the parameter with a empty name. start: usize, /// The length of the parameter (including braces). length: usize, }, - /// An invalid parameter name was found in the path. + /// An invalid parameter name was found in the route. /// /// # Examples /// @@ -103,7 +103,7 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::InvalidParameter { - /// path: "/{a/b}".to_string(), + /// route: "/{a/b}".to_string(), /// name: "a/b".to_string(), /// start: 1, /// length: 5, @@ -112,7 +112,7 @@ pub enum RouteError { /// let display = " /// invalid parameter name /// - /// Path: /{a/b} + /// Route: /{a/b} /// ^^^^^ /// /// tip: Parameter names must not contain the characters: ':', '*', '?', '{', '}', '/' @@ -121,8 +121,8 @@ pub enum RouteError { /// assert_eq!(error.to_string(), display.trim()); /// ``` InvalidParameter { - /// The path containing an invalid parameter. - path: String, + /// The route containing an invalid parameter. + route: String, /// The invalid parameter name. name: String, /// The position of the parameter with a invalid name. @@ -131,7 +131,7 @@ pub enum RouteError { length: usize, }, - /// A wildcard parameter with no name was found in the path. + /// A wildcard parameter with no name was found in the route. /// /// # Examples /// @@ -139,7 +139,7 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::EmptyWildcard { - /// path: "/{*}".to_string(), + /// route: "/{*}".to_string(), /// start: 1, /// length: 3, /// }; @@ -147,22 +147,22 @@ pub enum RouteError { /// let display = " /// empty wildcard name /// - /// Path: /{*} + /// Route: /{*} /// ^^^ /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` EmptyWildcard { - /// The path containing an empty wildcard parameter. - path: String, + /// The route containing an empty wildcard parameter. + route: String, /// The position of the wildcard parameter with a empty name. start: usize, /// The length of the parameter (including braces). length: usize, }, - /// An empty constraint name was found in the path. + /// An empty constraint name was found in the route. /// /// # Examples /// @@ -170,7 +170,7 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::EmptyConstraint { - /// path: "/{a:}".to_string(), + /// route: "/{a:}".to_string(), /// start: 1, /// length: 4, /// }; @@ -178,22 +178,22 @@ pub enum RouteError { /// let display = " /// empty constraint name /// - /// Path: /{a:} + /// Route: /{a:} /// ^^^^ /// "; /// /// assert_eq!(error.to_string(), display.trim()); /// ``` EmptyConstraint { - /// The path containing an empty constraint. - path: String, + /// The route containing an empty constraint. + route: String, /// The position of the parameter with an empty constraint. start: usize, /// The length of the parameter (including braces). length: usize, }, - /// An invalid constraint name was found in the path. + /// An invalid constraint name was found in the route. /// /// # Examples /// @@ -201,7 +201,7 @@ pub enum RouteError { /// use wayfind::errors::RouteError; /// /// let error = RouteError::InvalidConstraint { - /// path: "/{a:b/c}".to_string(), + /// route: "/{a:b/c}".to_string(), /// name: "b/c".to_string(), /// start: 1, /// length: 7, @@ -210,7 +210,7 @@ pub enum RouteError { /// let display = " /// invalid constraint name /// - /// Path: /{a:b/c} + /// Route: /{a:b/c} /// ^^^^^^^ /// /// tip: Constraint names must not contain the characters: ':', '*', '?', '{', '}', '/' @@ -219,8 +219,8 @@ pub enum RouteError { /// assert_eq!(error.to_string(), display.trim()); /// ``` InvalidConstraint { - /// The path containing an invalid constraint. - path: String, + /// The route containing an invalid constraint. + route: String, /// The invalid constraint name. name: String, /// The position of the parameter with an invalid constraint. @@ -235,34 +235,34 @@ impl Error for RouteError {} impl Display for RouteError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::EmptyPath => write!(f, "empty path"), + Self::EmptyRoute => write!(f, "empty route"), - Self::EmptyBraces { path, position } => { + Self::EmptyBraces { route, position } => { let arrow = " ".repeat(*position) + "^^"; write!( f, r#"empty braces - Path: {path} + Route: {route} {arrow}"# ) } - Self::UnescapedBrace { path, position } => { + Self::UnescapedBrace { route, position } => { let arrow = " ".repeat(*position) + "^"; write!( f, r#"unescaped brace - Path: {path} + Route: {route} {arrow} -tip: Use '{{{{' and '}}}}' to represent literal '{{' and '}}' characters in the path"# +tip: Use '{{{{' and '}}}}' to represent literal '{{' and '}}' characters in the route"# ) } Self::EmptyParameter { - path, + route, start, length, } => { @@ -271,13 +271,13 @@ tip: Use '{{{{' and '}}}}' to represent literal '{{' and '}}' characters in the f, r#"empty parameter name - Path: {path} + Route: {route} {arrow}"# ) } Self::InvalidParameter { - path, + route, start, length, .. @@ -287,7 +287,7 @@ tip: Use '{{{{' and '}}}}' to represent literal '{{' and '}}' characters in the f, r#"invalid parameter name - Path: {path} + Route: {route} {arrow} tip: Parameter names must not contain the characters: ':', '*', '?', '{{', '}}', '/'"# @@ -295,7 +295,7 @@ tip: Parameter names must not contain the characters: ':', '*', '?', '{{', '}}', } Self::EmptyWildcard { - path, + route, start, length, } => { @@ -304,13 +304,13 @@ tip: Parameter names must not contain the characters: ':', '*', '?', '{{', '}}', f, r#"empty wildcard name - Path: {path} + Route: {route} {arrow}"# ) } Self::EmptyConstraint { - path, + route, start, length, } => { @@ -319,13 +319,13 @@ tip: Parameter names must not contain the characters: ':', '*', '?', '{{', '}}', f, r#"empty constraint name - Path: {path} + Route: {route} {arrow}"# ) } Self::InvalidConstraint { - path, + route, start, length, .. @@ -335,7 +335,7 @@ tip: Parameter names must not contain the characters: ':', '*', '?', '{{', '}}', f, r#"invalid constraint name - Path: {path} + Route: {route} {arrow} tip: Constraint names must not contain the characters: ':', '*', '?', '{{', '}}', '/'"# diff --git a/src/lib.rs b/src/lib.rs index 47a585a6..a782db62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,10 @@ pub mod errors; pub(crate) mod node; pub use node::search::{Match, Parameter}; -pub(crate) mod parts; - pub(crate) mod path; pub use path::Path; +pub(crate) mod parser; + pub(crate) mod router; pub use router::Router; diff --git a/src/node/delete.rs b/src/node/delete.rs index b9ee15d2..8b29f306 100644 --- a/src/node/delete.rs +++ b/src/node/delete.rs @@ -1,7 +1,7 @@ use crate::{ errors::DeleteError, node::Node, - parts::{Part, Parts}, + parser::{ParsedRoute, RoutePart}, }; impl Node { @@ -11,17 +11,17 @@ impl Node { /// Logic should match that used by the insert method. /// /// If the route is found and deleted, we re-optimize the tree structure. - pub fn delete(&mut self, parts: &mut Parts<'_>) -> Result<(), DeleteError> { + pub fn delete(&mut self, parts: &mut ParsedRoute<'_>) -> Result<(), DeleteError> { if let Some(segment) = parts.pop() { let result = match segment { - Part::Static { prefix } => self.delete_static(parts, &prefix), - Part::Dynamic { name, constraint } => { + RoutePart::Static { prefix } => self.delete_static(parts, &prefix), + RoutePart::Dynamic { name, constraint } => { self.delete_dynamic(parts, &name, &constraint) } - Part::Wildcard { name, constraint } if parts.is_empty() => { + RoutePart::Wildcard { name, constraint } if parts.is_empty() => { self.delete_end_wildcard(parts, &name, &constraint) } - Part::Wildcard { name, constraint } => { + RoutePart::Wildcard { name, constraint } => { self.delete_wildcard(parts, &name, &constraint) } }; @@ -38,12 +38,16 @@ impl Node { } Err(DeleteError::NotFound { - path: String::from_utf8_lossy(parts.path).to_string(), + route: String::from_utf8_lossy(parts.route).to_string(), }) } } - fn delete_static(&mut self, parts: &mut Parts<'_>, prefix: &[u8]) -> Result<(), DeleteError> { + fn delete_static( + &mut self, + parts: &mut ParsedRoute<'_>, + prefix: &[u8], + ) -> Result<(), DeleteError> { let index = self .static_children .iter() @@ -52,7 +56,7 @@ impl Node { && child.prefix.iter().zip(prefix).all(|(a, b)| a == b) }) .ok_or(DeleteError::NotFound { - path: String::from_utf8_lossy(parts.path).to_string(), + route: String::from_utf8_lossy(parts.route).to_string(), })?; let child = &mut self.static_children[index]; @@ -77,7 +81,7 @@ impl Node { fn delete_dynamic( &mut self, - parts: &mut Parts<'_>, + parts: &mut ParsedRoute<'_>, name: &[u8], constraint: &Option>, ) -> Result<(), DeleteError> { @@ -86,7 +90,7 @@ impl Node { .iter() .position(|child| child.prefix == name && child.constraint == *constraint) .ok_or(DeleteError::NotFound { - path: String::from_utf8_lossy(parts.path).to_string(), + route: String::from_utf8_lossy(parts.route).to_string(), })?; let child = &mut self.dynamic_children[index]; @@ -105,7 +109,7 @@ impl Node { fn delete_wildcard( &mut self, - parts: &mut Parts<'_>, + parts: &mut ParsedRoute<'_>, name: &[u8], constraint: &Option>, ) -> Result<(), DeleteError> { @@ -114,7 +118,7 @@ impl Node { .iter() .position(|child| child.prefix == name && child.constraint == *constraint) .ok_or(DeleteError::NotFound { - path: String::from_utf8_lossy(parts.path).to_string(), + route: String::from_utf8_lossy(parts.route).to_string(), })?; let child = &mut self.wildcard_children[index]; @@ -133,7 +137,7 @@ impl Node { fn delete_end_wildcard( &mut self, - parts: &Parts<'_>, + parts: &ParsedRoute<'_>, name: &[u8], constraint: &Option>, ) -> Result<(), DeleteError> { @@ -142,7 +146,7 @@ impl Node { .iter() .position(|child| child.prefix == name && child.constraint == *constraint) .ok_or(DeleteError::NotFound { - path: String::from_utf8_lossy(parts.path).to_string(), + route: String::from_utf8_lossy(parts.route).to_string(), })?; self.end_wildcard_children.remove(index); diff --git a/src/node/insert.rs b/src/node/insert.rs index 8b1baab0..79be6665 100644 --- a/src/node/insert.rs +++ b/src/node/insert.rs @@ -1,7 +1,7 @@ use super::{Node, NodeData, NodeKind}; use crate::{ errors::InsertError, - parts::{Part, Parts}, + parser::{ParsedRoute, RoutePart}, }; use std::cmp::Ordering; @@ -10,24 +10,28 @@ impl Node { /// /// Recursively traverses the node tree, creating new nodes as necessary. /// Will error is there's already data at the end node. - pub fn insert(&mut self, parts: &mut Parts<'_>, data: NodeData) -> Result<(), InsertError> { + pub fn insert( + &mut self, + parts: &mut ParsedRoute<'_>, + data: NodeData, + ) -> Result<(), InsertError> { if let Some(segment) = parts.pop() { match segment { - Part::Static { prefix } => self.insert_static(parts, data, &prefix)?, - Part::Dynamic { name, constraint } => { + RoutePart::Static { prefix } => self.insert_static(parts, data, &prefix)?, + RoutePart::Dynamic { name, constraint } => { self.insert_dynamic(parts, data, &name, constraint)?; } - Part::Wildcard { name, constraint } if parts.is_empty() => { + RoutePart::Wildcard { name, constraint } if parts.is_empty() => { self.insert_end_wildcard(parts, data, &name, constraint)?; } - Part::Wildcard { name, constraint } => { + RoutePart::Wildcard { name, constraint } => { self.insert_wildcard(parts, data, &name, constraint)?; } }; } else { if self.data.is_some() { - return Err(InsertError::DuplicatePath { - path: String::from_utf8_lossy(parts.path).to_string(), + return Err(InsertError::DuplicateRoute { + route: String::from_utf8_lossy(parts.route).to_string(), }); } @@ -42,7 +46,7 @@ impl Node { fn insert_static( &mut self, - parts: &mut Parts<'_>, + parts: &mut ParsedRoute<'_>, data: NodeData, prefix: &[u8], ) -> Result<(), InsertError> { @@ -138,7 +142,7 @@ impl Node { fn insert_dynamic( &mut self, - parts: &mut Parts<'_>, + parts: &mut ParsedRoute<'_>, data: NodeData, name: &[u8], constraint: Option>, @@ -176,7 +180,7 @@ impl Node { fn insert_wildcard( &mut self, - parts: &mut Parts<'_>, + parts: &mut ParsedRoute<'_>, data: NodeData, name: &[u8], constraint: Option>, @@ -214,7 +218,7 @@ impl Node { fn insert_end_wildcard( &mut self, - parts: &Parts<'_>, + parts: &ParsedRoute<'_>, data: NodeData, name: &[u8], constraint: Option>, @@ -224,8 +228,8 @@ impl Node { .iter() .any(|child| child.prefix == name && child.constraint == constraint) { - return Err(InsertError::DuplicatePath { - path: String::from_utf8_lossy(parts.path).to_string(), + return Err(InsertError::DuplicateRoute { + route: String::from_utf8_lossy(parts.route).to_string(), }); } diff --git a/src/node/search.rs b/src/node/search.rs index 0e1f1748..b6a5e779 100644 --- a/src/node/search.rs +++ b/src/node/search.rs @@ -30,7 +30,7 @@ pub struct Parameter<'router, 'path> { impl Node { /// Searches for a matching route in the node tree. /// - /// This method traverses the tree to find a node that matches the given path, collecting parameters along the way. + /// This method traverses the tree to find a route node that matches the given path, collecting parameters along the way. /// We try nodes in the order: static, dynamic, wildcard, then end wildcard. pub fn search<'router, 'path>( &'router self, diff --git a/src/parts.rs b/src/parser.rs similarity index 55% rename from src/parts.rs rename to src/parser.rs index 56269fae..44fbe017 100644 --- a/src/parts.rs +++ b/src/parser.rs @@ -4,9 +4,9 @@ use std::fmt::Debug; /// Characters that are not allowed in parameter names or constraints. const INVALID_PARAM_CHARS: [u8; 6] = [b':', b'*', b'?', b'{', b'}', b'/']; -/// A parsed section of a path. +/// A parsed section of a route. #[derive(Debug, PartialEq, Eq)] -pub enum Part { +pub enum RoutePart { Static { prefix: Vec, }, @@ -22,29 +22,29 @@ pub enum Part { }, } -/// A parsed path. +/// A parsed route. #[derive(Debug, PartialEq, Eq)] -pub struct Parts<'a> { - /// The original path. - pub path: &'a [u8], +pub struct ParsedRoute<'a> { + /// The original route. + pub route: &'a [u8], - /// The parsed parts of the path, in reverse order. - /// We may want these to simply be indicies of the original path in the future, to reduce allocations. - pub inner: Vec, + /// The parsed parts of the route, in reverse order. + /// We may want these to simply be indicies of the original route in the future, to reduce allocations. + pub parts: Vec, } -impl<'a> Parts<'a> { - pub fn new(path: &'a [u8]) -> Result { - if path.is_empty() { - return Err(RouteError::EmptyPath); +impl<'a> ParsedRoute<'a> { + pub fn new(route: &'a [u8]) -> Result { + if route.is_empty() { + return Err(RouteError::EmptyRoute); } let mut parts = vec![]; let mut cursor = 0; let mut current_static = vec![]; - while cursor < path.len() { - match (path[cursor], path.get(cursor + 1)) { + while cursor < route.len() { + match (route[cursor], route.get(cursor + 1)) { (b'{', Some(b'{')) => { current_static.push(b'{'); cursor += 2; @@ -55,16 +55,16 @@ impl<'a> Parts<'a> { } (b'{', _) => { if !current_static.is_empty() { - parts.push(Part::Static { + parts.push(RoutePart::Static { prefix: std::mem::take(&mut current_static), }); } - cursor = Self::parse_parameter(path, cursor, &mut parts)?; + cursor = Self::parse_parameter(route, cursor, &mut parts)?; } (b'}', _) => { return Err(RouteError::UnescapedBrace { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), position: cursor, }) } @@ -76,41 +76,46 @@ impl<'a> Parts<'a> { } if !current_static.is_empty() { - parts.push(Part::Static { + parts.push(RoutePart::Static { prefix: std::mem::take(&mut current_static), }); } parts.reverse(); - Ok(Self { path, inner: parts }) + Ok(Self { route, parts }) } fn parse_parameter( - path: &[u8], + route: &[u8], cursor: usize, - parts: &mut Vec, + parts: &mut Vec, ) -> Result { let start = cursor + 1; - let end = path[start..] + let end = route[start..] .iter() .position(|&c| c == b'}') .map(|pos| start + pos) .ok_or(RouteError::UnescapedBrace { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), position: cursor, })?; if start == end { return Err(RouteError::EmptyBraces { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), position: cursor, }); } - let colon = path[start..end].iter().position(|&c| c == b':'); + let colon = route[start..end].iter().position(|&c| c == b':'); let (name, constraint) = colon.map_or_else( - || (&path[start..end], None), - |pos| (&path[start..start + pos], Some(&path[start + pos + 1..end])), + || (&route[start..end], None), + |pos| { + ( + &route[start..start + pos], + Some(&route[start + pos + 1..end]), + ) + }, ); let (is_wildcard, name) = if name.starts_with(b"*") { @@ -122,14 +127,14 @@ impl<'a> Parts<'a> { if name.is_empty() { if is_wildcard { return Err(RouteError::EmptyWildcard { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), start: cursor, length: end - start + 2, }); } return Err(RouteError::EmptyParameter { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), start: cursor, length: end - start + 2, }); @@ -137,7 +142,7 @@ impl<'a> Parts<'a> { if name.iter().any(|&c| INVALID_PARAM_CHARS.contains(&c)) { return Err(RouteError::InvalidParameter { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), name: String::from_utf8_lossy(name).to_string(), start: start - 1, length: end - start + 2, @@ -147,7 +152,7 @@ impl<'a> Parts<'a> { if let Some(constraint) = constraint { if constraint.is_empty() { return Err(RouteError::EmptyConstraint { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), start: start - 1, length: end - start + 2, }); @@ -155,7 +160,7 @@ impl<'a> Parts<'a> { if constraint.iter().any(|&c| INVALID_PARAM_CHARS.contains(&c)) { return Err(RouteError::InvalidConstraint { - path: String::from_utf8_lossy(path).to_string(), + route: String::from_utf8_lossy(route).to_string(), name: String::from_utf8_lossy(constraint).to_string(), start: start - 1, length: end - start + 2, @@ -164,12 +169,12 @@ impl<'a> Parts<'a> { } let part = if is_wildcard { - Part::Wildcard { + RoutePart::Wildcard { name: name.to_vec(), constraint: constraint.map(<[u8]>::to_vec), } } else { - Part::Dynamic { + RoutePart::Dynamic { name: name.to_vec(), constraint: constraint.map(<[u8]>::to_vec), } @@ -179,35 +184,35 @@ impl<'a> Parts<'a> { Ok(end + 1) } - pub fn pop(&mut self) -> Option { - self.inner.pop() + pub fn pop(&mut self) -> Option { + self.parts.pop() } #[must_use] pub fn is_empty(&self) -> bool { - self.inner.is_empty() + self.parts.is_empty() } - pub fn iter(&'a self) -> std::slice::Iter<'a, Part> { + pub fn iter(&'a self) -> std::slice::Iter<'a, RoutePart> { self.into_iter() } } -impl<'a> IntoIterator for Parts<'a> { - type Item = Part; +impl<'a> IntoIterator for ParsedRoute<'a> { + type Item = RoutePart; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.inner.into_iter() + self.parts.into_iter() } } -impl<'a> IntoIterator for &'a Parts<'a> { - type Item = &'a Part; - type IntoIter = std::slice::Iter<'a, Part>; +impl<'a> IntoIterator for &'a ParsedRoute<'a> { + type Item = &'a RoutePart; + type IntoIter = std::slice::Iter<'a, RoutePart>; fn into_iter(self) -> Self::IntoIter { - self.inner.iter() + self.parts.iter() } } @@ -218,10 +223,10 @@ mod tests { #[test] fn test_parts_static() { assert_eq!( - Parts::new(b"/abcd"), - Ok(Parts { - path: b"/abcd", - inner: vec![Part::Static { + ParsedRoute::new(b"/abcd"), + Ok(ParsedRoute { + route: b"/abcd", + parts: vec![RoutePart::Static { prefix: b"/abcd".to_vec() }] }) @@ -231,15 +236,15 @@ mod tests { #[test] fn test_parts_dynamic() { assert_eq!( - Parts::new(b"/{name}"), - Ok(Parts { - path: b"/{name}", - inner: vec![ - Part::Dynamic { + ParsedRoute::new(b"/{name}"), + Ok(ParsedRoute { + route: b"/{name}", + parts: vec![ + RoutePart::Dynamic { name: b"name".to_vec(), constraint: None }, - Part::Static { + RoutePart::Static { prefix: b"/".to_vec() }, ] @@ -250,15 +255,15 @@ mod tests { #[test] fn test_parts_wildcard() { assert_eq!( - Parts::new(b"/{*path}"), - Ok(Parts { - path: b"/{*path}", - inner: vec![ - Part::Wildcard { - name: b"path".to_vec(), + ParsedRoute::new(b"/{*route}"), + Ok(ParsedRoute { + route: b"/{*route}", + parts: vec![ + RoutePart::Wildcard { + name: b"route".to_vec(), constraint: None }, - Part::Static { + RoutePart::Static { prefix: b"/".to_vec() }, ] @@ -269,22 +274,22 @@ mod tests { #[test] fn test_parts_constraint() { assert_eq!( - Parts::new(b"/{name:alpha}/{id:numeric}"), - Ok(Parts { - path: b"/{name:alpha}/{id:numeric}", - inner: vec![ - Part::Dynamic { + ParsedRoute::new(b"/{name:alpha}/{id:numeric}"), + Ok(ParsedRoute { + route: b"/{name:alpha}/{id:numeric}", + parts: vec![ + RoutePart::Dynamic { name: b"id".to_vec(), constraint: Some(b"numeric".to_vec()) }, - Part::Static { + RoutePart::Static { prefix: b"/".to_vec() }, - Part::Dynamic { + RoutePart::Dynamic { name: b"name".to_vec(), constraint: Some(b"alpha".to_vec()) }, - Part::Static { + RoutePart::Static { prefix: b"/".to_vec() }, ] @@ -294,191 +299,191 @@ mod tests { #[test] fn test_parts_empty() { - let error = Parts::new(b"").unwrap_err(); - insta::assert_snapshot!(error, @"empty path"); + let error = ParsedRoute::new(b"").unwrap_err(); + insta::assert_snapshot!(error, @"empty route"); } #[test] fn test_parts_unclosed_braces() { - let error = Parts::new(b"/{").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{").unwrap_err(); + insta::assert_snapshot!(error, @r#" unescaped brace - Path: /{ + Route: /{ ^ - tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path - "###); + tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route + "#); - let error = Parts::new(b"/{name").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name").unwrap_err(); + insta::assert_snapshot!(error, @r#" unescaped brace - Path: /{name + Route: /{name ^ - tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path - "###); + tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route + "#); - let error = Parts::new(b"/name}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/name}").unwrap_err(); + insta::assert_snapshot!(error, @r#" unescaped brace - Path: /name} + Route: /name} ^ - tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path - "###); + tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route + "#); } #[test] fn test_parts_empty_braces() { - let error = Parts::new(b"/{}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty braces - Path: /{} + Route: /{} ^^ - "###); + "#); } #[test] fn test_parts_empty_name() { - let error = Parts::new(b"/{:}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{:}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty parameter name - Path: /{:} + Route: /{:} ^^^ - "###); + "#); - let error = Parts::new(b"/{:constraint}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{:constraint}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty parameter name - Path: /{:constraint} + Route: /{:constraint} ^^^^^^^^^^^^^ - "###); + "#); } #[test] fn test_parts_empty_wildcard() { - let error = Parts::new(b"/{*}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{*}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty wildcard name - Path: /{*} + Route: /{*} ^^^ - "###); + "#); - let error = Parts::new(b"/{*:constraint}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{*:constraint}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty wildcard name - Path: /{*:constraint} + Route: /{*:constraint} ^^^^^^^^^^^^^^ - "###); + "#); } #[test] fn test_parts_empty_constraint() { - let error = Parts::new(b"/{name:}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name:}").unwrap_err(); + insta::assert_snapshot!(error, @r#" empty constraint name - Path: /{name:} + Route: /{name:} ^^^^^^^ - "###); + "#); } #[test] fn test_parts_invalid_characters() { - let error = Parts::new(b"/{name/with/slash}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name/with/slash}").unwrap_err(); + insta::assert_snapshot!(error, @r#" invalid parameter name - Path: /{name/with/slash} + Route: /{name/with/slash} ^^^^^^^^^^^^^^^^^ tip: Parameter names must not contain the characters: ':', '*', '?', '{', '}', '/' - "###); + "#); - let error = Parts::new(b"/{name{with{brace}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name{with{brace}").unwrap_err(); + insta::assert_snapshot!(error, @r#" invalid parameter name - Path: /{name{with{brace} + Route: /{name{with{brace} ^^^^^^^^^^^^^^^^^ tip: Parameter names must not contain the characters: ':', '*', '?', '{', '}', '/' - "###); + "#); - let error = Parts::new(b"/{name{with}brace}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name{with}brace}").unwrap_err(); + insta::assert_snapshot!(error, @r#" invalid parameter name - Path: /{name{with}brace} + Route: /{name{with}brace} ^^^^^^^^^^^ tip: Parameter names must not contain the characters: ':', '*', '?', '{', '}', '/' - "###); + "#); - let error = Parts::new(b"/{name:with:colon}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"/{name:with:colon}").unwrap_err(); + insta::assert_snapshot!(error, @r#" invalid constraint name - Path: /{name:with:colon} + Route: /{name:with:colon} ^^^^^^^^^^^^^^^^^ tip: Constraint names must not contain the characters: ':', '*', '?', '{', '}', '/' - "###); + "#); } #[test] fn test_parts_escaped() { assert_eq!( - Parts::new(b"/{{name}}"), - Ok(Parts { - path: b"/{{name}}", - inner: vec![Part::Static { + ParsedRoute::new(b"/{{name}}"), + Ok(ParsedRoute { + route: b"/{{name}}", + parts: vec![RoutePart::Static { prefix: b"/{name}".to_vec() }] }) ); assert_eq!( - Parts::new(b"/name}}"), - Ok(Parts { - path: b"/name}}", - inner: vec![Part::Static { + ParsedRoute::new(b"/name}}"), + Ok(ParsedRoute { + route: b"/name}}", + parts: vec![RoutePart::Static { prefix: b"/name}".to_vec() }] }) ); assert_eq!( - Parts::new(b"/name{{"), - Ok(Parts { - path: b"/name{{", - inner: vec![Part::Static { + ParsedRoute::new(b"/name{{"), + Ok(ParsedRoute { + route: b"/name{{", + parts: vec![RoutePart::Static { prefix: b"/name{".to_vec() }] }) ); assert_eq!( - Parts::new(b"/{{{name}}}"), - Ok(Parts { - path: b"/{{{name}}}", - inner: vec![ - Part::Static { + ParsedRoute::new(b"/{{{name}}}"), + Ok(ParsedRoute { + route: b"/{{{name}}}", + parts: vec![ + RoutePart::Static { prefix: b"}".to_vec() }, - Part::Dynamic { + RoutePart::Dynamic { name: b"name".to_vec(), constraint: None }, - Part::Static { + RoutePart::Static { prefix: b"/{".to_vec() }, ] @@ -486,30 +491,30 @@ mod tests { ); assert_eq!( - Parts::new(b"/{{{{name}}}}"), - Ok(Parts { - path: b"/{{{{name}}}}", - inner: vec![Part::Static { + ParsedRoute::new(b"/{{{{name}}}}"), + Ok(ParsedRoute { + route: b"/{{{{name}}}}", + parts: vec![RoutePart::Static { prefix: b"/{{name}}".to_vec() }] }) ); assert_eq!( - Parts::new(b"{{}}"), - Ok(Parts { - path: b"{{}}", - inner: vec![Part::Static { + ParsedRoute::new(b"{{}}"), + Ok(ParsedRoute { + route: b"{{}}", + parts: vec![RoutePart::Static { prefix: b"{}".to_vec() }] }) ); assert_eq!( - Parts::new(b"{{:}}"), - Ok(Parts { - path: b"{{:}}", - inner: vec![Part::Static { + ParsedRoute::new(b"{{:}}"), + Ok(ParsedRoute { + route: b"{{:}}", + parts: vec![RoutePart::Static { prefix: b"{:}".to_vec() }] }) @@ -518,24 +523,24 @@ mod tests { #[test] fn test_parts_invalid_escaped() { - let error = Parts::new(b"{name}}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"{name}}").unwrap_err(); + insta::assert_snapshot!(error, @r#" unescaped brace - Path: {name}} + Route: {name}} ^ - tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path - "###); + tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route + "#); - let error = Parts::new(b"{{name}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + let error = ParsedRoute::new(b"{{name}").unwrap_err(); + insta::assert_snapshot!(error, @r#" unescaped brace - Path: {{name} + Route: {{name} ^ - tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the path - "###); + tip: Use '{{' and '}}' to represent literal '{' and '}' characters in the route + "#); } } diff --git a/src/path.rs b/src/path.rs index ed67505f..932bbfad 100644 --- a/src/path.rs +++ b/src/path.rs @@ -32,14 +32,14 @@ impl<'path> Path<'path> { /// ## Invalid /// /// ```rust - /// use wayfind::{Path, errors::PathError}; + /// use wayfind::{Path, errors::{EncodingError, PathError}}; /// /// let path = Path::new("/hello%GGworld").unwrap_err(); - /// assert_eq!(path, PathError::InvalidEncoding { + /// assert_eq!(path, PathError::EncodingError(EncodingError::InvalidEncoding { /// input: "/hello%GGworld".to_string(), /// position: 6, /// character: [b'%', b'G', b'G'], - /// }); + /// })); /// ``` pub fn new(path: &'path str) -> Result { let decoded = percent_decode(path.as_bytes())?; diff --git a/src/router.rs b/src/router.rs index 9ee256cc..a99b149a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,8 +1,9 @@ use crate::{ constraints::Constraint, + decode::percent_decode, errors::{ConstraintError, DeleteError, InsertError, SearchError}, node::{search::Match, Node, NodeData, NodeKind}, - parts::{Part, Parts}, + parser::{ParsedRoute, RoutePart}, path::Path, }; use std::{ @@ -143,23 +144,23 @@ impl Router { /// router.insert("/hello/{world}", 2).unwrap(); /// ``` pub fn insert(&mut self, route: &str, value: T) -> Result<(), InsertError> { - let route_path = Path::new(route)?; - if route.as_bytes() != route_path.decoded_bytes() { - return Err(InsertError::EncodedPath { + let decoded_route = percent_decode(route.as_bytes())?; + if route.as_bytes() != decoded_route.as_ref() { + return Err(InsertError::EncodedRoute { input: route.to_string(), - decoded: String::from_utf8_lossy(route_path.decoded_bytes()).to_string(), + decoded: String::from_utf8_lossy(&decoded_route).to_string(), }); } let route_arc = Arc::from(route); - let mut parts = Parts::new(route.as_bytes())?; + let mut parts = ParsedRoute::new(route.as_bytes())?; for part in &parts { - if let Part::Dynamic { + if let RoutePart::Dynamic { constraint: Some(name), .. } - | Part::Wildcard { + | RoutePart::Wildcard { constraint: Some(name), .. } = part @@ -199,7 +200,7 @@ impl Router { /// router.delete("/hello").unwrap(); /// ``` pub fn delete(&mut self, route: &str) -> Result<(), DeleteError> { - let mut parts = Parts::new(route.as_bytes())?; + let mut parts = ParsedRoute::new(route.as_bytes())?; self.root.delete(&mut parts) } @@ -211,7 +212,6 @@ impl Router { /// /// Returns a [`SearchError`] if the search resulted in invalid parameters. /// - /// /// # Examples /// /// ```rust diff --git a/tests/constraints.rs b/tests/constraints.rs index 37973295..e68e6c60 100644 --- a/tests/constraints.rs +++ b/tests/constraints.rs @@ -75,7 +75,7 @@ fn test_multiple_constraints() -> Result<(), Box> { router.insert("/profile/{username:length_3_to_10}.{ext:png_or_jpg}", 2)?; router.insert("/posts/{year:even_year}/{slug:valid_slug}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ p @@ -91,7 +91,7 @@ fn test_multiple_constraints() -> Result<(), Box> { ╰─ {name:length_3_to_10} ╰─ / ╰─ {id:year_1000_to_10000} ○ - "###); + "#); assert_router_matches!(router, { "/user/john/1234" => { @@ -164,13 +164,13 @@ fn test_unknown_constraints() { let mut router = Router::new(); let error = router.insert("/{name:unknown}", 0).unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" unknown constraint Constraint: unknown The router doesn't recognize this constraint - "###); + "#); } struct ConstraintA; @@ -197,7 +197,7 @@ fn constraint_duplicate_name_error() -> Result<(), Box> { router.constraint::()?; let error = router.constraint::().unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" duplicate constraint name The constraint name 'my_constraint' is already in use: @@ -209,7 +209,7 @@ fn constraint_duplicate_name_error() -> Result<(), Box> { try: - Check if you have accidentally added the same constraint twice - Ensure different constraints have different names - "###); + "#); Ok(()) } diff --git a/tests/encoding.rs b/tests/encoding.rs index 29a66408..6045ba74 100644 --- a/tests/encoding.rs +++ b/tests/encoding.rs @@ -87,12 +87,12 @@ fn percent_encoding_insert() { let mut router = Router::new(); let error = router.insert("/hello%20world", 0).unwrap_err(); - insta::assert_snapshot!(error, @r###" - encoded path + insta::assert_snapshot!(error, @r#" + encoded route Input: /hello%20world Decoded: /hello world - The router expects paths to be in their decoded form - "###); + The router expects routes to be in their decoded form + "#); } diff --git a/tests/matchit_delete.rs b/tests/matchit_delete.rs index 96a1aa7d..a2242143 100644 --- a/tests/matchit_delete.rs +++ b/tests/matchit_delete.rs @@ -24,7 +24,7 @@ fn normalized() -> Result<(), Box> { router.insert("/s/s/{s}/x", 12)?; router.insert("/s/s/{y}/d", 13)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ s ○ @@ -59,7 +59,7 @@ fn normalized() -> Result<(), Box> { │ ╰─ /baz ○ ╰─ {baz} ╰─ /bax ○ - "###); + "#); assert_eq!(router.delete("/x/{foo}/bar"), Ok(())); assert_eq!(router.delete("/x/{bar}/baz"), Ok(())); @@ -87,32 +87,32 @@ fn test() -> Result<(), Box> { router.insert("/home", 0)?; router.insert("/home/{id}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /home ○ ╰─ / ╰─ {id} ○ - "###); + "#); assert_eq!(router.delete("/home"), Ok(())); let error = router.delete("/home").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /home + Route: /home - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); assert_eq!(router.delete("/home/{id}"), Ok(())); let error = router.delete("/home/{id}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /home/{id} + Route: /home/{id} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); insta::assert_snapshot!(router, @"▽"); @@ -129,7 +129,7 @@ fn blog() -> Result<(), Box> { router.insert("/static/{*path}", 4)?; router.insert("/favicon.ico", 5)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ favicon.ico ○ @@ -144,7 +144,7 @@ fn blog() -> Result<(), Box> { ├─ static/ │ ╰─ {*path} ○ ╰─ {page} ○ - "###); + "#); assert_eq!(router.delete("/{page}"), Ok(())); assert_eq!(router.delete("/posts/{year}/{month}/{post}"), Ok(())); @@ -166,7 +166,7 @@ fn catchall() -> Result<(), Box> { router.insert("/bar/", 2)?; router.insert("/bar/{*catchall}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ bar ○ @@ -174,22 +174,22 @@ fn catchall() -> Result<(), Box> { │ ╰─ {*catchall} ○ ╰─ foo/ ╰─ {*catchall} ○ - "###); + "#); assert_eq!(router.delete("/foo/{*catchall}"), Ok(())); assert_eq!(router.delete("/bar/"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ bar ○ ╰─ / ╰─ {*catchall} ○ - "###); + "#); router.insert("/foo/{*catchall}", 4)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ bar ○ @@ -197,17 +197,17 @@ fn catchall() -> Result<(), Box> { │ ╰─ {*catchall} ○ ╰─ foo/ ╰─ {*catchall} ○ - "###); + "#); assert_eq!(router.delete("/bar/{*catchall}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ bar ○ ╰─ foo/ ╰─ {*catchall} ○ - "###); + "#); Ok(()) } @@ -225,7 +225,7 @@ fn overlapping_routes() -> Result<(), Box> { router.insert("/articles/{category}", 7)?; router.insert("/articles/{category}/{id}", 8)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -242,11 +242,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/home"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -263,11 +263,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/home", 9)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -284,11 +284,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/home/{id}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -303,11 +303,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/home/{id}", 10)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -324,11 +324,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/users"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -345,11 +345,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/users", 11)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -366,11 +366,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/users/{id}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -387,11 +387,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/users/{id}", 12)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -408,11 +408,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/users/{id}/posts"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -429,11 +429,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/users/{id}/posts", 13)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -450,11 +450,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/users/{id}/posts/{post_id}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -469,11 +469,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ / ╰─ {id} ○ ╰─ /posts ○ - "###); + "#); router.insert("/users/{id}/posts/{post_id}", 14)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -490,11 +490,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/articles"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles @@ -511,11 +511,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/articles", 15)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -532,11 +532,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/articles/{category}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -553,11 +553,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/articles/{category}", 16)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -574,11 +574,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); assert_eq!(router.delete("/articles/{category}/{id}"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -593,11 +593,11 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); router.insert("/articles/{category}/{id}", 17)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ articles ○ @@ -614,7 +614,7 @@ fn overlapping_routes() -> Result<(), Box> { ╰─ /posts ○ ╰─ / ╰─ {post_id} ○ - "###); + "#); Ok(()) } @@ -625,89 +625,89 @@ fn trailing_slash() -> Result<(), Box> { router.insert("/{home}/", 0)?; router.insert("/foo", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ foo ○ ╰─ {home} ╰─ / ○ - "###); + "#); let error = router.delete("/").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: / + Route: / - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ foo ○ ╰─ {home} ╰─ / ○ - "###); + "#); let error = router.delete("/{home}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /{home} + Route: /{home} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ foo ○ ╰─ {home} ╰─ / ○ - "###); + "#); let error = router.delete("/foo/").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /foo/ + Route: /foo/ - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ foo ○ ╰─ {home} ╰─ / ○ - "###); + "#); assert_eq!(router.delete("/foo"), Ok(())); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ {home} ╰─ / ○ - "###); + "#); let error = router.delete("/{home}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /{home} + Route: /{home} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ {home} ╰─ / ○ - "###); + "#); assert_eq!(router.delete("/{home}/"), Ok(())); @@ -721,10 +721,10 @@ fn remove_root() -> Result<(), Box> { let mut router = Router::new(); router.insert("/", 0)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ - "###); + "#); assert_eq!(router.delete("/"), Ok(())); @@ -742,7 +742,7 @@ fn check_escaped_params() -> Result<(), Box> { router.insert("/bar/{user}/{id}/baz", 3)?; router.insert("/baz/{product}/{user}/{id}", 4)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -760,18 +760,18 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); let error = router.delete("/foo/{a}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /foo/{a} + Route: /foo/{a} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -789,18 +789,18 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); let error = router.delete("/foo/{a}/bar").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /foo/{a}/bar + Route: /foo/{a}/bar - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -818,18 +818,18 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); let error = router.delete("/bar/{a}/{b}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /bar/{a}/{b} + Route: /bar/{a}/{b} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -847,18 +847,18 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); let error = router.delete("/bar/{a}/{b}/baz").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /bar/{a}/{b}/baz + Route: /bar/{a}/{b}/baz - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -876,18 +876,18 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); let error = router.delete("/baz/{a}/{b}/{c}").unwrap_err(); - insta::assert_snapshot!(error, @r###" + insta::assert_snapshot!(error, @r#" not found - Path: /baz/{a}/{b}/{c} + Route: /baz/{a}/{b}/{c} - The specified path does not exist in the router - "###); + The specified route does not exist in the router + "#); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ ba @@ -905,7 +905,7 @@ fn check_escaped_params() -> Result<(), Box> { ╰─ foo/ ╰─ {id} ○ ╰─ /bar ○ - "###); + "#); Ok(()) } diff --git a/tests/matchit_matches.rs b/tests/matchit_matches.rs index b6a70b48..13a2b48f 100644 --- a/tests/matchit_matches.rs +++ b/tests/matchit_matches.rs @@ -16,12 +16,12 @@ fn partial_overlap() -> Result<(), Box> { router.insert("/foo_bar", "Welcome!")?; router.insert("/foo/bar", "Welcome!")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo ├─ /bar ○ ╰─ _bar ○ - "###); + "#); assert_router_matches!(router, { "/foo/" => None @@ -31,11 +31,11 @@ fn partial_overlap() -> Result<(), Box> { router.insert("/foo", "Welcome!")?; router.insert("/foo/bar", "Welcome!")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo ○ ╰─ /bar ○ - "###); + "#); assert_router_matches!(router, { "/foo/" => None @@ -51,12 +51,12 @@ fn wildcard_overlap() -> Result<(), Box> { router.insert("/path/foo", "foo")?; router.insert("/path/{*rest}", "wildcard")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /path/ ├─ foo ○ ╰─ {*rest} ○ - "###); + "#); assert_router_matches!(router, { "/path/foo" => { @@ -83,13 +83,13 @@ fn wildcard_overlap() -> Result<(), Box> { router.insert("/path/foo/{arg}", "foo")?; router.insert("/path/{*rest}", "wildcard")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /path/ ├─ foo/ │ ╰─ {arg} ○ ╰─ {*rest} ○ - "###); + "#); assert_router_matches!(router, { "/path/foo/myarg" => { @@ -125,7 +125,7 @@ fn overlapping_param_backtracking() -> Result<(), Box> { router.insert("/{object}/{id}", "object with id")?; router.insert("/secret/{id}/path", "secret with id and path")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ secret/ @@ -134,7 +134,7 @@ fn overlapping_param_backtracking() -> Result<(), Box> { ╰─ {object} ╰─ / ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/secret/978/path" => { @@ -172,12 +172,12 @@ fn bare_catchall() -> Result<(), Box> { router.insert("{*foo}", 1)?; router.insert("foo/{*bar}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ├─ foo/ │ ╰─ {*bar} ○ ╰─ {*foo} ○ - "###); + "#); assert_router_matches!(router, { "x/y" => { @@ -231,7 +231,7 @@ fn normalized() -> Result<(), Box> { router.insert("/s/s/{s}/x", 13)?; router.insert("/s/s/{y}/d", 14)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ s ○ @@ -266,7 +266,7 @@ fn normalized() -> Result<(), Box> { │ ╰─ /baz ○ ╰─ {baz} ╰─ /bax ○ - "###); + "#); assert_router_matches!(router, { "/x/foo/bar" => { @@ -383,7 +383,7 @@ fn blog() -> Result<(), Box> { router.insert("/static/{*path}", 5)?; router.insert("/favicon.ico", 6)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ favicon.ico ○ @@ -398,7 +398,7 @@ fn blog() -> Result<(), Box> { ├─ static/ │ ╰─ {*path} ○ ╰─ {page} ○ - "###); + "#); assert_router_matches!(router, { "/about" => { @@ -459,7 +459,7 @@ fn double_overlap() -> Result<(), Box> { router.insert("/other/static/path", 6)?; router.insert("/other/long/static/path/", 7)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ other/ @@ -478,7 +478,7 @@ fn double_overlap() -> Result<(), Box> { ╰─ {object} ╰─ / ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/secret/978/path" => { @@ -538,7 +538,7 @@ fn catchall_off_by_one() -> Result<(), Box> { router.insert("/bar/", 3)?; router.insert("/bar/{*catchall}", 4)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ bar ○ @@ -546,7 +546,7 @@ fn catchall_off_by_one() -> Result<(), Box> { │ ╰─ {*catchall} ○ ╰─ foo/ ╰─ {*catchall} ○ - "###); + "#); assert_router_matches!(router, { "/foo" => None @@ -592,7 +592,7 @@ fn overlap() -> Result<(), Box> { router.insert("/xxx/{*x}", 9)?; router.insert("/xxx/", 10)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ ba @@ -605,7 +605,7 @@ fn overlap() -> Result<(), Box> { ├─ xxx/ ○ │ ╰─ {*x} ○ ╰─ {*bar} ○ - "###); + "#); assert_router_matches!(router, { "/foo" => { @@ -670,7 +670,7 @@ fn missing_trailing_slash_param() -> Result<(), Box> { router.insert("/foo/bar/baz", 2)?; router.insert("/foo/secret/978/", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo/ ├─ bar/baz ○ @@ -678,7 +678,7 @@ fn missing_trailing_slash_param() -> Result<(), Box> { ╰─ {object} ╰─ / ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/foo/secret/978/" => { @@ -705,7 +705,7 @@ fn extra_trailing_slash_param() -> Result<(), Box> { router.insert("/foo/bar/baz", 2)?; router.insert("/foo/secret/978", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo/ ├─ bar/baz ○ @@ -713,7 +713,7 @@ fn extra_trailing_slash_param() -> Result<(), Box> { ╰─ {object} ╰─ / ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/foo/secret/978/" => None @@ -733,13 +733,13 @@ fn missing_trailing_slash_catch_all() -> Result<(), Box> { router.insert("/foo/bar/baz", 2)?; router.insert("/foo/secret/978/", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo/ ├─ bar/baz ○ ├─ secret/978/ ○ ╰─ {*bar} ○ - "###); + "#); assert_router_matches!(router, { "/foo/secret/978" => { @@ -765,13 +765,13 @@ fn extra_trailing_slash_catch_all() -> Result<(), Box> { router.insert("/foo/bar/baz", 2)?; router.insert("/foo/secret/978", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo/ ├─ bar/baz ○ ├─ secret/978 ○ ╰─ {*bar} ○ - "###); + "#); assert_router_matches!(router, { "/foo/secret/978/" => { @@ -801,7 +801,7 @@ fn double_overlap_trailing_slash() -> Result<(), Box> { router.insert("/other/static/path", 6)?; router.insert("/other/long/static/path/", 7)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ other/ @@ -820,7 +820,7 @@ fn double_overlap_trailing_slash() -> Result<(), Box> { ╰─ {object} ╰─ / ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/secret/978/path/" => None @@ -858,14 +858,14 @@ fn trailing_slash_overlap() -> Result<(), Box> { router.insert("/foo/{x}/baz", 2)?; router.insert("/foo/bar/bar", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /foo/ ├─ bar/bar ○ ╰─ {x} ╰─ /baz ○ ╰─ / ○ - "###); + "#); assert_router_matches!(router, { "/foo/x/baz/" => { @@ -926,7 +926,7 @@ fn trailing_slash() -> Result<(), Box> { router.insert("/api/baz/foo/bar", 30)?; router.insert("/foo/{p}", 31)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ 0/ @@ -982,7 +982,7 @@ fn trailing_slash() -> Result<(), Box> { │ ╰─ /y ○ ╰─ y/ ○ ╰─ z ○ - "###); + "#); assert_router_matches!(router, { "/hi/" => None @@ -1031,7 +1031,7 @@ fn backtracking_trailing_slash() -> Result<(), Box> { router.insert("/a/{b}/{c}", 1)?; router.insert("/a/b/{c}/d/", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ b/ @@ -1040,7 +1040,7 @@ fn backtracking_trailing_slash() -> Result<(), Box> { ╰─ {b} ╰─ / ╰─ {c} ○ - "###); + "#); assert_router_matches!(router, { "/a/b/c/d" => None @@ -1056,13 +1056,13 @@ fn root_trailing_slash() -> Result<(), Box> { router.insert("/bar", 2)?; router.insert("/{baz}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ bar ○ ├─ foo ○ ╰─ {baz} ○ - "###); + "#); assert_router_matches!(router, { "/" => None @@ -1077,13 +1077,13 @@ fn catchall_overlap() -> Result<(), Box> { router.insert("/yyy/{*x}", 1)?; router.insert("/yyy{*x}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /yyy ├─ / │ ╰─ {*x} ○ ╰─ {*x} ○ - "###); + "#); assert_router_matches!(router, { "/yyy/y" => { @@ -1125,7 +1125,7 @@ fn escaped() -> Result<(), Box> { router.insert("/xxx/", 15)?; // router.insert("/xxx/{x}}{{}}}}{{}}{{{{}}y}", 16)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ baz/ @@ -1143,7 +1143,7 @@ fn escaped() -> Result<(), Box> { │ ╰─ x ○ ╰─ } ○ ╰─ y{ ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -1279,7 +1279,7 @@ fn basic() -> Result<(), Box> { router.insert("/sd;here", 20)?; router.insert("/sd=here", 21)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ├─ / │ ├─ a ○ @@ -1305,7 +1305,7 @@ fn basic() -> Result<(), Box> { │ ╰─ =here ○ ├─ ʯ ○ ╰─ β ○ - "###); + "#); assert_router_matches!(router, { "/a" => { @@ -1445,7 +1445,7 @@ fn wildcard() -> Result<(), Box> { router.insert("/get/abc/123abf/{param}", 55)?; router.insert("/get/abc/123abfff/{param}", 56)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ a @@ -1550,7 +1550,7 @@ fn wildcard() -> Result<(), Box> { ├─ gg ○ ╰─ {gg} ╰─ /hh ○ - "###); + "#); assert_router_matches!(router, { "/" => { diff --git a/tests/path_tree.rs b/tests/path_tree.rs index d06a3204..f5d66384 100644 --- a/tests/path_tree.rs +++ b/tests/path_tree.rs @@ -25,7 +25,7 @@ fn statics() -> Result<(), Box> { router.insert("/α", 10)?; router.insert("/β", 11)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ a ○ @@ -41,7 +41,7 @@ fn statics() -> Result<(), Box> { ╰─ � ├─ � ○ ╰─ � ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -122,7 +122,7 @@ fn wildcards() -> Result<(), Box> { router.insert("/info/{user}/public", 18)?; router.insert("/info/{user}/project/{project}", 19)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ cmd/ @@ -157,7 +157,7 @@ fn wildcards() -> Result<(), Box> { ├─ x ○ ╰─ {name} ○ ╰─ /about ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -242,11 +242,11 @@ fn single_named_parameter() -> Result<(), Box> { let mut router = Router::new(); router.insert("/users/{id}", 0)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /users/ ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/" => None @@ -304,7 +304,7 @@ fn static_and_named_parameter() -> Result<(), Box> { router.insert("/a/c/a", "/a/c/a")?; router.insert("/{id}/c/e", "/{id}/c/e")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ a/ @@ -314,7 +314,7 @@ fn static_and_named_parameter() -> Result<(), Box> { │ ╰─ d ○ ╰─ {id} ╰─ /c/e ○ - "###); + "#); assert_router_matches!(router, { "/" => None @@ -348,14 +348,14 @@ fn multi_named_parameters() -> Result<(), Box> { router.insert("/{lang}/{keyword}", true)?; router.insert("/{id}", true)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ {id} ○ ╰─ {lang} ╰─ / ╰─ {keyword} ○ - "###); + "#); assert_router_matches!(router, { "/" => None @@ -387,11 +387,11 @@ fn catch_all_parameter() -> Result<(), Box> { let mut router = Router::new(); router.insert("/src/{*filepath}", "* files")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /src/ ╰─ {*filepath} ○ - "###); + "#); assert_router_matches!(router, { "/src" => None @@ -417,11 +417,11 @@ fn catch_all_parameter() -> Result<(), Box> { router.insert("/src/", "dir")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /src/ ○ ╰─ {*filepath} ○ - "###); + "#); assert_router_matches!(router, { "/src/" => { @@ -521,7 +521,7 @@ fn static_and_catch_all_parameter() -> Result<(), Box> { router.insert("/a/c/a", "/a/c/a")?; router.insert("/a/{*c}", "/a/*c")?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ b/c ○ @@ -529,7 +529,7 @@ fn static_and_catch_all_parameter() -> Result<(), Box> { │ ├─ a ○ │ ╰─ d ○ ╰─ {*c} ○ - "###); + "#); assert_router_matches!(router, { "/" => None @@ -564,13 +564,13 @@ fn root_catch_all_parameter() -> Result<(), Box> { router.insert("/{*wildcard}", 2)?; router.insert("/users/{*wildcard}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ users/ │ ╰─ {*wildcard} ○ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -601,11 +601,11 @@ fn root_catch_all_parameter_1() -> Result<(), Box> { let mut router = Router::new(); router.insert("/{*wildcard}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { // NOTE: Different behaviour: path-tree would match "/{*wildcard}" @@ -628,11 +628,11 @@ fn root_catch_all_parameter_1() -> Result<(), Box> { router.insert("/", 0)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -651,14 +651,14 @@ fn test_named_routes_with_non_ascii_paths() -> Result<(), Box> { router.insert("/{*wildcard}", 1)?; router.insert("/matchme/{slug}/", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ matchme/ │ ╰─ {slug} │ ╰─ / ○ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/matchme/abc-s-def/" => { @@ -700,14 +700,14 @@ fn test_named_wildcard_collide() -> Result<(), Box> { router.insert("/git/{org}/{repo}", 1)?; router.insert("/git/{*wildcard}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /git/ ├─ {org} │ ╰─ / │ ╰─ {repo} ○ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/git/rust-lang/rust" => { @@ -735,13 +735,13 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/v1/{param}/{*wildcard}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/ ╰─ {param} ╰─ / ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/api/v1/entity" => None @@ -798,10 +798,10 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/v1/some/resource/name:customVerb", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /v1/some/resource/name:customVerb ○ - "###); + "#); assert_router_matches!(router, { "/v1/some/resource/name:customVerb" => { @@ -814,12 +814,12 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/v1/some/resource/{name}:customVerb", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /v1/some/resource/ ╰─ {name} ╰─ :customVerb ○ - "###); + "#); assert_router_matches!(router, { "/v1/some/resource/test:customVerb" => { @@ -835,11 +835,11 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/v1/{*wildcard}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/api/v1" => None @@ -871,11 +871,11 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/v1/{param}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/ ╰─ {param} ○ - "###); + "#); assert_router_matches!(router, { "/api/v1" => None @@ -899,7 +899,7 @@ fn match_params() -> Result<(), Box> { router.insert("/api/v1/{param}_{param2}", 5)?; router.insert("/api/v1/{param}:{param2}", 6)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/ ╰─ {param} @@ -915,7 +915,7 @@ fn match_params() -> Result<(), Box> { │ ╰─ {param2} ○ ╰─ ~ ╰─ {param2} ○ - "###); + "#); assert_router_matches!(router, { "/api/v1/entity-entity2" => { @@ -981,10 +981,10 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/v1/const", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/const ○ - "###); + "#); assert_router_matches!(router, { "/api/v1/const" => { @@ -1001,12 +1001,12 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/{param}/fixedEnd", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/ ╰─ {param} ╰─ /fixedEnd ○ - "###); + "#); assert_router_matches!(router, { "/api/abc/fixedEnd" => { @@ -1022,7 +1022,7 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/shop/product/:{filter}/color:{color}/size:{size}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /shop/product/: ╰─ {filter} @@ -1030,7 +1030,7 @@ fn match_params() -> Result<(), Box> { ╰─ {color} ╰─ /size: ╰─ {size} ○ - "###); + "#); assert_router_matches!(router, { "/shop/product/:test/color:blue/size:xs" => { @@ -1048,12 +1048,12 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/test{sign}{param}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /test ╰─ {sign} ╰─ {param} ○ - "###); + "#); assert_router_matches!(router, { "/test-" => None @@ -1069,7 +1069,7 @@ fn match_params() -> Result<(), Box> { router.insert("/_{name}", 6)?; router.insert("/{name}", 7)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ - @@ -1085,7 +1085,7 @@ fn match_params() -> Result<(), Box> { ├─ ~ │ ╰─ {name} ○ ╰─ {name} ○ - "###); + "#); assert_router_matches!(router, { "/name:john" => { @@ -1142,13 +1142,13 @@ fn match_params() -> Result<(), Box> { let mut router = Router::new(); router.insert("/api/v1/{param}/abc/{*wildcard}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /api/v1/ ╰─ {param} ╰─ /abc/ ╰─ {*wildcard} ○ - "###); + "#); assert_router_matches!(router, { "/api/v1/well/abc/wildcard" => { @@ -1275,7 +1275,7 @@ fn basic() -> Result<(), Box> { router.insert("/{org}/{repo}/{*path}", 12)?; router.insert("/api/{*plus}", 13)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ api/ @@ -1313,7 +1313,7 @@ fn basic() -> Result<(), Box> { ╰─ {user} ○ ╰─ / ╰─ {repo} ○ - "###); + "#); assert_router_matches!(router, { "/" => { @@ -1551,7 +1551,7 @@ fn github_tree() -> Result<(), Box> { 3002, )?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ○ ├─ 404 ○ @@ -1726,7 +1726,7 @@ fn github_tree() -> Result<(), Box> { │ ╰─ / │ ╰─ {id} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/rust-lang/rust" => { @@ -1801,11 +1801,11 @@ fn test_dots_no_ext() -> Result<(), Box> { let mut router = Router::new(); router.insert("/{name}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ {name} ○ - "###); + "#); assert_router_matches!(router, { "/abc.xyz.123" => { @@ -1855,13 +1855,13 @@ fn test_dots_ext_no_qualifier() -> Result<(), Box> { router.insert("/{name}.js", 2)?; router.insert("/{name}.js.gz", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ╰─ {name} ╰─ .js ○ ╰─ .gz ○ - "###); + "#); assert_router_matches!(router, { "/node.js" => { diff --git a/tests/poem.rs b/tests/poem.rs index be389120..ada74d30 100644 --- a/tests/poem.rs +++ b/tests/poem.rs @@ -35,12 +35,12 @@ fn test_insert_static_child_1() -> Result<(), Box> { router.insert("/abcdef", 2)?; router.insert("/abcdefgh", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /abc ○ ╰─ def ○ ╰─ gh ○ - "###); + "#); Ok(()) } @@ -53,7 +53,7 @@ fn test_insert_static_child_2() -> Result<(), Box> { router.insert("/ab1256", 3)?; router.insert("/ab125678", 4)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /ab ├─ 12 @@ -61,7 +61,7 @@ fn test_insert_static_child_2() -> Result<(), Box> { │ ╰─ 56 ○ │ ╰─ 78 ○ ╰─ cd ○ - "###); + "#); Ok(()) } @@ -72,11 +72,11 @@ fn test_insert_static_child_3() -> Result<(), Box> { router.insert("/abc", 1)?; router.insert("/ab", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /ab ○ ╰─ c ○ - "###); + "#); Ok(()) } @@ -88,14 +88,14 @@ fn test_insert_param_child() -> Result<(), Box> { router.insert("/abc/{p1}/p2", 2)?; router.insert("/abc/{p1}/{p3}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /abc/ ╰─ {p1} ○ ╰─ / ├─ p2 ○ ╰─ {p3} ○ - "###); + "#); Ok(()) } @@ -106,13 +106,13 @@ fn test_catch_all_child_1() -> Result<(), Box> { router.insert("/abc/{*p1}", 1)?; router.insert("/ab/de", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /ab ├─ /de ○ ╰─ c/ ╰─ {*p1} ○ - "###); + "#); Ok(()) } @@ -122,10 +122,10 @@ fn test_catch_all_child_2() -> Result<(), Box> { let mut router = Router::new(); router.insert("{*p1}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ {*p1} ○ - "###); + "#); Ok(()) } @@ -139,14 +139,14 @@ fn test_insert_regex_child() -> Result<(), Box> { router.insert("/abc/{name:digit_string}/def", 1)?; router.insert("/abc/def/{name:digit_string}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /abc/ ├─ def/ │ ╰─ {name:digit_string} ○ ╰─ {name:digit_string} ╰─ /def ○ - "###); + "#); Ok(()) } @@ -159,11 +159,11 @@ fn test_add_result() -> Result<(), Box> { router.insert("/a/b", 1)?; let error = router.insert("/a/b", 2).unwrap_err(); - insta::assert_snapshot!(error, @r###" - duplicate path + insta::assert_snapshot!(error, @r#" + duplicate route - Path: /a/b - "###); + Route: /a/b + "#); router.insert("/a/b/{p}/d", 1)?; router.insert("/a/b/c/d", 2)?; @@ -171,11 +171,11 @@ fn test_add_result() -> Result<(), Box> { router.insert("/a/{*p}", 1)?; let error = router.insert("/a/{*p}", 2).unwrap_err(); - insta::assert_snapshot!(error, @r###" - duplicate path + insta::assert_snapshot!(error, @r#" + duplicate route - Path: /a/{*p} - "###); + Route: /a/{*p} + "#); router.insert("/k/h/{name:digit_string}", 1)?; @@ -183,7 +183,7 @@ fn test_add_result() -> Result<(), Box> { // assert!(router.insert("/a/b/{*p}", 1).is_ok()); // assert!(router.insert("/a/b/{*p2}", 2).is_err()); - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ a/ @@ -197,7 +197,7 @@ fn test_add_result() -> Result<(), Box> { │ ╰─ {*p} ○ ╰─ k/h/ ╰─ {name:digit_string} ○ - "###); + "#); Ok(()) } @@ -221,7 +221,7 @@ fn test_matches() -> Result<(), Box> { router.insert("/kcd/{p1:digit_string}", 11)?; router.insert("/{package}/-/{package_tgz:ends_with_tgz}", 12)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ a @@ -249,7 +249,7 @@ fn test_matches() -> Result<(), Box> { │ ╰─ /-/ │ ╰─ {package_tgz:ends_with_tgz} ○ ╰─ {*p1} ○ - "###); + "#); assert_router_matches!(router, { "/ab/def" => { @@ -339,12 +339,12 @@ fn test_match_priority() -> Result<(), Box> { router.insert("/a/bc", 1)?; router.insert("/a/{*path}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ bc ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/123" => { @@ -358,13 +358,13 @@ fn test_match_priority() -> Result<(), Box> { router.insert("/a/{id}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ bc ○ ├─ {id} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/123" => { @@ -379,14 +379,14 @@ fn test_match_priority() -> Result<(), Box> { router.constraint::()?; router.insert("/a/{id:digit_string}", 4)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ bc ○ ├─ {id:digit_string} ○ ├─ {id} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/123" => { @@ -400,7 +400,7 @@ fn test_match_priority() -> Result<(), Box> { router.insert("/a/123", 5)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ 123 ○ @@ -408,7 +408,7 @@ fn test_match_priority() -> Result<(), Box> { ├─ {id:digit_string} ○ ├─ {id} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/123" => { @@ -425,11 +425,11 @@ fn test_catch_all_priority_in_sub_path() -> Result<(), Box> { let mut router = Router::new(); router.insert("/a/{*path}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/b/c/123" => { @@ -443,13 +443,13 @@ fn test_catch_all_priority_in_sub_path() -> Result<(), Box> { router.insert("/a/b/{*path}", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ b/ │ ╰─ {*path} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/b/c/123" => { @@ -463,7 +463,7 @@ fn test_catch_all_priority_in_sub_path() -> Result<(), Box> { router.insert("/a/b/c/{*path}", 3)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ├─ b/ @@ -471,7 +471,7 @@ fn test_catch_all_priority_in_sub_path() -> Result<(), Box> { │ │ ╰─ {*path} ○ │ ╰─ {*path} ○ ╰─ {*path} ○ - "###); + "#); assert_router_matches!(router, { "/a/b/c/123" => { @@ -492,14 +492,14 @@ fn test_issue_275() -> Result<(), Box> { router.insert("/{id1}/a", 1)?; router.insert("/{id2}/b", 2)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ / ├─ {id1} │ ╰─ /a ○ ╰─ {id2} ╰─ /b ○ - "###); + "#); assert_router_matches!(router, { "/abc/a" => { @@ -526,11 +526,11 @@ fn test_percent_decoded() -> Result<(), Box> { let mut router = Router::new(); router.insert("/a/{id}", 1)?; - insta::assert_snapshot!(router, @r###" + insta::assert_snapshot!(router, @r#" ▽ ╰─ /a/ ╰─ {id} ○ - "###); + "#); assert_router_matches!(router, { "/a/abc" => {