netsuke-build 0.1.0-beta1

A YAML-powered Ninja/Jinja hybrid build system.
//! Tests for theme resolution and token selection.

use super::*;
use crate::snapshot_test_support::{NoColorEnv, no_color_env};
use rstest::rstest;

#[rstest]
#[case::explicit_unicode_overrides_all(
    Some(ThemePreference::Unicode),
    Some(true),
    Some("1"),
    OutputMode::Accessible,
    true
)]
#[case::explicit_ascii_overrides_all(
    Some(ThemePreference::Ascii),
    Some(false),
    None,
    OutputMode::Standard,
    false
)]
#[case::auto_defers_to_no_emoji_true(
    Some(ThemePreference::Auto),
    Some(true),
    None,
    OutputMode::Standard,
    false
)]
#[case::auto_defers_to_no_color_env(
    Some(ThemePreference::Auto),
    None,
    Some("1"),
    OutputMode::Standard,
    false
)]
#[case::none_defers_to_no_emoji_true(None, Some(true), None, OutputMode::Standard, false)]
#[case::none_defers_to_no_color_env(None, None, Some("1"), OutputMode::Standard, false)]
#[case::accessible_mode_uses_ascii(None, None, None, OutputMode::Accessible, false)]
#[case::standard_mode_uses_unicode(None, None, None, OutputMode::Standard, true)]
#[case::no_emoji_false_defers_to_mode(None, Some(false), None, OutputMode::Standard, true)]
fn theme_resolution_precedence(
    no_color_env: NoColorEnv,
    #[case] theme: Option<ThemePreference>,
    #[case] no_emoji: Option<bool>,
    #[case] env_no_color: Option<&str>,
    #[case] mode: OutputMode,
    #[case] expect_unicode: bool,
) {
    let resolved = resolve_theme(theme, ThemeContext::new(no_emoji, None, mode), move |key| {
        no_color_env(env_no_color.map(String::from), key)
    });
    assert_eq!(resolved.tokens.emoji_allowed, expect_unicode);
    if expect_unicode {
        assert_eq!(resolved.tokens.symbols.success, UNICODE_SYMBOLS.success);
        assert_eq!(resolved.tokens.symbols.error, UNICODE_SYMBOLS.error);
    } else {
        assert_eq!(resolved.tokens.symbols.success, ASCII_SYMBOLS.success);
        assert_eq!(resolved.tokens.symbols.error, ASCII_SYMBOLS.error);
    }
}

#[test]
fn spacing_tokens_are_identical_across_themes() {
    let unicode_theme = resolve_theme(
        Some(ThemePreference::Unicode),
        ThemeContext::new(None, None, OutputMode::Standard),
        |_| None,
    );
    let ascii_theme = resolve_theme(
        Some(ThemePreference::Ascii),
        ThemeContext::new(None, None, OutputMode::Standard),
        |_| None,
    );
    assert_eq!(
        unicode_theme.tokens.spacing, ascii_theme.tokens.spacing,
        "spacing must be identical between Unicode and ASCII themes"
    );
}

#[rstest]
fn colour_policy_always_ignores_no_color_for_theme_resolution(no_color_env: NoColorEnv) {
    let resolved = resolve_theme(
        None,
        ThemeContext::new(None, Some(ColourPolicy::Always), OutputMode::Standard),
        move |key| no_color_env(Some(String::from("1")), key),
    );

    assert!(resolved.tokens.emoji_allowed);
    assert_eq!(resolved.tokens.symbols.success, UNICODE_SYMBOLS.success);
}

#[rstest]
fn colour_policy_never_forces_ascii_for_theme_resolution(no_color_env: NoColorEnv) {
    let resolved = resolve_theme(
        None,
        ThemeContext::new(None, Some(ColourPolicy::Never), OutputMode::Standard),
        move |key| no_color_env(None, key),
    );

    assert!(!resolved.tokens.emoji_allowed);
    assert_eq!(resolved.tokens.symbols.success, ASCII_SYMBOLS.success);
}

#[test]
fn unicode_symbols_contain_non_ascii() {
    assert!(!UNICODE_SYMBOLS.success.is_ascii());
    assert!(!UNICODE_SYMBOLS.error.is_ascii());
}

#[test]
fn ascii_symbols_are_ascii_only() {
    assert!(ASCII_SYMBOLS.success.is_ascii());
    assert!(ASCII_SYMBOLS.error.is_ascii());
    assert!(ASCII_SYMBOLS.warning.is_ascii());
    assert!(ASCII_SYMBOLS.info.is_ascii());
    assert!(ASCII_SYMBOLS.timing.is_ascii());
}