]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | use super::*; |
2 | ||
3 | use expect_test::{expect, Expect}; | |
4 | ||
5e7ed085 | 5 | fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) { |
1b1a35ee XL |
6 | let s = &format!("r{}", s); |
7 | let mut cursor = Cursor::new(s); | |
8 | cursor.bump(); | |
9 | let (n_hashes, err) = cursor.raw_double_quoted_string(0); | |
10 | assert_eq!(n_hashes, expected_hashes); | |
11 | assert_eq!(err, expected_err); | |
12 | } | |
13 | ||
14 | #[test] | |
15 | fn test_naked_raw_str() { | |
16 | check_raw_str(r#""abc""#, 0, None); | |
17 | } | |
18 | ||
19 | #[test] | |
20 | fn test_raw_no_start() { | |
21 | check_raw_str(r##""abc"#"##, 0, None); | |
22 | } | |
23 | ||
24 | #[test] | |
25 | fn test_too_many_terminators() { | |
26 | // this error is handled in the parser later | |
27 | check_raw_str(r###"#"abc"##"###, 1, None); | |
28 | } | |
29 | ||
30 | #[test] | |
31 | fn test_unterminated() { | |
32 | check_raw_str( | |
33 | r#"#"abc"#, | |
34 | 1, | |
35 | Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), | |
36 | ); | |
37 | check_raw_str( | |
38 | r###"##"abc"#"###, | |
39 | 2, | |
40 | Some(RawStrError::NoTerminator { | |
41 | expected: 2, | |
42 | found: 1, | |
43 | possible_terminator_offset: Some(7), | |
44 | }), | |
45 | ); | |
46 | // We're looking for "# not just any # | |
47 | check_raw_str( | |
48 | r###"##"abc#"###, | |
49 | 2, | |
50 | Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), | |
51 | ) | |
52 | } | |
53 | ||
54 | #[test] | |
55 | fn test_invalid_start() { | |
56 | check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); | |
57 | } | |
58 | ||
59 | #[test] | |
60 | fn test_unterminated_no_pound() { | |
61 | // https://github.com/rust-lang/rust/issues/70677 | |
62 | check_raw_str( | |
63 | r#"""#, | |
64 | 0, | |
65 | Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), | |
66 | ); | |
67 | } | |
68 | ||
5e7ed085 FG |
69 | #[test] |
70 | fn test_too_many_hashes() { | |
71 | let max_count = u8::MAX; | |
72 | let mut hashes: String = "#".repeat(max_count.into()); | |
73 | ||
74 | // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string. | |
75 | check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' })); | |
76 | ||
77 | // One more hash sign (256 = 2^8) becomes too many. | |
78 | hashes.push('#'); | |
79 | check_raw_str( | |
80 | &hashes, | |
81 | 0, | |
82 | Some(RawStrError::TooManyDelimiters { found: usize::from(max_count) + 1 }), | |
83 | ); | |
84 | } | |
85 | ||
1b1a35ee XL |
86 | #[test] |
87 | fn test_valid_shebang() { | |
88 | // https://github.com/rust-lang/rust/issues/70528 | |
89 | let input = "#!/usr/bin/rustrun\nlet x = 5;"; | |
90 | assert_eq!(strip_shebang(input), Some(18)); | |
91 | } | |
92 | ||
93 | #[test] | |
94 | fn test_invalid_shebang_valid_rust_syntax() { | |
95 | // https://github.com/rust-lang/rust/issues/70528 | |
96 | let input = "#! [bad_attribute]"; | |
97 | assert_eq!(strip_shebang(input), None); | |
98 | } | |
99 | ||
100 | #[test] | |
101 | fn test_shebang_second_line() { | |
102 | // Because shebangs are interpreted by the kernel, they must be on the first line | |
103 | let input = "\n#!/bin/bash"; | |
104 | assert_eq!(strip_shebang(input), None); | |
105 | } | |
106 | ||
107 | #[test] | |
108 | fn test_shebang_space() { | |
109 | let input = "#! /bin/bash"; | |
110 | assert_eq!(strip_shebang(input), Some(input.len())); | |
111 | } | |
112 | ||
113 | #[test] | |
114 | fn test_shebang_empty_shebang() { | |
115 | let input = "#! \n[attribute(foo)]"; | |
116 | assert_eq!(strip_shebang(input), None); | |
117 | } | |
118 | ||
119 | #[test] | |
120 | fn test_invalid_shebang_comment() { | |
121 | let input = "#!//bin/ami/a/comment\n["; | |
122 | assert_eq!(strip_shebang(input), None) | |
123 | } | |
124 | ||
125 | #[test] | |
126 | fn test_invalid_shebang_another_comment() { | |
127 | let input = "#!/*bin/ami/a/comment*/\n[attribute"; | |
128 | assert_eq!(strip_shebang(input), None) | |
129 | } | |
130 | ||
131 | #[test] | |
132 | fn test_shebang_valid_rust_after() { | |
133 | let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; | |
134 | assert_eq!(strip_shebang(input), Some(23)) | |
135 | } | |
136 | ||
137 | #[test] | |
138 | fn test_shebang_followed_by_attrib() { | |
139 | let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; | |
140 | assert_eq!(strip_shebang(input), Some(19)); | |
141 | } | |
142 | ||
143 | fn check_lexing(src: &str, expect: Expect) { | |
144 | let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); | |
145 | expect.assert_eq(&actual) | |
146 | } | |
147 | ||
148 | #[test] | |
149 | fn smoke_test() { | |
150 | check_lexing( | |
151 | "/* my source file */ fn main() { println!(\"zebra\"); }\n", | |
152 | expect![[r#" | |
153 | Token { kind: BlockComment { doc_style: None, terminated: true }, len: 20 } | |
154 | Token { kind: Whitespace, len: 1 } | |
155 | Token { kind: Ident, len: 2 } | |
156 | Token { kind: Whitespace, len: 1 } | |
157 | Token { kind: Ident, len: 4 } | |
158 | Token { kind: OpenParen, len: 1 } | |
159 | Token { kind: CloseParen, len: 1 } | |
160 | Token { kind: Whitespace, len: 1 } | |
161 | Token { kind: OpenBrace, len: 1 } | |
162 | Token { kind: Whitespace, len: 1 } | |
163 | Token { kind: Ident, len: 7 } | |
164 | Token { kind: Bang, len: 1 } | |
165 | Token { kind: OpenParen, len: 1 } | |
166 | Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 7 }, len: 7 } | |
167 | Token { kind: CloseParen, len: 1 } | |
168 | Token { kind: Semi, len: 1 } | |
169 | Token { kind: Whitespace, len: 1 } | |
170 | Token { kind: CloseBrace, len: 1 } | |
171 | Token { kind: Whitespace, len: 1 } | |
172 | "#]], | |
173 | ) | |
174 | } | |
175 | ||
176 | #[test] | |
177 | fn comment_flavors() { | |
178 | check_lexing( | |
179 | r" | |
180 | // line | |
181 | //// line as well | |
182 | /// outer doc line | |
183 | //! inner doc line | |
184 | /* block */ | |
185 | /**/ | |
186 | /*** also block */ | |
187 | /** outer doc block */ | |
188 | /*! inner doc block */ | |
189 | ", | |
190 | expect![[r#" | |
191 | Token { kind: Whitespace, len: 1 } | |
192 | Token { kind: LineComment { doc_style: None }, len: 7 } | |
193 | Token { kind: Whitespace, len: 1 } | |
194 | Token { kind: LineComment { doc_style: None }, len: 17 } | |
195 | Token { kind: Whitespace, len: 1 } | |
196 | Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } | |
197 | Token { kind: Whitespace, len: 1 } | |
198 | Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } | |
199 | Token { kind: Whitespace, len: 1 } | |
200 | Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } | |
201 | Token { kind: Whitespace, len: 1 } | |
202 | Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } | |
203 | Token { kind: Whitespace, len: 1 } | |
204 | Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } | |
205 | Token { kind: Whitespace, len: 1 } | |
206 | Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } | |
207 | Token { kind: Whitespace, len: 1 } | |
208 | Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } | |
209 | Token { kind: Whitespace, len: 1 } | |
210 | "#]], | |
211 | ) | |
212 | } | |
213 | ||
214 | #[test] | |
215 | fn nested_block_comments() { | |
216 | check_lexing( | |
217 | "/* /* */ */'a'", | |
218 | expect![[r#" | |
219 | Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } | |
220 | Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } | |
221 | "#]], | |
222 | ) | |
223 | } | |
224 | ||
225 | #[test] | |
226 | fn characters() { | |
227 | check_lexing( | |
228 | "'a' ' ' '\\n'", | |
229 | expect![[r#" | |
230 | Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } | |
231 | Token { kind: Whitespace, len: 1 } | |
232 | Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } | |
233 | Token { kind: Whitespace, len: 1 } | |
234 | Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 4 }, len: 4 } | |
235 | "#]], | |
236 | ); | |
237 | } | |
238 | ||
239 | #[test] | |
240 | fn lifetime() { | |
241 | check_lexing( | |
242 | "'abc", | |
243 | expect![[r#" | |
244 | Token { kind: Lifetime { starts_with_number: false }, len: 4 } | |
245 | "#]], | |
246 | ); | |
247 | } | |
248 | ||
249 | #[test] | |
250 | fn raw_string() { | |
251 | check_lexing( | |
252 | "r###\"\"#a\\b\x00c\"\"###", | |
253 | expect![[r#" | |
254 | Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 } | |
255 | "#]], | |
256 | ) | |
257 | } | |
258 | ||
259 | #[test] | |
260 | fn literal_suffixes() { | |
261 | check_lexing( | |
262 | r####" | |
263 | 'a' | |
264 | b'a' | |
265 | "a" | |
266 | b"a" | |
267 | 1234 | |
268 | 0b101 | |
269 | 0xABC | |
270 | 1.0 | |
271 | 1.0e10 | |
272 | 2us | |
273 | r###"raw"###suffix | |
274 | br###"raw"###suffix | |
275 | "####, | |
276 | expect![[r#" | |
277 | Token { kind: Whitespace, len: 1 } | |
278 | Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } | |
279 | Token { kind: Whitespace, len: 1 } | |
280 | Token { kind: Literal { kind: Byte { terminated: true }, suffix_start: 4 }, len: 4 } | |
281 | Token { kind: Whitespace, len: 1 } | |
282 | Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 3 }, len: 3 } | |
283 | Token { kind: Whitespace, len: 1 } | |
284 | Token { kind: Literal { kind: ByteStr { terminated: true }, suffix_start: 4 }, len: 4 } | |
285 | Token { kind: Whitespace, len: 1 } | |
286 | Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 4 }, len: 4 } | |
287 | Token { kind: Whitespace, len: 1 } | |
288 | Token { kind: Literal { kind: Int { base: Binary, empty_int: false }, suffix_start: 5 }, len: 5 } | |
289 | Token { kind: Whitespace, len: 1 } | |
290 | Token { kind: Literal { kind: Int { base: Hexadecimal, empty_int: false }, suffix_start: 5 }, len: 5 } | |
291 | Token { kind: Whitespace, len: 1 } | |
292 | Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 3 }, len: 3 } | |
293 | Token { kind: Whitespace, len: 1 } | |
294 | Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 6 }, len: 6 } | |
295 | Token { kind: Whitespace, len: 1 } | |
296 | Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 } | |
297 | Token { kind: Whitespace, len: 1 } | |
298 | Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 } | |
299 | Token { kind: Whitespace, len: 1 } | |
300 | Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 } | |
301 | Token { kind: Whitespace, len: 1 } | |
302 | "#]], | |
303 | ) | |
304 | } |