Add comprehensive Assets API tests - increase coverage from 43% to 81%

Add 19 new tests for Assets endpoint covering:

Move operations:
- test_move_asset (success case)
- test_move_asset_validation_error (edge cases)

Folder operations:
- test_create_folder (full params)
- test_create_folder_minimal (minimal params)
- test_create_folder_validation_error
- test_delete_folder (success)
- test_delete_folder_validation_error

List operations with filters:
- test_list_assets_with_folder_filter
- test_list_assets_with_kind_filter
- test_list_assets_empty

Error handling:
- test_get_asset_not_found
- test_delete_asset_failure
- test_rename_asset_failure
- test_move_asset_failure
- test_create_folder_failure
- test_delete_folder_failure

Pagination & edge cases:
- test_iter_all_assets (pagination iterator)
- test_normalize_asset_data_minimal
- test_list_folders_empty

Impact:
- Assets endpoint: 43% → 81% coverage (+38%)
- Total tests: 423 → 442 tests (+19)
- Overall coverage: 77.10% → 79.32% (+2.22%)
- All tests passing (442/442)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2025-10-23 01:54:26 +00:00
parent 8f6a81154c
commit 8e9bd5973a

View File

@@ -161,3 +161,347 @@ class TestAssetsEndpoint:
with pytest.raises(ValidationError):
endpoint.rename(1, "")
# Move operations
def test_move_asset(self, endpoint):
"""Test moving an asset to a different folder."""
mock_response = {
"data": {
"assets": {
"moveAsset": {
"responseResult": {"succeeded": True},
"asset": {
"id": 1,
"filename": "test.png",
"ext": "png",
"kind": "image",
"mime": "image/png",
"fileSize": 1024,
"folderId": 5,
"authorId": 1,
"authorName": "Admin",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
},
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
asset = endpoint.move(1, 5)
assert asset.folder_id == 5
def test_move_asset_validation_error(self, endpoint):
"""Test move asset with invalid inputs."""
with pytest.raises(ValidationError):
endpoint.move(0, 1) # Invalid asset ID
with pytest.raises(ValidationError):
endpoint.move(1, -1) # Invalid folder ID
# Folder operations
def test_create_folder(self, endpoint):
"""Test creating a folder."""
mock_response = {
"data": {
"assets": {
"createFolder": {
"responseResult": {"succeeded": True},
"folder": {"id": 1, "slug": "documents", "name": "Documents"},
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
folder = endpoint.create_folder("documents", "Documents")
assert isinstance(folder, AssetFolder)
assert folder.slug == "documents"
assert folder.name == "Documents"
def test_create_folder_minimal(self, endpoint):
"""Test creating a folder with minimal parameters."""
mock_response = {
"data": {
"assets": {
"createFolder": {
"responseResult": {"succeeded": True},
"folder": {"id": 2, "slug": "images", "name": None},
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
folder = endpoint.create_folder("images")
assert folder.slug == "images"
assert folder.name is None
def test_create_folder_validation_error(self, endpoint):
"""Test create folder with invalid slug."""
with pytest.raises(ValidationError):
endpoint.create_folder("") # Empty slug
with pytest.raises(ValidationError):
endpoint.create_folder("///") # Just slashes
def test_delete_folder(self, endpoint):
"""Test deleting a folder."""
mock_response = {
"data": {
"assets": {
"deleteFolder": {
"responseResult": {"succeeded": True}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
result = endpoint.delete_folder(1)
assert result is True
def test_delete_folder_validation_error(self, endpoint):
"""Test delete folder with invalid ID."""
with pytest.raises(ValidationError):
endpoint.delete_folder(0)
with pytest.raises(ValidationError):
endpoint.delete_folder(-1)
# List operations with filters
def test_list_assets_with_folder_filter(self, endpoint):
"""Test listing assets filtered by folder."""
mock_response = {
"data": {
"assets": {
"list": [
{
"id": 1,
"filename": "doc.pdf",
"ext": "pdf",
"kind": "binary",
"mime": "application/pdf",
"fileSize": 2048,
"folderId": 1,
"folder": {"id": 1, "slug": "documents", "name": "Documents"},
"authorId": 1,
"authorName": "Admin",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
}
]
}
}
}
endpoint._post = Mock(return_value=mock_response)
assets = endpoint.list(folder_id=1)
assert len(assets) == 1
assert assets[0].folder_id == 1
def test_list_assets_with_kind_filter(self, endpoint):
"""Test listing assets filtered by kind."""
mock_response = {
"data": {
"assets": {
"list": [
{
"id": 1,
"filename": "photo.jpg",
"ext": "jpg",
"kind": "image",
"mime": "image/jpeg",
"fileSize": 5120,
"folderId": 0,
"authorId": 1,
"authorName": "Admin",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
}
]
}
}
}
endpoint._post = Mock(return_value=mock_response)
assets = endpoint.list(kind="image")
assert len(assets) == 1
assert assets[0].kind == "image"
def test_list_assets_empty(self, endpoint):
"""Test listing assets when none exist."""
mock_response = {"data": {"assets": {"list": []}}}
endpoint._post = Mock(return_value=mock_response)
assets = endpoint.list()
assert len(assets) == 0
# Error handling
def test_get_asset_not_found(self, endpoint):
"""Test getting non-existent asset."""
mock_response = {
"data": {"assets": {"single": None}},
"errors": [{"message": "Asset not found"}],
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Asset not found"):
endpoint.get(999)
def test_delete_asset_failure(self, endpoint):
"""Test delete asset API failure."""
mock_response = {
"data": {
"assets": {
"deleteAsset": {
"responseResult": {"succeeded": False, "message": "Permission denied"}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Permission denied"):
endpoint.delete(1)
def test_rename_asset_failure(self, endpoint):
"""Test rename asset API failure."""
mock_response = {
"data": {
"assets": {
"renameAsset": {
"responseResult": {"succeeded": False, "message": "Name already exists"}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Name already exists"):
endpoint.rename(1, "duplicate.png")
def test_move_asset_failure(self, endpoint):
"""Test move asset API failure."""
mock_response = {
"data": {
"assets": {
"moveAsset": {
"responseResult": {"succeeded": False, "message": "Folder not found"}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Folder not found"):
endpoint.move(1, 999)
def test_create_folder_failure(self, endpoint):
"""Test create folder API failure."""
mock_response = {
"data": {
"assets": {
"createFolder": {
"responseResult": {"succeeded": False, "message": "Folder already exists"}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Folder already exists"):
endpoint.create_folder("existing")
def test_delete_folder_failure(self, endpoint):
"""Test delete folder API failure."""
mock_response = {
"data": {
"assets": {
"deleteFolder": {
"responseResult": {"succeeded": False, "message": "Folder not empty"}
}
}
}
}
endpoint._post = Mock(return_value=mock_response)
with pytest.raises(APIError, match="Folder not empty"):
endpoint.delete_folder(1)
# Pagination
def test_iter_all_assets(self, endpoint):
"""Test iterating over all assets with pagination."""
# First page (smaller batch to ensure pagination works)
mock_response_page1 = {
"data": {
"assets": {
"list": [
{
"id": i,
"filename": f"file{i}.png",
"ext": "png",
"kind": "image",
"mime": "image/png",
"fileSize": 1024,
"folderId": 0,
"authorId": 1,
"authorName": "Admin",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
}
for i in range(1, 6) # 5 items
]
}
}
}
# Second page (empty - pagination stops)
mock_response_page2 = {"data": {"assets": {"list": []}}}
endpoint._post = Mock(
side_effect=[mock_response_page1, mock_response_page2]
)
all_assets = list(endpoint.iter_all(batch_size=5))
assert len(all_assets) == 5
assert all_assets[0].id == 1
assert all_assets[4].id == 5
# Normalization edge cases
def test_normalize_asset_data_minimal(self, endpoint):
"""Test normalizing asset data with minimal fields."""
data = {
"id": 1,
"filename": "test.png",
"ext": "png",
"kind": "image",
"mime": "image/png",
"fileSize": 1024,
}
normalized = endpoint._normalize_asset_data(data)
assert normalized["id"] == 1
assert normalized["filename"] == "test.png"
# Check that snake_case fields are present
assert "file_size" in normalized
assert normalized["file_size"] == 1024
def test_list_folders_empty(self, endpoint):
"""Test listing folders when none exist."""
mock_response = {"data": {"assets": {"folders": []}}}
endpoint._post = Mock(return_value=mock_response)
folders = endpoint.list_folders()
assert len(folders) == 0