123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #!/usr/bin/env python3
- # coding=utf-8
- import os
- import re
- from pathlib import Path
- from unittest.mock import MagicMock, patch
- import praw.models
- import pytest
- from bdfr.__main__ import setup_logging
- from bdfr.configuration import Configuration
- from bdfr.connector import RedditConnector
- from bdfr.downloader import RedditDownloader
- @pytest.fixture()
- def args() -> Configuration:
- args = Configuration()
- args.time_format = 'ISO'
- return args
- @pytest.fixture()
- def downloader_mock(args: Configuration):
- downloader_mock = MagicMock()
- downloader_mock.args = args
- downloader_mock._sanitise_subreddit_name = RedditConnector.sanitise_subreddit_name
- downloader_mock._split_args_input = RedditConnector.split_args_input
- downloader_mock.master_hash_list = {}
- return downloader_mock
- @pytest.mark.parametrize(('test_ids', 'test_excluded', 'expected_len'), (
- (('aaaaaa',), (), 1),
- (('aaaaaa',), ('aaaaaa',), 0),
- ((), ('aaaaaa',), 0),
- (('aaaaaa', 'bbbbbb'), ('aaaaaa',), 1),
- (('aaaaaa', 'bbbbbb', 'cccccc'), ('aaaaaa',), 2),
- ))
- @patch('bdfr.site_downloaders.download_factory.DownloadFactory.pull_lever')
- def test_excluded_ids(
- mock_function: MagicMock,
- test_ids: tuple[str],
- test_excluded: tuple[str],
- expected_len: int,
- downloader_mock: MagicMock,
- ):
- downloader_mock.excluded_submission_ids = test_excluded
- mock_function.return_value = MagicMock()
- mock_function.return_value.__name__ = 'test'
- test_submissions = []
- for test_id in test_ids:
- m = MagicMock()
- m.id = test_id
- m.subreddit.display_name.return_value = 'https://www.example.com/'
- m.__class__ = praw.models.Submission
- test_submissions.append(m)
- downloader_mock.reddit_lists = [test_submissions]
- for submission in test_submissions:
- RedditDownloader._download_submission(downloader_mock, submission)
- assert mock_function.call_count == expected_len
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize('test_submission_id', (
- 'm1hqw6',
- ))
- def test_mark_hard_link(
- test_submission_id: str,
- downloader_mock: MagicMock,
- tmp_path: Path,
- reddit_instance: praw.Reddit
- ):
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.args.make_hard_links = True
- downloader_mock.download_directory = tmp_path
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.file_scheme = '{POSTID}'
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- original = Path(tmp_path, f'{test_submission_id}.png')
- RedditDownloader._download_submission(downloader_mock, submission)
- assert original.exists()
- downloader_mock.args.file_scheme = 'test2_{POSTID}'
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- RedditDownloader._download_submission(downloader_mock, submission)
- test_file_1_stats = original.stat()
- test_file_2_inode = Path(tmp_path, f'test2_{test_submission_id}.png').stat().st_ino
- assert test_file_1_stats.st_nlink == 2
- assert test_file_1_stats.st_ino == test_file_2_inode
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'test_creation_date'), (
- ('ndzz50', 1621204841.0),
- ))
- def test_file_creation_date(
- test_submission_id: str,
- test_creation_date: float,
- downloader_mock: MagicMock,
- tmp_path: Path,
- reddit_instance: praw.Reddit
- ):
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_directory = tmp_path
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.file_scheme = '{POSTID}'
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- for file_path in Path(tmp_path).iterdir():
- file_stats = os.stat(file_path)
- assert file_stats.st_mtime == test_creation_date
- def test_search_existing_files():
- results = RedditDownloader.scan_existing_files(Path('.'))
- assert len(results.keys()) != 0
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'test_hash'), (
- ('m1hqw6', 'a912af8905ae468e0121e9940f797ad7'),
- ))
- def test_download_submission_hash_exists(
- test_submission_id: str,
- test_hash: str,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.no_dupes = True
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- downloader_mock.master_hash_list = {test_hash: None}
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- folder_contents = list(tmp_path.iterdir())
- output = capsys.readouterr()
- assert len(folder_contents) == 0
- assert re.search(r'Resource hash .*? downloaded elsewhere', output.out)
- @pytest.mark.online
- @pytest.mark.reddit
- def test_download_submission_file_exists(
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id='m1hqw6')
- Path(tmp_path, 'Arneeman_Metagaming isn\'t always a bad thing_m1hqw6.png').touch()
- RedditDownloader._download_submission(downloader_mock, submission)
- folder_contents = list(tmp_path.iterdir())
- output = capsys.readouterr()
- assert len(folder_contents) == 1
- assert 'Arneeman_Metagaming isn\'t always a bad thing_m1hqw6.png'\
- ' from submission m1hqw6 already exists' in output.out
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'expected_files_len'), (
- ('ljyy27', 4),
- ))
- def test_download_submission(
- test_submission_id: str,
- expected_files_len: int,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path):
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- folder_contents = list(tmp_path.iterdir())
- assert len(folder_contents) == expected_files_len
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'min_score'), (
- ('ljyy27', 1),
- ))
- def test_download_submission_min_score_above(
- test_submission_id: str,
- min_score: int,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture,
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.min_score = min_score
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- output = capsys.readouterr()
- assert 'filtered due to score' not in output.out
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'min_score'), (
- ('ljyy27', 25),
- ))
- def test_download_submission_min_score_below(
- test_submission_id: str,
- min_score: int,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture,
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.min_score = min_score
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- output = capsys.readouterr()
- assert 'filtered due to score' in output.out
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'max_score'), (
- ('ljyy27', 25),
- ))
- def test_download_submission_max_score_below(
- test_submission_id: str,
- max_score: int,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture,
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.max_score = max_score
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- output = capsys.readouterr()
- assert 'filtered due to score' not in output.out
- @pytest.mark.online
- @pytest.mark.reddit
- @pytest.mark.parametrize(('test_submission_id', 'max_score'), (
- ('ljyy27', 1),
- ))
- def test_download_submission_max_score_above(
- test_submission_id: str,
- max_score: int,
- downloader_mock: MagicMock,
- reddit_instance: praw.Reddit,
- tmp_path: Path,
- capsys: pytest.CaptureFixture,
- ):
- setup_logging(3)
- downloader_mock.reddit_instance = reddit_instance
- downloader_mock.download_filter.check_url.return_value = True
- downloader_mock.args.folder_scheme = ''
- downloader_mock.args.max_score = max_score
- downloader_mock.file_name_formatter = RedditConnector.create_file_name_formatter(downloader_mock)
- downloader_mock.download_directory = tmp_path
- submission = downloader_mock.reddit_instance.submission(id=test_submission_id)
- RedditDownloader._download_submission(downloader_mock, submission)
- output = capsys.readouterr()
- assert 'filtered due to score' in output.out
|