soroban-abacus-flashcards/tests/test_config.py

154 lines
5.2 KiB
Python

"""Tests for configuration loading and parsing."""
import pytest
import json
import yaml
import tempfile
from pathlib import Path
from generate import load_config, parse_range
class TestConfigLoading:
"""Test configuration file loading."""
def test_load_yaml_config(self, temp_dir):
"""Test loading YAML configuration files."""
config_data = {
'range': '0-9',
'cards_per_page': 4,
'bead_shape': 'circle'
}
config_file = temp_dir / 'test.yaml'
with open(config_file, 'w') as f:
yaml.dump(config_data, f)
loaded = load_config(str(config_file))
assert loaded == config_data
def test_load_json_config(self, temp_dir):
"""Test loading JSON configuration files."""
config_data = {
'range': '0-99',
'color_scheme': 'place-value',
'margins': {'top': '1in', 'bottom': '1in'}
}
config_file = temp_dir / 'test.json'
with open(config_file, 'w') as f:
json.dump(config_data, f)
loaded = load_config(str(config_file))
assert loaded == config_data
def test_load_nonexistent_config(self):
"""Test handling of nonexistent config files."""
with pytest.raises(FileNotFoundError):
load_config('nonexistent.yaml')
class TestRangeParsing:
"""Test number range parsing functionality."""
def test_parse_simple_range(self):
"""Test parsing simple ranges like '0-9'."""
result = parse_range('0-9')
expected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
assert result == expected
def test_parse_range_with_step(self):
"""Test parsing ranges with custom steps."""
result = parse_range('0-10', step=2)
expected = [0, 2, 4, 6, 8, 10]
assert result == expected
result = parse_range('0-20', step=5)
expected = [0, 5, 10, 15, 20]
assert result == expected
def test_parse_comma_list(self):
"""Test parsing comma-separated number lists."""
result = parse_range('1,5,10,25')
expected = [1, 5, 10, 25]
assert result == expected
def test_parse_mixed_list_and_ranges(self):
"""Test parsing mixed comma-separated values with ranges."""
result = parse_range('1,5-7,10')
expected = [1, 5, 6, 7, 10]
assert result == expected
def test_parse_single_number(self):
"""Test parsing single numbers."""
result = parse_range('42')
expected = [42]
assert result == expected
def test_parse_negative_numbers(self):
"""Test handling of negative numbers (edge case)."""
# Note: The current implementation might not handle this correctly
# This test documents the expected behavior
with pytest.raises(ValueError):
parse_range('-5-5')
def test_parse_invalid_range(self):
"""Test handling of invalid range strings."""
with pytest.raises(ValueError):
parse_range('invalid')
# Range where start > end results in empty list (valid behavior)
result = parse_range('10-5')
assert result == []
def test_parse_large_range(self):
"""Test parsing large ranges."""
result = parse_range('0-100', step=25)
expected = [0, 25, 50, 75, 100]
assert result == expected
def test_parse_step_ignored_for_lists(self):
"""Test that step parameter is ignored for comma-separated lists."""
result = parse_range('1,2,3,4', step=10) # Step should be ignored
expected = [1, 2, 3, 4]
assert result == expected
class TestConfigIntegration:
"""Integration tests for configuration handling."""
def test_real_config_files(self, project_root):
"""Test loading real configuration files from the project."""
config_dir = project_root / 'config'
# Test default config
default_config = config_dir / 'default.yaml'
if default_config.exists():
config = load_config(str(default_config))
assert 'range' in config
assert 'cards_per_page' in config
def test_config_with_range_parsing(self, temp_dir):
"""Test integration of config loading with range parsing."""
config_data = {
'range': '5-15',
'step': 2,
'cards_per_page': 8
}
config_file = temp_dir / 'test.yaml'
with open(config_file, 'w') as f:
yaml.dump(config_data, f)
config = load_config(str(config_file))
numbers = parse_range(config['range'], config.get('step', 1))
expected = [5, 7, 9, 11, 13, 15]
assert numbers == expected
def test_config_defaults(self, sample_config):
"""Test that sample config has reasonable defaults."""
assert sample_config['cards_per_page'] > 0
assert sample_config['scale_factor'] > 0
assert sample_config['bead_shape'] in ['diamond', 'circle', 'square']
assert sample_config['color_scheme'] in ['monochrome', 'place-value', 'heaven-earth', 'alternating']