#![type_length_limit = "2893838"] use from_pest::FromPest; use log::{debug, error}; use pest::Parser; use rayon::prelude::*; use std::{ error::Error as StdError, ffi::OsStr, path::{Path, PathBuf}, }; use walkdir::WalkDir; use xkb_parser::{Rule, Xkb, XkbParser}; type Error = Box; #[test] fn parse_custom_fixtures() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/custom") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .filter(|x| x.extension() == Some(OsStr::new("xkb"))) .collect(), ) } #[test] fn parse_kbdgen_fixtures() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/kbdgen") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .filter(|x| x.extension() == Some(OsStr::new("xkb"))) .collect(), ) } #[test] fn parse_x11_symbols() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/x11/symbols") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .collect(), ) } #[test] fn parse_x11_keycodes() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/x11/keycodes") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .collect(), ) } #[test] fn parse_x11_types() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/x11/types") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .collect(), ) } #[test] fn parse_x11_geometry() -> Result<(), Error> { enable_logging(); log::info!("geometry"); parse_files( WalkDir::new("tests/fixtures/x11/geometry") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .collect(), ) } #[test] #[ignore] fn parse_x11_rules() -> Result<(), Error> { enable_logging(); parse_files( WalkDir::new("tests/fixtures/x11/rules") .into_iter() .filter_map(|x| x.ok()) .map(|x| x.path().to_path_buf()) .filter(|x| x.is_file()) .collect(), ) } fn parse_files(xkb_files: Vec) -> Result<(), Error> { let failed: usize = xkb_files .into_par_iter() .filter(|f| f.extension() != Some(OsStr::new("json"))) .filter(|f| f.extension() != Some(OsStr::new("ron"))) .filter(|f| f.extension() != Some(OsStr::new("xml"))) .filter(|f| f.file_name() != Some(OsStr::new("README"))) .map(|f: PathBuf| { debug!("next: {}", f.display()); let res = parse_one_file(&f); (f, res) }) .filter_map(|(f, x)| x.err().map(|e| (f, e))) .inspect(|(file_name, error)| { debug!("error parsing file {}:\n{}", file_name.display(), error); error!("failed: {}", file_name.display()); }) .count(); if failed > 0 { panic!("{} tests failed -- Set `VERBOSE_PARSE_ERRORS=1` for error messages", failed); } Ok(()) } fn parse_one_file(file_name: &Path) -> Result<(), Error> { let file = std::fs::read_to_string(&file_name)?; log::trace!(" read {}", file_name.display()); let mut parse_tree = XkbParser::parse(Rule::file, &file)?; log::trace!("parsed {}", file_name.display()); std::fs::write(file_name.with_extension("debug.ron"), format!("{:#?}", parse_tree))?; let _ = Xkb::from_pest(&mut parse_tree).map_err(|e| format!("ast generation failed: {:?}", e))?; log::trace!(" asted {}", file_name.display()); Ok(()) } fn enable_logging() { let verbosity = std::env::var("VERBOSE_PARSE_ERRORS").ok().and_then(|x| x.parse::().ok()); let level = match verbosity { None | Some(0) => log::LevelFilter::Warn, Some(1) => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, }; let _ = env_logger::builder() .filter(None, level) .default_format_timestamp(false) .is_test(true) .try_init(); }