import pytest from parser_lab.importing import read_upload, ImportOptions, ImportErrorDetail from parser_lab.paths import resolve_pointer,field_summary def test_csv_preserves_strings_and_quotes(): r = read_upload('id;answer\n001;"a\nb"\n002;\n'.encode(), 'a.csv', ImportOptions(delimiter=';')) assert r.records == [{'id': '001', 'answer': 'a\nb'}, {'id': '002', 'answer': ''}] def test_json_preserves_types_and_nested_selection(): r = read_upload(b'{"items":[{"x":null},{"x":false},{"x":0},{"x":""},{}]}', 'a.json', ImportOptions(record_pointer='/items')) assert r.records == [{'x': None}, {'x': False}, {'x': 0}, {'x': ''}, {}] assert resolve_pointer({'a/b': {'~c': 0}}, '/a~1b/~0c') == (True, 0) assert resolve_pointer({}, '/x') == (False, None) @pytest.mark.parametrize('data,name', [(b'a,a\n1,2','a.csv'), (b'a,b\n1,2,3','a.csv'), (b'{"x":1,"x":2}','a.json'), (b'{"x":NaN}','a.json'), (b'[1,2]','a.json'), (b'[]','a.json')]) def test_invalid_inputs_rejected(data, name): with pytest.raises(ImportErrorDetail): read_upload(data, name, ImportOptions()) def test_jsonl_reports_line_and_blanks(): assert read_upload(b'{"a":1}\n\n{"b":2}', 'a.jsonl', ImportOptions()).warnings with pytest.raises(ImportErrorDetail, match='3'): read_upload(b'{"a":1}\n\nBAD', 'a.jsonl', ImportOptions()) def test_encoding_limits_and_fields(): assert read_upload('имя;возраст\nОля;20'.encode('cp1251'), 'a.csv', ImportOptions(encoding='cp1251', delimiter=';')).records[0]['имя'] == 'Оля' assert '/later' in read_upload(b'[{}, {"later":1}]','a.json',ImportOptions()).fields with pytest.raises(ImportErrorDetail): read_upload(b'12345','a.json',ImportOptions(), max_bytes=4) with pytest.raises(ImportErrorDetail): read_upload(b'[{},{}]','a.json',ImportOptions(), max_records=1) with pytest.raises(ImportErrorDetail): read_upload(('[' + '{"x":'*21 + '0' + '}'*21 + ']').encode(),'a.json',ImportOptions()) def test_field_tree_and_missing_counts(): summary=field_summary([{'profile':{'age':20},'a/b':0},{'profile':{}},{}]) assert summary['/profile/age']['missing']==2 assert summary['/profile/age']['parent']=='/profile' assert summary['/a~1b']['label']=='a/b'