| use Piece::*; |
| |
| use super::*; |
| |
| #[track_caller] |
| fn same(fmt: &'static str, p: &[Piece<'static>]) { |
| let parser = Parser::new(fmt, None, None, false, ParseMode::Format); |
| assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p); |
| } |
| |
| fn fmtdflt() -> FormatSpec<'static> { |
| return FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }; |
| } |
| |
| fn musterr(s: &str) { |
| let mut p = Parser::new(s, None, None, false, ParseMode::Format); |
| p.next(); |
| assert!(!p.errors.is_empty()); |
| } |
| |
| #[test] |
| fn simple() { |
| same("asdf", &[Lit("asdf")]); |
| same("a{{b", &[Lit("a"), Lit("{b")]); |
| same("a}}b", &[Lit("a"), Lit("}b")]); |
| same("a}}", &[Lit("a"), Lit("}")]); |
| same("}}", &[Lit("}")]); |
| same("\\}}", &[Lit("\\"), Lit("}")]); |
| } |
| #[test] |
| fn invalid01() { |
| musterr("{") |
| } |
| #[test] |
| fn invalid02() { |
| musterr("}") |
| } |
| #[test] |
| fn invalid04() { |
| musterr("{3a}") |
| } |
| #[test] |
| fn invalid05() { |
| musterr("{:|}") |
| } |
| #[test] |
| fn invalid06() { |
| musterr("{:>>>}") |
| } |
| |
| #[test] |
| fn invalid_position() { |
| musterr("{18446744073709551616}"); |
| } |
| |
| #[test] |
| fn invalid_width() { |
| musterr("{:18446744073709551616}"); |
| } |
| |
| #[test] |
| fn invalid_precision() { |
| musterr("{:.18446744073709551616}"); |
| } |
| |
| #[test] |
| fn format_empty() { |
| same( |
| "{}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: fmtdflt(), |
| }))], |
| ); |
| } |
| #[test] |
| fn format_tab_empty() { |
| let fmt_pre = r###""\t{}""###; |
| let fmt = "\t{}"; |
| let parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); |
| assert_eq!( |
| parser.collect::<Vec<Piece<'static>>>(), |
| &[ |
| Lit("\t"), |
| NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 4..4, |
| format: fmtdflt(), |
| })) |
| ], |
| ); |
| } |
| #[test] |
| fn format_open_brace_tab() { |
| let fmt_pre = r###""{\t""###; |
| let fmt = "{\t"; |
| let mut parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); |
| let _ = parser.by_ref().collect::<Vec<Piece<'static>>>(); |
| assert_eq!(parser.errors[0].span, 4..4); |
| } |
| #[test] |
| fn format_position() { |
| same( |
| "{3}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: fmtdflt(), |
| }))], |
| ); |
| } |
| #[test] |
| fn format_position_nothing_else() { |
| same( |
| "{3:}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: fmtdflt(), |
| }))], |
| ); |
| } |
| #[test] |
| fn format_named() { |
| same( |
| "{name}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentNamed("name"), |
| position_span: 2..6, |
| format: fmtdflt(), |
| }))], |
| ) |
| } |
| #[test] |
| fn format_named_space_nothing() { |
| same( |
| "{name} {}", |
| &[ |
| NextArgument(Box::new(Argument { |
| position: ArgumentNamed("name"), |
| position_span: 2..6, |
| format: fmtdflt(), |
| })), |
| Lit(" "), |
| NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 9..9, |
| format: fmtdflt(), |
| })), |
| ], |
| ) |
| } |
| #[test] |
| fn format_raw() { |
| let snippet = r###"r#"assertion `left {op} right` failed"#"###.into(); |
| let source = r#"assertion `left {op} right` failed"#; |
| |
| let parser = Parser::new(source, Some(1), Some(snippet), true, ParseMode::Format); |
| let expected = &[ |
| Lit("assertion `left "), |
| NextArgument(Box::new(Argument { |
| position: ArgumentNamed("op"), |
| position_span: 20..22, |
| format: fmtdflt(), |
| })), |
| Lit(" right` failed"), |
| ]; |
| assert_eq!(parser.collect::<Vec<Piece<'static>>>(), expected); |
| } |
| #[test] |
| fn format_type() { |
| same( |
| "{3:x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| } |
| #[test] |
| fn format_align_fill() { |
| same( |
| "{3:>}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignRight, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{3:0<}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: FormatSpec { |
| fill: Some('0'), |
| fill_span: Some(4..5), |
| align: AlignLeft, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{3:*<abcd}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 2..3, |
| format: FormatSpec { |
| fill: Some('*'), |
| fill_span: Some(4..5), |
| align: AlignLeft, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "abcd", |
| ty_span: Some(6..10), |
| }, |
| }))], |
| ); |
| } |
| #[test] |
| fn format_counts() { |
| same( |
| "{:10x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| precision_span: None, |
| width: CountIs(10), |
| width_span: Some(3..5), |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:10$.10x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIs(10), |
| precision_span: Some(6..9), |
| width: CountIsParam(10), |
| width_span: Some(3..6), |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{1:0$.10x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentIs(1), |
| position_span: 2..3, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIs(10), |
| precision_span: Some(6..9), |
| width: CountIsParam(0), |
| width_span: Some(4..6), |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:.*x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(1), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIsStar(0), |
| precision_span: Some(3..5), |
| width: CountImplied, |
| width_span: None, |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:.10$x}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIsParam(10), |
| width: CountImplied, |
| precision_span: Some(3..7), |
| width_span: None, |
| ty: "x", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:a$.b$?}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIsName("b", 6..7), |
| precision_span: Some(5..8), |
| width: CountIsName("a", 3..4), |
| width_span: Some(3..5), |
| ty: "?", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:.4}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountIs(4), |
| precision_span: Some(3..5), |
| width: CountImplied, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }, |
| }))], |
| ) |
| } |
| #[test] |
| fn format_flags() { |
| same( |
| "{:-}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: Some(Sign::Minus), |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| same( |
| "{:+#}", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..2, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: Some(Sign::Plus), |
| alternate: true, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "", |
| ty_span: None, |
| }, |
| }))], |
| ); |
| } |
| #[test] |
| fn format_mixture() { |
| same( |
| "abcd {3:x} efg", |
| &[ |
| Lit("abcd "), |
| NextArgument(Box::new(Argument { |
| position: ArgumentIs(3), |
| position_span: 7..8, |
| format: FormatSpec { |
| fill: None, |
| fill_span: None, |
| align: AlignUnknown, |
| sign: None, |
| alternate: false, |
| zero_pad: false, |
| debug_hex: None, |
| precision: CountImplied, |
| width: CountImplied, |
| precision_span: None, |
| width_span: None, |
| ty: "x", |
| ty_span: None, |
| }, |
| })), |
| Lit(" efg"), |
| ], |
| ); |
| } |
| #[test] |
| fn format_whitespace() { |
| same( |
| "{ }", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..3, |
| format: fmtdflt(), |
| }))], |
| ); |
| same( |
| "{ }", |
| &[NextArgument(Box::new(Argument { |
| position: ArgumentImplicitlyIs(0), |
| position_span: 2..4, |
| format: fmtdflt(), |
| }))], |
| ); |
| } |
| #[test] |
| fn asm_linespans() { |
| let asm_pre = r###"r" |
| .intel_syntax noprefix |
| nop""###; |
| let asm = r" |
| .intel_syntax noprefix |
| nop"; |
| let mut parser = Parser::new(asm, Some(0), Some(asm_pre.into()), false, ParseMode::InlineAsm); |
| assert!(parser.is_source_literal); |
| assert_eq!( |
| parser.by_ref().collect::<Vec<Piece<'static>>>(), |
| &[Lit("\n .intel_syntax noprefix\n nop")] |
| ); |
| assert_eq!(parser.line_spans, &[2..2, 11..33, 42..45]); |
| } |
| #[test] |
| fn asm_concat() { |
| let asm_pre = r###"concat!("invalid", "_", "instruction")"###; |
| let asm = "invalid_instruction"; |
| let mut parser = Parser::new(asm, None, Some(asm_pre.into()), false, ParseMode::InlineAsm); |
| assert!(!parser.is_source_literal); |
| assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]); |
| assert_eq!(parser.line_spans, &[]); |
| } |
| |
| #[test] |
| fn diagnostic_format_flags() { |
| let lit = "{thing:blah}"; |
| let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); |
| assert!(!parser.is_source_literal); |
| |
| let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; |
| |
| assert_eq!( |
| **arg, |
| Argument { |
| position: ArgumentNamed("thing"), |
| position_span: 2..7, |
| format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() }, |
| } |
| ); |
| |
| assert_eq!(parser.line_spans, &[]); |
| assert!(parser.errors.is_empty()); |
| } |
| |
| #[test] |
| fn diagnostic_format_mod() { |
| let lit = "{thing:+}"; |
| let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); |
| assert!(!parser.is_source_literal); |
| |
| let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; |
| |
| assert_eq!( |
| **arg, |
| Argument { |
| position: ArgumentNamed("thing"), |
| position_span: 2..7, |
| format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() }, |
| } |
| ); |
| |
| assert_eq!(parser.line_spans, &[]); |
| assert!(parser.errors.is_empty()); |
| } |