import pytest from sqlalchemy import select from app.models.entities import Directory @pytest.mark.anyio async def test_list_root_directory_children_starts_empty(api_client) -> None: response = await api_client.get("/api/directories/dir_root/children") assert response.status_code == 200 payload = response.json() assert payload["directory"]["id"] == "dir_root" assert payload["directory"]["name"] == "/" assert payload["items"] == [] assert payload["next_cursor"] is None @pytest.mark.anyio async def test_create_directory_and_list_children(api_client) -> None: create_response = await api_client.post( "/api/directories", json={"parent_id": "dir_root", "name": "photos"}, ) assert create_response.status_code == 201 created_directory = create_response.json()["directory"] assert created_directory["parent_id"] == "dir_root" assert created_directory["name"] == "photos" list_response = await api_client.get("/api/directories/dir_root/children") assert list_response.status_code == 200 payload = list_response.json() assert [item["name"] for item in payload["items"]] == ["photos"] assert payload["items"][0]["kind"] == "directory" @pytest.mark.anyio async def test_list_children_includes_directories_before_files(api_client, create_file_metadata) -> None: create_response = await api_client.post( "/api/directories", json={"parent_id": "dir_root", "name": "photos"}, ) assert create_response.status_code == 201 await create_file_metadata(name="movie.mp4", content_hash="hash_movie_mp4") list_response = await api_client.get("/api/directories/dir_root/children") assert list_response.status_code == 200 payload = list_response.json() assert [item["kind"] for item in payload["items"]] == ["directory", "file"] assert payload["items"][0]["name"] == "photos" assert payload["items"][1]["name"] == "movie.mp4" assert payload["items"][1]["mime_type"] == "video/mp4" assert payload["items"][1]["size_bytes"] == 1048576 @pytest.mark.anyio async def test_create_directory_requires_existing_parent(api_client) -> None: response = await api_client.post( "/api/directories", json={"parent_id": "dir_missing", "name": "photos"}, ) assert response.status_code == 404 assert response.json()["error"]["code"] == "directory_not_found" @pytest.mark.anyio async def test_create_directory_rejects_duplicate_name(api_client) -> None: first = await api_client.post( "/api/directories", json={"parent_id": "dir_root", "name": "photos"}, ) second = await api_client.post( "/api/directories", json={"parent_id": "dir_root", "name": "photos"}, ) assert first.status_code == 201 assert second.status_code == 409 assert second.json()["error"]["code"] == "directory_conflict" @pytest.mark.anyio async def test_rename_directory(api_client) -> None: create_response = await api_client.post( "/api/directories", json={"parent_id": "dir_root", "name": "photos"}, ) directory_id = create_response.json()["directory"]["id"] rename_response = await api_client.post( f"/api/directories/{directory_id}/rename", json={"name": "images"}, ) assert rename_response.status_code == 200 assert rename_response.json()["directory"]["name"] == "images" list_response = await api_client.get("/api/directories/dir_root/children") assert [item["name"] for item in list_response.json()["items"]] == ["images"] @pytest.mark.anyio async def test_move_directory_updates_parent_listing_and_descendant_paths(api_client, session_factory) -> None: parent_a = await api_client.post("/api/directories", json={"parent_id": "dir_root", "name": "a"}) parent_b = await api_client.post("/api/directories", json={"parent_id": "dir_root", "name": "b"}) child = await api_client.post("/api/directories", json={"parent_id": parent_a.json()["directory"]["id"], "name": "child"}) move_response = await api_client.post( f"/api/directories/{parent_a.json()['directory']['id']}/move", json={"target_parent_id": parent_b.json()["directory"]["id"]}, ) assert move_response.status_code == 200 root_children = await api_client.get("/api/directories/dir_root/children") assert [item["name"] for item in root_children.json()["items"]] == ["b"] b_children = await api_client.get(f"/api/directories/{parent_b.json()['directory']['id']}/children") assert [item["name"] for item in b_children.json()["items"]] == ["a"] async with session_factory() as session: moved_directory = ( await session.execute(select(Directory).where(Directory.id == parent_a.json()["directory"]["id"])) ).scalar_one() moved_child = ( await session.execute(select(Directory).where(Directory.id == child.json()["directory"]["id"])) ).scalar_one() assert moved_directory.path_key == "/b/a" assert moved_child.path_key == "/b/a/child" @pytest.mark.anyio async def test_move_directory_rejects_descendant_target(api_client) -> None: parent = await api_client.post("/api/directories", json={"parent_id": "dir_root", "name": "a"}) child = await api_client.post("/api/directories", json={"parent_id": parent.json()["directory"]["id"], "name": "child"}) move_response = await api_client.post( f"/api/directories/{parent.json()['directory']['id']}/move", json={"target_parent_id": child.json()["directory"]["id"]}, ) assert move_response.status_code == 400 assert move_response.json()["error"]["code"] == "validation_error"