lib.rs (8751B)
1 #![forbid(unsafe_code)] 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 extern crate tempfile; 7 8 pub mod preferences; 9 pub mod prefreader; 10 pub mod profile; 11 12 #[cfg(test)] 13 mod test { 14 // use std::fs::File; 15 // use profile::Profile; 16 use crate::preferences::Pref; 17 use crate::prefreader::{parse, serialize, tokenize}; 18 use crate::prefreader::{Position, PrefToken}; 19 use std::collections::BTreeMap; 20 use std::io::Cursor; 21 use std::str; 22 23 #[test] 24 fn tokenize_simple() { 25 let prefs = " user_pref ( 'example.pref.string', 'value' ) ;\n \ 26 pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false);"; 27 28 let p = Position::new(); 29 30 let expected = vec![ 31 PrefToken::UserPrefFunction(p), 32 PrefToken::Paren('(', p), 33 PrefToken::String("example.pref.string".into(), p), 34 PrefToken::Comma(p), 35 PrefToken::String("value".into(), p), 36 PrefToken::Paren(')', p), 37 PrefToken::Semicolon(p), 38 PrefToken::PrefFunction(p), 39 PrefToken::Paren('(', p), 40 PrefToken::String("example.pref.int".into(), p), 41 PrefToken::Comma(p), 42 PrefToken::Int(-123, p), 43 PrefToken::Paren(')', p), 44 PrefToken::Semicolon(p), 45 PrefToken::StickyPrefFunction(p), 46 PrefToken::Paren('(', p), 47 PrefToken::String("example.pref.bool".into(), p), 48 PrefToken::Comma(p), 49 PrefToken::Bool(false, p), 50 PrefToken::Paren(')', p), 51 PrefToken::Semicolon(p), 52 ]; 53 54 tokenize_test(prefs, &expected); 55 } 56 57 #[test] 58 fn tokenize_comments() { 59 let prefs = "# bash style comment\n /*block comment*/ user_pref/*block comment*/(/*block \ 60 comment*/ 'example.pref.string' /*block comment*/,/*block comment*/ \ 61 'value'/*block comment*/ )// line comment"; 62 63 let p = Position::new(); 64 65 let expected = vec![ 66 PrefToken::CommentBashLine(" bash style comment".into(), p), 67 PrefToken::CommentBlock("block comment".into(), p), 68 PrefToken::UserPrefFunction(p), 69 PrefToken::CommentBlock("block comment".into(), p), 70 PrefToken::Paren('(', p), 71 PrefToken::CommentBlock("block comment".into(), p), 72 PrefToken::String("example.pref.string".into(), p), 73 PrefToken::CommentBlock("block comment".into(), p), 74 PrefToken::Comma(p), 75 PrefToken::CommentBlock("block comment".into(), p), 76 PrefToken::String("value".into(), p), 77 PrefToken::CommentBlock("block comment".into(), p), 78 PrefToken::Paren(')', p), 79 PrefToken::CommentLine(" line comment".into(), p), 80 ]; 81 82 tokenize_test(prefs, &expected); 83 } 84 85 #[test] 86 fn tokenize_escapes() { 87 let prefs = r#"user_pref('example\x20pref', "\u0020\u2603\uD800\uDC96\"\'\n\r\\\w)"#; 88 89 let p = Position::new(); 90 91 let expected = vec![ 92 PrefToken::UserPrefFunction(p), 93 PrefToken::Paren('(', p), 94 PrefToken::String("example pref".into(), p), 95 PrefToken::Comma(p), 96 PrefToken::String(" ☃𐂖\"'\n\r\\\\w".into(), p), 97 PrefToken::Paren(')', p), 98 ]; 99 100 tokenize_test(prefs, &expected); 101 } 102 103 fn tokenize_test(prefs: &str, expected: &[PrefToken]) { 104 println!("{}\n", prefs); 105 106 for (e, a) in expected.iter().zip(tokenize(prefs.as_bytes())) { 107 let success = match (e, &a) { 108 (&PrefToken::PrefFunction(_), &PrefToken::PrefFunction(_)) => true, 109 (&PrefToken::UserPrefFunction(_), &PrefToken::UserPrefFunction(_)) => true, 110 (&PrefToken::StickyPrefFunction(_), &PrefToken::StickyPrefFunction(_)) => true, 111 ( 112 &PrefToken::CommentBlock(ref data_e, _), 113 &PrefToken::CommentBlock(ref data_a, _), 114 ) => data_e == data_a, 115 ( 116 &PrefToken::CommentLine(ref data_e, _), 117 &PrefToken::CommentLine(ref data_a, _), 118 ) => data_e == data_a, 119 ( 120 &PrefToken::CommentBashLine(ref data_e, _), 121 &PrefToken::CommentBashLine(ref data_a, _), 122 ) => data_e == data_a, 123 (&PrefToken::Paren(data_e, _), &PrefToken::Paren(data_a, _)) => data_e == data_a, 124 (&PrefToken::Semicolon(_), &PrefToken::Semicolon(_)) => true, 125 (&PrefToken::Comma(_), &PrefToken::Comma(_)) => true, 126 (&PrefToken::String(ref data_e, _), &PrefToken::String(ref data_a, _)) => { 127 data_e == data_a 128 } 129 (&PrefToken::Int(data_e, _), &PrefToken::Int(data_a, _)) => data_e == data_a, 130 (&PrefToken::Bool(data_e, _), &PrefToken::Bool(data_a, _)) => data_e == data_a, 131 (&PrefToken::Error(ref data_e, _), &PrefToken::Error(ref data_a, _)) => { 132 *data_e == *data_a 133 } 134 (_, _) => false, 135 }; 136 if !success { 137 println!("Expected {:?}, got {:?}", e, a); 138 } 139 assert!(success); 140 } 141 } 142 143 #[test] 144 fn parse_simple() { 145 let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n \ 146 pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; 147 148 let mut expected: BTreeMap<String, Pref> = BTreeMap::new(); 149 expected.insert("example.pref.string".into(), Pref::new("value")); 150 expected.insert("example.pref.int".into(), Pref::new(-123)); 151 expected.insert("example.pref.bool".into(), Pref::new_sticky(false)); 152 153 parse_test(input, expected); 154 } 155 156 #[test] 157 fn parse_escape() { 158 let input = r#"user_pref('example\\pref\"string', 'val\x20ue' )"#; 159 160 let mut expected: BTreeMap<String, Pref> = BTreeMap::new(); 161 expected.insert("example\\pref\"string".into(), Pref::new("val ue")); 162 163 parse_test(input, expected); 164 } 165 166 #[test] 167 fn parse_empty() { 168 let inputs = ["", " ", "\n", "\n \n"]; 169 for input in inputs { 170 let expected: BTreeMap<String, Pref> = BTreeMap::new(); 171 parse_test(input, expected); 172 } 173 } 174 175 #[test] 176 fn parse_newline() { 177 let inputs = vec!["\na", "\n\nfoo"]; 178 for input in inputs { 179 assert!(parse(input.as_bytes()).is_err()); 180 } 181 } 182 183 #[test] 184 fn parse_minus() { 185 let inputs = ["pref(-", "user_pref(\"example.pref.int\", -);"]; 186 for input in inputs { 187 assert!(parse(input.as_bytes()).is_err()); 188 } 189 } 190 191 #[test] 192 fn parse_boolean_eof() { 193 let inputs = vec!["pref(true", "pref(false", "pref(false,", "pref(false)"]; 194 for input in inputs { 195 assert!(parse(input.as_bytes()).is_err()); 196 } 197 } 198 199 fn parse_test(input: &str, expected: BTreeMap<String, Pref>) { 200 match parse(input.as_bytes()) { 201 Ok(ref actual) => { 202 println!("Expected:\n{:?}\nActual\n{:?}", expected, actual); 203 assert_eq!(actual, &expected); 204 } 205 Err(e) => { 206 println!("{}", e); 207 assert!(false) 208 } 209 } 210 } 211 212 #[test] 213 fn serialize_simple() { 214 let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n \ 215 pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; 216 let expected = "sticky_pref(\"example.pref.bool\", false); 217 user_pref(\"example.pref.int\", -123); 218 user_pref(\"example.pref.string\", \"value\");\n"; 219 220 serialize_test(input, expected); 221 } 222 223 #[test] 224 fn serialize_quotes() { 225 let input = r#"user_pref('example\\with"quotes"', '"Value"')"#; 226 let expected = r#"user_pref("example\\with\"quotes\"", "\"Value\""); 227 "#; 228 229 serialize_test(input, expected); 230 } 231 232 fn serialize_test(input: &str, expected: &str) { 233 let buf = Vec::with_capacity(expected.len()); 234 let mut out = Cursor::new(buf); 235 serialize(&parse(input.as_bytes()).unwrap(), &mut out).unwrap(); 236 let data = out.into_inner(); 237 let actual = str::from_utf8(&*data).unwrap(); 238 println!("Expected:\n{:?}\nActual\n{:?}", expected, actual); 239 assert_eq!(actual, expected); 240 } 241 }