221 lines
7.2 KiB
Python
221 lines
7.2 KiB
Python
"""
|
|
Comprehensive tests for enhanced Arduino package index implementation with Pydantic
|
|
|
|
Tests all Pydantic models, validation rules, parsing functionality, and error handling.
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any, Dict
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
# Import the enhanced implementation
|
|
from ci.compiler.packages import (
|
|
Board,
|
|
Help,
|
|
Package,
|
|
PackageIndex,
|
|
PackageIndexParser,
|
|
PackageManagerConfig,
|
|
PackageParsingError,
|
|
Platform,
|
|
SystemDownload,
|
|
Tool,
|
|
ToolDependency,
|
|
format_size,
|
|
)
|
|
|
|
|
|
class TestHelp:
|
|
"""Test Help model validation"""
|
|
|
|
def test_valid_help(self):
|
|
"""Test valid help creation"""
|
|
help_data = {"online": "https://github.com/espressif/arduino-esp32"}
|
|
help_obj = Help(**help_data) # type: ignore
|
|
assert str(help_obj.online) == "https://github.com/espressif/arduino-esp32"
|
|
|
|
def test_invalid_url(self):
|
|
"""Test invalid URL validation"""
|
|
with pytest.raises(ValidationError):
|
|
Help(online="not-a-valid-url") # type: ignore
|
|
|
|
|
|
class TestBoard:
|
|
"""Test Board model validation"""
|
|
|
|
def test_valid_board(self):
|
|
"""Test valid board creation"""
|
|
board_data = {
|
|
"name": "ESP32 Dev Module",
|
|
"properties": {
|
|
"upload.tool": "esptool_py",
|
|
"upload.maximum_size": "1310720",
|
|
},
|
|
}
|
|
board = Board(**board_data) # type: ignore
|
|
assert board.name == "ESP32 Dev Module"
|
|
assert board.properties["upload.tool"] == "esptool_py"
|
|
|
|
def test_empty_name_validation(self):
|
|
"""Test empty name validation"""
|
|
with pytest.raises(ValidationError):
|
|
Board(name="", properties={})
|
|
|
|
def test_name_trimming(self):
|
|
"""Test name trimming functionality"""
|
|
board = Board(name=" ESP32 Dev Module ", properties={})
|
|
assert board.name == "ESP32 Dev Module"
|
|
|
|
|
|
class TestSystemDownload:
|
|
"""Test SystemDownload model validation"""
|
|
|
|
def test_size_conversion_from_string(self):
|
|
"""Test size conversion from string bytes to MB"""
|
|
system = SystemDownload(
|
|
host="test-host",
|
|
url="https://example.com/file.tar.gz", # type: ignore
|
|
archiveFileName="file.tar.gz",
|
|
checksum="SHA-256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
|
size="52428800", # type: ignore - 50 MB in bytes, validator converts
|
|
)
|
|
assert abs(system.size_mb - 50.0) < 0.1 # Should be ~50 MB
|
|
|
|
def test_invalid_checksum_format(self):
|
|
"""Test invalid checksum format validation"""
|
|
with pytest.raises(ValidationError):
|
|
SystemDownload(
|
|
host="test-host",
|
|
url="https://example.com/file.tar.gz", # type: ignore
|
|
archiveFileName="file.tar.gz",
|
|
checksum="invalid-checksum",
|
|
size=50.0, # type: ignore
|
|
)
|
|
|
|
|
|
class TestPlatform:
|
|
"""Test Platform model validation"""
|
|
|
|
def test_valid_platform(self):
|
|
"""Test valid platform creation"""
|
|
platform_data: Dict[str, Any] = {
|
|
"name": "ESP32 Arduino",
|
|
"architecture": "esp32",
|
|
"version": "2.0.5",
|
|
"category": "ESP32",
|
|
"url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.5/esp32-2.0.5.zip",
|
|
"archiveFileName": "esp32-2.0.5.zip",
|
|
"checksum": "SHA-256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
|
"size": "50000000",
|
|
"boards": [],
|
|
"toolsDependencies": [],
|
|
"help": {"online": "https://github.com/espressif/arduino-esp32"},
|
|
}
|
|
platform = Platform(**platform_data) # type: ignore
|
|
assert platform.name == "ESP32 Arduino"
|
|
assert platform.architecture == "esp32"
|
|
assert platform.size_mb == 50000000 / (1024 * 1024)
|
|
|
|
def test_invalid_archive_extension(self):
|
|
"""Test invalid archive extension validation"""
|
|
with pytest.raises(ValidationError):
|
|
Platform(
|
|
name="Test Platform",
|
|
architecture="test",
|
|
version="1.0.0",
|
|
category="Test",
|
|
url="https://example.com/file.txt", # type: ignore
|
|
archiveFileName="file.txt", # Invalid extension
|
|
checksum="SHA-256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
|
size=50.0, # type: ignore
|
|
boards=[],
|
|
toolsDependencies=[],
|
|
help=Help(online="https://example.com"), # type: ignore
|
|
)
|
|
|
|
|
|
class TestPackageIndexParser:
|
|
"""Test PackageIndexParser functionality"""
|
|
|
|
def test_parse_valid_json(self):
|
|
"""Test parsing valid package index JSON"""
|
|
valid_json: Dict[str, Any] = {
|
|
"packages": [
|
|
{
|
|
"name": "test",
|
|
"maintainer": "Test Maintainer",
|
|
"websiteURL": "https://example.com",
|
|
"email": "test@example.com",
|
|
"help": {"online": "https://example.com"},
|
|
"platforms": [],
|
|
"tools": [],
|
|
}
|
|
]
|
|
}
|
|
|
|
parser = PackageIndexParser()
|
|
package_index = parser.parse_package_index(json.dumps(valid_json))
|
|
assert len(package_index.packages) == 1
|
|
assert package_index.packages[0].name == "test"
|
|
|
|
def test_parse_invalid_json(self):
|
|
"""Test parsing invalid JSON"""
|
|
parser = PackageIndexParser()
|
|
|
|
with pytest.raises(PackageParsingError):
|
|
parser.parse_package_index("invalid json")
|
|
|
|
|
|
class TestUtilityFunctions:
|
|
"""Test utility functions"""
|
|
|
|
def test_format_size(self):
|
|
"""Test size formatting function"""
|
|
# Test KB
|
|
assert format_size(0.5) == "512.0 KB"
|
|
|
|
# Test MB
|
|
assert format_size(1.5) == "1.5 MB"
|
|
assert format_size(512.0) == "512.0 MB"
|
|
|
|
# Test GB
|
|
assert format_size(1536.0) == "1.5 GB"
|
|
assert format_size(2048.0) == "2.0 GB"
|
|
|
|
|
|
class TestRealDataParsing:
|
|
"""Test with real ESP32 package index data (if network available)"""
|
|
|
|
def test_esp32_package_parsing(self):
|
|
"""Test parsing real ESP32 package index"""
|
|
ESP32_URL = "https://espressif.github.io/arduino-esp32/package_esp32_index.json"
|
|
|
|
try:
|
|
parser = PackageIndexParser(timeout=10)
|
|
package_index = parser.parse_from_url(ESP32_URL)
|
|
|
|
# Basic validation
|
|
assert len(package_index.packages) > 0
|
|
|
|
esp32_package = package_index.packages[0]
|
|
assert esp32_package.name == "esp32"
|
|
assert len(esp32_package.platforms) > 0
|
|
assert len(esp32_package.tools) > 0
|
|
|
|
print(f"✅ Successfully parsed ESP32 package index:")
|
|
print(f" 📦 Packages: {len(package_index.packages)}")
|
|
print(f" 🛠️ Platforms: {len(esp32_package.platforms)}")
|
|
print(f" 🔧 Tools: {len(esp32_package.tools)}")
|
|
|
|
except Exception as e:
|
|
# Skip if network not available
|
|
pytest.skip(f"Network test skipped: {e}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Run tests
|
|
pytest.main([__file__, "-v"])
|