1 extern crate proc_macro2;
2 extern crate quote;
3 extern crate syn;
4 
5 mod features;
6 
7 use proc_macro2::{TokenStream, TokenTree};
8 use quote::ToTokens;
9 use std::str::FromStr;
10 use syn::{FloatSuffix, IntSuffix, Lit};
11 
lit(s: &str) -> Lit12 fn lit(s: &str) -> Lit {
13     match TokenStream::from_str(s)
14         .unwrap()
15         .into_iter()
16         .next()
17         .unwrap()
18     {
19         TokenTree::Literal(lit) => Lit::new(lit),
20         _ => panic!(),
21     }
22 }
23 
24 #[test]
strings()25 fn strings() {
26     fn test_string(s: &str, value: &str) {
27         match lit(s) {
28             Lit::Str(lit) => {
29                 assert_eq!(lit.value(), value);
30                 let again = lit.into_token_stream().to_string();
31                 if again != s {
32                     test_string(&again, value);
33                 }
34             }
35             wrong => panic!("{:?}", wrong),
36         }
37     }
38 
39     test_string("\"a\"", "a");
40     test_string("\"\\n\"", "\n");
41     test_string("\"\\r\"", "\r");
42     test_string("\"\\t\"", "\t");
43     test_string("\"��\"", "��"); // NOTE: This is an emoji
44     test_string("\"\\\"\"", "\"");
45     test_string("\"'\"", "'");
46     test_string("\"\"", "");
47     test_string("\"\\u{1F415}\"", "\u{1F415}");
48     test_string(
49         "\"contains\nnewlines\\\nescaped newlines\"",
50         "contains\nnewlinesescaped newlines",
51     );
52     test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
53 }
54 
55 #[test]
byte_strings()56 fn byte_strings() {
57     fn test_byte_string(s: &str, value: &[u8]) {
58         match lit(s) {
59             Lit::ByteStr(lit) => {
60                 assert_eq!(lit.value(), value);
61                 let again = lit.into_token_stream().to_string();
62                 if again != s {
63                     test_byte_string(&again, value);
64                 }
65             }
66             wrong => panic!("{:?}", wrong),
67         }
68     }
69 
70     test_byte_string("b\"a\"", b"a");
71     test_byte_string("b\"\\n\"", b"\n");
72     test_byte_string("b\"\\r\"", b"\r");
73     test_byte_string("b\"\\t\"", b"\t");
74     test_byte_string("b\"\\\"\"", b"\"");
75     test_byte_string("b\"'\"", b"'");
76     test_byte_string("b\"\"", b"");
77     test_byte_string(
78         "b\"contains\nnewlines\\\nescaped newlines\"",
79         b"contains\nnewlinesescaped newlines",
80     );
81     test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
82 }
83 
84 #[test]
bytes()85 fn bytes() {
86     fn test_byte(s: &str, value: u8) {
87         match lit(s) {
88             Lit::Byte(lit) => {
89                 assert_eq!(lit.value(), value);
90                 let again = lit.into_token_stream().to_string();
91                 assert_eq!(again, s);
92             }
93             wrong => panic!("{:?}", wrong),
94         }
95     }
96 
97     test_byte("b'a'", b'a');
98     test_byte("b'\\n'", b'\n');
99     test_byte("b'\\r'", b'\r');
100     test_byte("b'\\t'", b'\t');
101     test_byte("b'\\''", b'\'');
102     test_byte("b'\"'", b'"');
103 }
104 
105 #[test]
chars()106 fn chars() {
107     fn test_char(s: &str, value: char) {
108         match lit(s) {
109             Lit::Char(lit) => {
110                 assert_eq!(lit.value(), value);
111                 let again = lit.into_token_stream().to_string();
112                 if again != s {
113                     test_char(&again, value);
114                 }
115             }
116             wrong => panic!("{:?}", wrong),
117         }
118     }
119 
120     test_char("'a'", 'a');
121     test_char("'\\n'", '\n');
122     test_char("'\\r'", '\r');
123     test_char("'\\t'", '\t');
124     test_char("'��'", '��'); // NOTE: This is an emoji
125     test_char("'\\''", '\'');
126     test_char("'\"'", '"');
127     test_char("'\\u{1F415}'", '\u{1F415}');
128 }
129 
130 #[test]
ints()131 fn ints() {
132     fn test_int(s: &str, value: u64, suffix: IntSuffix) {
133         match lit(s) {
134             Lit::Int(lit) => {
135                 assert_eq!(lit.value(), value);
136                 assert_eq!(lit.suffix(), suffix);
137                 let again = lit.into_token_stream().to_string();
138                 if again != s {
139                     test_int(&again, value, suffix);
140                 }
141             }
142             wrong => panic!("{:?}", wrong),
143         }
144     }
145 
146     use syn::IntSuffix::*;
147     test_int("5", 5, None);
148     test_int("5u32", 5, U32);
149     test_int("5_0", 50, None);
150     test_int("5_____0_____", 50, None);
151     test_int("0x7f", 127, None);
152     test_int("0x7F", 127, None);
153     test_int("0b1001", 9, None);
154     test_int("0o73", 59, None);
155     test_int("0x7Fu8", 127, U8);
156     test_int("0b1001i8", 9, I8);
157     test_int("0o73u32", 59, U32);
158     test_int("0x__7___f_", 127, None);
159     test_int("0x__7___F_", 127, None);
160     test_int("0b_1_0__01", 9, None);
161     test_int("0o_7__3", 59, None);
162     test_int("0x_7F__u8", 127, U8);
163     test_int("0b__10__0_1i8", 9, I8);
164     test_int("0o__7__________________3u32", 59, U32);
165 }
166 
167 #[test]
floats()168 fn floats() {
169     #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
170     fn test_float(s: &str, value: f64, suffix: FloatSuffix) {
171         match lit(s) {
172             Lit::Float(lit) => {
173                 assert_eq!(lit.value(), value);
174                 assert_eq!(lit.suffix(), suffix);
175                 let again = lit.into_token_stream().to_string();
176                 if again != s {
177                     test_float(&again, value, suffix);
178                 }
179             }
180             wrong => panic!("{:?}", wrong),
181         }
182     }
183 
184     use syn::FloatSuffix::*;
185     test_float("5.5", 5.5, None);
186     test_float("5.5E12", 5.5e12, None);
187     test_float("5.5e12", 5.5e12, None);
188     test_float("1.0__3e-12", 1.03e-12, None);
189     test_float("1.03e+12", 1.03e12, None);
190 }
191