1414//! use expect_test::expect;
1515//!
1616//! let actual = 2 + 2;
17- //! let expected = expect![[ "5"]];
17+ //! let expected = expect!["5"]; // or expect![[ "5"]]
1818//! expected.assert_eq(&actual.to_string())
1919//! ```
2020//!
2525//! ```no_run
2626//! # use expect_test::expect;
2727//! let actual = 2 + 2;
28- //! let expected = expect![[ "4"] ];
28+ //! let expected = expect!["4"];
2929//! expected.assert_eq(&actual.to_string())
3030//! ```
3131//!
@@ -152,7 +152,7 @@ use std::{
152152use once_cell:: sync:: { Lazy , OnceCell } ;
153153
154154const HELP : & str = "
155- You can update all `expect![[]] ` tests by running:
155+ You can update all `expect!` tests by running:
156156
157157 env UPDATE_EXPECT=1 cargo test
158158
@@ -170,11 +170,13 @@ fn update_expect() -> bool {
170170/// expect![["
171171/// Foo { value: 92 }
172172/// "]];
173+ /// expect![r#"{"Foo": 92}"#];
173174/// ```
174175///
175176/// Leading indentation is stripped.
176177#[ macro_export]
177178macro_rules! expect {
179+ [ $data: literal] => { $crate:: expect![ [ $data] ] } ;
178180 [ [ $data: literal] ] => { $crate:: Expect {
179181 position: $crate:: Position {
180182 file: file!( ) ,
@@ -184,6 +186,7 @@ macro_rules! expect {
184186 data: $data,
185187 indent: true ,
186188 } } ;
189+ [ ] => { $crate:: expect![ [ "" ] ] } ;
187190 [ [ ] ] => { $crate:: expect![ [ "" ] ] } ;
188191}
189192
@@ -305,18 +308,20 @@ impl Expect {
305308 if i == self . position . line as usize - 1 {
306309 // `column` points to the first character of the macro invocation:
307310 //
308- // expect![[ ... ]]
309- // ^
311+ // expect![[r#""#]] expect![""]
312+ // ^ ^ ^ ^
313+ // column offset offset
310314 //
311315 // Seek past the exclam, then skip any whitespace and
312- // delimiters to get to our argument.
316+ // the macro delimiter to get to our argument.
313317 let byte_offset = line
314318 . char_indices ( )
315319 . skip ( ( self . position . column - 1 ) . try_into ( ) . unwrap ( ) )
316320 . skip_while ( |& ( _, c) | c != '!' )
317- . skip ( 1 )
321+ . skip ( 1 ) // !
322+ . skip_while ( |& ( _, c) | c. is_whitespace ( ) )
323+ . skip ( 1 ) // [({
318324 . skip_while ( |& ( _, c) | c. is_whitespace ( ) )
319- . skip_while ( |& ( _, c) | matches ! ( c, '[' | '(' | '{' ) )
320325 . next ( )
321326 . expect ( "Failed to parse macro invocation" )
322327 . 0 ;
@@ -336,21 +341,30 @@ impl Expect {
336341 let literal_start = literal_start + ( lit_to_eof. len ( ) - lit_to_eof_trimmed. len ( ) ) ;
337342
338343 let literal_len =
339- locate_end ( lit_to_eof_trimmed) . expect ( "Couldn't find matching `]]` for `expect![[ `." ) ;
344+ locate_end ( lit_to_eof_trimmed) . expect ( "Couldn't find closing delimiter for `expect!`." ) ;
340345 let literal_range = literal_start..literal_start + literal_len;
341346 Location { line_indent, literal_range }
342347 }
343348}
344349
345- fn locate_end ( lit_to_eof : & str ) -> Option < usize > {
346- assert ! ( lit_to_eof. chars( ) . next( ) . map_or( true , |c| !c. is_whitespace( ) ) ) ;
350+ fn locate_end ( arg_start_to_eof : & str ) -> Option < usize > {
351+ match arg_start_to_eof. chars ( ) . next ( ) ? {
352+ c if c. is_whitespace ( ) => panic ! ( "skip whitespace before calling `locate_end`" ) ,
353+
354+ // expect![[]]
355+ '[' => {
356+ let str_start_to_eof = arg_start_to_eof[ 1 ..] . trim_start ( ) ;
357+ let str_len = find_str_lit_len ( str_start_to_eof) ?;
358+ let str_end_to_eof = & str_start_to_eof[ str_len..] ;
359+ let closing_brace_offset = str_end_to_eof. find ( ']' ) ?;
360+ Some ( ( arg_start_to_eof. len ( ) - str_end_to_eof. len ( ) ) + closing_brace_offset + 1 )
361+ }
362+
363+ // expect![] | expect!{} | expect!()
364+ ']' | '}' | ')' => Some ( 0 ) ,
347365
348- if lit_to_eof. starts_with ( "]]" ) {
349- // expect![[ ]]
350- Some ( 0 )
351- } else {
352- // expect![["foo"]]
353- find_str_lit_len ( lit_to_eof)
366+ // expect!["..."] | expect![r#"..."#]
367+ _ => find_str_lit_len ( arg_start_to_eof) ,
354368 }
355369}
356370
@@ -533,6 +547,8 @@ impl FileRuntime {
533547#[ derive( Debug ) ]
534548struct Location {
535549 line_indent : usize ,
550+
551+ /// The byte range of the argument to `expect!`, including the inner `[]` if it exists.
536552 literal_range : Range < usize > ,
537553}
538554
@@ -590,6 +606,9 @@ fn format_patch(desired_indent: Option<usize>, patch: &str) -> String {
590606 let is_multiline = patch. contains ( '\n' ) ;
591607
592608 let mut buf = String :: new ( ) ;
609+ if matches ! ( lit_kind, StrLitKind :: Raw ( _) ) {
610+ buf. push ( '[' ) ;
611+ }
593612 lit_kind. write_start ( & mut buf) . unwrap ( ) ;
594613 if is_multiline {
595614 buf. push ( '\n' ) ;
@@ -611,6 +630,9 @@ fn format_patch(desired_indent: Option<usize>, patch: &str) -> String {
611630 }
612631 }
613632 lit_kind. write_end ( & mut buf) . unwrap ( ) ;
633+ if matches ! ( lit_kind, StrLitKind :: Raw ( _) ) {
634+ buf. push ( ']' ) ;
635+ }
614636 buf
615637}
616638
@@ -702,28 +724,33 @@ fn format_chunks(chunks: Vec<dissimilar::Chunk>) -> String {
702724mod tests {
703725 use super :: * ;
704726
727+ #[ test]
728+ fn test_trivial_assert ( ) {
729+ expect ! [ "5" ] . assert_eq ( "5" ) ;
730+ }
731+
705732 #[ test]
706733 fn test_format_patch ( ) {
707734 let patch = format_patch ( None , "hello\n world\n " ) ;
708735 expect ! [ [ r##"
709- r#"
736+ [ r#"
710737 hello
711738 world
712- "#"## ] ]
739+ "#] "## ] ]
713740 . assert_eq ( & patch) ;
714741
715742 let patch = format_patch ( None , r"hello\tworld" ) ;
716- expect ! [ [ r##"r#"hello\tworld"#"## ] ] . assert_eq ( & patch) ;
743+ expect ! [ [ r##"[ r#"hello\tworld"#] "## ] ] . assert_eq ( & patch) ;
717744
718745 let patch = format_patch ( None , "{\" foo\" : 42}" ) ;
719- expect ! [ [ r##"r#"{"foo": 42}"#"## ] ] . assert_eq ( & patch) ;
746+ expect ! [ [ r##"[ r#"{"foo": 42}"#] "## ] ] . assert_eq ( & patch) ;
720747
721748 let patch = format_patch ( Some ( 0 ) , "hello\n world\n " ) ;
722749 expect ! [ [ r##"
723- r#"
750+ [ r#"
724751 hello
725752 world
726- "#"## ] ]
753+ "#] "## ] ]
727754 . assert_eq ( & patch) ;
728755
729756 let patch = format_patch ( Some ( 4 ) , "single line" ) ;
0 commit comments