Skip to content

Commit 801e5f3

Browse files
committed
Add test for video_info command;
- Add improvements to base file; - Add changes to test_base file
1 parent 64252d7 commit 801e5f3

File tree

4 files changed

+118
-17
lines changed

4 files changed

+118
-17
lines changed

tests/commands/test_base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,23 @@ def test_data_to_csv_output(tmp_path):
171171
assert Path(output_file_path).is_file()
172172
assert expected_output == Path(output_file_path).read_text()
173173
assert str(output_file_path) == result
174+
175+
def test_filter_fields():
176+
channel_info = {
177+
'channel_id': '123456',
178+
'channel_name': 'Test Channel',
179+
'subscribers': 1000,
180+
'videos': 50,
181+
'category': 'Tech'
182+
}
183+
184+
info_columns = ['channel_id', 'channel_name', 'subscribers']
185+
filtered_info = Command.filter_fields(channel_info, info_columns)
186+
187+
expected_result = {
188+
'channel_id': '123456',
189+
'channel_name': 'Test Channel',
190+
'subscribers': 1000
191+
}
192+
193+
assert filtered_info == expected_result, f"Expected {expected_result}, but got {filtered_info}"

tests/commands/test_video_info.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import csv
2+
import pytest
3+
4+
from unittest.mock import Mock
5+
from pathlib import Path
6+
from youtool.commands import VideoInfo
7+
8+
9+
@pytest.fixture
10+
def youtube_mock(mocker, mock_video_info):
11+
mock = mocker.patch("youtool.commands.video_info.YouTube")
12+
mock_instance = mock.return_value
13+
mock_instance.videos_infos = Mock(return_value=mock_video_info)
14+
return mock_instance
15+
16+
@pytest.fixture
17+
def mock_video_info():
18+
return [
19+
{"id": "tmrhPou85HQ", "title": "Title 1", "description": "Description 1", "published_at": "2021-01-01", "view_count": 100, "like_count": 10, "comment_count": 5},
20+
{"id": "qoI_x9fylaw", "title": "Title 2", "description": "Description 2", "published_at": "2021-02-01", "view_count": 200, "like_count": 20, "comment_count": 10}
21+
]
22+
23+
def test_execute_with_ids_and_urls(youtube_mock, mocker, tmp_path, mock_video_info):
24+
ids = ["tmrhPou85HQ", "qoI_x9fylaw"]
25+
urls = ["https://www.youtube.com/watch?v=tmrhPou85HQ&ab_channel=Turicas", "https://www.youtube.com/watch?v=qoI_x9fylaw&ab_channel=PythonicCaf%C3%A9"]
26+
output_file_path = tmp_path / "output.csv"
27+
28+
VideoInfo.execute(ids=ids, urls=urls, output_file_path=str(output_file_path), api_key="test_api_key")
29+
30+
assert Path(output_file_path).is_file()
31+
with open(output_file_path, 'r') as f:
32+
reader = csv.DictReader(f)
33+
csv_data = list(reader)
34+
35+
assert csv_data[0]["id"] == "tmrhPou85HQ"
36+
assert csv_data[1]["id"] == "qoI_x9fylaw"
37+
38+
def test_execute_missing_arguments():
39+
with pytest.raises(Exception) as exc_info:
40+
VideoInfo.execute(api_key="test_api_key")
41+
42+
assert str(exc_info.value) == "Either 'ids' or 'urls' must be provided for the video-info command"
43+
44+
def test_execute_with_input_file_path(youtube_mock, mocker, tmp_path, mock_video_info):
45+
input_csv_content = """video_id,video_url
46+
tmrhPou85HQ,https://www.youtube.com/watch?v=tmrhPou85HQ&ab_channel=Turicas
47+
qoI_x9fylaw,https://www.youtube.com/watch?v=qoI_x9fylaw&ab_channel=PythonicCaf%C3%A9
48+
"""
49+
input_file_path = tmp_path / "input.csv"
50+
output_file_path = tmp_path / "output.csv"
51+
52+
with open(input_file_path, 'w') as f:
53+
f.write(input_csv_content)
54+
55+
VideoInfo.execute(input_file_path=str(input_file_path), output_file_path=str(output_file_path), api_key="test_api_key")
56+
57+
assert Path(output_file_path).is_file()
58+
with open(output_file_path, 'r') as f:
59+
reader = csv.DictReader(f)
60+
csv_data = list(reader)
61+
62+
assert csv_data[0]["id"] == "tmrhPou85HQ"
63+
assert csv_data[1]["id"] == "qoI_x9fylaw"
64+
65+
66+
def test_execute_with_info_columns(youtube_mock, mocker, tmp_path, mock_video_info):
67+
ids = ["tmrhPou85HQ", "qoI_x9fylaw"]
68+
output_file_path = tmp_path / "output.csv"
69+
70+
VideoInfo.execute(ids=ids, output_file_path=str(output_file_path), api_key="test_api_key", info_columns="id,title")
71+
72+
assert Path(output_file_path).is_file()
73+
with open(output_file_path, 'r') as f:
74+
reader = csv.DictReader(f)
75+
csv_data = list(reader)
76+
77+
assert csv_data[0]["id"] == "tmrhPou85HQ"
78+
assert csv_data[0]["title"] == "Title 1"
79+
assert csv_data[1]["id"] == "qoI_x9fylaw"
80+
assert csv_data[1]["title"] == "Title 2"

youtool/commands/base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@ def parse_arguments(cls, subparsers: argparse._SubParsersAction) -> None:
5050
parser.add_argument(argument_name, **argument_copy)
5151
parser.set_defaults(func=cls.execute)
5252

53+
@staticmethod
54+
def filter_fields(video_info: Dict, info_columns: Optional[List] = None) -> Dict:
55+
"""Filters the fields of a dictionary containing video information based on specified columns.
56+
57+
Args:
58+
video_info (Dict): A dictionary containing video information.
59+
info_columns (Optional[List], optional): A list specifying which fields to include in the filtered output.
60+
If None, returns the entire video_info dictionary. Defaults to None.
61+
62+
Returns:
63+
A dictionary containing only the fields specified in info_columns (if provided)
64+
or the entire video_info dictionary if info_columns is None.
65+
"""
66+
return {
67+
field: value for field, value in video_info.items() if field in info_columns
68+
} if info_columns else video_info
69+
70+
5371
@classmethod
5472
def execute(cls, **kwargs) -> str: # noqa: D417
5573
"""Executes the command.

youtool/commands/video_info.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,6 @@ class VideoInfo(Command):
2424
"id", "title", "description", "published_at", "view_count", "like_count", "comment_count"
2525
]
2626

27-
@staticmethod
28-
def filter_fields(video_info: Dict, info_columns: Optional[List] = None) -> Dict:
29-
"""Filters the fields of a dictionary containing video information based on specified columns.
30-
31-
Args:
32-
video_info (Dict): A dictionary containing video information.
33-
info_columns (Optional[List], optional): A list specifying which fields to include in the filtered output.
34-
If None, returns the entire video_info dictionary. Defaults to None.
35-
36-
Returns:
37-
A dictionary containing only the fields specified in info_columns (if provided)
38-
or the entire video_info dictionary if info_columns is None.
39-
"""
40-
return {
41-
field: value for field, value in video_info.items() if field in info_columns
42-
} if info_columns else video_info
43-
4427
@classmethod
4528
def execute(cls: Self, **kwargs) -> str:
4629
"""

0 commit comments

Comments
 (0)