|
|
"""Unit tests for project tools.""" |
|
|
|
|
|
import pytest |
|
|
from app.tools.projects import ( |
|
|
create_project, list_projects, join_project, check_project_id_available |
|
|
) |
|
|
from app.database import SessionLocal |
|
|
from app.models import Project, ProjectMembership |
|
|
|
|
|
|
|
|
class TestCheckProjectIdAvailable: |
|
|
"""Test project ID availability checking.""" |
|
|
|
|
|
def test_available_id(self, create_user): |
|
|
"""Test checking an available project ID.""" |
|
|
result = check_project_id_available("nonexistent-project") |
|
|
|
|
|
assert result["available"] == True |
|
|
assert result["project_id"] == "nonexistent-project" |
|
|
|
|
|
def test_unavailable_id(self, create_user): |
|
|
"""Test checking an ID that's already taken.""" |
|
|
user = create_user("Test", "User") |
|
|
|
|
|
|
|
|
create_project("takenid", "Description", user.id) |
|
|
|
|
|
|
|
|
result = check_project_id_available("takenid") |
|
|
|
|
|
assert result["available"] == False |
|
|
assert result["project_id"] == "takenid" |
|
|
|
|
|
|
|
|
class TestCreateProject: |
|
|
"""Test project creation with name as ID.""" |
|
|
|
|
|
def test_create_project_uses_name_as_id(self, create_user): |
|
|
"""Test that project name is used as project ID.""" |
|
|
user = create_user("Creator", "Test") |
|
|
|
|
|
result = create_project("fastgate", "A fast gateway", user.id) |
|
|
|
|
|
assert result["id"] == "fastgate" |
|
|
assert result["name"] == "fastgate" |
|
|
assert result["description"] == "A fast gateway" |
|
|
assert result["created_by"] == user.id |
|
|
|
|
|
def test_create_project_adds_owner_membership(self, create_user): |
|
|
"""Test that creator is added as owner.""" |
|
|
user = create_user("Owner", "Test") |
|
|
|
|
|
result = create_project("ownerproj", "Test", user.id) |
|
|
|
|
|
db = SessionLocal() |
|
|
try: |
|
|
membership = db.query(ProjectMembership).filter( |
|
|
ProjectMembership.project_id == result["id"], |
|
|
ProjectMembership.user_id == user.id |
|
|
).first() |
|
|
|
|
|
assert membership is not None |
|
|
assert membership.role == "owner" |
|
|
finally: |
|
|
db.close() |
|
|
|
|
|
def test_create_project_duplicate_id_fails(self, create_user): |
|
|
"""Test that creating project with existing ID fails.""" |
|
|
user = create_user("Test", "User") |
|
|
|
|
|
|
|
|
create_project("duplicate", "First project", user.id) |
|
|
|
|
|
|
|
|
result = create_project("duplicate", "Second project", user.id) |
|
|
|
|
|
assert "error" in result |
|
|
assert "already exists" in result["error"] |
|
|
|
|
|
def test_create_project_nonexistent_user(self): |
|
|
"""Test creating project with non-existent user fails.""" |
|
|
result = create_project("orphan", "No owner", "nonexistent-user-id") |
|
|
|
|
|
assert "error" in result |
|
|
assert "not found" in result["error"] |
|
|
|
|
|
|
|
|
class TestListProjects: |
|
|
"""Test listing user's projects.""" |
|
|
|
|
|
def test_list_projects_empty(self, create_user): |
|
|
"""Test listing projects for user with no projects.""" |
|
|
user = create_user("New", "User") |
|
|
|
|
|
result = list_projects(user.id) |
|
|
|
|
|
assert "projects" in result |
|
|
assert len(result["projects"]) == 0 |
|
|
|
|
|
def test_list_projects_with_owned_project(self, create_user): |
|
|
"""Test listing projects includes owned projects.""" |
|
|
user = create_user("Owner", "Test") |
|
|
create_project("ownedproj", "My project", user.id) |
|
|
|
|
|
result = list_projects(user.id) |
|
|
|
|
|
assert len(result["projects"]) == 1 |
|
|
assert result["projects"][0]["name"] == "ownedproj" |
|
|
assert result["projects"][0]["role"] == "owner" |
|
|
|
|
|
def test_list_projects_with_member_project(self, create_user): |
|
|
"""Test listing projects includes joined projects.""" |
|
|
owner = create_user("Owner", "Test") |
|
|
member = create_user("Member", "Test") |
|
|
|
|
|
create_project("sharedproj", "Shared project", owner.id) |
|
|
join_project("sharedproj", member.id) |
|
|
|
|
|
result = list_projects(member.id) |
|
|
|
|
|
assert len(result["projects"]) == 1 |
|
|
assert result["projects"][0]["name"] == "sharedproj" |
|
|
assert result["projects"][0]["role"] == "member" |
|
|
|
|
|
|
|
|
class TestJoinProject: |
|
|
"""Test joining existing projects.""" |
|
|
|
|
|
def test_join_project_success(self, create_user): |
|
|
"""Test successfully joining a project.""" |
|
|
owner = create_user("Owner", "Test") |
|
|
member = create_user("Member", "Test") |
|
|
|
|
|
create_project("jointest", "Test project", owner.id) |
|
|
result = join_project("jointest", member.id) |
|
|
|
|
|
assert "message" in result |
|
|
assert result["project_id"] == "jointest" |
|
|
assert result["role"] == "member" |
|
|
|
|
|
def test_join_project_already_member(self, create_user): |
|
|
"""Test joining a project you're already a member of.""" |
|
|
owner = create_user("Owner", "Test") |
|
|
member = create_user("Member", "Test") |
|
|
|
|
|
create_project("alreadyin", "Test project", owner.id) |
|
|
join_project("alreadyin", member.id) |
|
|
|
|
|
|
|
|
result = join_project("alreadyin", member.id) |
|
|
|
|
|
assert "Already a member" in result.get("message", "") |
|
|
|
|
|
def test_join_nonexistent_project(self, create_user): |
|
|
"""Test joining a project that doesn't exist.""" |
|
|
user = create_user("User", "Test") |
|
|
|
|
|
result = join_project("doesnotexist", user.id) |
|
|
|
|
|
assert "error" in result |
|
|
assert "not found" in result["error"] |
|
|
|
|
|
def test_join_project_nonexistent_user(self, create_user): |
|
|
"""Test joining with non-existent user.""" |
|
|
owner = create_user("Owner", "Test") |
|
|
create_project("validproj", "Test", owner.id) |
|
|
|
|
|
result = join_project("validproj", "nonexistent-user") |
|
|
|
|
|
assert "error" in result |
|
|
assert "not found" in result["error"] |
|
|
|