Skip to content

Commit ec83506

Browse files
Merge #27
27: Support single delimiter version of `expect![]` r=matklad a=ecstatic-morse Pairs of braces are no longer necessary that we parse string literals. Allow users to omit the inner `[]`. This represents a significant change to the public API, and you might have other tooling that depends on the paired braces, so I understand if you don't want it upstream. I think it reads a bit nicer, though. Depends on #26 (although it could be separated), and is similarly lacking in integration tests for now. Co-authored-by: Dylan MacKenzie <ecstaticmorse@gmail.com>
2 parents 1b035b3 + d7c381e commit ec83506

1 file changed

Lines changed: 50 additions & 23 deletions

File tree

src/lib.rs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
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
//!
@@ -25,7 +25,7 @@
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::{
152152
use once_cell::sync::{Lazy, OnceCell};
153153

154154
const 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]
177178
macro_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)]
534548
struct 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 {
702724
mod 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\nworld\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\nworld\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

Comments
 (0)