From a3588e347f62f6c4f92341f34775dd7a1dd41a37 Mon Sep 17 00:00:00 2001 From: mishtiagrawal02-cloud Date: Fri, 29 May 2026 01:51:24 +0530 Subject: [PATCH] fix: validate recommendation input values --- .gitignore | 1 + tests/test_basic.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ utils/recommender.py | 42 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b9216153..cb8d63d9 100644 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,4 @@ app.*.symbols venv/ .venv/ +.DS_Store diff --git a/tests/test_basic.py b/tests/test_basic.py index a7b0f05b..75b52192 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -182,6 +182,38 @@ def test_validate_all_valid(): errors = validate_recommendation_inputs("Python", "Beginner", "Web", "Low") assert errors == [], f"Unexpected errors: {errors}" +def test_validate_invalid_level(): + """Invalid level should return an error.""" + errors = validate_recommendation_inputs( + "Python", + "Expert", + "Web", + "Low" + ) + assert any("Invalid experience level" in e for e in errors) + + +def test_validate_invalid_interest(): + """Invalid interest should return an error.""" + errors = validate_recommendation_inputs( + "Python", + "Beginner", + "Blockchain", + "Low" + ) + assert any("Invalid interest" in e for e in errors) + + +def test_validate_invalid_time(): + """Invalid time should return an error.""" + errors = validate_recommendation_inputs( + "Python", + "Beginner", + "Web", + "Very High" + ) + assert any("Invalid time availability" in e for e in errors) + def test_validate_missing_skills(): """An empty skills field must produce an error.""" @@ -284,6 +316,20 @@ def test_recommend_api_missing_field(): assert response.status_code in (400, 415) assert "error" in response.get_json() +def test_recommend_api_invalid_level(): + """API should return 400 for invalid experience level.""" + client = get_client() + + response = client.post("/api/recommend", json={ + "skills": "Python", + "level": "Expert", + "interest": "Data", + "time": "Low" + }) + + assert response.status_code == 400 + assert "error" in response.get_json() + def test_recommend_api_empty_body(): """The API should return 400 when the body is not valid JSON.""" diff --git a/utils/recommender.py b/utils/recommender.py index 8a53c64b..66e0ed82 100644 --- a/utils/recommender.py +++ b/utils/recommender.py @@ -28,6 +28,31 @@ "c++": "cpp", "web dev": "javascript" } +VALID_LEVELS = { + "beginner", + "intermediate", + "advanced" +} + +VALID_TIME = { + "low", + "medium", + "high" +} + +VALID_INTERESTS = { + "web", + "data", + "education", + "automation", + "games", + "machine learning/ai", + "devops", + "mobile", + "artificial intelligence", + "cloud computing", + "mobile app development", +} def parse_skills(skills_string): @@ -133,7 +158,7 @@ def get_recommendations(skills_string, level, interest, time_availability): def validate_recommendation_inputs(skills, level, interest, time_availability): """ - Validate all four required fields. + Validate all recommendation inputs. Returns a list of error strings. An empty list means all inputs are valid. """ errors = [] @@ -143,11 +168,26 @@ def validate_recommendation_inputs(skills, level, interest, time_availability): if not level or not level.strip(): errors.append("Please select an experience level.") + elif level.strip().lower() not in VALID_LEVELS: + errors.append( + "Invalid experience level. " + "Choose Beginner, Intermediate, or Advanced." + ) if not interest or not interest.strip(): errors.append("Please select an area of interest.") + elif interest.strip().lower() not in VALID_INTERESTS: + errors.append( + "Invalid interest. " + "Choose a supported interest area." + ) if not time_availability or not time_availability.strip(): errors.append("Please select your time availability.") + elif time_availability.strip().lower() not in VALID_TIME: + errors.append( + "Invalid time availability. " + "Choose Low, Medium, or High." + ) return errors