#!/usr/bin/env python3
#exonware/xwsystem/tests/1.unit/serialization_tests/test_universal_options.py
"""
Test universal serialization options mapping.
Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.0.1.387
Generation Date: October 27, 2025
"""

import pytest
from pathlib import Path
# Try to import universal_options module
try:
    from exonware.xwsystem.io.serialization.universal_options import (
        map_universal_options,
        get_supported_universal_options,
        validate_universal_options
    )
    from exonware.xwsystem.io.serialization.auto_serializer import AutoSerializer
    _UNIVERSAL_OPTIONS_AVAILABLE = True
except ImportError:
    _UNIVERSAL_OPTIONS_AVAILABLE = False
    pytestmark = pytest.mark.skip(reason="universal_options module not available")
@pytest.mark.xwsystem_unit


class TestUniversalOptionsMapping:
    """Test universal options mapping to format-specific options."""

    def test_json_pretty_mapping(self):
        """Test pretty=True maps to JSON indent."""
        result = map_universal_options('JSON', pretty=True)
        assert result['indent'] == 2
        assert result['use_orjson'] == False

    def test_json_compact_mapping(self):
        """Test compact=True maps to JSON compact settings."""
        result = map_universal_options('JSON', compact=True)
        assert result['indent'] is None
        assert result['use_orjson'] == True

    def test_json_sorted_mapping(self):
        """Test sorted=True maps to JSON sort_keys."""
        result = map_universal_options('JSON', sorted=True)
        assert result['sort_keys'] == True

    def test_json_canonical_mapping(self):
        """Test canonical=True maps to JSON canonical settings."""
        result = map_universal_options('JSON', canonical=True)
        assert result['canonical'] == True
        assert result['sort_keys'] == True
        assert result['ensure_ascii'] == True
        assert result['indent'] is None

    def test_json_ensure_ascii_mapping(self):
        """Test ensure_ascii option for JSON."""
        result = map_universal_options('JSON', ensure_ascii=False)
        assert result['ensure_ascii'] == False

    def test_yaml_pretty_mapping(self):
        """Test pretty=True maps to YAML settings."""
        result = map_universal_options('YAML', pretty=True)
        assert result['default_flow_style'] == False
        assert result['indent'] == 2

    def test_yaml_compact_mapping(self):
        """Test compact=True maps to YAML flow style."""
        result = map_universal_options('YAML', compact=True)
        assert result['default_flow_style'] == True

    def test_yaml_sorted_mapping(self):
        """Test sorted=True maps to YAML sort_keys."""
        result = map_universal_options('YAML', sorted=True)
        assert result['sort_keys'] == True

    def test_yaml_canonical_mapping(self):
        """Test canonical=True maps to YAML canonical settings."""
        result = map_universal_options('YAML', canonical=True)
        assert result['canonical'] == True
        assert result['sort_keys'] == True

    def test_xml_pretty_mapping(self):
        """Test pretty=True maps to XML pretty_print."""
        result = map_universal_options('XML', pretty=True)
        assert result['pretty_print'] == True

    def test_xml_compact_mapping(self):
        """Test compact=True maps to XML compact settings."""
        result = map_universal_options('XML', compact=True)
        assert result['pretty_print'] == False

    def test_xml_declaration_mapping(self):
        """Test declaration option for XML."""
        result = map_universal_options('XML', declaration=True)
        assert result['full_document'] == True  # xmltodict uses full_document to control XML declaration
        result = map_universal_options('XML', declaration=False)
        assert result['full_document'] == False  # xmltodict uses full_document to control XML declaration

    def test_xml_encoding_mapping(self):
        """Test encoding option for XML."""
        result = map_universal_options('XML', encoding='utf-16')
        assert result['encoding'] == 'utf-16'

    def test_toml_pretty_mapping(self):
        """Test pretty=True maps to TOML settings."""
        result = map_universal_options('TOML', pretty=True)
        assert result['pretty'] == True

    def test_toml_sorted_mapping(self):
        """Test sorted=True maps to TOML sort_keys."""
        result = map_universal_options('TOML', sorted=True)
        assert result['sort_keys'] == True

    def test_compact_overrides_pretty(self):
        """Test that compact overrides pretty."""
        result = map_universal_options('JSON', pretty=True, compact=True)
        # Compact should win
        assert result['indent'] is None
        assert result['use_orjson'] == True

    def test_canonical_implies_sorted(self):
        """Test that canonical implies sorted."""
        result = map_universal_options('JSON', canonical=True)
        assert result['sort_keys'] == True

    def test_custom_indent_level(self):
        """Test custom indent level."""
        result = map_universal_options('JSON', pretty=True, indent=4)
        assert result['indent'] == 4
@pytest.mark.xwsystem_unit


class TestAutoSerializerWithUniversalOptions:
    """Test AutoSerializer integration with universal options."""

    def test_json_pretty_serialization(self):
        """Test JSON serialization with pretty option."""
        serializer = AutoSerializer()
        data = {'key': 'value', 'nested': {'a': 1, 'b': 2}}
        # Pretty
        result = serializer.detect_and_serialize(
            data,
            format_hint='JSON',
            pretty=True
        )
        assert isinstance(result, str)
        assert '\n' in result  # Should have newlines for pretty
        assert '  ' in result  # Should have indentation

    def test_json_compact_serialization(self):
        """Test JSON serialization with compact option."""
        serializer = AutoSerializer()
        data = {'key': 'value', 'nested': {'a': 1, 'b': 2}}
        # Compact
        result = serializer.detect_and_serialize(
            data,
            format_hint='JSON',
            compact=True
        )
        assert isinstance(result, (str, bytes))
        # Compact should have minimal whitespace
        if isinstance(result, str):
            assert result.count('\n') <= 1

    def test_json_sorted_serialization(self):
        """Test JSON serialization with sorted keys."""
        serializer = AutoSerializer()
        data = {'z': 1, 'a': 2, 'm': 3}
        result = serializer.detect_and_serialize(
            data,
            format_hint='JSON',
            sorted=True
        )
        assert isinstance(result, (str, bytes))
        # Keys should be sorted
        if isinstance(result, str):
            assert result.index('"a"') < result.index('"m"')
            assert result.index('"m"') < result.index('"z"')

    def test_yaml_pretty_serialization(self):
        """Test YAML serialization with pretty option."""
        serializer = AutoSerializer()
        data = {'key': 'value', 'list': [1, 2, 3]}
        result = serializer.detect_and_serialize(
            data,
            format_hint='YAML',
            pretty=True
        )
        assert isinstance(result, str)
        assert 'key:' in result
        assert '\n' in result

    def test_xml_pretty_serialization(self):
        """Test XML serialization with pretty option."""
        serializer = AutoSerializer()
        data = {'root': {'child': 'value'}}
        result = serializer.detect_and_serialize(
            data,
            format_hint='XML',
            pretty=True
        )
        assert isinstance(result, str)
        assert '<root>' in result or '<data>' in result

    def test_xml_no_declaration(self):
        """Test XML serialization without declaration."""
        serializer = AutoSerializer()
        data = {'key': 'value'}
        result = serializer.detect_and_serialize(
            data,
            format_hint='XML',
            declaration=False
        )
        assert isinstance(result, str)
        # Should not start with XML declaration
        assert not result.strip().startswith('<?xml')
@pytest.mark.xwsystem_unit


class TestUniversalOptionsValidation:
    """Test universal options validation."""

    def test_validate_valid_options(self):
        """Test validation of valid options."""
        is_valid, error = validate_universal_options("json", pretty=True, sorted=False)
        assert is_valid is True
        assert error is None
        is_valid, error = validate_universal_options("json", compact=True)
        assert is_valid is True
        is_valid, error = validate_universal_options("json", canonical=True)
        assert is_valid is True

    def test_validate_invalid_type(self):
        """Test validation with invalid types."""
        is_valid, error = validate_universal_options("json", pretty="yes")
        assert is_valid is False
        assert "expects type bool" in error or "expects type" in error
        is_valid, error = validate_universal_options("json", indent="4")
        assert is_valid is False
        assert "expects type int" in error or "expects type" in error

    def test_get_supported_options(self):
        """Test getting supported universal options."""
        options = get_supported_universal_options()
        assert 'pretty' in options
        assert 'compact' in options
        assert 'sorted' in options
        assert 'canonical' in options
        assert 'indent' in options
        assert 'declaration' in options
        assert 'ensure_ascii' in options
        assert 'encoding' in options
        # Check structure
        assert options['pretty']['type'] == bool
        assert options['pretty']['default'] == False
        assert 'JSON' in options['pretty']['formats']
