def test_get_subreddit_search(
        test_subreddits: list[str],
        search_term: str,
        time_filter: str,
        limit: int,
        max_expected_len: int,
        downloader_mock: MagicMock,
        reddit_instance: praw.Reddit,
):
    downloader_mock._determine_sort_function.return_value = praw.models.Subreddit.hot
    downloader_mock.args.limit = limit
    downloader_mock.args.search = search_term
    downloader_mock.args.subreddit = test_subreddits
    downloader_mock.reddit_instance = reddit_instance
    downloader_mock.sort_filter = RedditTypes.SortType.HOT
    downloader_mock.args.time = time_filter
    downloader_mock.time_filter = RedditConnector.create_time_filter(downloader_mock)
    results = RedditConnector.get_subreddits(downloader_mock)
    results = [sub for res in results for sub in res]
    assert all([isinstance(res, praw.models.Submission) for res in results])
    assert all([res.subreddit.display_name in test_subreddits for res in results])
    assert len(results) <= max_expected_len
    if max_expected_len != 0:
        assert len(results) > 0
    assert not any([isinstance(m, MagicMock) for m in results])
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
def test_check_user_existence_good(
        test_redditor_name: str,
        reddit_instance: praw.Reddit,
        downloader_mock: MagicMock,
):
    downloader_mock.reddit_instance = reddit_instance
    RedditConnector.check_user_existence(downloader_mock, test_redditor_name)
def test_check_user_existence_banned(
        test_redditor_name: str,
        reddit_instance: praw.Reddit,
        downloader_mock: MagicMock,
):
    downloader_mock.reddit_instance = reddit_instance
    with pytest.raises(BulkDownloaderException, match='is banned'):
        RedditConnector.check_user_existence(downloader_mock, test_redditor_name)
def test_get_user_authenticated_lists(
        test_flag: str,
        downloader_mock: MagicMock,
        authenticated_reddit_instance: praw.Reddit,
):
    downloader_mock.args.__dict__[test_flag] = True
    downloader_mock.reddit_instance = authenticated_reddit_instance
    downloader_mock.args.limit = 10
    downloader_mock._determine_sort_function.return_value = praw.models.Subreddit.hot
    downloader_mock.sort_filter = RedditTypes.SortType.HOT
    downloader_mock.args.user = [RedditConnector.resolve_user_name(downloader_mock, 'me')]
    results = RedditConnector.get_user_data(downloader_mock)
    assert_all_results_are_submissions_or_comments(10, results)
def test_create_file_name_formatter(test_file_scheme: str, test_folder_scheme: str, downloader_mock: MagicMock):
    downloader_mock.args.file_scheme = test_file_scheme
    downloader_mock.args.folder_scheme = test_folder_scheme
    result = RedditConnector.create_file_name_formatter(downloader_mock)

    assert isinstance(result, FileNameFormatter)
    assert result.file_format_string == test_file_scheme
    assert result.directory_format_string == test_folder_scheme.split('/')
def test_create_download_filter(skip_extensions: list[str], skip_domains: list[str], downloader_mock: MagicMock):
    downloader_mock.args.skip = skip_extensions
    downloader_mock.args.skip_domain = skip_domains
    result = RedditConnector.create_download_filter(downloader_mock)

    assert isinstance(result, DownloadFilter)
    assert result.excluded_domains == skip_domains
    assert result.excluded_extensions == skip_extensions
def test_get_user_submissions(test_user: str, limit: int, downloader_mock: MagicMock, reddit_instance: praw.Reddit):
    downloader_mock.args.limit = limit
    downloader_mock.determine_sort_function.return_value = praw.models.Subreddit.hot
    downloader_mock.sort_filter = RedditTypes.SortType.HOT
    downloader_mock.args.submitted = True
    downloader_mock.args.user = [test_user]
    downloader_mock.authenticated = False
    downloader_mock.reddit_instance = reddit_instance
    downloader_mock.create_filtered_listing_generator.return_value = \
        RedditConnector.create_filtered_listing_generator(
            downloader_mock,
            reddit_instance.redditor(test_user).submissions,
        )
    results = RedditConnector.get_user_data(downloader_mock)
    results = assert_all_results_are_submissions(limit, results)
    assert all([res.author.name == test_user for res in results])
    assert not any([isinstance(m, MagicMock) for m in results])
def test_get_submissions_from_link(
        test_submission_ids: list[str],
        reddit_instance: praw.Reddit,
        downloader_mock: MagicMock):
    downloader_mock.args.link = test_submission_ids
    downloader_mock.reddit_instance = reddit_instance
    results = RedditConnector.get_submissions_from_link(downloader_mock)
    assert all([isinstance(sub, praw.models.Submission) for res in results for sub in res])
    assert len(results[0]) == len(test_submission_ids)
def downloader_mock(args: Configuration):
    downloader_mock = MagicMock()
    downloader_mock.args = args
    downloader_mock.sanitise_subreddit_name = RedditConnector.sanitise_subreddit_name
    downloader_mock.create_filtered_listing_generator = lambda x: RedditConnector.create_filtered_listing_generator(
        downloader_mock, x)
    downloader_mock.split_args_input = RedditConnector.split_args_input
    downloader_mock.master_hash_list = {}
    return downloader_mock
def test_get_subreddit_time_verification(
        test_time: str,
        test_delta: timedelta,
        downloader_mock: MagicMock,
        reddit_instance: praw.Reddit,
):
    downloader_mock.args.limit = 10
    downloader_mock.args.sort = 'top'
    downloader_mock.args.time = test_time
    downloader_mock.time_filter = RedditConnector.create_time_filter(downloader_mock)
    downloader_mock.sort_filter = RedditConnector.create_sort_filter(downloader_mock)
    downloader_mock.determine_sort_function.return_value = RedditConnector.determine_sort_function(downloader_mock)
    downloader_mock.args.subreddit = ['all']
    downloader_mock.reddit_instance = reddit_instance
    results = RedditConnector.get_subreddits(downloader_mock)
    results = [sub for res1 in results for sub in res1]
    assert all([isinstance(res1, praw.models.Submission) for res1 in results])
    nowtime = datetime.now()
    for r in results:
        result_time = datetime.fromtimestamp(r.created_utc)
        time_diff = nowtime - result_time
        assert time_diff < test_delta
def test_get_multireddits_public(
        test_user: str,
        test_multireddits: list[str],
        limit: int,
        reddit_instance: praw.Reddit,
        downloader_mock: MagicMock,
):
    downloader_mock.determine_sort_function.return_value = praw.models.Subreddit.hot
    downloader_mock.sort_filter = RedditTypes.SortType.HOT
    downloader_mock.args.limit = limit
    downloader_mock.args.multireddit = test_multireddits
    downloader_mock.args.user = [test_user]
    downloader_mock.reddit_instance = reddit_instance
    downloader_mock.create_filtered_listing_generator.return_value = \
        RedditConnector.create_filtered_listing_generator(
            downloader_mock,
            reddit_instance.multireddit(test_user, test_multireddits[0]),
        )
    results = RedditConnector.get_multireddits(downloader_mock)
    results = [sub for res in results for sub in res]
    assert all([isinstance(res, praw.models.Submission) for res in results])
    assert len(results) == limit
    assert not any([isinstance(m, MagicMock) for m in results])
def test_get_subreddit_normal(
        test_subreddits: list[str],
        limit: int,
        sort_type: str,
        time_filter: str,
        max_expected_len: int,
        downloader_mock: MagicMock,
        reddit_instance: praw.Reddit,
):
    downloader_mock.args.limit = limit
    downloader_mock.args.sort = sort_type
    downloader_mock.time_filter = RedditConnector.create_time_filter(downloader_mock)
    downloader_mock.sort_filter = RedditConnector.create_sort_filter(downloader_mock)
    downloader_mock.determine_sort_function.return_value = RedditConnector.determine_sort_function(downloader_mock)
    downloader_mock.args.subreddit = test_subreddits
    downloader_mock.reddit_instance = reddit_instance
    results = RedditConnector.get_subreddits(downloader_mock)
    test_subreddits = downloader_mock.split_args_input(test_subreddits)
    results = [sub for res1 in results for sub in res1]
    assert all([isinstance(res1, praw.models.Submission) for res1 in results])
    assert all([res.subreddit.display_name in test_subreddits for res in results])
    assert len(results) <= max_expected_len
    assert not any([isinstance(m, MagicMock) for m in results])
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
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_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
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)
def test_create_sort_filter(test_sort: str, expected: str, downloader_mock: MagicMock):
    downloader_mock.args.sort = test_sort
    result = RedditConnector.create_sort_filter(downloader_mock)

    assert isinstance(result, RedditTypes.SortType)
    assert result.name.lower() == expected
def test_create_time_filter(test_time: str, expected: str, downloader_mock: MagicMock):
    downloader_mock.args.time = test_time
    result = RedditConnector.create_time_filter(downloader_mock)

    assert isinstance(result, RedditTypes.TimeType)
    assert result.name.lower() == expected
def test_determine_directories(tmp_path: Path, downloader_mock: MagicMock):
    downloader_mock.args.directory = tmp_path / 'test'
    downloader_mock.config_directories.user_config_dir = tmp_path
    RedditConnector.determine_directories(downloader_mock)
    assert Path(tmp_path / 'test').exists()
def test_check_subreddit_status_good(test_subreddit_name: str, reddit_instance: praw.Reddit):
    test_subreddit = reddit_instance.subreddit(test_subreddit_name)
    RedditConnector.check_subreddit_status(test_subreddit)
def test_check_subreddit_status_bad(test_subreddit_name: str, expected_message: str, reddit_instance: praw.Reddit):
    test_subreddit = reddit_instance.subreddit(test_subreddit_name)
    with pytest.raises(BulkDownloaderException, match=expected_message):
        RedditConnector.check_subreddit_status(test_subreddit)
def test_create_file_name_formatter_bad(test_file_scheme: str, test_folder_scheme: str, downloader_mock: MagicMock):
    downloader_mock.args.file_scheme = test_file_scheme
    downloader_mock.args.folder_scheme = test_folder_scheme
    with pytest.raises(BulkDownloaderException):
        RedditConnector.create_file_name_formatter(downloader_mock)
def test_create_authenticator(downloader_mock: MagicMock):
    result = RedditConnector.create_authenticator(downloader_mock)
    assert isinstance(result, SiteAuthenticator)
def test_read_submission_ids_from_file(downloader_mock: MagicMock, tmp_path: Path):
    test_file = tmp_path / 'test.txt'
    test_file.write_text('aaaaaa\nbbbbbb')
    results = RedditConnector.read_id_files([str(test_file)])
    assert results == {'aaaaaa', 'bbbbbb'}
def test_split_subreddit_entries(test_subreddit_entries: list[str], expected: set[str]):
    results = RedditConnector.split_args_input(test_subreddit_entries)
    assert results == expected
def test_sanitise_subreddit_name(test_name: str, expected: str):
    result = RedditConnector.sanitise_subreddit_name(test_name)
    assert result == expected