phper-test 0.2.0

PHPer testing utilities.
Documentation
use crate::utils;
use once_cell::sync::OnceCell;
use std::{
    env,
    fs::read_to_string,
    io::Write,
    ops::{Deref, DerefMut},
    path::Path,
    process::Command,
};
use tempfile::NamedTempFile;

pub struct Context {
    pub php_bin: String,
    pub ini_content: String,
}

impl Context {
    pub fn get_global() -> &'static Context {
        static CONTEXT: OnceCell<Context> = OnceCell::new();
        &CONTEXT.get_or_init(|| {
            let mut ini_content = String::new();

            let php_config = env::var("PHP_CONFIG").unwrap_or("php-config".to_string());
            let php_bin = utils::execute_command(&[php_config.as_str(), "--php-binary"]);
            let ini_file = utils::execute_command(&[
                php_bin.as_str(),
                "-d",
                "display_errors=stderr",
                "-r",
                "echo php_ini_loaded_file();",
            ]);
            let ini_files = utils::execute_command(&[
                php_bin.as_str(),
                "-d",
                "display_errors=stderr",
                "-r",
                "echo php_ini_scanned_files();",
            ]);

            if !ini_file.is_empty() {
                ini_content.push_str(&read_to_string(ini_file).unwrap());
            }
            if !ini_files.is_empty() {
                for file in ini_files.split(',') {
                    let file = file.trim();
                    if !file.is_empty() {
                        ini_content.push_str(&read_to_string(file).unwrap());
                    }
                }
            }

            Context {
                php_bin,
                ini_content,
            }
        })
    }

    pub fn create_tmp_php_ini_file(&self, lib_path: impl AsRef<Path>) -> NamedTempFile {
        let mut out_ini_temp_file = NamedTempFile::new().unwrap();
        let out_ini_file = out_ini_temp_file.as_file_mut();

        out_ini_file.write_all(self.ini_content.as_bytes()).unwrap();
        out_ini_file
            .write_fmt(format_args!(
                "extension={}\n",
                lib_path.as_ref().to_str().unwrap()
            ))
            .unwrap();

        out_ini_temp_file
    }

    pub fn create_command_with_tmp_php_ini_args(
        &self,
        tmp_php_ini_file: &NamedTempFile,
        script: impl AsRef<Path>,
    ) -> ContextCommand {
        let mut cmd = Command::new(&self.php_bin);
        let args = vec![
            "-n".to_owned(),
            "-c".to_owned(),
            tmp_php_ini_file.path().to_str().unwrap().to_owned(),
            script.as_ref().to_str().unwrap().to_owned(),
        ];
        cmd.args(&args);
        ContextCommand { cmd, args }
    }
}

pub struct ContextCommand {
    cmd: Command,
    args: Vec<String>,
}

impl ContextCommand {
    pub fn get_args(&self) -> &[String] {
        &self.args
    }
}

impl Deref for ContextCommand {
    type Target = Command;

    fn deref(&self) -> &Self::Target {
        &self.cmd
    }
}

impl DerefMut for ContextCommand {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.cmd
    }
}