vexy-vsvg-plugin-sdk 2.4.2

Plugin SDK for vexy-vsvg
Documentation
// this_file: crates/vexy-vsvg-plugin-sdk/src/plugin_test_macros.rs

//! Test macros for validating plugins against SVG fixture files.
//!
//! This module provides two macros that automatically discover and run fixture-based tests
//! for plugins. Fixtures are SVG pairs (input + expected output) stored in `testdata/plugins/`.
//!
//! # Macros
//!
//! - `plugin_fixture_tests!` - For plugins with no parameters
//! - `plugin_fixture_tests_with_params!` - For plugins that read parameters from fixture metadata
//!
//! # Fixture Format
//!
//! Fixtures live at `testdata/plugins/{plugin_name}/` and follow SVGO's structure:
//! - Each subdirectory or numbered file pair represents one test case
//! - Input SVG and expected output SVG are compared after optimization
//! - Optional JSON params can be embedded in fixture metadata
//!
//! # Usage
//!
//! Add to the bottom of any plugin module:
//!
//! ```ignore
//! plugin_fixture_tests!(MyPlugin, "myPluginName");
//! ```
//!
//! This generates a `#[test]` that loads all fixtures from `testdata/plugins/myPluginName/`
//! and validates the plugin produces expected output.

extern crate vexy_vsvg;

#[macro_export]
macro_rules! plugin_fixture_tests {
    ($plugin_struct:ident, $plugin_name:expr) => {
        #[cfg(test)]
        mod tests {
            use super::*;
            use std::path::PathBuf;
            use vexy_vsvg::Config;
            use vexy_vsvg_test_utils::{create_test_dir, load_fixtures};

            #[test]
            fn fixture_tests() -> Result<(), Box<dyn std::error::Error>> {
                let fixtures_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                    .join("..")
                    .join("..")
                    .join("testdata")
                    .join("plugins")
                    .join($plugin_name);

                if !fixtures_path.exists() {
                    println!("No fixtures found for plugin: {}", $plugin_name);
                    return Ok(());
                }

                let fixtures = load_fixtures(&fixtures_path)?;

                for fixture in fixtures {
                    let mut config = Config::new();
                    config.plugins = vec![vexy_vsvg::PluginConfig::Name($plugin_name.to_string())];
                    config.js2svg.pretty = true;
                    config.js2svg.indent = "    ".to_string();
                    config.js2svg.final_newline = false;

                    let registry = $crate::registry::create_migrated_plugin_registry();
                    let options = vexy_vsvg::OptimizeOptions::new(config).with_registry(registry);
                    let result = vexy_vsvg::optimize(&fixture.input, options)?;
                    assert_eq!(
                        result.data,
                        fixture.expected,
                        "Fixture: {} (Path: {:?})",
                        fixture.name,
                        fixtures_path.join(fixture.name.clone())
                    );
                }
                Ok(())
            }
        }
    };
}

/// Generates fixture tests for plugins that accept parameters.
///
/// Like `plugin_fixture_tests!`, but reads `params` field from fixture metadata and passes
/// it to the plugin via `config.configure_plugin()`. Useful for plugins with configurable
/// behavior (e.g., `convertColors` with `shorthex`, `rgb2hex` options).
///
/// # Example
///
/// ```ignore
/// plugin_fixture_tests_with_params!(ConvertColorsPlugin, "convertColors");
/// ```
#[macro_export]
macro_rules! plugin_fixture_tests_with_params {
    ($plugin_struct:ident, $plugin_name:expr) => {
        #[cfg(test)]
        mod tests {
            use super::*;
            use std::path::PathBuf;
            use vexy_vsvg::Config;
            use vexy_vsvg_test_utils::{create_test_dir, load_fixtures};

            #[test]
            fn fixture_tests_with_params() -> Result<(), Box<dyn std::error::Error>> {
                let fixtures_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                    .join("..")
                    .join("..")
                    .join("testdata")
                    .join("plugins")
                    .join($plugin_name);

                if !fixtures_path.exists() {
                    println!("No fixtures found for plugin: {}", $plugin_name);
                    return Ok(());
                }

                let fixtures = load_fixtures(&fixtures_path)?;

                for fixture in fixtures {
                    let mut config = Config::new();
                    config.plugins = vec![vexy_vsvg::PluginConfig::Name($plugin_name.to_string())];
                    if let Some(params) = fixture.params {
                        config.configure_plugin($plugin_name, params);
                    }
                    config.js2svg.pretty = true;
                    config.js2svg.indent = "    ".to_string();
                    config.js2svg.final_newline = false;

                    let registry = $crate::registry::create_migrated_plugin_registry();
                    let options = vexy_vsvg::OptimizeOptions::new(config).with_registry(registry);
                    let result = vexy_vsvg::optimize(&fixture.input, options)?;
                    assert_eq!(
                        result.data,
                        fixture.expected,
                        "Fixture: {} (Path: {:?})",
                        fixture.name,
                        fixtures_path.join(fixture.name.clone())
                    );
                }
                Ok(())
            }
        }
    };
}