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::>>(), 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::>>(), &[ 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::>>(); 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::>>(), 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:*>>(), &[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::>>(), &[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::>>() 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::>>() 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()); }