class TestProjectRepositoryForCategories(Test): def setUp(self): super(TestProjectRepositoryForCategories, self).setUp() self.project_repo = ProjectRepository(db) def test_get_category_return_none_if_no_category(self): """Test get_category method returns None if there is no category with the specified id""" category = self.project_repo.get_category(200) assert category is None, category def test_get_category_returns_category(self): """Test get_category method returns a category if exists""" category = CategoryFactory.create() retrieved_category = self.project_repo.get_category(category.id) assert category == retrieved_category, retrieved_category def test_get_category_by(self): """Test get_category returns a category with the specified attribute""" category = CategoryFactory.create(name='My Cat', short_name='mycat') retrieved_category = self.project_repo.get_category_by(name=category.name) assert category == retrieved_category, retrieved_category def test_get_category_by_returns_none_if_no_category(self): """Test get_category returns None if no category matches the query""" CategoryFactory.create(name='My Project', short_name='mycategory') category = self.project_repo.get_by(name='no_name') assert category is None, category def get_all_returns_list_of_all_categories(self): """Test get_all_categories returns a list of all the existing categories""" categories = CategoryFactory.create_batch(3) retrieved_categories = self.project_repo.get_all_categories() assert isinstance(retrieved_categories, list) assert len(retrieved_categories) == len(categories), retrieved_categories for category in retrieved_categories: assert category in categories, category def test_filter_categories_by_no_matches(self): """Test filter_categories_by returns an empty list if no categories match the query""" CategoryFactory.create(name='My Project', short_name='mycategory') retrieved_categories = self.project_repo.filter_categories_by(name='no_name') assert isinstance(retrieved_categories, list) assert len(retrieved_categories) == 0, retrieved_categories def test_filter_categories_by_one_condition(self): """Test filter_categories_by returns a list of categories that meet the filtering condition""" CategoryFactory.create_batch(3, description='generic category') should_be_missing = CategoryFactory.create(description='other category') retrieved_categories = (self.project_repo .filter_categories_by(description='generic category')) assert len(retrieved_categories) == 3, retrieved_categories assert should_be_missing not in retrieved_categories, retrieved_categories def test_filter_categories_by_limit_offset(self): """Test that filter_categories_by supports limit and offset options""" CategoryFactory.create_batch(4) all_categories = self.project_repo.filter_categories_by() first_two = self.project_repo.filter_categories_by(limit=2) last_two = self.project_repo.filter_categories_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_categories[:2] assert last_two == all_categories[2:] def test_save_category(self): """Test save_category persist the category""" category = CategoryFactory.build() assert self.project_repo.get(category.id) is None self.project_repo.save_category(category) assert self.project_repo.get_category(category.id) == category, "Category not saved" def test_save_category_fails_if_integrity_error(self): """Test save_category raises a DBIntegrityError if the instance to be saved lacks a required value""" category = CategoryFactory.build(name=None) assert_raises(DBIntegrityError, self.project_repo.save_category, category) def test_save_category_only_saves_categories(self): """Test save_category raises a WrongObjectError when an object which is not a Category instance is saved""" bad_object = ProjectFactory.build() assert_raises(WrongObjectError, self.project_repo.save_category, bad_object) def test_update_category(self): """Test update_category persists the changes made to the category""" category = CategoryFactory.create(description='this is a category') category.description = 'the description has changed' self.project_repo.update_category(category) updated_category = self.project_repo.get_category(category.id) assert updated_category.description == 'the description has changed', updated_category def test_update_category_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" category = CategoryFactory.create() category.name = None assert_raises(DBIntegrityError, self.project_repo.update_category, category) def test_update_category_only_updates_categories(self): """Test update_category raises a WrongObjectError when an object which is not a Category instance is updated""" bad_object = ProjectFactory.build() assert_raises(WrongObjectError, self.project_repo.update_category, bad_object) def test_delete_category(self): """Test delete_category removes the category instance""" category = CategoryFactory.create() self.project_repo.delete_category(category) deleted = self.project_repo.get_category(category.id) assert deleted is None, deleted def test_delete_category_only_deletes_categories(self): """Test delete_category raises a WrongObjectError if is requested to delete other than a category""" bad_object = dict() assert_raises(WrongObjectError, self.project_repo.delete_category, bad_object)
class TestProjectRepositoryForCategories(Test): def setUp(self): super(TestProjectRepositoryForCategories, self).setUp() self.project_repo = ProjectRepository(db) @with_context def test_get_category_return_none_if_no_category(self): """Test get_category method returns None if there is no category with the specified id""" category = self.project_repo.get_category(200) assert category is None, category @with_context def test_get_category_returns_category(self): """Test get_category method returns a category if exists""" category = CategoryFactory.create() retrieved_category = self.project_repo.get_category(category.id) assert category == retrieved_category, retrieved_category @with_context def test_get_category_by(self): """Test get_category returns a category with the specified attribute""" category = CategoryFactory.create(name='My Cat', short_name='mycat') retrieved_category = self.project_repo.get_category_by( name=category.name) assert category == retrieved_category, retrieved_category @with_context def test_get_category_by_returns_none_if_no_category(self): """Test get_category returns None if no category matches the query""" CategoryFactory.create(name='My Project', short_name='mycategory') category = self.project_repo.get_by(name='no_name') assert category is None, category @with_context def get_all_returns_list_of_all_categories(self): """Test get_all_categories returns a list of all the existing categories""" categories = CategoryFactory.create_batch(3) retrieved_categories = self.project_repo.get_all_categories() assert isinstance(retrieved_categories, list) assert len(retrieved_categories) == len( categories), retrieved_categories for category in retrieved_categories: assert category in categories, category @with_context def test_filter_categories_by_no_matches(self): """Test filter_categories_by returns an empty list if no categories match the query""" CategoryFactory.create(name='My Project', short_name='mycategory') retrieved_categories = self.project_repo.filter_categories_by( name='no_name') assert isinstance(retrieved_categories, list) assert len(retrieved_categories) == 0, retrieved_categories @with_context def test_filter_categories_by_ownerid(self): """Test filter_categories_by removes ownerid from query.""" CategoryFactory.create(name='My Project', short_name='mycategory') retrieved_categories = self.project_repo.filter_categories_by( short_name='mycategory', owner_id=1) assert isinstance(retrieved_categories, list) assert len(retrieved_categories) == 1, retrieved_categories @with_context def test_filter_categories_by_one_condition(self): """Test filter_categories_by returns a list of categories that meet the filtering condition""" CategoryFactory.create_batch(3, description='generic category') should_be_missing = CategoryFactory.create( description='other category') retrieved_categories = (self.project_repo.filter_categories_by( description='generic category')) assert len(retrieved_categories) == 3, retrieved_categories assert should_be_missing not in retrieved_categories, retrieved_categories @with_context def test_filter_categories_by_limit_offset(self): """Test that filter_categories_by supports limit and offset options""" CategoryFactory.create_batch(4) all_categories = self.project_repo.filter_categories_by() first_two = self.project_repo.filter_categories_by(limit=2) last_two = self.project_repo.filter_categories_by(limit=2, offset=2) assert len(first_two) == 2, first_two assert len(last_two) == 2, last_two assert first_two == all_categories[:2] assert last_two == all_categories[2:] @with_context def test_save_category(self): """Test save_category persist the category""" category = CategoryFactory.build() assert self.project_repo.get(category.id) is None self.project_repo.save_category(category) assert self.project_repo.get_category( category.id) == category, "Category not saved" @with_context def test_save_category_fails_if_integrity_error(self): """Test save_category raises a DBIntegrityError if the instance to be saved lacks a required value""" category = CategoryFactory.build(name=None) assert_raises(DBIntegrityError, self.project_repo.save_category, category) @with_context def test_save_category_only_saves_categories(self): """Test save_category raises a WrongObjectError when an object which is not a Category instance is saved""" bad_object = ProjectFactory.build() assert_raises(WrongObjectError, self.project_repo.save_category, bad_object) @with_context def test_update_category(self): """Test update_category persists the changes made to the category""" category = CategoryFactory.create(description='this is a category') category.description = 'the description has changed' self.project_repo.update_category(category) updated_category = self.project_repo.get_category(category.id) assert updated_category.description == 'the description has changed', updated_category @with_context def test_update_category_fails_if_integrity_error(self): """Test update raises a DBIntegrityError if the instance to be updated lacks a required value""" category = CategoryFactory.create() category.name = None assert_raises(DBIntegrityError, self.project_repo.update_category, category) @with_context def test_update_category_only_updates_categories(self): """Test update_category raises a WrongObjectError when an object which is not a Category instance is updated""" bad_object = ProjectFactory.build() assert_raises(WrongObjectError, self.project_repo.update_category, bad_object) @with_context def test_delete_category(self): """Test delete_category removes the category instance""" category = CategoryFactory.create() self.project_repo.delete_category(category) deleted = self.project_repo.get_category(category.id) assert deleted is None, deleted @with_context def test_delete_category_only_deletes_categories(self): """Test delete_category raises a WrongObjectError if is requested to delete other than a category""" bad_object = dict() assert_raises(WrongObjectError, self.project_repo.delete_category, bad_object)
class TestBaseAnalyst(Test): def setUp(self): super(TestBaseAnalyst, self).setUp() BaseAnalyst.__abstractmethods__ = frozenset() self.ctx = ContextFixtures() self.base_analyst = BaseAnalyst() self.project_repo = ProjectRepository(db) self.result_repo = ResultRepository(db) self.task_repo = TaskRepository(db) assert_dict_equal.__self__.maxDiff = None assert_equal.__self__.maxDiff = None @with_context @patch("pybossa_lc.analysis.base.BaseAnalyst.analyse") def test_analyse_all(self, mock_analyse): """Test that all results are analysed.""" project = ProjectFactory() tasks = TaskFactory.create_batch(2, project=project, n_answers=1) for task in tasks: TaskRunFactory.create(task=task) result = self.result_repo.get_by(task_id=tasks[0].id) result.info = dict(annotations=[{}]) self.result_repo.update(result) self.base_analyst.analyse_all(project.id) expected = [call(t.id, analyse_full=True) for t in tasks] assert_equal(mock_analyse.call_args_list, expected) @with_context @patch("pybossa_lc.analysis.base.BaseAnalyst.analyse") def test_analyse_empty(self, mock_analyse): """Test that empty results are analysed.""" project = ProjectFactory() tasks = TaskFactory.create_batch(2, project=project, n_answers=1) for task in tasks: TaskRunFactory.create(task=task) result = self.result_repo.get_by(task_id=tasks[0].id) result.info = dict(annotations=[{}]) self.result_repo.update(result) all_results = self.result_repo.filter_by(project_id=project.id) self.base_analyst.analyse_empty(project.id) expected = [call(r.task_id) for r in all_results if not r.info] assert_equal(mock_analyse.call_args_list, expected) @with_context def test_key_dropped(self): """Test the correct keys are dropped.""" data = [{'foo': None, 'bar': None}] df = pandas.DataFrame(data, range(len(data))) excluded = ['foo'] df = self.base_analyst.drop_keys(df, excluded) assert_not_in('foo', df.keys()) assert_in('bar', df.keys()) @with_context def test_empty_rows_dropped(self): """Test empty rows are dropped.""" data = [{'foo': 'bar'}, {'foo': None}] df = pandas.DataFrame(data, range(len(data))) df = self.base_analyst.drop_empty_rows(df) assert_equals(df['foo'].tolist(), ['bar']) @with_context def test_partial_rows_not_dropped(self): """Test partial rows are not dropped.""" data = [{'foo': 'bar', 'baz': None}] df = pandas.DataFrame(data, range(len(data))) df = self.base_analyst.drop_empty_rows(df) expected = {'foo': {0: 'bar'}, 'baz': {0: None}} assert_dict_equal(df.to_dict(), expected) @with_context def test_match_fails_when_percentage_not_met(self): """Test False is returned when min answers not met.""" data = [{'foo': 'bar', 'baz': None}] df = pandas.DataFrame(data, range(len(data))) min_answers = 2 has_matches = self.base_analyst.has_n_matches(min_answers, df) assert_equal(has_matches, False) @with_context def test_match_fails_when_nan_cols(self): """Test False is returned when NaN columns only.""" data = [{'foo': None}] df = pandas.DataFrame(data, range(len(data))) df = df.replace('', numpy.nan) min_answers = 2 has_matches = self.base_analyst.has_n_matches(min_answers, df) assert_equal(has_matches, False) @with_context def test_match_succeeds_when_percentage_met(self): """Test True returned when match percentage met.""" data = [{'foo': 'bar'}, {'foo': 'bar'}] df = pandas.DataFrame(data, range(len(data))) min_answers = 2 has_matches = self.base_analyst.has_n_matches(min_answers, df) assert_equal(has_matches, True) @with_context def test_get_dataframe_with_dict(self): """Test the task run dataframe with a dict as the info.""" info = {'foo': 'bar'} n_task_runs = 2 task = TaskFactory() taskruns = TaskRunFactory.create_batch(n_task_runs, task=task, info=info) df = self.base_analyst.get_task_run_df(task, taskruns) assert_equal(df['foo'].tolist(), [info['foo']] * n_task_runs) assert_equal(df['info'].tolist(), [info] * n_task_runs) @with_context def test_get_dataframe_with_list(self): """Test the task run dataframe with a list as the info.""" info = [{'foo': 'bar'}, {'baz': 'qux'}] n_task_runs = 2 task = TaskFactory() taskruns = TaskRunFactory.create_batch(n_task_runs, task=task, info=info) df = self.base_analyst.get_task_run_df(task, taskruns) assert_equal(df['info'].tolist(), [info] * n_task_runs) @with_context def test_protected_keys_prefixed_when_exploded(self): """Test that protected info keys are prefixed.""" info = {'foo': 'bar', 'info': 'baz'} task = TaskFactory() taskrun = TaskRunFactory.create(task=task, info=info) df = self.base_analyst.get_task_run_df(task, [taskrun]) assert_equal(df['_info'].tolist(), [info['info']]) @with_context def test_user_ids_in_task_run_dataframe(self): """Test that user IDs are included in the task run dataframe.""" task = TaskFactory() taskruns = TaskRunFactory.create_batch(2, task=task) df = self.base_analyst.get_task_run_df(task, taskruns) assert_equal(df['user_id'].tolist(), [tr.user_id for tr in taskruns]) def test_titlecase_normalisation(self): """Test titlecase normalisation.""" rules = dict(case='title') norm = self.base_analyst.normalise_transcription('Some words', rules) assert_equal(norm, 'Some Words') def test_lowercase_normalisation(self): """Test lowercase normalisation.""" rules = dict(case='lower') norm = self.base_analyst.normalise_transcription('Some words', rules) assert_equal(norm, 'some words') def test_uppercase_normalisation(self): """Test uppercase normalisation.""" rules = dict(case='upper') norm = self.base_analyst.normalise_transcription('Some words', rules) assert_equal(norm, 'SOME WORDS') def test_whitespace_normalisation(self): """Test whitespace normalisation.""" rules = dict(whitespace='normalise') norm = self.base_analyst.normalise_transcription(' Two Words', rules) assert_equal(norm, 'Two Words') def test_whitespace_replace_underscore(self): """Test replacing whitespace with underscore normalisation.""" rules = dict(whitespace='underscore') norm = self.base_analyst.normalise_transcription(' Two Words', rules) assert_equal(norm, 'Two_Words') def test_whitespace_replace_full_stop(self): """Test replacing whitespace with full stop normalisation.""" rules = dict(whitespace='full_stop') norm = self.base_analyst.normalise_transcription(' Two Words', rules) assert_equal(norm, 'Two.Words') def test_trim_punctuation_normalisation(self): """Test trim punctuation normalisation.""" rules = dict(trim_punctuation=True) norm = self.base_analyst.normalise_transcription(':Oh, a word.', rules) assert_equal(norm, 'Oh, a word') def test_date_not_normalised_if_rule_inactive(self): """Test date conversion not applied of rule not activate.""" norm = self.base_analyst.normalise_transcription('foo', {}) assert_equal(norm, 'foo') def test_date_conversion_with_slash(self): """Test date conversion with slash seperators.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19/11/1984', rules) assert_equal(norm, '1984-11-19') def test_date_conversion_with_hyphen(self): """Test date conversion with hyphen seperator.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19-11-1984', rules) assert_equal(norm, '1984-11-19') def test_date_conversion_with_no_seperator(self): """Test date conversion with no seperator.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19111984', rules) assert_equal(norm, '') def test_date_conversion_with_no_year_and_year_last(self): """Test date conversion with no year and year last.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19/11', rules) assert_equal(norm, '-11-19') def test_date_conversion_with_no_year_and_year_first(self): """Test date conversion with no year and year first.""" rules = dict(date_format=True, yearfirst=True) norm = self.base_analyst.normalise_transcription('11/19', rules) assert_equal(norm, '-11-19') def test_date_conversion_with_invalid_string(self): """Test date conversion with invalid string.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('No date', rules) assert_equal(norm, '') def test_date_conversion_with_zero(self): """Test date conversion with zero.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('0', rules) assert_equal(norm, '') def test_date_conversion_with_non_zero_integer(self): """Test date conversion with non-zero integer.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('1', rules) assert_equal(norm, '') def test_date_conversion_with_trailing_punctuation(self): """Test date conversion with trailing punctuation.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19/11/', rules) assert_equal(norm, '-11-19') def test_date_conversion_with_trailing_whitespace(self): """Test date conversion with trailing whitespace.""" rules = dict(date_format=True, dayfirst=True) norm = self.base_analyst.normalise_transcription('19/11/1984 ', rules) assert_equal(norm, '1984-11-19') @with_context def test_n_answers_increased_when_task_complete(self): """Test n answers required for a task is updated.""" n_original_answers = 1 task = TaskFactory.create(n_answers=n_original_answers) TaskRunFactory.create(task=task) self.base_analyst.update_n_answers_required(task, False) assert_equal(task.n_answers, n_original_answers + 1) assert_equal(task.state, 'ongoing') @with_context def test_n_answers_not_increased_when_still_task_runs(self): """Test n answers not updated when task runs still required.""" n_original_answers = 2 task = TaskFactory.create(n_answers=n_original_answers) TaskRunFactory.create(task=task) self.base_analyst.update_n_answers_required(task, False) assert_equal(task.n_answers, n_original_answers) assert_equal(task.state, 'ongoing') @with_context def test_n_answers_not_increased_when_max_answers_reached(self): """Test n answers not updated when max answers reached.""" n_answers = 3 task = TaskFactory.create(n_answers=n_answers) TaskRunFactory.create_batch(n_answers, task=task) self.base_analyst.update_n_answers_required(task, False, max_answers=n_answers) assert_equal(task.n_answers, n_answers) assert_equal(task.state, 'completed') @with_context def test_n_answers_reduced_when_task_complete(self): """Test n answers reduced to number of task runs when task complete.""" n_answers = 3 task = TaskFactory.create(n_answers=n_answers) TaskRunFactory.create_batch(n_answers - 1, task=task) self.base_analyst.update_n_answers_required(task, True, max_answers=n_answers) assert_equal(task.n_answers, n_answers - 1) assert_equal(task.state, 'completed') def test_overlap_ratio_is_1_with_equal_rects(self): """Test for an overlap ratio of 1.""" rect = {'x': 100, 'y': 100, 'w': 100, 'h': 100} overlap = self.base_analyst.get_overlap_ratio(rect, rect) assert_equal(overlap, 1) def test_overlap_ratio_is_0_with_adjacent_rects(self): """Test for an overlap ratio of 0.""" r1 = {'x': 100, 'y': 100, 'w': 100, 'h': 100} r2 = {'x': 100, 'y': 201, 'w': 100, 'h': 100} overlap = self.base_analyst.get_overlap_ratio(r1, r2) assert_equal(overlap, 0) def test_overlap_ratio_with_partially_overlapping_rects(self): """Test for an overlap ratio of 0.33.""" r1 = {'x': 100, 'y': 100, 'w': 100, 'h': 100} r2 = {'x': 150, 'y': 100, 'w': 100, 'h': 100} overlap = self.base_analyst.get_overlap_ratio(r1, r2) assert_equal('{:.2f}'.format(overlap), '0.33') def test_overlap_ratio_where_union_is_zero(self): """Test for an overlap ratio where the union is zero.""" r1 = {'x': 0, 'y': 0, 'w': 100, 'h': 100} r2 = {'x': 101, 'y': 0, 'w': 100, 'h': 100} overlap = self.base_analyst.get_overlap_ratio(r1, r2) assert_equal(overlap, 0) def test_rect_from_selection(self): """Test that we get the correct rect.""" coords = dict(x=400, y=200, w=100, h=150) coords_str = '{0},{1},{2},{3}'.format(coords['x'], coords['y'], coords['w'], coords['h']) fake_anno = { 'target': { 'selector': { 'value': '?xywh={}'.format(coords_str) } } } rect = self.base_analyst.get_rect_from_selection_anno(fake_anno) assert_dict_equal(rect, coords) def test_rect_from_selection_with_floats(self): """Test that we get the correct rect with rounded coordinates.""" coords = dict(x=400.001, y=200.499, w=100.501, h=150.999) coords_str = '{0},{1},{2},{3}'.format(coords['x'], coords['y'], coords['w'], coords['h']) fake_anno = { 'target': { 'selector': { 'value': '?xywh={}'.format(coords_str) } } } rect = self.base_analyst.get_rect_from_selection_anno(fake_anno) assert_dict_equal(rect, {'x': 400, 'y': 200, 'w': 101, 'h': 151}) @with_context def test_get_project_template(self): """Test that the correct template is returned.""" category = CategoryFactory() tmpl_fixtures = TemplateFixtures(category) tmpl1 = tmpl_fixtures.create() tmpl2 = tmpl_fixtures.create() fake_templates = [tmpl1, tmpl2] category.info = dict(templates=fake_templates) self.project_repo.update_category(category) project_info = dict(template_id=tmpl1['id']) project = ProjectFactory(category=category, info=project_info) ret_tmpl = self.base_analyst.get_project_template(project) assert_equal(ret_tmpl, tmpl1) @with_context @raises(ValueError) def test_get_invalid_project_template(self): """Test that getting an invalid template throws an error.""" fake_templates = [{'id': 'foo'}] user_info = dict(templates=fake_templates) project_info = dict(template_id='bar') UserFactory.create(info=user_info) project = ProjectFactory(info=project_info) self.base_analyst.get_project_template(project) @with_context @raises(ValueError) def test_get_non_existant_project_template(self): """Test that getting a non-existant template throws an error.""" project = ProjectFactory() self.base_analyst.get_project_template(project) def test_dataframe_keys_replaced(self): """Test that dataframe keys are replaced and columns merged.""" data = [{'foo': '你好', 'baz': 'qux'}, {'foo': 1, 'quux': 'qux'}] old_df = pandas.DataFrame(data, range(len(data))) new_df = self.base_analyst.replace_df_keys(old_df, quux='baz') assert_dict_equal(new_df.to_dict(), { 'foo': { 0: '你好', 1: 1 }, 'baz': { 0: 'qux', 1: 'qux' } }) @with_context @patch('pybossa_lc.analysis.base.send_mail') @patch('pybossa_lc.analysis.base.render_template') @patch('pybossa_lc.analysis.base.Queue.enqueue') def test_comment_annotations_emailed(self, mock_enqueue, mock_render, mock_send_mail): """Test that comment annotation emails are sent.""" mock_render.return_value = True comment = 'foo' creator = 'bar' target = 'example.com' fake_anno = { 'creator': { 'id': 'example.com/user1', 'type': 'Person', 'name': creator, 'nickname': 'nick' }, 'body': { 'type': 'TextualBody', 'purpose': 'commenting', 'value': comment, 'format': 'text/plain' } } task = self.ctx.create_task(1, target) json_anno = json.dumps(fake_anno, indent=2, sort_keys=True) self.base_analyst.email_comment_anno(task, fake_anno) expected_render_args = [ call('/account/email/new_comment_anno.md', annotation=json_anno, creator=creator, comment=comment, raw_image=None, link=None), call('/account/email/new_comment_anno.html', annotation=json_anno, creator=creator, comment=comment, raw_image=None, link=None) ] assert_equal(mock_render.call_args_list, expected_render_args) expected_msg = { 'body': True, 'html': True, 'subject': 'New Comment Annotation', 'recipients': flask_app.config.get('ADMINS') } mock_enqueue.assert_called_once_with(mock_send_mail, expected_msg) @with_context @patch('pybossa_lc.model.base.wa_client') def test_modified_results_not_updated(self, mock_client): """Test results are not updated if an Annotation has been modified.""" task = self.ctx.create_task(1) TaskRunFactory(task=task) result = self.result_repo.get_by(task_id=task.id) self.base_analyst.analyse(result.id) mock_client.search_annotations.return_value = [{ 'modified': 'fake-time' }] assert_equal(mock_client.create_annotation.called, False) @with_context @patch('pybossa_lc.model.base.wa_client') def test_parent_results_not_updated(self, mock_client): """Test results are not updated if an Annotation has children.""" task = self.ctx.create_task(1) TaskRunFactory(task=task) result = self.result_repo.get_by(task_id=task.id) result.info = dict(has_children=True) self.result_repo.update(result) self.base_analyst.analyse(result.id) assert_equal(mock_client.create_annotation.called, False) @with_context @patch('pybossa_lc.model.base.wa_client') def test_result_with_child_not_updated(self, mock_client): """Test that a result is not updated when it has a child.""" task = self.ctx.create_task(1) TaskRunFactory(task=task) result = self.result_repo.get_by(task_id=task.id) info = dict(annotations='foo', has_children=True) result.info = info self.result_repo.update(result) self.base_analyst.analyse(result.id) assert_equal(result.info, info) @with_context def test_analysis_exception_if_no_annotation_collection(self): """Test that AnnotationCollection must be setup.""" task = self.ctx.create_task(1, 'example.com', anno_collection=None) TaskRunFactory.create(task=task) result = self.result_repo.filter_by(project_id=task.project_id)[0] assert_raises(AnalysisException, self.base_analyst.analyse, result.id)