1extern crate yaml_rust;
27
28mod configparser;
29
30use configparser::ConfigParser;
31use std::collections::HashMap;
32use std::fmt;
33use yaml_rust::{Yaml, YamlLoader};
34
35use std::path::PathBuf;
36
37#[derive(Clone)]
39pub struct Config {
40 pub language: String,
41 pub shell_config: ShellConfig,
42 pub alias: HashMap<String, String>,
43 pub output_config: OutputConfig,
44 pub prompt_config: PromptConfig,
45}
46
47#[derive(Clone)]
48pub struct ShellConfig {
49 pub exec: String,
50 pub args: Vec<String>
51}
52
53#[derive(Clone)]
54pub struct OutputConfig {
55 pub translate_output: bool,
56}
57
58#[derive(Clone)]
59pub struct PromptConfig {
60 pub prompt_line: String,
61 pub history_size: usize,
62 pub translate: bool,
63 pub break_enabled: bool,
64 pub break_str: String,
65 pub min_duration: usize,
66 pub rc_ok: String,
67 pub rc_err: String,
68 pub git_branch: String,
69 pub git_commit_ref: usize,
70 pub git_commit_prepend: Option<String>,
71 pub git_commit_append: Option<String>
72}
73
74#[derive(Copy, Clone, PartialEq, fmt::Debug)]
75pub enum ConfigErrorCode {
76 NoSuchFileOrDirectory,
77 CouldNotReadFile,
78 YamlSyntaxError,
79}
80
81pub struct ConfigError {
82 pub code: ConfigErrorCode,
83 pub message: String,
84}
85
86impl fmt::Display for ConfigErrorCode {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 let code_str: &str = match self {
89 ConfigErrorCode::NoSuchFileOrDirectory => "NoSuchFileOrDirectory",
90 ConfigErrorCode::CouldNotReadFile => "CouldNotReadFile",
91 ConfigErrorCode::YamlSyntaxError => "YamlSyntaxError",
92 };
93 write!(f, "{}", code_str)
94 }
95}
96
97impl fmt::Display for ConfigError {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 write!(f, "{} ({})", self.message, self.code)
100 }
101}
102
103impl Config {
104 pub fn default() -> Config {
108 let alias_config: HashMap<String, String> = HashMap::new();
109 Config {
110 language: String::from("ru"),
111 shell_config: ShellConfig::default(),
112 alias: alias_config,
113 output_config: OutputConfig::default(),
114 prompt_config: PromptConfig::default(),
115 }
116 }
117
118 pub fn parse_config(config_file: PathBuf) -> Result<Config, ConfigError> {
122 let config_str: String = match std::fs::read_to_string(config_file.clone()) {
124 Ok(config) => config,
125 Err(err) => match err.kind() {
126 std::io::ErrorKind::NotFound => {
127 return Err(ConfigError {
128 code: ConfigErrorCode::NoSuchFileOrDirectory,
129 message: format!("No such file or directory: {}", config_file.display()),
130 })
131 }
132 _ => {
133 return Err(ConfigError {
134 code: ConfigErrorCode::CouldNotReadFile,
135 message: format!("Could not read file {}", config_file.display())
136 })
137 }
138 },
139 };
140 Config::parse_config_str(config_str)
141 }
142
143 fn parse_config_str(config: String) -> Result<Config, ConfigError> {
147 let yaml_docs: Vec<Yaml> = match YamlLoader::load_from_str(config.as_str()) {
149 Ok(doc) => doc,
150 Err(_) => {
151 return Err(ConfigError {
152 code: ConfigErrorCode::YamlSyntaxError,
153 message: String::from("Configuration is not a valid YAML"),
154 });
155 }
156 };
157 if yaml_docs.len() == 0 {
159 return Err(ConfigError {
160 code: ConfigErrorCode::YamlSyntaxError,
161 message: String::from("File does not contain any YAML document"),
162 });
163 };
164 let yaml_doc: &Yaml = &yaml_docs[0];
165 let language: String = match ConfigParser::get_child(&yaml_doc, String::from("language")) {
168 Ok(node) => match Config::parse_language(&node) {
169 Ok(l) => l,
170 Err(err) => return Err(err),
171 },
172 Err(_) => String::from("ru"),
173 };
174 let alias_config: HashMap<String, String> = match ConfigParser::get_child(&yaml_doc, String::from("alias")) {
176 Ok(node) => match Config::parse_alias(&node) {
177 Ok(cfg) => cfg,
178 Err(err) => return Err(err),
179 },
180 Err(_) => HashMap::new(),
181 };
182 let shell_config: ShellConfig = match ConfigParser::get_child(&yaml_doc, String::from("shell")) {
183 Ok(node) => match ShellConfig::parse_config(&node) {
184 Ok(cfg) => cfg,
185 Err(err) => return Err(err)
186 },
187 Err(_) => ShellConfig::default()
188 };
189 let output_config: OutputConfig =
191 match ConfigParser::get_child(&yaml_doc, String::from("output")) {
192 Ok(node) => match OutputConfig::parse_config(&node) {
193 Ok(config) => config,
194 Err(err) => return Err(err),
195 },
196 Err(_) => OutputConfig::default(),
197 };
198 let prompt_config: PromptConfig =
200 match ConfigParser::get_child(&yaml_doc, String::from("prompt")) {
201 Ok(node) => match PromptConfig::parse_config(&node) {
202 Ok(config) => config,
203 Err(err) => return Err(err),
204 },
205 Err(_) => PromptConfig::default(),
206 };
207 Ok(Config {
208 language: language,
209 shell_config: shell_config,
210 alias: alias_config,
211 output_config: output_config,
212 prompt_config: prompt_config,
213 })
214 }
215
216 pub fn get_alias(&self, alias: &String) -> Option<String> {
220 match self.alias.get(alias) {
221 Some(cmd) => Some(cmd.clone()),
222 None => None,
223 }
224 }
225
226 fn parse_alias(alias_yaml: &Yaml) -> Result<HashMap<String, String>, ConfigError> {
230 if !alias_yaml.is_array() {
231 return Err(ConfigError {
232 code: ConfigErrorCode::YamlSyntaxError,
233 message: String::from("'alias' key is not an array"),
234 });
235 }
236 let mut alias_table: HashMap<String, String> = HashMap::new();
237 for pair in alias_yaml.as_vec().unwrap() {
239 for p in pair.as_hash().unwrap().iter() {
240 let key: String = String::from(p.0.as_str().unwrap());
241 let value: String = String::from(p.1.as_str().unwrap());
242 alias_table.insert(key, value);
243 }
244 }
245 Ok(alias_table)
246 }
247
248 fn parse_language(language_yaml: &Yaml) -> Result<String, ConfigError> {
252 match language_yaml.as_str() {
253 Some(s) => Ok(String::from(s)),
254 None => Err(ConfigError {
255 code: ConfigErrorCode::YamlSyntaxError,
256 message: String::from("'language' is not a string"),
257 }),
258 }
259 }
260}
261
262impl ShellConfig {
263 pub fn default() -> ShellConfig {
264 ShellConfig {
265 exec: String::from("bash"),
266 args: vec![]
267 }
268 }
269
270 pub fn parse_config(shell_yaml: &Yaml) -> Result<ShellConfig, ConfigError> {
271 let exec: String = match ConfigParser::get_string(&shell_yaml, String::from("exec")) {
272 Ok(s) => s,
273 Err(err) => return Err(err)
274 };
275
276 let args: Vec<String> = match ConfigParser::get_child(&shell_yaml, String::from("args")) {
277 Ok(args_yaml) => {
278 let mut args: Vec<String> = Vec::new();
279 for arg in args_yaml.as_vec().unwrap() {
281 args.push(match arg.as_str() {
282 Some(s) => String::from(s),
283 None => return Err(ConfigError {code: ConfigErrorCode::YamlSyntaxError, message: String::from("Shell arg is not a string")})
284 });
285 }
286 args
287 },
288 Err(_) => Vec::new()
289 };
290 Ok(ShellConfig {
291 exec: exec,
292 args: args
293 })
294 }
295}
296
297impl OutputConfig {
298 pub fn default() -> OutputConfig {
299 OutputConfig {
300 translate_output: true,
301 }
302 }
303
304 pub fn parse_config(output_yaml: &Yaml) -> Result<OutputConfig, ConfigError> {
305 let translate_output: bool =
306 match ConfigParser::get_bool(&output_yaml, String::from("translate")) {
307 Ok(t) => t,
308 Err(err) => return Err(err),
309 };
310 Ok(OutputConfig {
311 translate_output: translate_output,
312 })
313 }
314}
315
316impl PromptConfig {
317 pub fn default() -> PromptConfig {
321 PromptConfig {
322 prompt_line: String::from("${USER}@${HOSTNAME}:${WRKDIR}$"),
323 history_size: 256,
324 translate: false,
325 break_enabled: false,
326 break_str: String::from("❯"),
327 min_duration: 2000,
328 rc_ok: String::from("✔"),
329 rc_err: String::from("✖"),
330 git_branch: String::from("on "),
331 git_commit_ref: 8,
332 git_commit_append: None,
333 git_commit_prepend: None
334 }
335 }
336
337 pub fn parse_config(prompt_config_yaml: &Yaml) -> Result<PromptConfig, ConfigError> {
341 let prompt_line: String =
343 match ConfigParser::get_string(&prompt_config_yaml, String::from("prompt_line")) {
344 Ok(ret) => ret,
345 Err(err) => return Err(err),
346 };
347 let history_size: usize =
349 match ConfigParser::get_usize(&prompt_config_yaml, String::from("history_size")) {
350 Ok(ret) => ret,
351 Err(err) => return Err(err),
352 };
353 let translate: bool =
355 match ConfigParser::get_bool(&prompt_config_yaml, String::from("translate")) {
356 Ok(ret) => ret,
357 Err(err) => return Err(err),
358 };
359 let brk: &Yaml = match ConfigParser::get_child(&prompt_config_yaml, String::from("break")) {
361 Ok(ret) => ret,
362 Err(err) => return Err(err),
363 };
364 let break_enabled: bool = match ConfigParser::get_bool(&brk, String::from("enabled")) {
366 Ok(ret) => ret,
367 Err(err) => return Err(err),
368 };
369 let break_str: String = match ConfigParser::get_string(&brk, String::from("with")) {
371 Ok(ret) => ret,
372 Err(err) => return Err(err),
373 };
374 let duration: &Yaml =
376 match ConfigParser::get_child(&prompt_config_yaml, String::from("duration")) {
377 Ok(ret) => ret,
378 Err(err) => return Err(err),
379 };
380 let min_duration: usize =
382 match ConfigParser::get_usize(&duration, String::from("min_elapsed_time")) {
383 Ok(ret) => ret,
384 Err(err) => return Err(err),
385 };
386 let rc: &Yaml = match ConfigParser::get_child(&prompt_config_yaml, String::from("rc")) {
388 Ok(ret) => ret,
389 Err(err) => return Err(err),
390 };
391 let rc_ok: String = match ConfigParser::get_string(&rc, String::from("ok")) {
393 Ok(ret) => ret,
394 Err(err) => return Err(err),
395 };
396 let rc_err: String = match ConfigParser::get_string(&rc, String::from("error")) {
398 Ok(ret) => ret,
399 Err(err) => return Err(err),
400 };
401 let git: &Yaml = match ConfigParser::get_child(&prompt_config_yaml, String::from("git")) {
403 Ok(ret) => ret,
404 Err(err) => return Err(err),
405 };
406 let git_branch: String = match ConfigParser::get_string(&git, String::from("branch")) {
408 Ok(ret) => ret,
409 Err(err) => return Err(err),
410 };
411 let git_commit_ref: usize =
413 match ConfigParser::get_usize(&git, String::from("commit_ref_len")) {
414 Ok(ret) => ret,
415 Err(err) => return Err(err),
416 };
417 let git_commit_prepend: Option<String> =
419 match ConfigParser::get_string(&git, String::from("commit_prepend")) {
420 Ok(ret) => Some(ret),
421 Err(_) => None,
422 };
423 let git_commit_append: Option<String> =
425 match ConfigParser::get_string(&git, String::from("commit_append")) {
426 Ok(ret) => Some(ret),
427 Err(_) => None,
428 };
429 Ok(PromptConfig {
430 prompt_line: prompt_line,
431 history_size: history_size,
432 translate: translate,
433 break_enabled: break_enabled,
434 break_str: break_str,
435 min_duration: min_duration,
436 rc_ok: rc_ok,
437 rc_err: rc_err,
438 git_branch: git_branch,
439 git_commit_ref: git_commit_ref,
440 git_commit_append: git_commit_append,
441 git_commit_prepend: git_commit_prepend
442 })
443 }
444}
445
446#[cfg(test)]
447mod tests {
448 use super::*;
449 use std::io::Write;
450
451 #[test]
452 fn test_config_default() {
453 let config: Config = Config::default();
454 assert!(config.get_alias(&String::from("чд")).is_none());
455 assert_eq!(config.output_config.translate_output, true);
456 assert_eq!(config.language, String::from("ru"));
457 let prompt_config: PromptConfig = config.prompt_config;
458 assert_eq!(prompt_config.prompt_line, String::from("${USER}@${HOSTNAME}:${WRKDIR}$"));
459 assert_eq!(prompt_config.break_enabled, false);
460 assert_eq!(prompt_config.break_str, String::from("❯"));
461 assert_eq!(prompt_config.git_branch, String::from("on "));
462 assert_eq!(prompt_config.git_commit_ref, 8);
463 assert_eq!(prompt_config.git_commit_prepend, None);
464 assert_eq!(prompt_config.git_commit_append, None);
465 assert_eq!(prompt_config.history_size, 256);
466 assert_eq!(prompt_config.min_duration, 2000);
467 assert_eq!(prompt_config.rc_err, String::from("✖"));
468 assert_eq!(prompt_config.rc_ok, String::from("✔"));
469 assert_eq!(prompt_config.translate, false);
470 assert_eq!(config.shell_config.exec, String::from("bash"));
471 assert_eq!(config.shell_config.args.len(), 0);
472 }
473
474 #[test]
475 fn test_config_file() {
476 let config_file: tempfile::NamedTempFile = write_config_file_en();
478 let config_file_path: PathBuf = PathBuf::from(config_file.path().to_str().unwrap());
479 println!("Generated config file: {}", config_file_path.display());
480 let config: Result<Config, ConfigError> =Config::parse_config(config_file_path);
481 assert!(config.is_ok());
482 let config: Config = config.ok().unwrap();
483 assert!(config.get_alias(&String::from("чд")).is_some());
485 assert_eq!(config.output_config.translate_output, true);
486 assert_eq!(config.language, String::from("ru"));
487 let prompt_config: PromptConfig = config.prompt_config;
488 assert_eq!(prompt_config.prompt_line, String::from("${USER}@${HOSTNAME}:${WRKDIR}$"));
489 assert_eq!(prompt_config.break_enabled, false);
490 assert_eq!(prompt_config.break_str, String::from("❯"));
491 assert_eq!(prompt_config.git_branch, String::from("on "));
492 assert_eq!(prompt_config.git_commit_ref, 8);
493 assert_eq!(prompt_config.git_commit_prepend, None);
494 assert_eq!(prompt_config.git_commit_append, None);
495 assert_eq!(prompt_config.history_size, 256);
496 assert_eq!(prompt_config.min_duration, 2000);
497 assert_eq!(prompt_config.rc_err, String::from("✖"));
498 assert_eq!(prompt_config.rc_ok, String::from("✔"));
499 assert_eq!(prompt_config.translate, false);
500 assert_eq!(config.shell_config.exec, String::from("bash"));
501 assert_eq!(config.shell_config.args.len(), 0);
502
503 }
504
505 #[test]
506 fn test_config_no_file() {
507 assert_eq!(
508 Config::parse_config(PathBuf::from("config.does.not.exist.yml"))
509 .err()
510 .unwrap()
511 .code,
512 ConfigErrorCode::NoSuchFileOrDirectory
513 );
514 }
515
516 #[cfg(not(target_os = "macos"))]
517 #[test]
518 fn test_config_not_accessible() {
519 assert_eq!(
520 Config::parse_config(PathBuf::from("/dev/ttyS0"))
521 .err()
522 .unwrap()
523 .code,
524 ConfigErrorCode::CouldNotReadFile
525 );
526 }
527
528 #[test]
529 fn test_config_en_alias() {
530 let config: String =
532 String::from("alias:\n - чд: \"cd\"\n - пвд: \"pwd\"\n - уич: \"which\"");
533 match Config::parse_config_str(config) {
534 Ok(config) => {
535 assert_eq!(
537 config.get_alias(&String::from("чд")).unwrap(),
538 String::from("cd")
539 );
540 assert_eq!(
541 config.get_alias(&String::from("пвд")).unwrap(),
542 String::from("pwd")
543 );
544 assert_eq!(
545 config.get_alias(&String::from("уич")).unwrap(),
546 String::from("which")
547 );
548 assert!(config
549 .get_alias(&String::from("thiskeydoesnotexist"))
550 .is_none());
551 }
552 Err(error) => panic!(
553 "Parse_config should have returned OK, but returned {} ({:?})",
554 error.message, error.code
555 ),
556 };
557 }
558
559 #[test]
560 fn test_config_no_alias() {
561 let config: String = String::from("language: ru\n");
563 let config: Config = Config::parse_config_str(config).ok().unwrap();
564 assert!(config.get_alias(&String::from("чд")).is_none());
565 }
566
567 #[test]
568 fn test_config_alias_not_array() {
569 let config: String = String::from("alias: 5\n");
570 assert_eq!(
571 Config::parse_config_str(config).err().unwrap().code,
572 ConfigErrorCode::YamlSyntaxError
573 );
574 }
575
576 #[test]
577 fn test_config_shell_config() {
578 let config: String = String::from("shell:\n exec: \"sh\"\n args:\n - \"-l\"\n - \"-h\"\n");
579 let config: Config = Config::parse_config_str(config).ok().unwrap();
580 assert_eq!(config.shell_config.exec, String::from("sh"));
581 assert_eq!(config.shell_config.args, vec![String::from("-l"), String::from("-h")]);
582 }
583
584 #[test]
585 fn test_config_shell_config_bad() {
586 let config: String = String::from("shell:\n args:\n - \"-l\"\n - \"-h\"\n");
587 assert!(Config::parse_config_str(config).is_err());
588 let config: String = String::from("shell:\n args: 5\n");
589 assert!(Config::parse_config_str(config).is_err());
590 }
591
592 #[test]
593 fn test_config_output_config() {
594 let config: String =
595 String::from("alias:\n - чд: \"cd\"\n - пвд: \"pwd\"\n - уич: \"which\"");
596 let config: Config = Config::parse_config_str(config).ok().unwrap();
597 assert!(config.output_config.translate_output);
598 let config: String = String::from("output:\n translate: false\n");
600 let config: Config = Config::parse_config_str(config).ok().unwrap();
601 assert!(!config.output_config.translate_output);
602 }
603
604 #[test]
605 fn test_config_bad_output_config() {
606 let config: String = String::from("output: 5\n");
607 assert_eq!(
608 Config::parse_config_str(config).err().unwrap().code,
609 ConfigErrorCode::YamlSyntaxError
610 );
611 let config: String = String::from("output:\n translate: foobar\n");
612 assert_eq!(
613 Config::parse_config_str(config).err().unwrap().code,
614 ConfigErrorCode::YamlSyntaxError
615 );
616 let config: String = String::from("output:\n trsnlate: true\n");
617 assert_eq!(
618 Config::parse_config_str(config).err().unwrap().code,
619 ConfigErrorCode::YamlSyntaxError
620 );
621 }
622
623 #[test]
624 fn test_config_language() {
625 let config: String = String::from("language: bg\n");
626 let config: Config = Config::parse_config_str(config).ok().unwrap();
627 assert_eq!(config.language, String::from("bg"));
628 }
629
630 #[test]
631 fn test_config_language_missing() {
632 let config: String = String::from("output:\n translate: false\n");
633 let config: Config = Config::parse_config_str(config).ok().unwrap();
634 assert_eq!(config.language, String::from("ru"));
635 }
636
637 #[test]
638 #[should_panic]
639 fn test_config_language_badvalue() {
640 let config: String = String::from("language:\n name: ru\n");
641 assert!(Config::parse_config_str(config).is_ok());
642 }
643
644 #[test]
645 fn test_config_prompt_default() {
646 let config: String = String::from("language:\n ru\n");
647 let config: Config = Config::parse_config_str(config).ok().unwrap();
648 let prompt_config: PromptConfig = config.prompt_config;
649 assert_eq!(prompt_config.prompt_line, String::from("${USER}@${HOSTNAME}:${WRKDIR}$"));
650 assert_eq!(prompt_config.break_enabled, false);
651 assert_eq!(prompt_config.break_str, String::from("❯"));
652 assert_eq!(prompt_config.git_branch, String::from("on "));
653 assert_eq!(prompt_config.git_commit_ref, 8);
654 assert_eq!(prompt_config.history_size, 256);
655 assert_eq!(prompt_config.min_duration, 2000);
656 assert_eq!(prompt_config.rc_err, String::from("✖"));
657 assert_eq!(prompt_config.rc_ok, String::from("✔"));
658 assert_eq!(prompt_config.translate, false);
659 }
660
661 #[test]
662 fn test_config_prompt() {
663 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n commit_prepend: \"(\"\n commit_append: \")\"\n");
664 let config: Config = Config::parse_config_str(config).ok().unwrap();
665 let prompt_config: PromptConfig = config.prompt_config;
667 assert_eq!(prompt_config.prompt_line, String::from("${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}"));
668 assert_eq!(prompt_config.break_enabled, false);
669 assert_eq!(prompt_config.break_str, String::from(">"));
670 assert_eq!(prompt_config.git_branch, String::from("on "));
671 assert_eq!(prompt_config.git_commit_ref, 4);
672 assert_eq!(prompt_config.git_commit_prepend, Some(String::from("(")));
673 assert_eq!(prompt_config.git_commit_append, Some(String::from(")")));
674 assert_eq!(prompt_config.history_size, 1024);
675 assert_eq!(prompt_config.min_duration, 5000);
676 assert_eq!(prompt_config.rc_err, String::from("x_x"));
677 assert_eq!(prompt_config.rc_ok, String::from("^_^"));
678 assert_eq!(prompt_config.translate, true);
679 }
680
681 #[test]
682 fn test_config_prompt_bad() {
683 let config: String = String::from("prompt:\n prompt_le: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
684 assert!(Config::parse_config_str(config).is_err());
685 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n histosize: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
686 assert!(Config::parse_config_str(config).is_err());
687 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n trslate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
688 assert!(Config::parse_config_str(config).is_err());
689 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n bak:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
690 assert!(Config::parse_config_str(config).is_err());
691 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n eled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
692 assert!(Config::parse_config_str(config).is_err());
693 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n th: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
694 assert!(Config::parse_config_str(config).is_err());
695 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n dution:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
696 assert!(Config::parse_config_str(config).is_err());
697 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsime: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
698 assert!(Config::parse_config_str(config).is_err());
699 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n r:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
700 assert!(Config::parse_config_str(config).is_err());
701 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n o: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
702 assert!(Config::parse_config_str(config).is_err());
703 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n err: \"x_x\"\n git:\n branch: \"on \"\n commit_ref_len: 4\n");
704 assert!(Config::parse_config_str(config).is_err());
705 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n gi:\n branch: \"on \"\n commit_ref_len: 4\n");
706 assert!(Config::parse_config_str(config).is_err());
707 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n brch: \"on \"\n commit_ref_len: 4\n");
708 assert!(Config::parse_config_str(config).is_err());
709 let config: String = String::from("prompt:\n prompt_line: \"${USER} on ${HOSTNAME} in ${WRKDIR} ${GIT_BRANCH} (${GIT_COMMIT}) ${CMD_TIME}\"\n history_size: 1024\n translate: true\n break:\n enabled: false\n with: \">\"\n duration:\n min_elapsed_time: 5000\n rc:\n ok: \"^_^\"\n error: \"x_x\"\n git:\n branch: \"on \"\n com_ref_len: 4\n");
710 assert!(Config::parse_config_str(config).is_err());
711 }
712
713 #[test]
714 fn test_config_bad_syntax() {
715 let config: String = String::from("foobar: 5:\n");
716 assert_eq!(
717 Config::parse_config_str(config).err().unwrap().code,
718 ConfigErrorCode::YamlSyntaxError
719 );
720 }
721
722 #[test]
723 fn test_config_empty_yaml() {
724 let config: String = String::from("\n");
725 assert_eq!(
726 Config::parse_config_str(config).err().unwrap().code,
727 ConfigErrorCode::YamlSyntaxError
728 );
729 }
730
731 #[test]
732 fn test_config_error_display() {
733 println!(
734 "{};{};{}",
735 ConfigErrorCode::CouldNotReadFile,
736 ConfigErrorCode::NoSuchFileOrDirectory,
737 ConfigErrorCode::YamlSyntaxError
738 );
739 println!(
740 "{}",
741 ConfigError {
742 code: ConfigErrorCode::NoSuchFileOrDirectory,
743 message: String::from("No such file or directory ~/.config/pyc/pyc.yml")
744 }
745 );
746 }
747
748 fn write_config_file_en() -> tempfile::NamedTempFile {
751 let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
753 write!(
754 tmpfile,
755 "alias:\n - чд: \"cd\"\n - пвд: \"pwd\"\n - уич: \"which\""
756 )
757 .unwrap();
758 tmpfile
759 }
760}