Skip to content

Commit e3722b0

Browse files
committed
Merge branch 'feature/video-livechat' into feature/video-transcription
2 parents 32a7f84 + 097cf8c commit e3722b0

File tree

11 files changed

+174
-23
lines changed

11 files changed

+174
-23
lines changed

tests/commands/test_base.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ def execute(cls, **kwargs):
1919

2020
@pytest.fixture
2121
def subparsers():
22+
"""Fixture to create subparsers for argument parsing."""
2223
parser = argparse.ArgumentParser()
2324
return parser.add_subparsers()
2425

2526

2627
def test_generate_parser(subparsers):
28+
"""Test to verify the parser generation.
29+
30+
This test checks if the `generate_parser` method correctly generates a parser
31+
for the command and sets the appropriate properties
32+
"""
2733
parser = TestCommand.generate_parser(subparsers)
2834

2935
assert parser is not None, "Parser should not be None"
@@ -32,6 +38,11 @@ def test_generate_parser(subparsers):
3238

3339

3440
def test_parse_arguments(subparsers):
41+
"""Test to verify argument parsing.
42+
43+
This test checks if the `parse_arguments` method correctly adds the command's
44+
arguments to the parser and sets the default function to the command's execute method.
45+
"""
3546
subparsers_mock = MagicMock(spec=subparsers)
3647

3748
TestCommand.parse_arguments(subparsers_mock)
@@ -43,6 +54,11 @@ def test_parse_arguments(subparsers):
4354

4455

4556
def test_command():
57+
"""Test to verify that the `execute` method is implemented.
58+
59+
This test ensures that if a command does not implement the `execute` method,
60+
a `NotImplementedError` is raised.
61+
"""
4662
class MyCommand(Command):
4763
pass
4864

@@ -52,6 +68,7 @@ class MyCommand(Command):
5268

5369
@pytest.fixture
5470
def mock_csv_file():
71+
"""Fixture to provide mock CSV content for tests."""
5572

5673
csv_content = """URL
5774
http://example.com
@@ -60,6 +77,14 @@ def mock_csv_file():
6077
return csv_content
6178

6279
def test_data_from_csv_valid(mock_csv_file):
80+
"""Test to verify reading data from a valid CSV file.
81+
82+
This test checks if the `data_from_csv` method correctly reads data from a valid CSV file
83+
and returns the expected list of URLs.
84+
85+
Args:
86+
mock_csv_file (str): The mock CSV file content.
87+
"""
6388
with patch('pathlib.Path.is_file', return_value=True):
6489
with patch('builtins.open', mock_open(read_data=mock_csv_file)):
6590
data_column_name = "URL"
@@ -70,6 +95,11 @@ def test_data_from_csv_valid(mock_csv_file):
7095
assert result[1] == "http://example2.com"
7196

7297
def test_data_from_csv_file_not_found():
98+
"""Test to verify behavior when the specified column is not found in the CSV file.
99+
100+
This test checks if the `data_from_csv` method raises an exception when the specified
101+
column does not exist in the CSV file.
102+
"""
73103
with patch('pathlib.Path.is_file', return_value=False):
74104
file_path = Path("/fake/path/not_found.csv")
75105
with pytest.raises(FileNotFoundError):
@@ -86,12 +116,18 @@ def test_data_from_csv_column_not_found(mock_csv_file):
86116

87117
@pytest.fixture
88118
def sample_data():
119+
"""Fixture to provide sample data for tests."""
89120
return [
90121
{"id": "123", "name": "Channel One"},
91122
{"id": "456", "name": "Channel Two"}
92123
]
93124

94125
def test_data_to_csv_with_output_file_path(tmp_path, sample_data):
126+
"""Test to verify writing data to a CSV file with an output file path specified.
127+
128+
This test checks if the `data_to_csv` method correctly writes the sample data to
129+
a CSV file when an output file path is provided.
130+
"""
95131
output_file_path = tmp_path / "output.csv"
96132

97133
result_path = Command.data_to_csv(sample_data, str(output_file_path))
@@ -105,13 +141,24 @@ def test_data_to_csv_with_output_file_path(tmp_path, sample_data):
105141
assert rows[0]["id"] == "123" and rows[1]["id"] == "456"
106142

107143
def test_data_to_csv_without_output_file_path(sample_data):
144+
"""Test to verify writing data to a CSV format without an output file path specified.
145+
146+
This test checks if the `data_to_csv` method correctly returns the CSV content
147+
as a string when no output file path is provided.
148+
"""
108149
csv_content = Command.data_to_csv(sample_data)
109150

110151
assert "id,name" in csv_content
111152
assert "123,Channel One" in csv_content
112153
assert "456,Channel Two" in csv_content
113154

114155
def test_data_to_csv_output(tmp_path):
156+
"""
157+
Test to verify the content of the output CSV file.
158+
159+
This test checks if the `data_to_csv` method writes the expected content
160+
to the output CSV file.
161+
"""
115162
output_file_path = tmp_path / "output.csv"
116163

117164
data = [

tests/commands/test_channel_id.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,30 @@
88

99
@pytest.fixture
1010
def csv_file(tmp_path):
11+
"""Fixture to create a temporary CSV file with a single YouTube channel URL."""
12+
1113
csv_content = "channel_url\nhttps://www.youtube.com/@Turicas/featured\n"
1214
csv_file = tmp_path / "urls.csv"
1315
csv_file.write_text(csv_content)
1416
return csv_file
1517

1618
@pytest.fixture
1719
def youtube_api_mock():
20+
"""Fixture to mock the YouTube API.
21+
22+
This fixture mocks the `YouTube` class and its `channel_id_from_url` method
23+
to return a channel ID based on the URL.
24+
"""
1825
with patch("youtool.commands.channel_id.YouTube") as mock:
1926
mock.return_value.channel_id_from_url.side_effect = lambda url: f"channel-{url}"
2027
yield mock
2128

2229
def test_channels_ids_csv_preparation(youtube_api_mock):
30+
"""Fixture to mock the YouTube API.
31+
32+
This fixture mocks the `YouTube` class and its `channel_id_from_url` method
33+
to return a channel ID based on the URL.
34+
"""
2335
urls = ["https://www.youtube.com/@Turicas/featured", "https://www.youtube.com/c/PythonicCaf%C3%A9"]
2436
api_key = "test_api_key"
2537
id_column_name = "custom_id_column"
@@ -40,16 +52,29 @@ def test_channels_ids_csv_preparation(youtube_api_mock):
4052

4153

4254
def test_resolve_urls_with_direct_urls():
43-
# Tests whether the function returns the directly given list of URLs.
55+
"""Test to verify resolving URLs when provided directly.
56+
57+
This test checks if the `resolve_urls` method of the `ChannelId` class correctly
58+
returns the given list of URLs when provided directly.
59+
"""
4460
urls = ["https://www.youtube.com/@Turicas/featured"]
4561
result = ChannelId.resolve_urls(urls, None, None)
4662
assert result == urls
4763

4864
def test_resolve_urls_with_file_path(csv_file):
65+
"""Test to verify resolving URLs from a CSV file.
66+
67+
This test checks if the `resolve_urls` method of the `ChannelId` class correctly
68+
reads URLs from a given CSV file.
69+
"""
4970
result = ChannelId.resolve_urls(None, csv_file, "channel_url")
5071
assert result == ["https://www.youtube.com/@Turicas/featured"]
5172

5273
def test_resolve_urls_raises_exception():
53-
# Tests whether the function throws an exception when neither urls nor urls_file_path are provided.
74+
"""Test to verify exception raising when no URLs are provided.
75+
76+
This test checks if the `resolve_urls` method of the `ChannelId` class raises an exception
77+
when neither direct URLs nor a file path are provided.
78+
"""
5479
with pytest.raises(Exception, match="Either 'username' or 'url' must be provided for the channel-id command"):
5580
ChannelId.resolve_urls(None, None, None)

tests/commands/test_channel_info.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import pytest
1+
from unittest.mock import Mock, call
22

3-
from unittest.mock import patch, Mock, call
4-
5-
from youtool.commands.channel_info import ChannelInfo, YouTube
3+
from youtool.commands.channel_info import ChannelInfo
64

75

86
def test_filter_fields():
7+
"""Test to verify the filtering of channel information fields.
8+
9+
This test checks if the `filter_fields` method of the `ChannelInfo` class correctly
10+
filters out unwanted fields from the channel information dictionary based on the provided columns.
11+
"""
912
channel_info = {
1013
'channel_id': '123456',
1114
'channel_name': 'Test Channel',
@@ -26,7 +29,15 @@ def test_filter_fields():
2629
assert filtered_info == expected_result, f"Expected {expected_result}, but got {filtered_info}"
2730

2831

29-
def test_channel_ids_from_urls_and_usernames(mocker, channels_urls, usernames):
32+
def test_channel_ids_from_urls_and_usernames(mocker):
33+
"""Test to verify fetching channel IDs from both URLs and usernames.
34+
35+
This test checks if the `execute` method of the `ChannelInfo` class correctly fetches channel IDs
36+
from a list of URLs and usernames, and then calls the `channels_infos` method with these IDs.
37+
"""
38+
urls = ["https://www.youtube.com/@Turicas/featured", "https://www.youtube.com/c/PythonicCaf%C3%A9"]
39+
usernames = ["Turicas", "PythonicCafe"]
40+
3041
ids_from_urls_mock = "id_from_url"
3142
ids_from_usernames_mock = "id_from_username"
3243
youtube_mock = mocker.patch("youtool.commands.channel_info.YouTube")

tests/commands/test_video_comments.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99

1010
def test_video_comments(mocker):
11+
"""Test case for fetching video comments and verifying the output.
12+
13+
This test mocks the YouTube API to simulate fetching comments for a video,
14+
then compares the generated CSV output with expected comments.
15+
"""
1116
youtube_mock = mocker.patch("youtool.commands.video_comments.YouTube")
1217
video_id = "video_id_mock"
1318

@@ -30,6 +35,11 @@ def test_video_comments(mocker):
3035

3136

3237
def test_video_comments_with_file_output(mocker, tmp_path):
38+
"""Test case for fetching video comments and saving them to a CSV file.
39+
40+
This test mocks the YouTube API to simulate fetching comments for a video,
41+
then saves the comments to a temporary CSV file.
42+
"""
3343
youtube_mock = mocker.patch("youtool.commands.video_comments.YouTube")
3444
video_id = "video_id_mock"
3545

tests/commands/test_video_info.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,26 @@
88

99
@pytest.fixture
1010
def youtube_mock(mocker, mock_video_info):
11+
"""Fixture to mock the YouTube instance and its videos_infos method."""
1112
mock = mocker.patch("youtool.commands.video_info.YouTube")
1213
mock_instance = mock.return_value
1314
mock_instance.videos_infos = Mock(return_value=mock_video_info)
1415
return mock_instance
1516

1617
@pytest.fixture
1718
def mock_video_info():
19+
"""Fixture to return mock video information."""
1820
return [
1921
{"id": "tmrhPou85HQ", "title": "Title 1", "description": "Description 1", "published_at": "2021-01-01", "view_count": 100, "like_count": 10, "comment_count": 5},
2022
{"id": "qoI_x9fylaw", "title": "Title 2", "description": "Description 2", "published_at": "2021-02-01", "view_count": 200, "like_count": 20, "comment_count": 10}
2123
]
2224

2325
def test_execute_with_ids_and_urls(youtube_mock, mocker, tmp_path, mock_video_info):
26+
"""Test the execute method with provided video IDs and URLs.
27+
28+
This test verifies that the execute method can handle both video IDs and URLs,
29+
and correctly writes the video information to the output CSV file.
30+
"""
2431
ids = ["tmrhPou85HQ", "qoI_x9fylaw"]
2532
urls = ["https://www.youtube.com/watch?v=tmrhPou85HQ&ab_channel=Turicas", "https://www.youtube.com/watch?v=qoI_x9fylaw&ab_channel=PythonicCaf%C3%A9"]
2633
output_file_path = tmp_path / "output.csv"
@@ -36,12 +43,25 @@ def test_execute_with_ids_and_urls(youtube_mock, mocker, tmp_path, mock_video_in
3643
assert csv_data[1]["id"] == "qoI_x9fylaw"
3744

3845
def test_execute_missing_arguments():
46+
"""Test the execute method raises an exception when missing required arguments.
47+
48+
This test verifies that the execute method raises an exception if neither
49+
video IDs nor URLs are provided.
50+
51+
Raises:
52+
Exception: If neither 'ids' nor 'urls' is provided.
53+
"""
3954
with pytest.raises(Exception) as exc_info:
4055
VideoInfo.execute(api_key="test_api_key")
4156

4257
assert str(exc_info.value) == "Either 'ids' or 'urls' must be provided for the video-info command"
4358

4459
def test_execute_with_input_file_path(youtube_mock, mocker, tmp_path, mock_video_info):
60+
"""Test the execute method with an input CSV file containing video URLs and IDs.
61+
62+
This test verifies that the execute method can read video URLs and IDs from
63+
an input CSV file and correctly writes the video information to the output CSV file.
64+
"""
4565
input_csv_content = """video_id,video_url
4666
tmrhPou85HQ,https://www.youtube.com/watch?v=tmrhPou85HQ&ab_channel=Turicas
4767
qoI_x9fylaw,https://www.youtube.com/watch?v=qoI_x9fylaw&ab_channel=PythonicCaf%C3%A9
@@ -64,6 +84,12 @@ def test_execute_with_input_file_path(youtube_mock, mocker, tmp_path, mock_video
6484

6585

6686
def test_execute_with_info_columns(youtube_mock, mocker, tmp_path, mock_video_info):
87+
"""Test the execute method with specified info columns.
88+
89+
This test verifies that the execute method can filter the video information
90+
based on specified columns and correctly writes the filtered information
91+
to the output CSV file.
92+
"""
6793
ids = ["tmrhPou85HQ", "qoI_x9fylaw"]
6894
output_file_path = tmp_path / "output.csv"
6995

tests/commands/test_video_livechat.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99

1010
def test_video_livechat(mocker):
11+
"""Test case for fetching live chat messages from a YouTube video.
12+
13+
Mocks the YouTube API to return expected live chat messages and verifies if the execute method correctly formats and returns the data.
14+
"""
1115
youtube_mock = mocker.patch("youtool.commands.video_livechat.YouTube")
1216
video_id = "video_id_mock"
1317

@@ -30,6 +34,10 @@ def test_video_livechat(mocker):
3034

3135

3236
def test_video_livechat_with_file_output(mocker, tmp_path):
37+
"""Test case for fetching live chat messages from a YouTube video and saving them to a CSV file.
38+
39+
Mocks the YouTube API to return expected live chat messages and verifies if the execute method correctly saves the data to a CSV file.
40+
"""
3341
youtube_mock = mocker.patch("youtool.commands.video_livechat.YouTube")
3442
video_id = "video_id_mock"
3543

tests/commands/test_video_search.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
import pytest
33

44
from io import StringIO
5-
from unittest.mock import Mock, call
5+
from unittest.mock import Mock
66
from datetime import datetime
77

88
from youtool.commands.video_search import VideoSearch
99

1010

1111
def test_video_search_string_output(mocker, videos_ids, videos_urls):
12+
"""Test the execution of the video-search command and verify the output as string.
13+
14+
This test simulates the execution of the `VideoSearch.execute` command with a list of video IDs and URLs,
15+
and checks if the output is correctly formatted as a CSV string.
16+
"""
1217
youtube_mock = mocker.patch("youtool.commands.video_search.YouTube")
1318
expected_videos_infos = [
1419
{
@@ -31,6 +36,11 @@ def test_video_search_string_output(mocker, videos_ids, videos_urls):
3136

3237

3338
def test_video_search_file_output(mocker, videos_ids, videos_urls, tmp_path):
39+
"""Test the execution of the video-search command and verify the output to a file.
40+
41+
This test simulates the execution of the `VideoSearch.execute` command with a list of video IDs and URLs,
42+
and checks if the output is correctly written to a CSV file.
43+
"""
3444
youtube_mock = mocker.patch("youtool.commands.video_search.YouTube")
3545
expected_videos_infos = [
3646
{
@@ -62,5 +72,13 @@ def test_video_search_file_output(mocker, videos_ids, videos_urls, tmp_path):
6272

6373

6474
def test_video_search_no_id_and_url_error():
75+
"""Test if the video-search command raises an exception when neither IDs nor URLs are provided.
76+
77+
This test checks if executing the `VideoSearch.execute` command without providing IDs or URLs
78+
raises the expected exception.
79+
80+
Assertions:
81+
- Assert that the raised exception matches the expected error message.
82+
"""
6583
with pytest.raises(Exception, match="Either 'ids' or 'urls' must be provided"):
6684
VideoSearch.execute(ids=None, urls=None)

tests/test_cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
"command", COMMANDS
1313
)
1414
def test_missing_api_key(monkeypatch: pytest.MonkeyPatch, command: Command):
15+
"""Test to verify behavior when the YouTube API key is missing.
16+
17+
This test ensures that when the YouTube API key is not set, running any command
18+
from the youtool CLI results in an appropriate error message and exit code.
19+
"""
1520
monkeypatch.delenv('YOUTUBE_API_KEY', raising=False)
1621
cli_path = Path("youtool") / "cli.py"
1722
command_string = ["python", cli_path, command.name]

0 commit comments

Comments
 (0)