partiql-conformance-test-generator 0.7.2

PartiQL conformance test generator
Documentation
use crate::generator::{NamespaceNode, Node, TestTree};
use crate::util::Escaper;

use codegen::Scope;
use miette::IntoDiagnostic;

use std::fs::{DirBuilder, File};
use std::io::Write;
use std::path::{Path, PathBuf};

const FILE_HEADER: &str = "\
// ********************************************************************************************** //
//  *NOTE*: This file is generated by partiql-conformance-test-generator. Do not edit directly.
// ********************************************************************************************** //

#[allow(unused_imports)]
use super::*;

";

#[derive(Debug)]
pub struct Writer {}

impl Writer {
    pub fn new() -> Self {
        Self {}
    }

    pub fn write(&self, path: impl AsRef<Path>, mut root: NamespaceNode) -> miette::Result<()> {
        let path: PathBuf = path
            .as_ref()
            .components()
            .map(|c| c.as_os_str().to_string_lossy().to_string().escape_path())
            .collect();
        std::fs::create_dir_all(&path).into_diagnostic()?;

        write_module(&path, &mut root)?;

        Ok(())
    }
}

fn write_module(path: impl AsRef<Path>, module: &mut NamespaceNode) -> miette::Result<bool> {
    DirBuilder::new()
        .recursive(true)
        .create(&path)
        .into_diagnostic()?;

    let mut sub_mods = vec![];

    for (name, child) in &mut module.children {
        let mut child_path: PathBuf = path.as_ref().into();
        child_path.push(name);
        let is_sub_mod = match child {
            TestTree::Node(Node::Test(s)) => write_scope(child_path, s.module.scope())?,
            TestTree::Node(Node::Value(e)) => write_file(child_path, &e.value)?,
            TestTree::Namespace(m) => write_module(child_path, m)?,
        };
        if is_sub_mod {
            sub_mods.push(name.clone());
        }
    }

    if !sub_mods.is_empty() {
        write_dir_mod(&path, sub_mods.iter())?;
    }

    Ok(!sub_mods.is_empty())
}

fn write_dir_mod<'a>(
    path: impl AsRef<Path>,
    sub_mods: impl Iterator<Item = &'a String>,
) -> miette::Result<bool> {
    std::fs::create_dir_all(&path).into_diagnostic()?;

    let mut contents = FILE_HEADER.to_string();
    for sub_mod in sub_mods {
        contents.push_str(&format!("mod {};\n", sub_mod.replace(".rs", "")))
    }

    let file_path = path.as_ref().join("mod.rs");
    File::create(file_path)
        .into_diagnostic()?
        .write_all(contents.as_bytes())
        .into_diagnostic()?;
    Ok(true)
}

fn write_scope(path: impl AsRef<Path>, scope: &Scope) -> miette::Result<bool> {
    let contents = format!("{}{}", FILE_HEADER, scope.to_string());
    write_file(path, &contents)?;
    Ok(true)
}

fn write_file(path: impl AsRef<Path>, contents: &str) -> miette::Result<bool> {
    let mut file = File::create(path).into_diagnostic()?;
    file.write_all(contents.as_bytes()).into_diagnostic()?;
    file.sync_all().into_diagnostic()?;
    Ok(false)
}