| use crate::{Literal, test_util::{assert_parse_ok_eq, assert_roundtrip}}; |
| use super::CharLit; |
| |
| // ===== Utility functions ======================================================================= |
| |
| macro_rules! check { |
| ($lit:literal) => { check!($lit, stringify!($lit), "") }; |
| ($lit:literal, $input:expr, $suffix:literal) => { |
| let input = $input; |
| let expected = CharLit { |
| raw: input, |
| start_suffix: input.len() - $suffix.len(), |
| value: $lit, |
| }; |
| |
| assert_parse_ok_eq(input, CharLit::parse(input), expected.clone(), "CharLit::parse"); |
| assert_parse_ok_eq(input, Literal::parse(input), Literal::Char(expected), "Literal::parse"); |
| let lit = CharLit::parse(input).unwrap(); |
| assert_eq!(lit.value(), $lit); |
| assert_eq!(lit.suffix(), $suffix); |
| assert_roundtrip(expected.to_owned(), input); |
| }; |
| } |
| |
| |
| // ===== Actual tests ============================================================================ |
| |
| #[test] |
| fn alphanumeric() { |
| check!('a'); |
| check!('b'); |
| check!('y'); |
| check!('z'); |
| check!('A'); |
| check!('B'); |
| check!('Y'); |
| check!('Z'); |
| |
| check!('0'); |
| check!('1'); |
| check!('8'); |
| check!('9'); |
| } |
| |
| #[test] |
| fn special_chars() { |
| check!(' '); |
| check!('!'); |
| check!('"'); |
| check!('#'); |
| check!('$'); |
| check!('%'); |
| check!('&'); |
| check!('('); |
| check!(')'); |
| check!('*'); |
| check!('+'); |
| check!(','); |
| check!('-'); |
| check!('.'); |
| check!('/'); |
| check!(':'); |
| check!(';'); |
| check!('<'); |
| check!('='); |
| check!('>'); |
| check!('?'); |
| check!('@'); |
| check!('['); |
| check!(']'); |
| check!('^'); |
| check!('_'); |
| check!('`'); |
| check!('{'); |
| check!('|'); |
| check!('}'); |
| check!('~'); |
| } |
| |
| #[test] |
| fn unicode() { |
| check!('న'); |
| check!('犬'); |
| check!('🦊'); |
| } |
| |
| #[test] |
| fn quote_escapes() { |
| check!('\''); |
| check!('\"'); |
| } |
| |
| #[test] |
| fn ascii_escapes() { |
| check!('\n'); |
| check!('\r'); |
| check!('\t'); |
| check!('\\'); |
| check!('\0'); |
| |
| check!('\x00'); |
| check!('\x01'); |
| check!('\x0c'); |
| check!('\x0D'); |
| check!('\x13'); |
| check!('\x30'); |
| check!('\x30'); |
| check!('\x4B'); |
| check!('\x6b'); |
| check!('\x7F'); |
| check!('\x7f'); |
| } |
| |
| #[test] |
| fn unicode_escapes() { |
| check!('\u{0}'); |
| check!('\u{00}'); |
| check!('\u{b}'); |
| check!('\u{B}'); |
| check!('\u{7e}'); |
| check!('\u{E4}'); |
| check!('\u{e4}'); |
| check!('\u{fc}'); |
| check!('\u{Fc}'); |
| check!('\u{fC}'); |
| check!('\u{FC}'); |
| check!('\u{b10}'); |
| check!('\u{B10}'); |
| check!('\u{0b10}'); |
| check!('\u{2764}'); |
| check!('\u{1f602}'); |
| check!('\u{1F602}'); |
| |
| check!('\u{0}'); |
| check!('\u{0__}'); |
| check!('\u{3_b}'); |
| check!('\u{1_F_6_0_2}'); |
| check!('\u{1_F6_02_____}'); |
| } |
| |
| #[test] |
| fn suffixes() { |
| check!('a', r##"'a'peter"##, "peter"); |
| check!('#', r##"'#'peter"##, "peter"); |
| check!('\n', r##"'\n'peter"##, "peter"); |
| check!('\'', r##"'\''peter"##, "peter"); |
| check!('\"', r##"'\"'peter"##, "peter"); |
| } |
| |
| #[test] |
| fn invald_ascii_escapes() { |
| assert_err!(CharLit, r"'\x80'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\x81'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\x8a'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\x8F'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xa0'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xB0'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xc3'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xDf'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xff'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xfF'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xFf'", NonAsciiXEscape, 1..5); |
| assert_err!(CharLit, r"'\xFF'", NonAsciiXEscape, 1..5); |
| } |
| |
| #[test] |
| fn invalid_escapes() { |
| assert_err!(CharLit, r"'\a'", UnknownEscape, 1..3); |
| assert_err!(CharLit, r"'\y'", UnknownEscape, 1..3); |
| assert_err!(CharLit, r"'\", UnterminatedEscape, 1); |
| assert_err!(CharLit, r"'\x'", UnterminatedEscape, 1..4); |
| assert_err!(CharLit, r"'\x1'", InvalidXEscape, 1..5); |
| assert_err!(CharLit, r"'\xaj'", InvalidXEscape, 1..5); |
| assert_err!(CharLit, r"'\xjb'", InvalidXEscape, 1..5); |
| } |
| |
| #[test] |
| fn invalid_unicode_escapes() { |
| assert_err!(CharLit, r"'\u'", UnicodeEscapeWithoutBrace, 1..3); |
| assert_err!(CharLit, r"'\u '", UnicodeEscapeWithoutBrace, 1..3); |
| assert_err!(CharLit, r"'\u3'", UnicodeEscapeWithoutBrace, 1..3); |
| |
| assert_err!(CharLit, r"'\u{'", UnterminatedUnicodeEscape, 1..5); |
| assert_err!(CharLit, r"'\u{12'", UnterminatedUnicodeEscape, 1..7); |
| assert_err!(CharLit, r"'\u{a0b'", UnterminatedUnicodeEscape, 1..8); |
| assert_err!(CharLit, r"'\u{a0_b '", UnterminatedUnicodeEscape, 1..11); |
| |
| assert_err!(CharLit, r"'\u{_}'", InvalidStartOfUnicodeEscape, 4); |
| assert_err!(CharLit, r"'\u{_5f}'", InvalidStartOfUnicodeEscape, 4); |
| |
| assert_err!(CharLit, r"'\u{x}'", NonHexDigitInUnicodeEscape, 4); |
| assert_err!(CharLit, r"'\u{0x}'", NonHexDigitInUnicodeEscape, 5); |
| assert_err!(CharLit, r"'\u{3bx}'", NonHexDigitInUnicodeEscape, 6); |
| assert_err!(CharLit, r"'\u{3b_x}'", NonHexDigitInUnicodeEscape, 7); |
| assert_err!(CharLit, r"'\u{4x_}'", NonHexDigitInUnicodeEscape, 5); |
| |
| assert_err!(CharLit, r"'\u{1234567}'", TooManyDigitInUnicodeEscape, 10); |
| assert_err!(CharLit, r"'\u{1234567}'", TooManyDigitInUnicodeEscape, 10); |
| assert_err!(CharLit, r"'\u{1_23_4_56_7}'", TooManyDigitInUnicodeEscape, 14); |
| assert_err!(CharLit, r"'\u{abcdef123}'", TooManyDigitInUnicodeEscape, 10); |
| |
| assert_err!(CharLit, r"'\u{110000}'", InvalidUnicodeEscapeChar, 1..10); |
| } |
| |
| #[test] |
| fn parse_err() { |
| assert_err!(CharLit, r"''", EmptyCharLiteral, None); |
| assert_err!(CharLit, r"' ''", UnexpectedChar, 3); |
| |
| assert_err!(CharLit, r"'", UnterminatedCharLiteral, None); |
| assert_err!(CharLit, r"'a", UnterminatedCharLiteral, None); |
| assert_err!(CharLit, r"'\n", UnterminatedCharLiteral, None); |
| assert_err!(CharLit, r"'\x35", UnterminatedCharLiteral, None); |
| |
| assert_err!(CharLit, r"'ab'", OverlongCharLiteral, None); |
| assert_err!(CharLit, r"'a _'", OverlongCharLiteral, None); |
| assert_err!(CharLit, r"'\n3'", OverlongCharLiteral, None); |
| |
| assert_err!(CharLit, r"", Empty, None); |
| |
| assert_err!(CharLit, r"'''", UnescapedSingleQuote, 1); |
| assert_err!(CharLit, r"''''", UnescapedSingleQuote, 1); |
| |
| assert_err!(CharLit, "'\n'", UnescapedSpecialWhitespace, 1); |
| assert_err!(CharLit, "'\t'", UnescapedSpecialWhitespace, 1); |
| assert_err!(CharLit, "'\r'", UnescapedSpecialWhitespace, 1); |
| } |