"""Unit tests for FormData.from_sheet_row + sheet row helpers. No DB, no network. Pins the Google Form Responses header keys and YoG rules. """ from __future__ import annotations from datetime import datetime, timezone from g_sheet import plugins from g_sheet.enums import FORM_DATA_FIELDS from g_sheet.models import FormData FORM_RESPONSE_RECORD = { "Timestamp": "7/2/2026 17:50:19", "Email": "nusratazra@gmail.com", "Full Name": "Nusrat Azra", "Gender": "Female", "Date of Birth": "7/24/1984", "Marital Status": "Single", "CGPA": "3.5", "University": "Karachi University", "If your university is not listed above, please specify its name.": "", "Educational Degree": "Masters", "Year of Graduation": "12/2/2007", "Position Applied For": "Executive Secretary", "LinkedIn Profile Link": ( "https://www.linkedin.com/in/nusrat-azra-executive-manager-to-c-suite-3bb86719/" ), "Drop your updated resume": "https://drive.google.com/open?id=1l5HOY5R6KiL6270A_sV56FkdX6EIGfI4", "How soon can you join us?": "1 - 2 weeks", "Phone number (03XX-XXXXXXX)": "03312464228", "Are you willing to relocate?": "Yes", "Residing City": "Karachi", "Residing Country": "Pakistan", "Area of Interest": "", "Recruiter": "", "Director / POC / Category": "Operations", "National Identification No. (42000-XXXXXXX-X)": "4250105627772", "Where did you hear about the position you're applying for?": "Indeed", "Current Salary": "110k", "Expected Salary": "150k", "HR Comment": "Good profile", } def test_from_sheet_row_maps_form_response_keys(): mapped = FormData.from_sheet_row( "Form Responses - Candidate Database Sheet 2026", 9, FORM_RESPONSE_RECORD, ) assert mapped["name"] == "Nusrat Azra" assert mapped["candidate_email"] == "nusratazra@gmail.com" assert mapped["candidate_number"] == "03312464228" assert mapped["gender"] == "Female" assert mapped["date_of_birth"] == datetime(1984, 7, 24, tzinfo=timezone.utc) assert mapped["cnic"] == "4250105627772" assert mapped["cgpa"] == "3.5" assert mapped["degree"] == "Masters" assert mapped["university"] == "Karachi University" assert mapped["position_applied_for"] == "Executive Secretary" assert mapped["notice_period"] == "1 - 2 weeks" assert mapped["source_of_application"] == "Indeed" assert mapped["ho_availability"] == "Yes" assert mapped["marital_status"] == "Single" assert mapped["residing_city"] == "Karachi" assert mapped["residing_country"] == "Pakistan" assert mapped["director_poc_category"] == "Operations" assert mapped["hr_comments"] == "Good profile" assert mapped["current_salary_value"] == 110000 assert mapped["expected_salary_value"] == 150000 assert mapped["entry_year"] == "12/2/2007" assert mapped["entry_date"] is not None assert mapped["entry_time"] == "17:50" assert mapped["name"] != "7/2/2026 17:50:19" assert mapped["row_number"] == 9 assert mapped["sheet"] == "Form Responses - Candidate Database Sheet 2026" assert mapped["raw_record"]["Full Name"] == "Nusrat Azra" def test_year_of_graduation_prefers_second_when_present(): data = { "Full Name": "Ada", "Year of Graduation": "2010", "Year of Graduation_1": "2015", } mapped = FormData.from_sheet_row("tab", 2, data) assert mapped["entry_year"] == "2015" def test_year_of_graduation_uses_first_when_second_blank(): data = { "Full Name": "Ada", "Year of Graduation": "2010", "Year of Graduation_1": " ", } mapped = FormData.from_sheet_row("tab", 2, data) assert mapped["entry_year"] == "2010" def test_year_of_graduation_none_when_both_blank(): data = { "Full Name": "Ada", "Year of Graduation": "", "Year of Graduation_1": "", } mapped = FormData.from_sheet_row("tab", 2, data) assert mapped["entry_year"] is None def test_year_of_graduation_single_column(): data = {"Full Name": "Ada", "Year of Graduation": "2012"} mapped = FormData.from_sheet_row("tab", 2, data) assert mapped["entry_year"] == "2012" def test_duplicate_year_header_becomes_year_of_graduation_1(): headers = plugins.normalise_headers( ["Full Name", "Year of Graduation", "Year of Graduation"], ) assert headers == ["Full Name", "Year of Graduation", "Year of Graduation_1"] def test_parse_salary_and_score(): assert plugins.parse_salary("110k") == 110000 assert plugins.parse_salary("60k-70k") == 60000 assert plugins.parse_salary("Negotiable") is None assert plugins.parse_score("7") == 7 assert plugins.parse_score("15") is None def test_rows_to_indexed_records_keeps_true_sheet_row_across_blank(): rows = [ ["Name", "Age"], ["Ada", "30"], ["", ""], ["Bob", "40"], ] indexed = plugins.rows_to_indexed_records(rows) assert indexed == [ (2, {"Name": "Ada", "Age": "30"}), (4, {"Name": "Bob", "Age": "40"}), ] assert plugins.rows_to_records(rows) == [ {"Name": "Ada", "Age": "30"}, {"Name": "Bob", "Age": "40"}, ] def test_form_data_fields_match_model(): assert set(FORM_DATA_FIELDS) == set(FormData.model_fields)