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