async def test_get_user_gallery(mock_client): post_id1 = 234563 post_id2 = 393282 username = "******" event = MockTelegramEvent.with_inline_query(query=f"gallery:{username}") submission1 = MockSubmission(post_id1) submission2 = MockSubmission(post_id2) inline = InlineFunctionality(MockExportAPI()) inline.api.with_user_folder(username, "gallery", [submission1, submission2]) with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert event.answer.call_args[1]['next_offset'] == "2" assert event.answer.call_args[1]['gallery'] is True assert isinstance(args[0], list) assert len(args[0]) == 2 assert isinstance(args[0][0], _MockInlineBuilder._MockInlinePhoto) assert isinstance(args[0][1], _MockInlineBuilder._MockInlinePhoto) assert args[0][0].kwargs['file'] == submission1.thumbnail_url assert args[0][0].kwargs['id'] == str(post_id1) assert args[0][0].kwargs['text'] == submission1.link assert len(args[0][0].kwargs['buttons']) == 1 assert args[0][0].kwargs['buttons'][ 0].data == f"neaten_me:{submission1.submission_id}".encode() assert args[0][1].kwargs['file'] == submission2.thumbnail_url assert args[0][1].kwargs['id'] == str(post_id2) assert args[0][1].kwargs['text'] == submission2.link assert len(args[0][1].kwargs['buttons']) == 1 assert args[0][1].kwargs['buttons'][ 0].data == f"neaten_me:{submission2.submission_id}".encode()
async def test_thumb_and_different_submission_link(mock_client): post_id1 = 382632 post_id2 = 382672 event = MockTelegramEvent.with_message( text= f"https://t.furaffinity.net/{post_id1}@1600-1562445328.jpg\nhttps://furaffinity.net/view/{post_id2}", client=mock_client, ) submission1 = MockSubmission(post_id1) submission2 = MockSubmission(post_id2) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_submissions([submission1, submission2]) with pytest.raises(StopPropagation): await neaten.call(event) submission1._send_message.assert_called_once() args1, kwargs1 = submission1._send_message.call_args assert args1[0] == mock_client assert args1[1] == event.input_chat assert kwargs1['reply_to'] == event.message.id submission2._send_message.assert_called_once() args2, kwargs2 = submission2._send_message.call_args assert args2[0] == mock_client assert args2[1] == event.input_chat assert kwargs2['reply_to'] == event.message.id
async def test_search_with_spaces(mock_client): search_term = "deer YCH" event = MockTelegramEvent.with_inline_query(query=search_term) post_id1 = 213231 post_id2 = 84331 submission1 = MockSubmission(post_id1) submission2 = MockSubmission(post_id2) inline = InlineFunctionality(MockExportAPI()) inline.api.with_search_results(search_term, [submission1, submission2]) with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert event.answer.call_args[1]['next_offset'] == "2" assert event.answer.call_args[1]['gallery'] is True assert isinstance(args[0], list) assert len(args[0]) == 2 for result in args[0]: assert isinstance(result, _MockInlineBuilder._MockInlinePhoto) assert args[0][0].kwargs['file'] == submission1.thumbnail_url assert args[0][0].kwargs['id'] == str(post_id1) assert args[0][0].kwargs['text'] == submission1.link assert len(args[0][0].kwargs['buttons']) == 1 assert args[0][0].kwargs['buttons'][ 0].data == f"neaten_me:{submission1.submission_id}".encode() assert args[0][1].kwargs['file'] == submission2.thumbnail_url assert args[0][1].kwargs['id'] == str(post_id2) assert args[0][1].kwargs['text'] == submission2.link assert len(args[0][1].kwargs['buttons']) == 1 assert args[0][1].kwargs['buttons'][ 0].data == f"neaten_me:{submission2.submission_id}".encode()
async def test_submission_direct_link(): post_id = 12345 image_id = 98765434 username = "******" sub = MockSubmission(post_id, username=username, image_id=image_id) event = MockTelegramEvent.with_inline_query(query=sub.download_url) inline = InlineNeatenFunctionality(MockExportAPI().with_user_folder( username, "gallery", [ MockSubmission(12346, image_id=image_id + 50), sub, MockSubmission(12344, image_id=image_id - 50), ])) with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args, kwargs = event.answer.call_args assert isinstance(args[0], list) assert len(args[0]) == 1 assert kwargs['gallery'] is True result = args[0][0] assert isinstance(result, _MockInlineBuilder._MockInlinePhoto) assert result.kwargs['file'] == sub.thumbnail_url assert result.kwargs['id'] == str(post_id) assert result.kwargs['text'] == sub.link assert len(result.kwargs['buttons']) == 1 assert result.kwargs['buttons'][0].data == f"neaten_me:{post_id}".encode()
async def test_direct_link_and_matching_submission_link(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text= "http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png https://furaffinity.net/view/{2}/" .format(username, image_id, post_id), client=mock_client, ) submission = MockSubmission(post_id, image_id=image_id) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_user_folder( username, "gallery", [submission, MockSubmission(post_id - 1, image_id=image_id - 15)]) with pytest.raises(StopPropagation): await neaten.call(event) submission._send_message.assert_called_once() args, kwargs = submission._send_message.call_args assert args[0] == mock_client assert args[1] == event.input_chat assert kwargs['reply_to'] == event.message.id
async def test_result_last_on_page(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id), client=mock_client, ) submission = MockSubmission(post_id, image_id=image_id) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_user_folder(username, "gallery", [ MockSubmission(post_id + 4, image_id=image_id + 16), MockSubmission(post_id + 3, image_id=image_id + 2), MockSubmission(post_id + 2, image_id=image_id + 1), submission ]) with pytest.raises(StopPropagation): await neaten.call(event) submission._send_message.assert_called_once() args, kwargs = submission._send_message.call_args assert args[0] == mock_client assert args[1] == event.input_chat assert kwargs['reply_to'] == event.message.id
async def test_result_missing_between_pages(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id)) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_user_folder( username, "gallery", [ MockSubmission(post_id + 1, image_id=image_id + 16), MockSubmission(post_id, image_id=image_id + 3) ], page=1) neaten.api.with_user_folder( username, "gallery", [ MockSubmission(post_id - 2, image_id=image_id - 27), MockSubmission(post_id - 3, image_id=image_id - 34) ], page=2) with pytest.raises(StopPropagation): await neaten.call(event) event.reply.assert_called_with( f"Error finding submission: Could not locate the image by {username} with image id {image_id}.", )
async def test_result_on_third_page(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id), client=mock_client, ) neaten = NeatenFunctionality(MockExportAPI()) for page in [1, 2, 3]: neaten.api.with_user_folder( username, "gallery", [ MockSubmission(post_id + 1 + (3 - page) * 5, image_id=image_id + 16 + (3 - page) * 56), MockSubmission(post_id + (3 - page) * 5, image_id=image_id + (3 - page) * 56), MockSubmission(post_id - 2 + (3 - page) * 5, image_id=image_id - 27 + (3 - page) * 56), MockSubmission(post_id - 3 + (3 - page) * 5, image_id=image_id - 34 + (3 - page) * 56) ], page=page) submission = await neaten.api.get_full_submission(str(post_id)) with pytest.raises(StopPropagation): await neaten.call(event) submission._send_message.assert_called_once() args, kwargs = submission._send_message.call_args assert args[0] == mock_client assert args[1] == event.input_chat assert kwargs['reply_to'] == event.message.id
async def test_submission_link_and_different_direct_link(mock_client): username = "******" image_id1 = 1560331512 image_id2 = image_id1 + 300 post_id1 = 232347 post_id2 = 233447 event = MockTelegramEvent.with_message( text= "https://furaffinity.net/view/{2}/ http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png" .format(username, image_id1, post_id2), client=mock_client) submission1 = MockSubmission(post_id1, image_id=image_id1) submission2 = MockSubmission(post_id2, image_id=image_id2) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_user_folder(username, "gallery", [ submission2, submission1, MockSubmission(post_id1 - 1, image_id=image_id1 - 15) ]) with pytest.raises(StopPropagation): await neaten.call(event) submission1._send_message.assert_called_once() args1, kwargs1 = submission1._send_message.call_args assert args1[0] == mock_client assert args1[1] == event.input_chat assert kwargs1['reply_to'] == event.message.id submission2._send_message.assert_called_once() args2, kwargs2 = submission2._send_message.call_args assert args2[0] == mock_client assert args2[1] == event.input_chat assert kwargs2['reply_to'] == event.message.id
async def test_two_submission_links(mock_client): post_id1 = 23636984 post_id2 = 23636996 event = MockTelegramEvent.with_message( text="furaffinity.net/view/{}\nfuraffinity.net/view/{}".format( post_id1, post_id2), client=mock_client, ) submission1 = MockSubmission(post_id1) submission2 = MockSubmission(post_id2) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_submissions([submission1, submission2]) with pytest.raises(StopPropagation): await neaten.call(event) submission1._send_message.assert_called_once() args1, kwargs1 = submission1._send_message.call_args assert args1[0] == mock_client assert args1[1] == event.input_chat assert kwargs1['reply_to'] == event.message.id submission2._send_message.assert_called_once() args2, kwargs2 = submission2._send_message.call_args assert args2[0] == mock_client assert args2[1] == event.input_chat assert kwargs2['reply_to'] == event.message.id
async def test_submission_id__no_result(): post_id = 12345 event = MockTelegramEvent.with_inline_query(query=str(post_id)) inline = InlineNeatenFunctionality(MockExportAPI().with_submissions( [MockSubmission(12344), MockSubmission(12346)])) await inline.call(event) event.answer.assert_not_called()
async def test_query_not_id_or_link(): post_id = 12345 sub = MockSubmission(post_id) event = MockTelegramEvent.with_inline_query(query="test") inline = InlineNeatenFunctionality(MockExportAPI().with_submissions( [MockSubmission(12344), sub, MockSubmission(12346)])) await inline.call(event) event.answer.assert_not_called()
async def test_submission_direct_link__not_found(): post_id = 12345 username = "******" sub = MockSubmission(post_id, username=username) event = MockTelegramEvent.with_inline_query(query=sub.download_url) inline = InlineNeatenFunctionality(MockExportAPI().with_user_folder( username, "gallery", [MockSubmission(12344), MockSubmission(12346)])) await inline.call(event) event.answer.assert_not_called()
async def test_search_with_offset(mock_client): post_id = 234563 search_term = "YCH" offset = 2 event = MockTelegramEvent.with_inline_query(query=search_term, offset=offset) submission = MockSubmission(post_id) inline = InlineFunctionality(MockExportAPI()) inline.api.with_search_results(search_term, [submission], page=offset) with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert isinstance(args[0], list) assert len(args[0]) > 0 for result in args[0]: assert isinstance(result, _MockInlineBuilder._MockInlinePhoto) assert result.kwargs['file'] == submission.thumbnail_url assert result.kwargs['id'] == str(post_id) assert result.kwargs['text'] == submission.link assert len(result.kwargs['buttons']) == 1 assert result.kwargs['buttons'][ 0].data == f"neaten_me:{post_id}".encode()
async def test_over_max_favs(mock_client): username = "******" post_ids = list(range(123456, 123456 + 72)) submissions = [MockSubmission(x) for x in post_ids] inline = InlineFunctionality(MockExportAPI()) inline.api.with_user_favs(username, submissions) event = MockTelegramEvent.with_inline_query(query=f"favs:{username}") with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert event.answer.call_args[1]['next_offset'] == submissions[ inline.INLINE_MAX - 1].fav_id assert event.answer.call_args[1]['gallery'] is True assert isinstance(args[0], list) assert len(args[0]) == inline.INLINE_MAX assert isinstance(args[0][0], _MockInlineBuilder._MockInlinePhoto) assert isinstance(args[0][1], _MockInlineBuilder._MockInlinePhoto) for x in range(inline.INLINE_MAX): assert args[0][x].kwargs['file'] == submissions[x].thumbnail_url assert args[0][x].kwargs['id'] == str(post_ids[x]) assert args[0][x].kwargs['text'] == submissions[x].link assert len(args[0][x].kwargs['buttons']) == 1 assert args[0][x].kwargs['buttons'][ 0].data == f"neaten_me:{submissions[x].submission_id}".encode()
async def test_get_new_results__returns_new_results(mock_client): api = MockExportAPI() api.with_browse_results([ MockSubmission("1222"), MockSubmission("1221"), MockSubmission("1220") ]) watcher = SubscriptionWatcher(api, mock_client) watcher.latest_ids.append("1220") watcher.running = True results = await watcher._get_new_results() assert len(results) == 2 assert results[0].submission_id == "1221" assert results[1].submission_id == "1222"
async def test_run__passes_correct_blocklists_to_subscriptions(mock_client): submission = MockSubmission("12322") api = MockExportAPI().with_submission(submission) watcher = SubscriptionWatcher(api, mock_client) method_called = MockMethod([submission]) watcher._get_new_results = method_called.async_call watcher.BACK_OFF = 1 watcher.blocklists = {156: {"test", "ych"}, -200: {"example"}} sub1 = MockSubscription("deer", 156) sub2 = MockSubscription("dog", -232) watcher.subscriptions = [sub1, sub2] task = asyncio.get_event_loop().create_task(watcher_killer(watcher)) # Run watcher await watcher.run() await task assert submission in sub1.submissions_checked assert len(sub1.blocklists) == 1 assert sub1.blocklists[0] in [ AndQuery([NotQuery(WordQuery("test")), NotQuery(WordQuery("ych"))]), AndQuery([NotQuery(WordQuery("ych")), NotQuery(WordQuery("test"))]) ] assert submission in sub2.submissions_checked assert len(sub2.blocklists) == 1 assert sub2.blocklists[0] == AndQuery([]) assert method_called.called
async def test_over_max_submissions_continue_end(mock_client): username = "******" posts = 72 post_ids = list(range(123456, 123456 + posts)) submissions = [MockSubmission(x) for x in post_ids] mock_api = MockExportAPI() mock_api.with_user_folder(username, "gallery", submissions) inline = InlineFunctionality(mock_api) skip = posts - inline.INLINE_MAX + 3 event = MockTelegramEvent.with_inline_query(query=f"gallery:{username}", offset=f"1:{skip}") with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert event.answer.call_args[1]['next_offset'] == "2" assert event.answer.call_args[1]['gallery'] is True assert isinstance(args[0], list) assert len(args[0]) == inline.INLINE_MAX - 3 assert isinstance(args[0][0], _MockInlineBuilder._MockInlinePhoto) assert isinstance(args[0][1], _MockInlineBuilder._MockInlinePhoto) for x in range(inline.INLINE_MAX - 3): assert args[0][x].kwargs['file'] == submissions[x + skip].thumbnail_url assert args[0][x].kwargs['id'] == str(post_ids[x + skip]) assert args[0][x].kwargs['text'] == submissions[x + skip].link assert len(args[0][x].kwargs['buttons']) == 1 assert args[0][x].kwargs['buttons'][ 0].data == f"neaten_me:{submissions[x + skip].submission_id}".encode( )
async def test_second_page(mock_client): post_id = 234563 username = "******" event = MockTelegramEvent.with_inline_query(query=f"scraps:{username}", offset="2") submission = MockSubmission(post_id) inline = InlineFunctionality(MockExportAPI()) inline.api.with_user_folder(username, "scraps", [submission], page=2) with pytest.raises(StopPropagation): await inline.call(event) event.answer.assert_called_once() args = event.answer.call_args[0] assert event.answer.call_args[1]['next_offset'] == "3" assert event.answer.call_args[1]['gallery'] is True assert isinstance(args[0], list) assert len(args[0]) == 1 assert isinstance(args[0][0], _MockInlineBuilder._MockInlinePhoto) assert args[0][0].kwargs['file'] == submission.thumbnail_url assert args[0][0].kwargs['id'] == str(post_id) assert args[0][0].kwargs['text'] == submission.link assert len(args[0][0].kwargs['buttons']) == 1 assert args[0][0].kwargs['buttons'][ 0].data == f"neaten_me:{submission.submission_id}".encode()
async def test_get_new_results__handles_empty_latest_ids(mock_client): api = MockExportAPI() api.with_browse_results([ MockSubmission("1223"), MockSubmission("1222"), MockSubmission("1220") ]) watcher = SubscriptionWatcher(api, mock_client) watcher.running = True results = await watcher._get_new_results() assert len(results) == 0 assert len(watcher.latest_ids) == 3 assert watcher.latest_ids[0] == "1220" assert watcher.latest_ids[1] == "1222" assert watcher.latest_ids[2] == "1223"
async def test_run__failed_to_send_doesnt_kill_watcher(mock_client): submission = MockSubmission("12322") api = MockExportAPI().with_browse_results([submission], 1) watcher = SubscriptionWatcher(api, mock_client) submission.send_message = lambda *args: (_ for _ in ()).throw(Exception) watcher.BACK_OFF = 3 sub1 = MockSubscription("deer", 0) watcher.subscriptions = [sub1] api.call_after_x_browse = (lambda: watcher.stop(), 2) # Run watcher start_time = datetime.datetime.now() await watcher.run() end_time = datetime.datetime.now() time_waited = end_time - start_time assert 3 <= time_waited.seconds <= 5
async def test_run__checks_all_new_results(mock_client): submission1 = MockSubmission("12322") submission2 = MockSubmission("12324") api = MockExportAPI().with_submissions([submission1, submission2]) watcher = SubscriptionWatcher(api, mock_client) method_called = MockMethod([submission1, submission2]) watcher._get_new_results = method_called.async_call watcher.BACK_OFF = 1 sub = MockSubscription("deer", 0) watcher.subscriptions = [sub] task = asyncio.get_event_loop().create_task(watcher_killer(watcher)) # Run watcher await watcher.run() await task assert submission1 in sub.submissions_checked assert submission2 in sub.submissions_checked assert method_called.called
async def test_get_new_results__handles_sub_id_drop(mock_client): api = MockExportAPI() api.with_browse_results([MockSubmission("1220")]) watcher = SubscriptionWatcher(api, mock_client) watcher.latest_ids.append("1225") watcher.running = True results = await watcher._get_new_results() assert len(results) == 0
async def test_direct_in_progress_message_groupchat(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id)) goal_submission = MockSubmission(post_id, image_id=image_id) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_user_folder( username, "gallery", [goal_submission, MockSubmission(post_id - 1, image_id=image_id - 15)]) with pytest.raises(StopPropagation): await neaten.call(event) event.reply.assert_called_with("⏳ Neatening image link") event.reply.return_value.delete.assert_called_once()
async def test_run__calls_update_latest_ids(mock_client): submission1 = MockSubmission("12322") submission2 = MockSubmission("12324") api = MockExportAPI().with_submissions([submission1, submission2]) watcher = SubscriptionWatcher(api, mock_client) mock_new_results = MockMethod([submission1, submission2]) watcher._get_new_results = mock_new_results.async_call mock_update_latest = MockMethod() watcher._update_latest_ids = mock_update_latest.call # Shorten the wait watcher.BACK_OFF = 1 task = asyncio.get_event_loop().create_task(watcher_killer(watcher)) # Run watcher await watcher.run() await task assert mock_update_latest.called assert mock_update_latest.args[0] == [submission2]
async def test_direct_no_match_groupchat(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id), chat_type=ChatType.GROUP) neaten = NeatenFunctionality(MockExportAPI()) for folder in ['gallery', 'scraps']: neaten.api.with_user_folder(username, folder, [ MockSubmission(post_id, image_id=image_id + 4), MockSubmission(post_id - 1, image_id=image_id - 15) ]) with pytest.raises(StopPropagation): await neaten.call(event) event.reply.assert_called_with("⏳ Neatening image link") event.reply.return_value.delete.assert_called_once()
async def test_ignore_channel_post(mock_client): post_id = 23636984 event = MockTelegramEvent.with_channel_post( text=f"https://www.furaffinity.net/view/{post_id}/") submission = MockSubmission(post_id) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_submission(submission) await neaten.call(event) submission._send_message.assert_not_called()
async def test_direct_no_match(mock_client): username = "******" image_id = 1560331512 post_id = 232347 event = MockTelegramEvent.with_message( text="http://d.furaffinity.net/art/{0}/{1}/{1}.pic_of_me.png".format( username, image_id)) neaten = NeatenFunctionality(MockExportAPI()) for folder in ['gallery', 'scraps']: neaten.api.with_user_folder(username, folder, [ MockSubmission(post_id, image_id=image_id + 4), MockSubmission(post_id - 1, image_id=image_id - 15) ]) with pytest.raises(StopPropagation): await neaten.call(event) event.reply.assert_called() event.reply.assert_called_with( f"Error finding submission: Could not locate the image by {username} with image id {image_id}.", )
async def test_submission_link_in_group_caption(mock_client): post_id = 23636984 event = MockTelegramEvent.with_message( chat_type=ChatType.GROUP, text=f"https://www.furaffinity.net/view/{post_id}/").with_document() submission = MockSubmission(post_id) neaten = NeatenFunctionality(MockExportAPI()) neaten.api.with_submission(submission) await neaten.call(event) submission._send_message.assert_not_called()
def test_update_latest_ids(mock_client): api = MockExportAPI() watcher = SubscriptionWatcher(api, mock_client) id_list = ["1234", "1233", "1230", "1229"] submissions = [MockSubmission(x) for x in id_list] mock_save_json = MockMethod() watcher.save_to_json = mock_save_json.call watcher._update_latest_ids(submissions) assert list(watcher.latest_ids) == id_list assert mock_save_json.called