ola-parser 1.0.1

Ola Language Parser
Documentation
// SPDX-License-Identifier: Apache-2.0

use std::sync::mpsc;
use std::time::Duration;
use std::{fs, path::Path, thread};
use walkdir::WalkDir;

#[test]
fn test_ext_source() {
    fn timeout_after<T, F>(d: Duration, f: F) -> Result<T, String>
    where
        T: Send + 'static,
        F: FnOnce() -> T,
        F: Send + 'static,
    {
        let (done_tx, done_rx) = mpsc::channel();
        let handle = thread::spawn(move || {
            let val = f();
            done_tx.send(()).expect("Unable to send completion signal");
            val
        });

        match done_rx.recv_timeout(d) {
            Ok(_) => Ok(handle.join().expect("Thread panicked")),
            Err(_) => Err(format!("Thread timeout-ed after {d:?}")),
        }
    }
    let source_delimiter = regex::Regex::new(r"====.*====").unwrap();

    let semantic_tests =
        WalkDir::new(Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/semanticTests"))
            .into_iter()
            .collect::<Result<Vec<_>, _>>()
            .unwrap()
            .into_iter();

    let errors = semantic_tests
        .map::<Result<_, String>, _>(|entry| {
            if entry.file_name().to_string_lossy().ends_with(".ola") {
                let source = match fs::read_to_string(entry.path()) {
                    Ok(source) => source,
                    Err(err) if matches!(err.kind(), std::io::ErrorKind::InvalidData) => {
                        return Ok(vec![])
                    }
                    Err(err) => return Err(err.to_string()),
                };
                Ok(source_delimiter
                    .split(&source)
                    .filter(|source_part| !source_part.is_empty())
                    .map(|part| (entry.path().to_string_lossy().to_string(), part.to_string()))
                    .collect::<Vec<_>>())
            } else {
                Ok(vec![])
            }
        })
        .collect::<Result<Vec<_>, _>>()
        .unwrap()
        .into_iter()
        .flatten()
        .filter_map(|(path, source_part)| {
            let result = match timeout_after(Duration::from_secs(5), move || {
                crate::parse(&source_part, 0)
            }) {
                Ok(result) => result,
                Err(err) => return Some(format!("{:?}: \n\t{}", path, err)),
            };

            if let Err(err) = result.map_err(|diags| {
                format!(
                    "{:?}:\n\t{}",
                    path,
                    diags
                        .iter()
                        .map(|diag| format!("{diag:?}"))
                        .collect::<Vec<_>>()
                        .join("\n\t")
                )
            }) {
                return Some(err);
            }

            None
        })
        .collect::<Vec<_>>();

    assert!(errors.is_empty(), "{}", errors.join("\n"));
}