"""用户批量导入 CSV / XLSX / XLS 回归测试。""" import io import unittest from pathlib import Path from unittest.mock import patch from openpyxl import Workbook from routes.users import ( _normalize_department, _parse_user_import_csv, _parse_user_import_file, _parse_user_import_xls, ) ROOT = Path(__file__).resolve().parents[1] APP_JS = (ROOT / 'static' / 'js' / 'app.js').read_text(encoding='utf-8') HEADERS = ['用户名', '密码', '真实姓名', '角色', '员工级别', '岗位', '手机', '邮箱', '状态'] class UserImportFileTest(unittest.TestCase): def test_accepts_excel_style_cr_line_endings(self): content = ( '用户名,密码,真实姓名,角色,员工级别,岗位,手机,邮箱,状态\r' 'zhangsan,Abc123!@#45,张三,viewer,employee,采购专员,,,1\r' ) rows = _parse_user_import_csv(content.encode('utf-8-sig')) self.assertEqual(1, len(rows)) self.assertEqual('zhangsan', rows[0]['用户名']) self.assertEqual('Abc123!@#45', rows[0]['密码']) def test_accepts_crlf_and_gbk(self): content = ( '用户名,密码,真实姓名,角色,员工级别,岗位,部门,手机,邮箱,状态\r\n' 'lisi,Xyz789$%^01,李四,viewer,employee,仓库专员,天猫,,,1\r\n' ) rows = _parse_user_import_file(content.encode('gbk'), '用户列表.CSV') self.assertEqual('李四', rows[0]['真实姓名']) self.assertEqual('天猫', rows[0]['部门']) def test_department_options_accept_blank_and_reject_unknown(self): self.assertEqual('', _normalize_department('')) for department in ('天猫', '京东', '天猫国际', '京东国际', '阿里', '新媒体', '拼多多', 'AI指挥部', '采购部', '产品部'): self.assertEqual(department, _normalize_department(department)) with self.assertRaisesRegex(ValueError, '部门必须为'): _normalize_department('其他部门') def test_accepts_xlsx_and_preserves_integer_phone(self): workbook = Workbook() sheet = workbook.active sheet.append(HEADERS) sheet.append(['wangwu', 'Safe123!@#45', '王五', 'viewer', 'employee', '仓库专员', 13800138000, '', 1]) output = io.BytesIO() workbook.save(output) workbook.close() rows = _parse_user_import_file(output.getvalue(), '用户列表.xlsx') self.assertEqual(1, len(rows)) self.assertEqual('wangwu', rows[0]['用户名']) self.assertEqual('13800138000', rows[0]['手机']) self.assertEqual('1', rows[0]['状态']) def test_accepts_xls_first_sheet(self): class FakeSheet: nrows = 2 def row_values(self, index): return HEADERS if index == 0 else [ 'zhaoliu', 'Strong123!@#', '赵六', 'viewer', 'employee', '采购专员', 13900139000.0, '', 1.0 ] class FakeBook: nsheets = 1 def sheet_by_index(self, index): self.requested_index = index return FakeSheet() with patch('xlrd.open_workbook', return_value=FakeBook()) as open_workbook: rows = _parse_user_import_xls(b'fake-xls') open_workbook.assert_called_once_with(file_contents=b'fake-xls') self.assertEqual('zhaoliu', rows[0]['用户名']) self.assertEqual('13900139000', rows[0]['手机']) def test_rejects_wrong_template_headers(self): with self.assertRaisesRegex(ValueError, '表头'): _parse_user_import_csv('账号,口令\na,b\n'.encode('utf-8')) def test_reports_malformed_csv_without_partial_iteration(self): malformed = '用户名,密码\n"zhangsan,Abc123!@#45\n'.encode('utf-8') with self.assertRaisesRegex(ValueError, 'CSV格式错误'): _parse_user_import_csv(malformed) def test_rejects_unsupported_extension(self): with self.assertRaisesRegex(ValueError, '仅支持CSV、XLSX、XLS'): _parse_user_import_file(b'content', 'users.txt') def test_frontend_accepts_all_three_formats(self): self.assertIn('accept=".csv,.xlsx,.xls"', APP_JS) self.assertIn("['csv', 'xlsx', 'xls'].includes(extension)", APP_JS) self.assertIn('file_base64: result.slice(commaIndex + 1)', APP_JS) self.assertIn('id="userDepartmentFilter"', APP_JS) self.assertIn('id="editDepartment"', APP_JS) if __name__ == '__main__': unittest.main()