from fastapi.testclient import TestClient from sqlalchemy import create_engine, Column, Integer, String, Date, Enum from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker DATABASE_URL = "sqlite:///./test_todo.db" engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() class Todo(Base): __tablename__ = "todos" id = Column(Integer, primary_key=True, index=True) title = Column(String(100), nullable=False) description = Column(String(500)) due_date = Column(Date, nullable=False) status = Column(Enum('pending', 'completed'), default='pending') Base.metadata.create_all(bind=engine) def get_db(): db = SessionLocal() try: yield db finally: db.close() app = FastAPI() @app.post("/todos/", response_model=Todo, status_code=201) def create_todo(todo: TodoCreate, db: Session = Depends(get_db)): db_todo = Todo(**todo.model_dump()) db.add(db_todo) db.commit() db.refresh(db_todo) return db_todo @app.get("/todos/", response_model=list[Todo]) def list_todos(status: str | None = None, db: Session = Depends(get_db)): if status: query = db.query(Todo).filter_by(status=status) else: query = db.query(Todo) return query.all() @app.get("/todos/{todo_id}", response_model=Todo) def get_todo(todo_id: int, db: Session = Depends(get_db)): todo = db.query(Todo).filter(Todo.id == todo_id).first() if not todo: raise HTTPException(status_code=404, detail="Not found") return todo @app.put("/todos/{todo_id}", response_model=Todo) def update_todo(todo_id: int, todo: TodoCreate, db: Session = Depends(get_db)): db_todo = db.query(Todo).filter(Todo.id == todo_id).first() if not db_todo: raise HTTPException(status_code=404, detail="Not found") for key, value in todo.model_dump().items(): setattr(db_todo, key, value) db.commit() db.refresh(db_todo) return db_todo @app.delete("/todos/{todo_id}", status_code=204) def delete_todo(todo_id: int, db: Session = Depends(get_db)): db_todo = db.query(Todo).filter(Todo.id == todo_id).first() if not db_todo: raise HTTPException(status_code=404, detail="Not found") db.delete(db_todo) db.commit() client = TestClient(app) def test_create_todo(): response = client.post("/todos/", json={"title": "Test Todo", "description": "This is a test todo.", "due_date": "2023-12-31"}) assert response.status_code == 201 data = response.json() assert "id" in data assert data["title"] == "Test Todo" assert data["description"] == "This is a test todo." assert data["due_date"] == "2023-12-31" assert data["status"] == "pending" def test_list_todos(): response = client.get("/todos/") assert response.status_code == 200 data = response.json() assert len(data) > 0 def test_get_todo_by_id(): todo_id = create_test_todo().json()["id"] response = client.get(f"/todos/{todo_id}") assert response.status_code == 200 data = response.json() assert "id" in data assert data["title"] == "Test Todo" def test_get_nonexistent_todo(): response = client.get("/todos/999") assert response.status_code == 404 def test_update_todo(): todo_id = create_test_todo().json()["id"] response = client.put(f"/todos/{todo_id}", json={"title": "Updated Todo"}) assert response.status_code == 200 data = response.json() assert "id" in data assert data["title"] == "Updated Todo" def test_delete_todo(): todo_id = create_test_todo().json()["id"] response = client.delete(f"/todos/{todo_id}") assert response.status_code == 204 def create_test_todo(): return client.post("/todos/", json={"title": "Test Todo", "description": "This is a test todo.", "due_date": "2023