From b6c8100ebf7496ddbec08264bb70543fa02c5bcf Mon Sep 17 00:00:00 2001 From: Ramshankar Yadhunath Date: Thu, 1 Jul 2021 14:07:20 +0530 Subject: [PATCH 1/3] Delete python directory --- python/README.md | 72 -------- python/intellij_setup.png | Bin 61875 -> 0 bytes python/intellij_test_setup.png | Bin 59105 -> 0 bytes python/src/__init__.py | 0 python/src/command_parser.py | 163 ------------------- python/src/run.py | 21 --- python/src/video.py | 31 ---- python/src/video_library.py | 45 ----- python/src/video_player.py | 140 ---------------- python/src/video_playlist.py | 5 - python/src/videos.txt | 5 - python/test/part1_test.py | 238 --------------------------- python/test/part2_test.py | 237 --------------------------- python/test/part3_test.py | 142 ---------------- python/test/part4_test.py | 271 ------------------------------- python/test/videolibrary_test.py | 26 --- 16 files changed, 1396 deletions(-) delete mode 100644 python/README.md delete mode 100644 python/intellij_setup.png delete mode 100644 python/intellij_test_setup.png delete mode 100644 python/src/__init__.py delete mode 100644 python/src/command_parser.py delete mode 100644 python/src/run.py delete mode 100644 python/src/video.py delete mode 100644 python/src/video_library.py delete mode 100644 python/src/video_player.py delete mode 100644 python/src/video_playlist.py delete mode 100644 python/src/videos.txt delete mode 100644 python/test/part1_test.py delete mode 100644 python/test/part2_test.py delete mode 100644 python/test/part3_test.py delete mode 100644 python/test/part4_test.py delete mode 100644 python/test/videolibrary_test.py diff --git a/python/README.md b/python/README.md deleted file mode 100644 index d259b4a..0000000 --- a/python/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Youtube Challenge - Python -The Python Youtube Challenge uses Python3. -The below commands use Python3 specifically, to account for users that might -have Python2 installed alongside Python3. - -NOTE: **Please do not edit videos.txt as it will cause tests to break. There is no need to modify this file to complete this challenge.** - -## Installing Python and pytest -[This guide](https://realpython.com/installing-python/) explains how to check if you already -have Python installed, and if not, how to install it on your machine. -Please make sure you install Python 3.7 or higher. - -The tests are using `pytest`, if you don't have `pytest` installed yet, you can do so by running: -```shell script -python3 -m pip install pytest -``` - -pip should be installed already if you installed Python from the official source. If not, you -can find many guides online on how to install pip for your operating system. - -## Setting up -You can write code in any editor you'd like. However, different editors have -different ways of dealing with Python code, so in case of doubt we recommend -you run the code and tests from the command line as shown below. - -## Running and testing from the Commandline -To run the command-line application: -```shell script -python3 -m src.run -``` - -You can close the app by typing `EXIT` as a command. - -#### Running the tests -To run all the tests: -```shell script -python3 -m pytest -``` -For more verbose test output you can use -```shell script -python3 -m pytest -v -``` - -```shell script -python3 -m pytest test/part1_test.py -python3 -m pytest test/part2_test.py -python3 -m pytest test/part3_test.py -python3 -m pytest test/part4_test.py -``` - -For more information on pytest commandline options, such as only running a specific test, -you can read more [here](https://docs.pytest.org/en/6.2.x/usage.html#). - -## Running and testing from IntelliJ/PyCharm -* Mark both the `python/` and `src/` directory as Sources Root - * (Right-click on src/ > Mark Directory As > Sources Root ) -* Mark the `test/` directory as Test Sources Root - * (Right-click on test/ > Mark Directory As > Test Sources Root) - -This will allow your editor to correctly index the project. - -To run the Application, create a new "Run/Debug configuration": -* Run > Edit Configurations > "+" Button > Python -![intellij_setup](intellij_setup.png) - -To run the tests, add a pytest configuration as follows: -* Run > Edit Configurations > "+" Button > Python tests > pytest - -![intellij_test_setup](intellij_test_setup.png) - -Then you will be able to run and debug the unit tests. - diff --git a/python/intellij_setup.png b/python/intellij_setup.png deleted file mode 100644 index 8d99b11081ef520189afddb9a5b123c1d92e103d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61875 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

W!g5_m{@Eo9ZIZ3p4QJsZTr|F2f{tOb}p|b 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 diff --git a/python/intellij_test_setup.png b/python/intellij_test_setup.png deleted file mode 100644 index 788cb45a98cb0e34020b2a4d6bca10a515f8ef2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59105 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 - Plays specified video. - PLAY_RANDOM - Plays a random video from the library. - STOP - Stop the current video. - PAUSE - Pause the current video. - CONTINUE - Resume the current paused video. - SHOW_PLAYING - Displays the title, url and paused status of the video that is currently playing (or paused). - CREATE_PLAYLIST - Creates a new (empty) playlist with the provided name. - ADD_TO_PLAYLIST - Adds the requested video to the playlist. - REMOVE_FROM_PLAYLIST - Removes the specified video from the specified playlist - CLEAR_PLAYLIST - Removes all the videos from the playlist. - DELETE_PLAYLIST - Deletes the playlist. - SHOW_PLAYLIST - List all the videos in this playlist. - SHOW_ALL_PLAYLISTS - Display all the available playlists. - SEARCH_VIDEOS - Display all the videos whose titles contain the search_term. - SEARCH_VIDEOS_WITH_TAG -Display all videos whose tags contains the provided tag. - FLAG_VIDEO - Mark a video as flagged. - ALLOW_VIDEO - Removes a flag from a video. - HELP - Displays help. - EXIT - Terminates the program execution. - """) - print(help_text) diff --git a/python/src/run.py b/python/src/run.py deleted file mode 100644 index dbb22c0..0000000 --- a/python/src/run.py +++ /dev/null @@ -1,21 +0,0 @@ -"""A youtube terminal simulator.""" -from .video_player import VideoPlayer -from .command_parser import CommandException -from .command_parser import CommandParser - - -if __name__ == "__main__": - print("""Hello and welcome to YouTube, what would you like to do? - Enter HELP for list of available commands or EXIT to terminate.""") - video_player = VideoPlayer() - parser = CommandParser(video_player) - while True: - command = input("YT> ") - if command.upper() == "EXIT": - break - try: - parser.execute_command(command.split()) - except CommandException as e: - print(e) - print("YouTube has now terminated its execution. " - "Thank you and goodbye!") diff --git a/python/src/video.py b/python/src/video.py deleted file mode 100644 index 52da908..0000000 --- a/python/src/video.py +++ /dev/null @@ -1,31 +0,0 @@ -"""A video class.""" - -from typing import Sequence - - -class Video: - """A class used to represent a Video.""" - - def __init__(self, video_title: str, video_id: str, video_tags: Sequence[str]): - """Video constructor.""" - self._title = video_title - self._video_id = video_id - - # Turn the tags into a tuple here so it's unmodifiable, - # in case the caller changes the 'video_tags' they passed to us - self._tags = tuple(video_tags) - - @property - def title(self) -> str: - """Returns the title of a video.""" - return self._title - - @property - def video_id(self) -> str: - """Returns the video id of a video.""" - return self._video_id - - @property - def tags(self) -> Sequence[str]: - """Returns the list of tags of a video.""" - return self._tags diff --git a/python/src/video_library.py b/python/src/video_library.py deleted file mode 100644 index 57140e6..0000000 --- a/python/src/video_library.py +++ /dev/null @@ -1,45 +0,0 @@ -"""A video library class.""" - -from .video import Video -from pathlib import Path -import csv - - -# Helper Wrapper around CSV reader to strip whitespace from around -# each item. -def _csv_reader_with_strip(reader): - yield from ((item.strip() for item in line) for line in reader) - - -class VideoLibrary: - """A class used to represent a Video Library.""" - - def __init__(self): - """The VideoLibrary class is initialized.""" - self._videos = {} - with open(Path(__file__).parent / "videos.txt") as video_file: - reader = _csv_reader_with_strip( - csv.reader(video_file, delimiter="|")) - for video_info in reader: - title, url, tags = video_info - self._videos[url] = Video( - title, - url, - [tag.strip() for tag in tags.split(",")] if tags else [], - ) - - def get_all_videos(self): - """Returns all available video information from the video library.""" - return list(self._videos.values()) - - def get_video(self, video_id): - """Returns the video object (title, url, tags) from the video library. - - Args: - video_id: The video url. - - Returns: - The Video object for the requested video_id. None if the video - does not exist. - """ - return self._videos.get(video_id, None) diff --git a/python/src/video_player.py b/python/src/video_player.py deleted file mode 100644 index bb79af8..0000000 --- a/python/src/video_player.py +++ /dev/null @@ -1,140 +0,0 @@ -"""A video player class.""" - -from .video_library import VideoLibrary - - -class VideoPlayer: - """A class used to represent a Video Player.""" - - def __init__(self): - self._video_library = VideoLibrary() - - def number_of_videos(self): - num_videos = len(self._video_library.get_all_videos()) - print(f"{num_videos} videos in the library") - - def show_all_videos(self): - """Returns all videos.""" - - print("show_all_videos needs implementation") - - def play_video(self, video_id): - """Plays the respective video. - - Args: - video_id: The video_id to be played. - """ - print("play_video needs implementation") - - def stop_video(self): - """Stops the current video.""" - - print("stop_video needs implementation") - - def play_random_video(self): - """Plays a random video from the video library.""" - - print("play_random_video needs implementation") - - def pause_video(self): - """Pauses the current video.""" - - print("pause_video needs implementation") - - def continue_video(self): - """Resumes playing the current video.""" - - print("continue_video needs implementation") - - def show_playing(self): - """Displays video currently playing.""" - - print("show_playing needs implementation") - - def create_playlist(self, playlist_name): - """Creates a playlist with a given name. - - Args: - playlist_name: The playlist name. - """ - print("create_playlist needs implementation") - - def add_to_playlist(self, playlist_name, video_id): - """Adds a video to a playlist with a given name. - - Args: - playlist_name: The playlist name. - video_id: The video_id to be added. - """ - print("add_to_playlist needs implementation") - - def show_all_playlists(self): - """Display all playlists.""" - - print("show_all_playlists needs implementation") - - def show_playlist(self, playlist_name): - """Display all videos in a playlist with a given name. - - Args: - playlist_name: The playlist name. - """ - print("show_playlist needs implementation") - - def remove_from_playlist(self, playlist_name, video_id): - """Removes a video to a playlist with a given name. - - Args: - playlist_name: The playlist name. - video_id: The video_id to be removed. - """ - print("remove_from_playlist needs implementation") - - def clear_playlist(self, playlist_name): - """Removes all videos from a playlist with a given name. - - Args: - playlist_name: The playlist name. - """ - print("clears_playlist needs implementation") - - def delete_playlist(self, playlist_name): - """Deletes a playlist with a given name. - - Args: - playlist_name: The playlist name. - """ - print("deletes_playlist needs implementation") - - def search_videos(self, search_term): - """Display all the videos whose titles contain the search_term. - - Args: - search_term: The query to be used in search. - """ - print("search_videos needs implementation") - - def search_videos_tag(self, video_tag): - """Display all videos whose tags contains the provided tag. - - Args: - video_tag: The video tag to be used in search. - """ - print("search_videos_tag needs implementation") - - def flag_video(self, video_id, flag_reason=""): - """Mark a video as flagged. - - Args: - video_id: The video_id to be flagged. - flag_reason: Reason for flagging the video. - """ - print("flag_video needs implementation") - - def allow_video(self, video_id): - """Removes a flag from a video. - - Args: - video_id: The video_id to be allowed again. - """ - print("allow_video needs implementation") diff --git a/python/src/video_playlist.py b/python/src/video_playlist.py deleted file mode 100644 index 5836da4..0000000 --- a/python/src/video_playlist.py +++ /dev/null @@ -1,5 +0,0 @@ -"""A video playlist class.""" - - -class Playlist: - """A class used to represent a Playlist.""" diff --git a/python/src/videos.txt b/python/src/videos.txt deleted file mode 100644 index 0800bb7..0000000 --- a/python/src/videos.txt +++ /dev/null @@ -1,5 +0,0 @@ -Funny Dogs | funny_dogs_video_id | #dog , #animal -Amazing Cats | amazing_cats_video_id | #cat , #animal -Another Cat Video | another_cat_video_id | #cat , #animal -Life at Google | life_at_google_video_id | #google , #career -Video about nothing | nothing_video_id | \ No newline at end of file diff --git a/python/test/part1_test.py b/python/test/part1_test.py deleted file mode 100644 index b2568a6..0000000 --- a/python/test/part1_test.py +++ /dev/null @@ -1,238 +0,0 @@ -import re -from src.video_player import VideoPlayer - - -def test_number_of_videos(capfd): - player = VideoPlayer() - player.number_of_videos() - out, err = capfd.readouterr() - assert "5 videos in the library" in out - - -def test_show_all_videos(capfd): - player = VideoPlayer() - player.show_all_videos() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 6 - assert "Here's a list of all available videos:" in lines[0] - assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert "Funny Dogs (funny_dogs_video_id) [#dog #animal]" in lines[3] - assert "Life at Google (life_at_google_video_id) [#google #career]" in lines[4] - assert "Video about nothing (nothing_video_id) []" in lines[5] - - -def test_play_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Playing video: Amazing Cats" in out - - -def test_play_video_nonexistent(capfd): - player = VideoPlayer() - player.play_video("does_not_exist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot play video: Video does not exist" in out - - -def test_play_video_stop_previous(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.play_video("funny_dogs_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" in lines[1] - assert "Playing video: Funny Dogs" in lines[2] - - -def test_play_video_dont_stop_previous_if_nonexistent(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.play_video("some_other_video") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" not in out - assert "Cannot play video: Video does not exist" in lines[1] - - -def test_stop_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.stop_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" in lines[1] - - -def test_stop_video_twice(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.stop_video() - player.stop_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" in lines[1] - assert "Cannot stop video: No video is currently playing" in lines[2] - - -def test_stop_video_none_playing(capfd): - player = VideoPlayer() - player.stop_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot stop video: No video is currently playing" in out - - -def test_play_random_video(capfd): - player = VideoPlayer() - player.play_random_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert re.match( - "Playing video: (Amazing Cats|Another Cat Video|Funny Dogs|Life at Google|Video about nothing)", - out) - - -def test_play_random_stops_previous_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.play_random_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" in lines[1] - assert re.match( - "Playing video: (Amazing Cats|Another Cat Video|Funny Dogs|Life at Google|Video about nothing)", - lines[2]) - - -def test_show_playing(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Playing video: Amazing Cats" in lines[0] - assert "Currently playing: Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - - -def test_show_nothing_playing(capfd): - player = VideoPlayer() - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "No video is currently playing" in lines[0] - - -def test_pause_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Playing video: Amazing Cats" in lines[0] - assert "Pausing video: Amazing Cats" in lines[1] - - -def test_pause_video_show_playing(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ - "[#cat #animal] - PAUSED" in lines[2] - - -def test_pause_video_play_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - player.play_video("amazing_cats_video_id") - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Playing video: Amazing Cats" in lines[0] - assert "Pausing video: Amazing Cats" in lines[1] - assert "Stopping video: Amazing Cats" in lines[2] - assert "Playing video: Amazing Cats" in lines[3] - assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ - "[#cat #animal]" in lines[4] - assert "PAUSED" not in lines[4] - - -def test_pause_already_paused_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - player.pause_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Pausing video: Amazing Cats" in lines[1] - assert "Video already paused: Amazing Cats" in lines[2] - - -def test_pause_video_none_playing(capfd): - player = VideoPlayer() - player.pause_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot pause video: No video is currently playing" in lines[0] - - -def test_continue_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - player.continue_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Pausing video: Amazing Cats" in lines[1] - assert "Continuing video: Amazing Cats" in lines[2] - - -def test_continue_video_not_paused(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.continue_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Cannot continue video: Video is not paused" in lines[1] - - -def test_continue_none_playing(capfd): - player = VideoPlayer() - player.continue_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot continue video: No video is currently playing" in lines[0] diff --git a/python/test/part2_test.py b/python/test/part2_test.py deleted file mode 100644 index 99ff02a..0000000 --- a/python/test/part2_test.py +++ /dev/null @@ -1,237 +0,0 @@ -from src.video_player import VideoPlayer - - -def test_create_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_PLAYlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Successfully created new playlist: my_PLAYlist" in lines[0] - - -def test_create_existing_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.create_playlist("my_COOL_PLAYLIST") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert ("Cannot create playlist: A playlist with the same name already " - "exists") in lines[1] - - -def test_add_to_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_COOL_playlist") - player.add_to_playlist("my_cool_PLAYLIST", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully created new playlist: my_COOL_playlist" in lines[0] - assert "Added video to my_cool_PLAYLIST: Amazing Cats" in lines[1] - - -def test_add_to_playlist_already_added(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] - assert "Cannot add video to my_cool_playlist: Video already added" in lines[2] - - -def test_add_to_playlist_nonexistent_video(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.add_to_playlist("my_cool_playlist", "some_other_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] - assert "Cannot add video to my_cool_playlist: Video does not exist" in lines[2] - - -def test_add_to_playlist_nonexistent_playlist(capfd): - player = VideoPlayer() - player.add_to_playlist("another_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot add video to another_playlist: Playlist does not exist" in lines[0] - - -def test_add_to_playlist_nonexistent_playlist_nonexistent_video(capfd): - player = VideoPlayer() - player.add_to_playlist("another_playlist", "does_not_exist_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot add video to another_playlist: Playlist does not exist" in lines[0] - - -def test_show_all_playlists_no_playlists_exist(capfd): - player = VideoPlayer() - player.show_all_playlists() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "No playlists exist yet" in lines[0] - - -def test_show_all_playlists(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playLIST") - player.create_playlist("anotheR_playlist") - player.show_all_playlists() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Showing all playlists:" in lines[2] - assert "anotheR_playlist" in lines[3] - assert "my_cool_playLIST" in lines[4] - - -def test_show_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.show_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.show_playlist("my_COOL_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 6 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Showing playlist: my_cool_playlist" in lines[1] - assert "No videos here yet" in lines[2] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[3] - assert "Showing playlist: my_COOL_playlist" in lines[4] - assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[5] - - -def test_remove_from_playlist_then_re_add(capfd): - player = VideoPlayer() - player.create_playlist("MY_playlist") - player.add_to_playlist("my_playlist", "amazing_cats_video_id") - player.add_to_playlist("my_playlist", "life_at_google_video_id") - player.remove_from_playlist("my_playlist", "amazing_cats_video_id") - player.add_to_playlist("my_playlist", "amazing_cats_video_id") - player.show_playlist("my_playLIST") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 8 - assert "Showing playlist: my_playLIST" in lines[5] - assert "Life at Google (life_at_google_video_id) [#google #career]" in lines[6] - assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[7] - - -def test_show_playlist_nonexistent_playlist(capfd): - player = VideoPlayer() - player.show_playlist("another_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot show playlist another_playlist: Playlist does not exist" in lines[0] - - -def test_remove_from_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.remove_from_playlist("my_COOL_playlist", "amazing_cats_video_id") - player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 4 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] - assert "Removed video from my_COOL_playlist: Amazing Cats" in lines[2] - assert "Cannot remove video from my_cool_playlist: Video is not in playlist" in lines[3] - - -def test_remove_from_playlist_video_is_not_in_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Cannot remove video from my_cool_playlist: Video is not in playlist" in lines[1] - - -def test_remove_from_playlist_nonexistent_video(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.remove_from_playlist("my_cool_playlist", "some_other_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] - assert "Cannot remove video from my_cool_playlist: Video does not exist" in lines[2] - - -def test_remove_from_playlist_nonexistent_playlist(capfd): - player = VideoPlayer() - player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot remove video from my_cool_playlist: Playlist does not exist" in lines[0] - - -def test_clear_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") - player.show_playlist("my_cool_playlist") - player.clear_playlist("my_COOL_playlist") - player.show_playlist("my_cool_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 7 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] - assert "Showing playlist: my_cool_playlist" in lines[2] - assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[3] - assert "Successfully removed all videos from my_COOL_playlist" in lines[4] - assert "Showing playlist: my_cool_playlist" in lines[5] - assert "No videos here yet" in lines[6] - - -def test_clear_playlist_nonexistent(capfd): - player = VideoPlayer() - player.clear_playlist("my_cool_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot clear playlist my_cool_playlist: Playlist does not exist" in lines[0] - - -def test_delete_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_cool_playlist") - player.delete_playlist("my_cool_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully created new playlist: my_cool_playlist" in lines[0] - assert "Deleted playlist: my_cool_playlist" in lines[1] - - -def test_delete_playlist_nonexistent(capfd): - player = VideoPlayer() - player.delete_playlist("my_cool_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot delete playlist my_cool_playlist: Playlist does not exist" in lines[0] diff --git a/python/test/part3_test.py b/python/test/part3_test.py deleted file mode 100644 index 817dce3..0000000 --- a/python/test/part3_test.py +++ /dev/null @@ -1,142 +0,0 @@ -from src.video_player import VideoPlayer -from unittest import mock - - -@mock.patch('builtins.input', lambda *args: 'No') -def test_search_videos_with_no_answer(capfd): - player = VideoPlayer() - player.search_videos("cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Here are the results for cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ( - "If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video" not in out - - -@mock.patch('builtins.input', lambda *args: '2') -def test_search_videos_and_play_answer(capfd): - player = VideoPlayer() - player.search_videos("cat") - - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 6 - assert "Here are the results for cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video: Another Cat Video" in lines[5] - - -@mock.patch('builtins.input', lambda *args: '6') -def test_search_videos_number_out_of_bounds(capfd): - player = VideoPlayer() - player.search_videos("cat") - - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Here are the results for cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video" not in out - - -@mock.patch('builtins.input', lambda *args: 'ab3g') -def test_search_videos_invalid_number(capfd): - player = VideoPlayer() - player.search_videos("cat") - - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Here are the results for cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video" not in out - - -def test_search_videos_no_results(capfd): - player = VideoPlayer() - player.search_videos("blah") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "No search results for blah" in lines[0] - - -@mock.patch('builtins.input', lambda *args: 'No') -def test_search_videos_with_tag_no_answer(capfd): - player = VideoPlayer() - player.search_videos_tag("#cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Here are the results for #cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - - -@mock.patch('builtins.input', lambda *args: '1') -def test_search_videos_with_tag_play_answered_number(capfd): - player = VideoPlayer() - player.search_videos_tag("#cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 6 - assert "Here are the results for #cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video: Amazing Cats" in lines[5] - - -@mock.patch('builtins.input', lambda *args: '5') -def test_search_videos_with_tag_number_out_of_bounds(capfd): - player = VideoPlayer() - player.search_videos_tag("#cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Here are the results for #cat:" in lines[0] - assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] - assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - assert "Playing video" not in out - - -def test_search_videos_tag_no_results(capfd): - player = VideoPlayer() - player.search_videos_tag("#blah") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "No search results for #blah" in lines[0] diff --git a/python/test/part4_test.py b/python/test/part4_test.py deleted file mode 100644 index 381a48d..0000000 --- a/python/test/part4_test.py +++ /dev/null @@ -1,271 +0,0 @@ -from unittest import mock - -from src.video_player import VideoPlayer - - -def test_flag_video_with_reason(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Successfully flagged video: Amazing Cats (reason: dont_like_cats)" \ - in lines[0] - - -def test_flag_video_without_reason(capfd): - player = VideoPlayer() - player.flag_video("another_cat_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Successfully flagged video: Another Cat Video " \ - "(reason: Not supplied)" in lines[0] - - -def test_flag_video_already_flagged(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.flag_video("amazing_cats_video_id", "dont_like_cats") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully flagged video: Amazing Cats (reason: dont_like_cats)" in \ - lines[0] - assert "Cannot flag video: Video is already flagged" in lines[1] - - -def test_flag_video_nonexistent(capfd): - player = VideoPlayer() - player.flag_video("video_does_not_exist", "flag_video_reason") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot flag video: Video does not exist" in lines[0] - - -def test_flag_video_can_no_longer_play(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id") - player.play_video("amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully flagged video: Amazing Cats " \ - "(reason: Not supplied)" in lines[0] - assert "Cannot play video: Video is currently flagged " \ - "(reason: Not supplied)" in lines[1] - - -def test_flag_videos_play_random(capfd): - player = VideoPlayer() - player.flag_video("funny_dogs_video_id") - player.flag_video("amazing_cats_video_id") - player.flag_video("another_cat_video_id") - player.flag_video("life_at_google_video_id") - player.flag_video("nothing_video_id") - player.play_random_video() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 6 - assert "Successfully flagged video: Funny Dogs " \ - "(reason: Not supplied)" in lines[0] - assert "Successfully flagged video: Amazing Cats " \ - "(reason: Not supplied)" in lines[1] - assert "Successfully flagged video: Another Cat Video " \ - "(reason: Not supplied)" in lines[2] - assert "Successfully flagged video: Life at Google " \ - "(reason: Not supplied)" in lines[3] - assert "Successfully flagged video: Video about nothing " \ - "(reason: Not supplied)" in lines[4] - assert "No videos available" in lines[5] - - -def test_flag_video_add_to_playlist(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id") - player.create_playlist("my_playlist") - player.add_to_playlist("my_playlist", "amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert ("Successfully flagged video: Amazing Cats " - "(reason: Not supplied)") in lines[0] - assert "Successfully created new playlist: my_playlist" in lines[1] - assert ("Cannot add video to my_playlist: Video is currently " - "flagged (reason: Not supplied)") in lines[2] - - -def test_flag_video_show_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_playlist") - player.add_to_playlist("my_playlist", "amazing_cats_video_id") - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.show_playlist("my_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Successfully created new playlist: my_playlist" in lines[0] - assert "Added video to my_playlist: Amazing Cats" in lines[1] - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[2] - assert "Showing playlist: my_playlist" in lines[3] - assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " - "(reason: dont_like_cats)") in lines[4] - - -def test_flag_video_show_all_videos(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.show_all_videos() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 7 - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[0] - assert "Here's a list of all available videos:" in lines[1] - assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " - "(reason: dont_like_cats)") in lines[2] - assert "Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[3] - assert "Funny Dogs (funny_dogs_video_id) [#dog #animal]" in lines[4] - assert "Life at Google (life_at_google_video_id) [#google #career]" in \ - lines[5] - assert "Video about nothing (nothing_video_id) []" in lines[6] - - -@mock.patch('builtins.input', lambda *args: 'No') -def test_flag_video_search_videos(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.search_videos("cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[0] - assert "Here are the results for cat:" in lines[1] - assert "1) Another Cat Video (another_cat_video_id) [#cat #animal]" in \ - lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - - -@mock.patch('builtins.input', lambda *args: 'No') -def test_flag_video_search_videos_with_tag(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.search_videos_tag("#cat") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[0] - assert "Here are the results for #cat:" in lines[1] - assert "1) Another Cat Video (another_cat_video_id) [#cat #animal]" in \ - lines[2] - assert ("Would you like to play any of the above? If yes, " - "specify the number of the video.") in lines[3] - assert ("If your answer is not a valid number, we will assume " - "it's a no.") in lines[4] - - -def test_flag_video_stops_playing_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 4 - assert "Playing video: Amazing Cats" in lines[0] - assert "Stopping video: Amazing Cats" in lines[1] - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[2] - assert "No video is currently playing" in lines[3] - - -def test_flag_video_leaves_video_if_video_is_different(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.flag_video("another_cat_video_id", "dont_like_cats") - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 3 - assert "Playing video: Amazing Cats" in lines[0] - assert "Successfully flagged video: Another Cat Video " \ - "(reason: dont_like_cats)" in lines[1] - assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ - "[#cat #animal]" in lines[2] - - -def test_flag_video_stops_paused_video(capfd): - player = VideoPlayer() - player.play_video("amazing_cats_video_id") - player.pause_video() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.show_playing() - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 5 - assert "Playing video: Amazing Cats" in lines[0] - assert "Pausing video: Amazing Cats" in lines[1] - assert "Stopping video: Amazing Cats" in lines[2] - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[3] - assert "No video is currently playing" in lines[4] - - -def test_allow_video(capfd): - player = VideoPlayer() - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.allow_video("amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 2 - assert "Successfully flagged video: Amazing Cats " \ - "(reason: dont_like_cats)" in lines[0] - assert "Successfully removed flag from video: Amazing Cats" in lines[1] - - -def test_allow_video_not_flagged(capfd): - player = VideoPlayer() - player.allow_video("amazing_cats_video_id") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot remove flag from video: Video is not flagged" in lines[0] - - -def test_allow_video_nonexistent(capfd): - player = VideoPlayer() - player.allow_video("video_does_not_exist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 1 - assert "Cannot remove flag from video: Video does not exist" in lines[0] - - -def test_allow_video_show_playlist(capfd): - player = VideoPlayer() - player.create_playlist("my_playlist") - player.add_to_playlist("my_playlist", "amazing_cats_video_id") - player.flag_video("amazing_cats_video_id", "dont_like_cats") - player.show_playlist("my_playlist") - player.allow_video("amazing_cats_video_id") - player.show_playlist("my_playlist") - out, err = capfd.readouterr() - lines = out.splitlines() - assert len(lines) == 8 - assert "Successfully created new playlist: my_playlist" in lines[0] - assert "Added video to my_playlist: Amazing Cats" in lines[1] - assert ("Successfully flagged video: Amazing Cats " - "(reason: dont_like_cats)") in lines[2] - assert "Showing playlist: my_playlist" in lines[3] - assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " - "(reason: dont_like_cats)") in lines[4] - assert "Successfully removed flag from video: Amazing Cats" in lines[5] - assert "Showing playlist: my_playlist" in lines[6] - assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[7] diff --git a/python/test/videolibrary_test.py b/python/test/videolibrary_test.py deleted file mode 100644 index 7496742..0000000 --- a/python/test/videolibrary_test.py +++ /dev/null @@ -1,26 +0,0 @@ -from src.video_library import VideoLibrary - - -def test_library_has_all_videos(): - library = VideoLibrary() - assert len(library.get_all_videos()) == 5 - - -def test_parses_tags_correctly(): - library = VideoLibrary() - video = library.get_video("amazing_cats_video_id") - - assert video is not None - assert video.title == "Amazing Cats" - assert video.video_id == "amazing_cats_video_id" - assert set(video.tags) == {"#cat", "#animal"} - - -def test_parses_video_correctly_without_tags(): - library = VideoLibrary() - video = library.get_video("nothing_video_id") - - assert video is not None - assert video.title == "Video about nothing" - assert video.video_id == "nothing_video_id" - assert video.tags == () From 31e49d08875a4b753bb181a355ed1ed2859d1fdb Mon Sep 17 00:00:00 2001 From: Ramshankar Yadhunath Date: Thu, 1 Jul 2021 14:08:06 +0530 Subject: [PATCH 2/3] Make submission --- python/README.md | 72 +++++++ python/intellij_setup.png | Bin 0 -> 61875 bytes python/intellij_test_setup.png | Bin 0 -> 59105 bytes python/src/command_parser.py | 163 ++++++++++++++ python/src/run.py | 21 ++ python/src/video.py | 42 ++++ python/src/video_library.py | 45 ++++ python/src/video_player.py | 376 +++++++++++++++++++++++++++++++++ python/src/video_playlist.py | 8 + python/src/videos.txt | 5 + 10 files changed, 732 insertions(+) create mode 100644 python/README.md create mode 100644 python/intellij_setup.png create mode 100644 python/intellij_test_setup.png create mode 100644 python/src/command_parser.py create mode 100644 python/src/run.py create mode 100644 python/src/video.py create mode 100644 python/src/video_library.py create mode 100644 python/src/video_player.py create mode 100644 python/src/video_playlist.py create mode 100644 python/src/videos.txt diff --git a/python/README.md b/python/README.md new file mode 100644 index 0000000..d470604 --- /dev/null +++ b/python/README.md @@ -0,0 +1,72 @@ +# Youtube Challenge - Python +The Python Youtube Challenge uses Python3. +The below commands use Python3 specifically, to account for users that might +have Python2 installed alongside Python3. + +NOTE: **Please do not edit videos.txt as it will cause tests to break. There is no need to modify this file to complete this challenge.** + +## Installing Python and pytest +[This guide](https://realpython.com/installing-python/) explains how to check if you already +have Python installed, and if not, how to install it on your machine. +Please make sure you install Python 3.7 or higher. + +The tests are using `pytest`, if you don't have `pytest` installed yet, you can do so by running: +```shell script +python3 -m pip install pytest +``` + +pip should be installed already if you installed Python from the official source. If not, you +can find many guides online on how to install pip for your operating system. + +## Setting up +You can write code in any editor you'd like. However, different editors have +different ways of dealing with Python code, so in case of doubt we recommend +you run the code and tests from the command line as shown below. + +## Running and testing from the Commandline +To run the command-line application: +```shell script +python3 -m src.run +``` + +You can close the app by typing `EXIT` as a command. + +#### Running the tests +To run all the tests: +```shell script +python3 -m pytest +``` +For more verbose test output you can use +```shell script +python3 -m pytest -v +``` + +```shell script +python3 -m pytest test/part1_test.py +python3 -m pytest test/part2_test.py +python3 -m pytest test/part3_test.py +python3 -m pytest test/part4_test.py +``` + +For more information on pytest commandline options, such as only running a specific test, +you can read more [here](https://docs.pytest.org/en/6.2.x/usage.html#). + +## Running and testing from IntelliJ/PyCharm +* Mark both the `python/` and `src/` directory as Sources Root + * (Right-click on src/ > Mark Directory As > Sources Root ) +* Mark the `test/` directory as Test Sources Root + * (Right-click on test/ > Mark Directory As > Test Sources Root) + +This will allow your editor to correctly index the project. + +To run the Application, create a new "Run/Debug configuration": +* Run > Edit Configurations > "+" Button > Python +![intellij_setup](intellij_setup.png) + +To run the tests, add a pytest configuration as follows: +* Run > Edit Configurations > "+" Button > Python tests > pytest + +![intellij_test_setup](intellij_test_setup.png) + +Then you will be able to run and debug the unit tests. + diff --git a/python/intellij_setup.png b/python/intellij_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..8d99b11081ef520189afddb9a5b123c1d92e103d GIT binary patch literal 61875 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

W!g5_m{@Eo9ZIZ3p4QJsZTr|F2f{tOb}p|b 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 literal 0 HcmV?d00001 diff --git a/python/intellij_test_setup.png b/python/intellij_test_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..788cb45a98cb0e34020b2a4d6bca10a515f8ef2f GIT binary patch literal 59105 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 - Plays specified video. + PLAY_RANDOM - Plays a random video from the library. + STOP - Stop the current video. + PAUSE - Pause the current video. + CONTINUE - Resume the current paused video. + SHOW_PLAYING - Displays the title, url and paused status of the video that is currently playing (or paused). + CREATE_PLAYLIST - Creates a new (empty) playlist with the provided name. + ADD_TO_PLAYLIST - Adds the requested video to the playlist. + REMOVE_FROM_PLAYLIST - Removes the specified video from the specified playlist + CLEAR_PLAYLIST - Removes all the videos from the playlist. + DELETE_PLAYLIST - Deletes the playlist. + SHOW_PLAYLIST - List all the videos in this playlist. + SHOW_ALL_PLAYLISTS - Display all the available playlists. + SEARCH_VIDEOS - Display all the videos whose titles contain the search_term. + SEARCH_VIDEOS_WITH_TAG -Display all videos whose tags contains the provided tag. + FLAG_VIDEO - Mark a video as flagged. + ALLOW_VIDEO - Removes a flag from a video. + HELP - Displays help. + EXIT - Terminates the program execution. + """) + print(help_text) diff --git a/python/src/run.py b/python/src/run.py new file mode 100644 index 0000000..915bda0 --- /dev/null +++ b/python/src/run.py @@ -0,0 +1,21 @@ +"""A youtube terminal simulator.""" +from .video_player import VideoPlayer +from .command_parser import CommandException +from .command_parser import CommandParser + + +if __name__ == "__main__": + print("""Hello and welcome to YouTube, what would you like to do? + Enter HELP for list of available commands or EXIT to terminate.""") + video_player = VideoPlayer() + parser = CommandParser(video_player) + while True: + command = input("YT> ") + if command.upper() == "EXIT": + break + try: + parser.execute_command(command.split()) + except CommandException as e: + print(e) + print("YouTube has now terminated its execution. " + "Thank you and goodbye!") diff --git a/python/src/video.py b/python/src/video.py new file mode 100644 index 0000000..d0355be --- /dev/null +++ b/python/src/video.py @@ -0,0 +1,42 @@ +"""A video class.""" + +from typing import Sequence + + +class Video: + """A class used to represent a Video.""" + + def __init__(self, video_title: str, video_id: str, video_tags: Sequence[str]): + """Video constructor.""" + self._title = video_title + self._video_id = video_id + + # Turn the tags into a tuple here so it's unmodifiable, + # in case the caller changes the 'video_tags' they passed to us + self._tags = tuple(video_tags) + self._flag_msg = "" + + @property + def title(self) -> str: + """Returns the title of a video.""" + return self._title + + @property + def video_id(self) -> str: + """Returns the video id of a video.""" + return self._video_id + + @property + def tags(self) -> Sequence[str]: + """Returns the list of tags of a video.""" + return self._tags + + @property + def flag_msg(self) -> str: + """Returns the flag message of a video.""" + return self._flag_msg + + def assign_flag_msg(self, msg): + """Assigns the flag message to the video.""" + + self._flag_msg = msg diff --git a/python/src/video_library.py b/python/src/video_library.py new file mode 100644 index 0000000..52c4fac --- /dev/null +++ b/python/src/video_library.py @@ -0,0 +1,45 @@ +"""A video library class.""" + +from .video import Video +from pathlib import Path +import csv + + +# Helper Wrapper around CSV reader to strip whitespace from around +# each item. +def _csv_reader_with_strip(reader): + yield from ((item.strip() for item in line) for line in reader) + + +class VideoLibrary: + """A class used to represent a Video Library.""" + + def __init__(self): + """The VideoLibrary class is initialized.""" + self._videos = {} + with open(Path(__file__).parent / "videos.txt") as video_file: + reader = _csv_reader_with_strip( + csv.reader(video_file, delimiter="|")) + for video_info in reader: + title, url, tags = video_info + self._videos[url] = Video( + title, + url, + [tag.strip() for tag in tags.split(",")] if tags else [], + ) + + def get_all_videos(self): + """Returns all available video information from the video library.""" + return list(self._videos.values()) + + def get_video(self, video_id): + """Returns the video object (title, url, tags) from the video library. + + Args: + video_id: The video url. + + Returns: + The Video object for the requested video_id. None if the video + does not exist. + """ + return self._videos.get(video_id, None) diff --git a/python/src/video_player.py b/python/src/video_player.py new file mode 100644 index 0000000..ad911f9 --- /dev/null +++ b/python/src/video_player.py @@ -0,0 +1,376 @@ +"""A video player class.""" + +from .video_library import VideoLibrary + +import random +from collections import defaultdict + + +class VideoPlayer: + """A class used to represent a Video Player.""" + + def __init__(self): + self._video_library = VideoLibrary() + self.currently_playing = None + self.paused_video = None + + self.playlists = defaultdict(list) + self.playlist_names = defaultdict() + + def number_of_videos(self): + num_videos = len(self._video_library.get_all_videos()) + print(f"{num_videos} videos in the library") + + def show_all_videos(self): + """Returns all videos.""" + + all_videos = self._video_library.get_all_videos() + titles = [video.title for video in all_videos] + ids = [video.video_id for video in all_videos] + tags = [video.tags for video in all_videos] + flag_msgs = [video.flag_msg for video in all_videos] + + sorted_videos = ([(title, url, (" ".join(tags)), flag_msg) for title, url, tags, flag_msg in sorted(zip( + titles, + ids, + tags, + flag_msgs + ))]) + + print("Here's a list of all available videos:") + for video in sorted_videos: + if video[3] == "": + print(f' {video[0]} ({video[1]}) [{video[2]}]') + else: + print(f' {video[0]} ({video[1]}) [{video[2]}] - FLAGGED (reason: {video[3]})') + + def play_video(self, video_id): + """Plays the respective video. + + Args: + video_id: The video_id to be played. + """ + + video_to_play = self._video_library.get_video(video_id) + + if video_to_play == None: + print("Cannot play video: Video does not exist") + else: + if video_to_play.flag_msg == "": + if self.currently_playing == None: + print(f"Playing video: {video_to_play.title}") + self.paused_video = None + self.currently_playing = video_to_play + else: + print(f"Stopping video: {self.currently_playing.title}") + print(f"Playing video: {video_to_play.title}") + self.paused_video = None + self.currently_playing = video_to_play + else: + print(f"Cannot play video: Video is currently flagged (reason: {video_to_play.flag_msg})") + + + def stop_video(self): + """Stops the current video.""" + + if self.currently_playing == None: + print("Cannot stop video: No video is currently playing") + else: + print(f"Stopping video: {self.currently_playing.title}") + self.currently_playing = None + + def play_random_video(self): + """Plays a random video from the video library.""" + + all_videos = self._video_library.get_all_videos() + all_videos = [video for video in all_videos if video.flag_msg == ''] + + if len(all_videos) != 0: + random_video_idx = random.randrange(len(all_videos)) + video_to_play = all_videos[random_video_idx] + + if self.currently_playing == None: + print(f"Playing video: {video_to_play.title}") + self.paused_video = None + self.currently_playing = video_to_play + else: + print(f"Stopping video: {self.currently_playing.title}") + print(f"Playing video: {video_to_play.title}") + self.paused_video = None + self.currently_playing = video_to_play + + else: + print("No videos available") + + def pause_video(self): + """Pauses the current video.""" + + if self.currently_playing == None: + print("Cannot pause video: No video is currently playing") + + else: + + if self.paused_video == None: + print(f"Pausing video: {self.currently_playing.title}") + self.paused_video = self.currently_playing + else: + print(f"Video already paused: {self.paused_video.title}") + + def continue_video(self): + """Resumes playing the current video.""" + + if self.currently_playing == None: + print("Cannot continue video: No video is currently playing") + + else: + + if self.paused_video == None: + print("Cannot continue video: Video is not paused") + else: + print(f"Continuing video: {self.paused_video.title}") + self.paused_video = None + + def show_playing(self): + """Displays video currently playing.""" + + if self.currently_playing == None: + print("No video is currently playing") + + else: + if self.paused_video == None: + print(f"Currently playing: {self.currently_playing.title} ({self.currently_playing.video_id}) [{' '.join(self.currently_playing.tags)}]") + else: + print(f"Currently playing: {self.currently_playing.title} ({self.currently_playing.video_id}) [{' '.join(self.currently_playing.tags)}] - PAUSED") + + + def create_playlist(self, playlist_name): + """Creates a playlist with a given name. + + Args: + playlist_name: The playlist name. + """ + + if playlist_name.lower() in self.playlist_names.keys(): + print("Cannot create playlist: A playlist with the same name already exists") + + else: + self.playlists[playlist_name] = [] + self.playlist_names[playlist_name.lower()] = playlist_name + print(f"Successfully created new playlist: {playlist_name}") + + def add_to_playlist(self, playlist_name, video_id): + """Adds a video to a playlist with a given name. + + Args: + playlist_name: The playlist name. + video_id: The video_id to be added. + """ + + video_to_play = self._video_library.get_video(video_id) + + if playlist_name.lower() not in self.playlist_names.keys(): + print(f"Cannot add video to {playlist_name}: Playlist does not exist") + elif video_to_play == None: + print(f"Cannot add video to {playlist_name}: Video does not exist") + else: + if video_to_play.flag_msg == "": + if video_to_play in self.playlists[self.playlist_names[playlist_name.lower()]]: + print(f"Cannot add video to {playlist_name}: Video already added") + else: + self.playlists[self.playlist_names[playlist_name.lower()]].append(video_to_play) + print(f"Added video to {playlist_name}: {video_to_play.title}") + else: + print(f"Cannot add video to {playlist_name}: Video is currently flagged (reason: {video_to_play.flag_msg})") + + def show_all_playlists(self): + """Display all playlists.""" + + if len(self.playlists.keys()) == 0: + print("No playlists exist yet") + else: + print("Showing all playlists:") + for pl in sorted(self.playlists.keys()): + print(f" {pl}") + + def show_playlist(self, playlist_name): + """Display all videos in a playlist with a given name. + + Args: + playlist_name: The playlist name. + """ + + if playlist_name.lower() not in self.playlist_names.keys(): + print(f"Cannot show playlist {playlist_name}: Playlist does not exist") + else: + print(f"Showing playlist: {playlist_name}") + if len(self.playlists[self.playlist_names[playlist_name.lower()]]) == 0: + print(" No videos here yet") + else: + for video in self.playlists[self.playlist_names[playlist_name.lower()]]: + if video.flag_msg == '': + print(f" {video.title} ({video.video_id}) [{' '.join(video.tags)}]") + else: + print(f" {video.title} ({video.video_id}) [{' '.join(video.tags)}] - FLAGGED (reason: {video.flag_msg})") + + def remove_from_playlist(self, playlist_name, video_id): + """Removes a video to a playlist with a given name. + + Args: + playlist_name: The playlist name. + video_id: The video_id to be removed. + """ + + video_to_play = self._video_library.get_video(video_id) + + if playlist_name.lower() not in self.playlist_names.keys(): + print(f"Cannot remove video from {playlist_name}: Playlist does not exist") + elif video_to_play == None: + print(f"Cannot remove video from {playlist_name}: Video does not exist") + else: + if video_to_play not in self.playlists[self.playlist_names[playlist_name.lower()]]: + print(f"Cannot remove video from {playlist_name}: Video is not in playlist") + else: + self.playlists[self.playlist_names[playlist_name.lower()]].remove(video_to_play) + print(f"Removed video from {playlist_name}: {video_to_play.title}") + + def clear_playlist(self, playlist_name): + """Removes all videos from a playlist with a given name. + + Args: + playlist_name: The playlist name. + """ + + if playlist_name.lower() not in self.playlist_names.keys(): + print(f"Cannot clear playlist {playlist_name}: Playlist does not exist") + + else: + self.playlists[self.playlist_names[playlist_name.lower()]] = [] + print(f"Successfully removed all videos from {playlist_name}") + + def delete_playlist(self, playlist_name): + """Deletes a playlist with a given name. + + Args: + playlist_name: The playlist name. + """ + + if playlist_name.lower() not in self.playlist_names.keys(): + print(f"Cannot delete playlist {playlist_name}: Playlist does not exist") + + else: + deleted = self.playlists.pop(self.playlist_names[playlist_name.lower()]) + deleted = self.playlist_names.pop(playlist_name.lower()) + print(f"Deleted playlist: {playlist_name}") + + def search_videos(self, search_term): + """Display all the videos whose titles contain the search_term. + + Args: + search_term: The query to be used in search. + """ + + all_videos = self._video_library.get_all_videos() + all_videos = [video for video in all_videos if video.flag_msg == ''] + qualified_videos = {video.title:video for video in all_videos if search_term.lower() in video.title.lower()} + qualified_videos = dict(sorted(qualified_videos.items())) + + if len(qualified_videos) != 0: + print(f"Here are the results for {search_term}:") + sno = 1 + for key, value in qualified_videos.items(): + tags = " ".join(value.tags) + print(f" {sno}) {key} ({value.video_id}) [{tags}]") + sno += 1 + + print("Would you like to play any of the above? If yes, specify the number of the video.") + print("If your answer is not a valid number, we will assume it's a no.") + + try: + choice = int(input()) + if (choice>0 and choice<=len(qualified_videos)): + video_to_play = list(qualified_videos.keys())[choice-1] + print(f"Playing video: {video_to_play}") + self.currently_playing = qualified_videos[video_to_play] + except: + pass + + else: + print(f"No search results for {search_term}") + + def search_videos_tag(self, video_tag): + """Display all videos whose tags contains the provided tag. + + Args: + video_tag: The video tag to be used in search. + """ + + all_videos = self._video_library.get_all_videos() + all_videos = [video for video in all_videos if video.flag_msg == ''] + qualified_videos = {video.title:video for video in all_videos if video_tag.lower() in\ + [tag.lower() for tag in video.tags]} + qualified_videos = dict(sorted(qualified_videos.items())) + + if len(qualified_videos) != 0: + print(f"Here are the results for {video_tag}:") + sno = 1 + for key, value in qualified_videos.items(): + tags = " ".join(value.tags) + print(f" {sno}) {key} ({value.video_id}) [{tags}]") + sno += 1 + + print("Would you like to play any of the above? If yes, specify the number of the video.") + print("If your answer is not a valid number, we will assume it's a no.") + + try: + choice = int(input()) + if (choice>0 and choice<=len(qualified_videos)): + video_to_play = list(qualified_videos.keys())[choice-1] + print(f"Playing video: {video_to_play}") + self.currently_playing = qualified_videos[video_to_play] + except: + pass + + else: + print(f"No search results for {video_tag}") + + def flag_video(self, video_id, flag_reason=""): + """Mark a video as flagged. + + Args: + video_id: The video_id to be flagged. + flag_reason: Reason for flagging the video. + """ + + video_to_flag = self._video_library.get_video(video_id) + + if video_to_flag == None: + print(f"Cannot flag video: Video does not exist") + + elif video_to_flag.flag_msg != "": + print(f"Cannot flag video: Video is already flagged") + + else: + if flag_reason == "": + flag_reason = "Not supplied" + if self.currently_playing == video_to_flag or self.paused_video == video_to_flag: + self.stop_video() + video_to_flag.assign_flag_msg(flag_reason) + print(f"Successfully flagged video: {video_to_flag.title} (reason: {flag_reason})") + + def allow_video(self, video_id): + """Removes a flag from a video. + + Args: + video_id: The video_id to be allowed again. + """ + + video_to_unflag = self._video_library.get_video(video_id) + if video_to_unflag == None: + print(f"Cannot remove flag from video: Video does not exist") + + elif video_to_unflag.flag_msg == "": + print(f"Cannot remove flag from video: Video is not flagged") + + else: + video_to_unflag.assign_flag_msg("") + print(f"Successfully removed flag from video: {video_to_unflag.title}") \ No newline at end of file diff --git a/python/src/video_playlist.py b/python/src/video_playlist.py new file mode 100644 index 0000000..d04fd11 --- /dev/null +++ b/python/src/video_playlist.py @@ -0,0 +1,8 @@ +"""A video playlist class.""" + + +class Playlist: + """A class used to represent a Playlist.""" + + def __init__(self): + self.playlist_name = None diff --git a/python/src/videos.txt b/python/src/videos.txt new file mode 100644 index 0000000..d3c3fb8 --- /dev/null +++ b/python/src/videos.txt @@ -0,0 +1,5 @@ +Funny Dogs | funny_dogs_video_id | #dog , #animal +Amazing Cats | amazing_cats_video_id | #cat , #animal +Another Cat Video | another_cat_video_id | #cat , #animal +Life at Google | life_at_google_video_id | #google , #career +Video about nothing | nothing_video_id | \ No newline at end of file From 3c1225d2c376b4972d3d7273d242d9a18eb5c879 Mon Sep 17 00:00:00 2001 From: Ramshankar Yadhunath Date: Thu, 1 Jul 2021 14:10:16 +0530 Subject: [PATCH 3/3] Make submission --- .../part1_test.cpython-38-pytest-6.2.4.pyc | Bin 0 -> 18535 bytes .../part2_test.cpython-38-pytest-6.2.4.pyc | Bin 0 -> 18676 bytes .../part3_test.cpython-38-pytest-6.2.4.pyc | Bin 0 -> 11675 bytes .../part4_test.cpython-38-pytest-6.2.4.pyc | Bin 0 -> 20297 bytes ...eolibrary_test.cpython-38-pytest-6.2.4.pyc | Bin 0 -> 3596 bytes python/test/part1_test.py | 238 +++++++++++++++ python/test/part2_test.py | 237 +++++++++++++++ python/test/part3_test.py | 142 +++++++++ python/test/part4_test.py | 271 ++++++++++++++++++ python/test/videolibrary_test.py | 26 ++ 10 files changed, 914 insertions(+) create mode 100644 python/test/__pycache__/part1_test.cpython-38-pytest-6.2.4.pyc create mode 100644 python/test/__pycache__/part2_test.cpython-38-pytest-6.2.4.pyc create mode 100644 python/test/__pycache__/part3_test.cpython-38-pytest-6.2.4.pyc create mode 100644 python/test/__pycache__/part4_test.cpython-38-pytest-6.2.4.pyc create mode 100644 python/test/__pycache__/videolibrary_test.cpython-38-pytest-6.2.4.pyc create mode 100644 python/test/part1_test.py create mode 100644 python/test/part2_test.py create mode 100644 python/test/part3_test.py create mode 100644 python/test/part4_test.py create mode 100644 python/test/videolibrary_test.py diff --git a/python/test/__pycache__/part1_test.cpython-38-pytest-6.2.4.pyc b/python/test/__pycache__/part1_test.cpython-38-pytest-6.2.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ed5b1ba69ca20eabe97785b256b1348747ba1a8 GIT binary patch literal 18535 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 literal 0 HcmV?d00001 diff --git a/python/test/__pycache__/part2_test.cpython-38-pytest-6.2.4.pyc b/python/test/__pycache__/part2_test.cpython-38-pytest-6.2.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5fa09e2554212e14b4e68c6fc56570cd8b9bb68 GIT binary patch literal 18676 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 VW=}GZmf{2LAsT~JAB27k{{schC@ug1 literal 0 HcmV?d00001 diff --git a/python/test/__pycache__/part4_test.cpython-38-pytest-6.2.4.pyc b/python/test/__pycache__/part4_test.cpython-38-pytest-6.2.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b57c139b81672257c350792a40d7af80fade17d2 GIT binary patch literal 20297 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 literal 0 HcmV?d00001 diff --git a/python/test/part1_test.py b/python/test/part1_test.py new file mode 100644 index 0000000..8422d27 --- /dev/null +++ b/python/test/part1_test.py @@ -0,0 +1,238 @@ +import re +from src.video_player import VideoPlayer + + +def test_number_of_videos(capfd): + player = VideoPlayer() + player.number_of_videos() + out, err = capfd.readouterr() + assert "5 videos in the library" in out + + +def test_show_all_videos(capfd): + player = VideoPlayer() + player.show_all_videos() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 6 + assert "Here's a list of all available videos:" in lines[0] + assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert "Funny Dogs (funny_dogs_video_id) [#dog #animal]" in lines[3] + assert "Life at Google (life_at_google_video_id) [#google #career]" in lines[4] + assert "Video about nothing (nothing_video_id) []" in lines[5] + + +def test_play_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Playing video: Amazing Cats" in out + + +def test_play_video_nonexistent(capfd): + player = VideoPlayer() + player.play_video("does_not_exist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot play video: Video does not exist" in out + + +def test_play_video_stop_previous(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.play_video("funny_dogs_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" in lines[1] + assert "Playing video: Funny Dogs" in lines[2] + + +def test_play_video_dont_stop_previous_if_nonexistent(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.play_video("some_other_video") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" not in out + assert "Cannot play video: Video does not exist" in lines[1] + + +def test_stop_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.stop_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" in lines[1] + + +def test_stop_video_twice(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.stop_video() + player.stop_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" in lines[1] + assert "Cannot stop video: No video is currently playing" in lines[2] + + +def test_stop_video_none_playing(capfd): + player = VideoPlayer() + player.stop_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot stop video: No video is currently playing" in out + + +def test_play_random_video(capfd): + player = VideoPlayer() + player.play_random_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert re.match( + "Playing video: (Amazing Cats|Another Cat Video|Funny Dogs|Life at Google|Video about nothing)", + out) + + +def test_play_random_stops_previous_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.play_random_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" in lines[1] + assert re.match( + "Playing video: (Amazing Cats|Another Cat Video|Funny Dogs|Life at Google|Video about nothing)", + lines[2]) + + +def test_show_playing(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Playing video: Amazing Cats" in lines[0] + assert "Currently playing: Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + + +def test_show_nothing_playing(capfd): + player = VideoPlayer() + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "No video is currently playing" in lines[0] + + +def test_pause_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Playing video: Amazing Cats" in lines[0] + assert "Pausing video: Amazing Cats" in lines[1] + + +def test_pause_video_show_playing(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ + "[#cat #animal] - PAUSED" in lines[2] + + +def test_pause_video_play_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + player.play_video("amazing_cats_video_id") + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Playing video: Amazing Cats" in lines[0] + assert "Pausing video: Amazing Cats" in lines[1] + assert "Stopping video: Amazing Cats" in lines[2] + assert "Playing video: Amazing Cats" in lines[3] + assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ + "[#cat #animal]" in lines[4] + assert "PAUSED" not in lines[4] + + +def test_pause_already_paused_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + player.pause_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Pausing video: Amazing Cats" in lines[1] + assert "Video already paused: Amazing Cats" in lines[2] + + +def test_pause_video_none_playing(capfd): + player = VideoPlayer() + player.pause_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot pause video: No video is currently playing" in lines[0] + + +def test_continue_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + player.continue_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Pausing video: Amazing Cats" in lines[1] + assert "Continuing video: Amazing Cats" in lines[2] + + +def test_continue_video_not_paused(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.continue_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Cannot continue video: Video is not paused" in lines[1] + + +def test_continue_none_playing(capfd): + player = VideoPlayer() + player.continue_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot continue video: No video is currently playing" in lines[0] diff --git a/python/test/part2_test.py b/python/test/part2_test.py new file mode 100644 index 0000000..ff6bd10 --- /dev/null +++ b/python/test/part2_test.py @@ -0,0 +1,237 @@ +from src.video_player import VideoPlayer + + +def test_create_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_PLAYlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Successfully created new playlist: my_PLAYlist" in lines[0] + + +def test_create_existing_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.create_playlist("my_COOL_PLAYLIST") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert ("Cannot create playlist: A playlist with the same name already " + "exists") in lines[1] + + +def test_add_to_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_COOL_playlist") + player.add_to_playlist("my_cool_PLAYLIST", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully created new playlist: my_COOL_playlist" in lines[0] + assert "Added video to my_cool_PLAYLIST: Amazing Cats" in lines[1] + + +def test_add_to_playlist_already_added(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] + assert "Cannot add video to my_cool_playlist: Video already added" in lines[2] + + +def test_add_to_playlist_nonexistent_video(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.add_to_playlist("my_cool_playlist", "some_other_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] + assert "Cannot add video to my_cool_playlist: Video does not exist" in lines[2] + + +def test_add_to_playlist_nonexistent_playlist(capfd): + player = VideoPlayer() + player.add_to_playlist("another_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot add video to another_playlist: Playlist does not exist" in lines[0] + + +def test_add_to_playlist_nonexistent_playlist_nonexistent_video(capfd): + player = VideoPlayer() + player.add_to_playlist("another_playlist", "does_not_exist_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot add video to another_playlist: Playlist does not exist" in lines[0] + + +def test_show_all_playlists_no_playlists_exist(capfd): + player = VideoPlayer() + player.show_all_playlists() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "No playlists exist yet" in lines[0] + + +def test_show_all_playlists(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playLIST") + player.create_playlist("anotheR_playlist") + player.show_all_playlists() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Showing all playlists:" in lines[2] + assert "anotheR_playlist" in lines[3] + assert "my_cool_playLIST" in lines[4] + + +def test_show_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.show_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.show_playlist("my_COOL_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 6 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Showing playlist: my_cool_playlist" in lines[1] + assert "No videos here yet" in lines[2] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[3] + assert "Showing playlist: my_COOL_playlist" in lines[4] + assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[5] + + +def test_remove_from_playlist_then_re_add(capfd): + player = VideoPlayer() + player.create_playlist("MY_playlist") + player.add_to_playlist("my_playlist", "amazing_cats_video_id") + player.add_to_playlist("my_playlist", "life_at_google_video_id") + player.remove_from_playlist("my_playlist", "amazing_cats_video_id") + player.add_to_playlist("my_playlist", "amazing_cats_video_id") + player.show_playlist("my_playLIST") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 8 + assert "Showing playlist: my_playLIST" in lines[5] + assert "Life at Google (life_at_google_video_id) [#google #career]" in lines[6] + assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[7] + + +def test_show_playlist_nonexistent_playlist(capfd): + player = VideoPlayer() + player.show_playlist("another_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot show playlist another_playlist: Playlist does not exist" in lines[0] + + +def test_remove_from_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.remove_from_playlist("my_COOL_playlist", "amazing_cats_video_id") + player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 4 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] + assert "Removed video from my_COOL_playlist: Amazing Cats" in lines[2] + assert "Cannot remove video from my_cool_playlist: Video is not in playlist" in lines[3] + + +def test_remove_from_playlist_video_is_not_in_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Cannot remove video from my_cool_playlist: Video is not in playlist" in lines[1] + + +def test_remove_from_playlist_nonexistent_video(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.remove_from_playlist("my_cool_playlist", "some_other_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] + assert "Cannot remove video from my_cool_playlist: Video does not exist" in lines[2] + + +def test_remove_from_playlist_nonexistent_playlist(capfd): + player = VideoPlayer() + player.remove_from_playlist("my_cool_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot remove video from my_cool_playlist: Playlist does not exist" in lines[0] + + +def test_clear_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.add_to_playlist("my_cool_playlist", "amazing_cats_video_id") + player.show_playlist("my_cool_playlist") + player.clear_playlist("my_COOL_playlist") + player.show_playlist("my_cool_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 7 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Added video to my_cool_playlist: Amazing Cats" in lines[1] + assert "Showing playlist: my_cool_playlist" in lines[2] + assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[3] + assert "Successfully removed all videos from my_COOL_playlist" in lines[4] + assert "Showing playlist: my_cool_playlist" in lines[5] + assert "No videos here yet" in lines[6] + + +def test_clear_playlist_nonexistent(capfd): + player = VideoPlayer() + player.clear_playlist("my_cool_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot clear playlist my_cool_playlist: Playlist does not exist" in lines[0] + + +def test_delete_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_cool_playlist") + player.delete_playlist("my_cool_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully created new playlist: my_cool_playlist" in lines[0] + assert "Deleted playlist: my_cool_playlist" in lines[1] + + +def test_delete_playlist_nonexistent(capfd): + player = VideoPlayer() + player.delete_playlist("my_cool_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot delete playlist my_cool_playlist: Playlist does not exist" in lines[0] diff --git a/python/test/part3_test.py b/python/test/part3_test.py new file mode 100644 index 0000000..87a0cf7 --- /dev/null +++ b/python/test/part3_test.py @@ -0,0 +1,142 @@ +from src.video_player import VideoPlayer +from unittest import mock + + +@mock.patch('builtins.input', lambda *args: 'No') +def test_search_videos_with_no_answer(capfd): + player = VideoPlayer() + player.search_videos("cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Here are the results for cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ( + "If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video" not in out + + +@mock.patch('builtins.input', lambda *args: '2') +def test_search_videos_and_play_answer(capfd): + player = VideoPlayer() + player.search_videos("cat") + + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 6 + assert "Here are the results for cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video: Another Cat Video" in lines[5] + + +@mock.patch('builtins.input', lambda *args: '6') +def test_search_videos_number_out_of_bounds(capfd): + player = VideoPlayer() + player.search_videos("cat") + + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Here are the results for cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video" not in out + + +@mock.patch('builtins.input', lambda *args: 'ab3g') +def test_search_videos_invalid_number(capfd): + player = VideoPlayer() + player.search_videos("cat") + + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Here are the results for cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video" not in out + + +def test_search_videos_no_results(capfd): + player = VideoPlayer() + player.search_videos("blah") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "No search results for blah" in lines[0] + + +@mock.patch('builtins.input', lambda *args: 'No') +def test_search_videos_with_tag_no_answer(capfd): + player = VideoPlayer() + player.search_videos_tag("#cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Here are the results for #cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + + +@mock.patch('builtins.input', lambda *args: '1') +def test_search_videos_with_tag_play_answered_number(capfd): + player = VideoPlayer() + player.search_videos_tag("#cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 6 + assert "Here are the results for #cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video: Amazing Cats" in lines[5] + + +@mock.patch('builtins.input', lambda *args: '5') +def test_search_videos_with_tag_number_out_of_bounds(capfd): + player = VideoPlayer() + player.search_videos_tag("#cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Here are the results for #cat:" in lines[0] + assert "1) Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[1] + assert "2) Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + assert "Playing video" not in out + + +def test_search_videos_tag_no_results(capfd): + player = VideoPlayer() + player.search_videos_tag("#blah") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "No search results for #blah" in lines[0] diff --git a/python/test/part4_test.py b/python/test/part4_test.py new file mode 100644 index 0000000..a6c9907 --- /dev/null +++ b/python/test/part4_test.py @@ -0,0 +1,271 @@ +from unittest import mock + +from src.video_player import VideoPlayer + + +def test_flag_video_with_reason(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Successfully flagged video: Amazing Cats (reason: dont_like_cats)" \ + in lines[0] + + +def test_flag_video_without_reason(capfd): + player = VideoPlayer() + player.flag_video("another_cat_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Successfully flagged video: Another Cat Video " \ + "(reason: Not supplied)" in lines[0] + + +def test_flag_video_already_flagged(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.flag_video("amazing_cats_video_id", "dont_like_cats") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully flagged video: Amazing Cats (reason: dont_like_cats)" in \ + lines[0] + assert "Cannot flag video: Video is already flagged" in lines[1] + + +def test_flag_video_nonexistent(capfd): + player = VideoPlayer() + player.flag_video("video_does_not_exist", "flag_video_reason") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot flag video: Video does not exist" in lines[0] + + +def test_flag_video_can_no_longer_play(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id") + player.play_video("amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully flagged video: Amazing Cats " \ + "(reason: Not supplied)" in lines[0] + assert "Cannot play video: Video is currently flagged " \ + "(reason: Not supplied)" in lines[1] + + +def test_flag_videos_play_random(capfd): + player = VideoPlayer() + player.flag_video("funny_dogs_video_id") + player.flag_video("amazing_cats_video_id") + player.flag_video("another_cat_video_id") + player.flag_video("life_at_google_video_id") + player.flag_video("nothing_video_id") + player.play_random_video() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 6 + assert "Successfully flagged video: Funny Dogs " \ + "(reason: Not supplied)" in lines[0] + assert "Successfully flagged video: Amazing Cats " \ + "(reason: Not supplied)" in lines[1] + assert "Successfully flagged video: Another Cat Video " \ + "(reason: Not supplied)" in lines[2] + assert "Successfully flagged video: Life at Google " \ + "(reason: Not supplied)" in lines[3] + assert "Successfully flagged video: Video about nothing " \ + "(reason: Not supplied)" in lines[4] + assert "No videos available" in lines[5] + + +def test_flag_video_add_to_playlist(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id") + player.create_playlist("my_playlist") + player.add_to_playlist("my_playlist", "amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert ("Successfully flagged video: Amazing Cats " + "(reason: Not supplied)") in lines[0] + assert "Successfully created new playlist: my_playlist" in lines[1] + assert ("Cannot add video to my_playlist: Video is currently " + "flagged (reason: Not supplied)") in lines[2] + + +def test_flag_video_show_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_playlist") + player.add_to_playlist("my_playlist", "amazing_cats_video_id") + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.show_playlist("my_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Successfully created new playlist: my_playlist" in lines[0] + assert "Added video to my_playlist: Amazing Cats" in lines[1] + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[2] + assert "Showing playlist: my_playlist" in lines[3] + assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " + "(reason: dont_like_cats)") in lines[4] + + +def test_flag_video_show_all_videos(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.show_all_videos() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 7 + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[0] + assert "Here's a list of all available videos:" in lines[1] + assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " + "(reason: dont_like_cats)") in lines[2] + assert "Another Cat Video (another_cat_video_id) [#cat #animal]" in lines[3] + assert "Funny Dogs (funny_dogs_video_id) [#dog #animal]" in lines[4] + assert "Life at Google (life_at_google_video_id) [#google #career]" in \ + lines[5] + assert "Video about nothing (nothing_video_id) []" in lines[6] + + +@mock.patch('builtins.input', lambda *args: 'No') +def test_flag_video_search_videos(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.search_videos("cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[0] + assert "Here are the results for cat:" in lines[1] + assert "1) Another Cat Video (another_cat_video_id) [#cat #animal]" in \ + lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + + +@mock.patch('builtins.input', lambda *args: 'No') +def test_flag_video_search_videos_with_tag(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.search_videos_tag("#cat") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[0] + assert "Here are the results for #cat:" in lines[1] + assert "1) Another Cat Video (another_cat_video_id) [#cat #animal]" in \ + lines[2] + assert ("Would you like to play any of the above? If yes, " + "specify the number of the video.") in lines[3] + assert ("If your answer is not a valid number, we will assume " + "it's a no.") in lines[4] + + +def test_flag_video_stops_playing_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 4 + assert "Playing video: Amazing Cats" in lines[0] + assert "Stopping video: Amazing Cats" in lines[1] + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[2] + assert "No video is currently playing" in lines[3] + + +def test_flag_video_leaves_video_if_video_is_different(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.flag_video("another_cat_video_id", "dont_like_cats") + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 3 + assert "Playing video: Amazing Cats" in lines[0] + assert "Successfully flagged video: Another Cat Video " \ + "(reason: dont_like_cats)" in lines[1] + assert "Currently playing: Amazing Cats (amazing_cats_video_id) " \ + "[#cat #animal]" in lines[2] + + +def test_flag_video_stops_paused_video(capfd): + player = VideoPlayer() + player.play_video("amazing_cats_video_id") + player.pause_video() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.show_playing() + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 5 + assert "Playing video: Amazing Cats" in lines[0] + assert "Pausing video: Amazing Cats" in lines[1] + assert "Stopping video: Amazing Cats" in lines[2] + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[3] + assert "No video is currently playing" in lines[4] + + +def test_allow_video(capfd): + player = VideoPlayer() + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.allow_video("amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 2 + assert "Successfully flagged video: Amazing Cats " \ + "(reason: dont_like_cats)" in lines[0] + assert "Successfully removed flag from video: Amazing Cats" in lines[1] + + +def test_allow_video_not_flagged(capfd): + player = VideoPlayer() + player.allow_video("amazing_cats_video_id") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot remove flag from video: Video is not flagged" in lines[0] + + +def test_allow_video_nonexistent(capfd): + player = VideoPlayer() + player.allow_video("video_does_not_exist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 1 + assert "Cannot remove flag from video: Video does not exist" in lines[0] + + +def test_allow_video_show_playlist(capfd): + player = VideoPlayer() + player.create_playlist("my_playlist") + player.add_to_playlist("my_playlist", "amazing_cats_video_id") + player.flag_video("amazing_cats_video_id", "dont_like_cats") + player.show_playlist("my_playlist") + player.allow_video("amazing_cats_video_id") + player.show_playlist("my_playlist") + out, err = capfd.readouterr() + lines = out.splitlines() + assert len(lines) == 8 + assert "Successfully created new playlist: my_playlist" in lines[0] + assert "Added video to my_playlist: Amazing Cats" in lines[1] + assert ("Successfully flagged video: Amazing Cats " + "(reason: dont_like_cats)") in lines[2] + assert "Showing playlist: my_playlist" in lines[3] + assert ("Amazing Cats (amazing_cats_video_id) [#cat #animal] - FLAGGED " + "(reason: dont_like_cats)") in lines[4] + assert "Successfully removed flag from video: Amazing Cats" in lines[5] + assert "Showing playlist: my_playlist" in lines[6] + assert "Amazing Cats (amazing_cats_video_id) [#cat #animal]" in lines[7] diff --git a/python/test/videolibrary_test.py b/python/test/videolibrary_test.py new file mode 100644 index 0000000..820626a --- /dev/null +++ b/python/test/videolibrary_test.py @@ -0,0 +1,26 @@ +from src.video_library import VideoLibrary + + +def test_library_has_all_videos(): + library = VideoLibrary() + assert len(library.get_all_videos()) == 5 + + +def test_parses_tags_correctly(): + library = VideoLibrary() + video = library.get_video("amazing_cats_video_id") + + assert video is not None + assert video.title == "Amazing Cats" + assert video.video_id == "amazing_cats_video_id" + assert set(video.tags) == {"#cat", "#animal"} + + +def test_parses_video_correctly_without_tags(): + library = VideoLibrary() + video = library.get_video("nothing_video_id") + + assert video is not None + assert video.title == "Video about nothing" + assert video.video_id == "nothing_video_id" + assert video.tags == ()