def test_rename(testdb, fs, mocker): m = mocker.patch('memini.core.database.rename_table') fs.create_file(template.path('table1')) commands.rename('table1', 'table3') assert os.path.exists(template.path('table3')) assert not os.path.exists(template.path('table1')) m.assert_called_with('table1', 'table3')
def test_edit(fs, mocker): m = mocker.patch('memini.core.template.edit') fs.create_file(template.path('tpl1')) assert os.path.isfile(template.path('tpl1')) commands.edit('tpl1') m.assert_called_with('tpl1') with pytest.raises(NotFoundError) as excinfo: commands.edit('tpl2.odt') assert str(excinfo.value) == 'Cannot find any template "tpl2.odt".'
def test_rename_to_existing_template(testdb, fs): fs.create_file(template.path('table1')) fs.create_file(template.path('table3')) with pytest.raises(DestinationExistsError) as excinfo: commands.rename('table1', 'table3') assert str(excinfo.value) == 'Action cancelled: a template named '\ '"table3" already exists. Please rename or remove it before using '\ 'this name.'
def test_duplicate(testdb, fs, capsys): fs.create_file(template.path('table1')) commands.duplicate('table1', 'table3') assert os.path.exists(template.path('table1')) assert os.path.exists(template.path('table3')) assert database.table_exists('table1') assert database.table_exists('table3') commands.show('table1') table1_content = capsys.readouterr().out commands.show('table3') table3_content = capsys.readouterr().out assert table1_content == table3_content
def test_rename_missing_template(testdb, fs, mocker): # No template for source table: automatic creation def create_fake_template(*args): fs.create_file(template.path('table1')) m = mocker.patch('memini.core.template.create', side_effect=create_fake_template) commands.rename('table1', 'table4') m.assert_called_with('table1') assert os.path.exists(template.path('table4')) assert not os.path.exists(template.path('table1')) assert database.table_exists('table4') assert not database.table_exists('table1')
def generate(table_name, nb=DEFAULT_Q_NB, scheme=None, oldest_prevail=False, output=None, force=False, tpl=None, edit_after=True, use_previous=False): """ Generate a new document using n data from the table and the matching template. """ if use_previous: sw_data = sweepstakes.load_sweepstake(int(table_name)) table_name, rows = sw_data[0], sw_data[1:] table_name = table_name[0] if len(rows[0]) != len(database.get_cols(table_name)): raise ColumnsDoNotMatchError( len(database.get_cols(table_name)), len(rows[0]), table_name, database.get_cols(table_name), sweepstakes._get_sweepstake_name(use_previous)) if tpl is None: tpl_name = table_name else: if not os.path.isfile(template.path(tpl)): raise NotFoundError(f'Cannot find template file: {tpl}') tpl_name = tpl if output is None: output = f'{table_name}.{TEMPLATE_EXT}' if os.path.exists(output) and not force: overwrite = terminal.ask_yes_no(f'Output file {output} already ' f'exists, overwrite it?') if not overwrite: raise CommandCancelledError('generate') if not use_previous: rows = database.draw_rows(table_name, nb, oldest_prevail=oldest_prevail) data = _process_data(rows, scheme=scheme) template.sanitize(template.path(tpl_name)) basic = Template(source='', filepath=template.path(tpl_name)) basic_generated = basic.generate(o=data).render() with open(output, 'wb') as f: f.write(basic_generated.getvalue()) if edit_after: edit(output)
def test_delete(fs, mocker, testdb): fs.create_file(template.path('table1')) m = mocker.patch('memini.core.terminal.ask_yes_no') # User cancels the deletions m.side_effect = [False, False] commands.delete('table1') m.assert_has_calls([call('Delete table "table1"?'), call('Delete template "table1"?')]) assert os.path.exists(template.path('table1')) assert database.table_exists('table1') # User confirms the deletions m.side_effect = [True, True] commands.delete('table1') assert not os.path.exists(template.path('table1')) assert not database.table_exists('table1')
def test_list_(testdb, capsys, fs, sw): fs.create_file(template.path('template1')) fs.create_file(template.path('template2')) commands.list_('tables') captured = capsys.readouterr() assert captured.out == 'table1\ntable2\n' commands.list_('templates') captured = capsys.readouterr() assert captured.out == 'template1.odt\ntemplate2.odt\n' for s in sw: fs.create_file(s) commands.list_('sweepstakes') captured = capsys.readouterr() assert captured.out == \ '1_2020-07-02@15:13:22.json\n'\ '2_2020-07-02@15:13:23.json\n'\ '3_2020-07-02@15:13:24.json\n' with pytest.raises(CommandError) as excinfo: commands.list_('foo') assert str(excinfo.value) == 'Sorry, I can only list "tables", '\ '"templates" or "sweepstakes". Please use one of these three '\ 'keywords. I will not try to list "foo".'
def test_create_already_existing_table_or_template(testdb, capsys, fs): fs.create_file('some_source.txt') with pytest.raises(DestinationExistsError) as excinfo: commands.create('table1', 'some_source.txt', '<Latin>:<Français>') assert str(excinfo.value) == 'Action cancelled: a table named '\ '"table1" already exists. Please rename or remove it '\ 'before using this name.' fs.create_file(template.path('already_in_use')) with pytest.raises(DestinationExistsError) as excinfo: commands.create('already_in_use', 'some_source.txt', '<Latin>:<Français>') assert str(excinfo.value) == 'Action cancelled: a template named '\ '"already_in_use" already exists. Please rename or remove it '\ 'before using this name.'
def test_merge_errors(mocker, testdb, fs, capsys): with pytest.raises(MergeError) as excinfo: commands.merge([], 'table5') assert str(excinfo.value) == 'At least one table must be provided as '\ 'source.' with pytest.raises(MergeError) as excinfo: commands.merge(['table1', 'table2', 'table3', 'table4', 'table5'], 'table6') assert str(excinfo.value) == 'One or more tables cannot be found: '\ 'table3, table4, table5' with pytest.raises(MergeError) as excinfo: commands.merge(['table1', 'table2'], 'table3') assert str(excinfo.value) == 'All tables used as sources must have the '\ 'same number of columns. Found [2, 3] instead.' f1 = os.path.join(TESTS_DATADIR, 'latin_add.txt') fs.add_real_file(f1) # No template for source table: automatic creation def create_fake_template3(*args): fs.create_file(template.path('table3')) mocker.patch('memini.core.template.create', side_effect=create_fake_template3) commands.create('table3', f1, '<Latin>:<Français>') with pytest.raises(MergeError) as excinfo: commands.merge(['table1', 'table3'], 'table2') assert str(excinfo.value) == 'Number of columns mismatch: destination '\ 'table table2 has 3 columns, while source table(s) have 2 columns.' # Solitary template (no matching table) fs.create_file(template.path('table4')) with pytest.raises(MergeError) as excinfo: commands.merge(['table1', 'table3'], 'table4') assert str(excinfo.value) == 'Action cancelled: a template matching '\ '"table4" already exists, but not the matching table. Please rename '\ 'or remove it before using this name.'
def test_edit(mocker): mock_popen = mocker.patch('subprocess.Popen') template.edit('table1') mock_popen.assert_called_with([prefs.EDITOR, template.path('table1')])
def test_list_(fs): fs.create_file(template.path('table1')) fs.create_file(template.path('table2')) assert template.list_() == ['table1.odt', 'table2.odt']
def test_path(): expected = os.path.join(USER_TEMPLATES_PATH, f'NAME.{TEMPLATE_EXT}') assert template.path('NAME') == expected
def create_fake_template(*args): fs.create_file(template.path('table1'))
def test_merge(mocker, testdb, fs, capsys): f1 = os.path.join(TESTS_DATADIR, 'latin_add.txt') f2 = os.path.join(TESTS_DATADIR, 'latin.txt') fs.add_real_file(f1) fs.add_real_file(f2) # No template for source table: automatic creation def create_fake_template3(*args): fs.create_file(template.path('table3')) # No template for source table: automatic creation def create_fake_template4(*args): fs.create_file(template.path('table4')) # No template for source table: automatic creation def create_fake_template5(*args): fs.create_file(template.path('table5')) mocker.patch('memini.core.template.create', side_effect=create_fake_template3) commands.create('table3', f1, '<Latin>:<Français>') mocker.patch('memini.core.template.create', side_effect=create_fake_template5) commands.create('table5', f2, '<Latin>:<Français>') mocker.patch('memini.core.template.create', side_effect=create_fake_template4) commands.merge(['table1', 'table3'], 'table4') commands.show('table4') captured = capsys.readouterr() assert captured.out == \ ' id | col1 | col2 \n'\ '----+---------------------+------------------------------------\n'\ ' 1 | adventus, us, m. | arrivée \n'\ ' 2 | aqua , ae, f | eau \n'\ ' 3 | candidus, a, um | blanc \n'\ ' 4 | sol, solis, m | soleil \n'\ ' 5 | judex, dicis, m. | juge \n'\ ' 6 | judicium, i, n. | jugement, décision \n'\ ' 7 | jus, uris, n | droit \n'\ ' 8 | justitia, ae, f. | justice (vertu) \n'\ ' 9 | juvenis, is , m | homme jeune (30 à45 ans) \n'\ ' 10 | juventus, utis, f. | jeunesse \n'\ ' 11 | labor, oris, m. | peine, souffrance, travail pénible \n'\ ' 12 | lacrima, ae, f. | larme \n'\ ' 13 | laetitia, ae, f. | la joie \n' os.remove(template.path('table5')) mocker.patch('memini.core.template.create', side_effect=create_fake_template5) commands.merge(['table1'], 'table5') commands.show('table5') captured = capsys.readouterr() assert captured.out == \ ' id | Latin | Français \n'\ '----+----------------------+---------------------\n'\ ' 1 | actio, onis, f. | procès , plaidoirie \n'\ ' 2 | admiratio, onis, f. | admiration \n'\ ' 3 | adventus, us, m. | arrivée \n'\ ' 4 | aedilis, is, m. | édile \n'\ ' 5 | aetas, atis, f âge | vie \n'\ ' 6 | ambitio, onis, f. | ambition \n'\ ' 7 | ambitus, us, m. | la brigue \n'\ ' 8 | amicitia, ae, f. | amitié \n'\ ' 9 | amicus, i, m. | ami \n'\ ' 10 | amor, oris, m. | amour \n'\ ' 11 | anima, ae, f. | coeur, âme \n'\ ' 12 | adventus, us, m. | arrivée \n'\ ' 13 | aqua , ae, f | eau \n'\ ' 14 | candidus, a, um | blanc \n'\ ' 15 | sol, solis, m | soleil \n'