xref: /third_party/rust/crates/syn/tests/test_lit.rs (revision fad3a1d3)
1#![allow(
2    clippy::float_cmp,
3    clippy::non_ascii_literal,
4    clippy::single_match_else,
5    clippy::uninlined_format_args
6)]
7
8#[macro_use]
9mod macros;
10
11use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
12use quote::ToTokens;
13use std::str::FromStr;
14use syn::{Lit, LitFloat, LitInt, LitStr};
15
16fn lit(s: &str) -> Lit {
17    let mut tokens = TokenStream::from_str(s).unwrap().into_iter();
18    match tokens.next().unwrap() {
19        TokenTree::Literal(lit) => {
20            assert!(tokens.next().is_none());
21            Lit::new(lit)
22        }
23        wrong => panic!("{:?}", wrong),
24    }
25}
26
27#[test]
28fn strings() {
29    fn test_string(s: &str, value: &str) {
30        match lit(s) {
31            Lit::Str(lit) => {
32                assert_eq!(lit.value(), value);
33                let again = lit.into_token_stream().to_string();
34                if again != s {
35                    test_string(&again, value);
36                }
37            }
38            wrong => panic!("{:?}", wrong),
39        }
40    }
41
42    test_string("\"a\"", "a");
43    test_string("\"\\n\"", "\n");
44    test_string("\"\\r\"", "\r");
45    test_string("\"\\t\"", "\t");
46    test_string("\"�\"", "�"); // NOTE: This is an emoji
47    test_string("\"\\\"\"", "\"");
48    test_string("\"'\"", "'");
49    test_string("\"\"", "");
50    test_string("\"\\u{1F415}\"", "\u{1F415}");
51    test_string("\"\\u{1_2__3_}\"", "\u{123}");
52    test_string(
53        "\"contains\nnewlines\\\nescaped newlines\"",
54        "contains\nnewlinesescaped newlines",
55    );
56    test_string(
57        "\"escaped newline\\\n \x0C unsupported whitespace\"",
58        "escaped newline\x0C unsupported whitespace",
59    );
60    test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
61    test_string("\"...\"q", "...");
62    test_string("r\"...\"q", "...");
63    test_string("r##\"...\"##q", "...");
64}
65
66#[test]
67fn byte_strings() {
68    fn test_byte_string(s: &str, value: &[u8]) {
69        match lit(s) {
70            Lit::ByteStr(lit) => {
71                assert_eq!(lit.value(), value);
72                let again = lit.into_token_stream().to_string();
73                if again != s {
74                    test_byte_string(&again, value);
75                }
76            }
77            wrong => panic!("{:?}", wrong),
78        }
79    }
80
81    test_byte_string("b\"a\"", b"a");
82    test_byte_string("b\"\\n\"", b"\n");
83    test_byte_string("b\"\\r\"", b"\r");
84    test_byte_string("b\"\\t\"", b"\t");
85    test_byte_string("b\"\\\"\"", b"\"");
86    test_byte_string("b\"'\"", b"'");
87    test_byte_string("b\"\"", b"");
88    test_byte_string(
89        "b\"contains\nnewlines\\\nescaped newlines\"",
90        b"contains\nnewlinesescaped newlines",
91    );
92    test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
93    test_byte_string("b\"...\"q", b"...");
94    test_byte_string("br\"...\"q", b"...");
95    test_byte_string("br##\"...\"##q", b"...");
96}
97
98#[test]
99fn bytes() {
100    fn test_byte(s: &str, value: u8) {
101        match lit(s) {
102            Lit::Byte(lit) => {
103                assert_eq!(lit.value(), value);
104                let again = lit.into_token_stream().to_string();
105                assert_eq!(again, s);
106            }
107            wrong => panic!("{:?}", wrong),
108        }
109    }
110
111    test_byte("b'a'", b'a');
112    test_byte("b'\\n'", b'\n');
113    test_byte("b'\\r'", b'\r');
114    test_byte("b'\\t'", b'\t');
115    test_byte("b'\\''", b'\'');
116    test_byte("b'\"'", b'"');
117    test_byte("b'a'q", b'a');
118}
119
120#[test]
121fn chars() {
122    fn test_char(s: &str, value: char) {
123        match lit(s) {
124            Lit::Char(lit) => {
125                assert_eq!(lit.value(), value);
126                let again = lit.into_token_stream().to_string();
127                if again != s {
128                    test_char(&again, value);
129                }
130            }
131            wrong => panic!("{:?}", wrong),
132        }
133    }
134
135    test_char("'a'", 'a');
136    test_char("'\\n'", '\n');
137    test_char("'\\r'", '\r');
138    test_char("'\\t'", '\t');
139    test_char("'�'", '�'); // NOTE: This is an emoji
140    test_char("'\\''", '\'');
141    test_char("'\"'", '"');
142    test_char("'\\u{1F415}'", '\u{1F415}');
143    test_char("'a'q", 'a');
144}
145
146#[test]
147fn ints() {
148    fn test_int(s: &str, value: u64, suffix: &str) {
149        match lit(s) {
150            Lit::Int(lit) => {
151                assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
152                assert_eq!(lit.suffix(), suffix);
153                let again = lit.into_token_stream().to_string();
154                if again != s {
155                    test_int(&again, value, suffix);
156                }
157            }
158            wrong => panic!("{:?}", wrong),
159        }
160    }
161
162    test_int("5", 5, "");
163    test_int("5u32", 5, "u32");
164    test_int("0E", 0, "E");
165    test_int("0ECMA", 0, "ECMA");
166    test_int("0o0A", 0, "A");
167    test_int("5_0", 50, "");
168    test_int("5_____0_____", 50, "");
169    test_int("0x7f", 127, "");
170    test_int("0x7F", 127, "");
171    test_int("0b1001", 9, "");
172    test_int("0o73", 59, "");
173    test_int("0x7Fu8", 127, "u8");
174    test_int("0b1001i8", 9, "i8");
175    test_int("0o73u32", 59, "u32");
176    test_int("0x__7___f_", 127, "");
177    test_int("0x__7___F_", 127, "");
178    test_int("0b_1_0__01", 9, "");
179    test_int("0o_7__3", 59, "");
180    test_int("0x_7F__u8", 127, "u8");
181    test_int("0b__10__0_1i8", 9, "i8");
182    test_int("0o__7__________________3u32", 59, "u32");
183    test_int("0e1\u{5c5}", 0, "e1\u{5c5}");
184}
185
186#[test]
187fn floats() {
188    fn test_float(s: &str, value: f64, suffix: &str) {
189        match lit(s) {
190            Lit::Float(lit) => {
191                assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
192                assert_eq!(lit.suffix(), suffix);
193                let again = lit.into_token_stream().to_string();
194                if again != s {
195                    test_float(&again, value, suffix);
196                }
197            }
198            wrong => panic!("{:?}", wrong),
199        }
200    }
201
202    test_float("5.5", 5.5, "");
203    test_float("5.5E12", 5.5e12, "");
204    test_float("5.5e12", 5.5e12, "");
205    test_float("1.0__3e-12", 1.03e-12, "");
206    test_float("1.03e+12", 1.03e12, "");
207    test_float("9e99e99", 9e99, "e99");
208    test_float("1e_0", 1.0, "");
209    test_float("0.0ECMA", 0.0, "ECMA");
210}
211
212#[test]
213fn negative() {
214    let span = Span::call_site();
215    assert_eq!("-1", LitInt::new("-1", span).to_string());
216    assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
217    assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
218    assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
219    assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
220    assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
221    assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
222    assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
223}
224
225#[test]
226fn suffix() {
227    fn get_suffix(token: &str) -> String {
228        let lit = syn::parse_str::<Lit>(token).unwrap();
229        match lit {
230            Lit::Str(lit) => lit.suffix().to_owned(),
231            Lit::ByteStr(lit) => lit.suffix().to_owned(),
232            Lit::Byte(lit) => lit.suffix().to_owned(),
233            Lit::Char(lit) => lit.suffix().to_owned(),
234            Lit::Int(lit) => lit.suffix().to_owned(),
235            Lit::Float(lit) => lit.suffix().to_owned(),
236            _ => unimplemented!(),
237        }
238    }
239
240    assert_eq!(get_suffix("\"\"s"), "s");
241    assert_eq!(get_suffix("r\"\"r"), "r");
242    assert_eq!(get_suffix("b\"\"b"), "b");
243    assert_eq!(get_suffix("br\"\"br"), "br");
244    assert_eq!(get_suffix("r#\"\"#r"), "r");
245    assert_eq!(get_suffix("'c'c"), "c");
246    assert_eq!(get_suffix("b'b'b"), "b");
247    assert_eq!(get_suffix("1i32"), "i32");
248    assert_eq!(get_suffix("1_i32"), "i32");
249    assert_eq!(get_suffix("1.0f32"), "f32");
250    assert_eq!(get_suffix("1.0_f32"), "f32");
251}
252
253#[test]
254fn test_deep_group_empty() {
255    let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
256        Delimiter::None,
257        TokenStream::from_iter(vec![TokenTree::Group(Group::new(
258            Delimiter::None,
259            TokenStream::from_iter(vec![TokenTree::Literal(Literal::string("hi"))]),
260        ))]),
261    ))]);
262
263    snapshot!(tokens as Lit, @r#""hi""# );
264}
265
266#[test]
267fn test_error() {
268    let err = syn::parse_str::<LitStr>("...").unwrap_err();
269    assert_eq!("expected string literal", err.to_string());
270
271    let err = syn::parse_str::<LitStr>("5").unwrap_err();
272    assert_eq!("expected string literal", err.to_string());
273}
274