Skip to content
Merged
1 change: 1 addition & 0 deletions cpp/src/helper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <vector>

std::string trim(std::string s);

Expand Down
68 changes: 68 additions & 0 deletions solutions/cpp/solution1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
cmake_minimum_required(VERSION 3.14)

set(CMAKE_CXX_STANDARD 11)

project(youtube)

include(FetchContent)
FetchContent_Declare(
googletest
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/53495a2a7d6ba7e0691a7f3602e9a5324bba6e45.zip
)

set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)

if(MSVC)
add_compile_options(/Wall)
else()
add_compile_options(
-Wall
-Wextra
-pedantic
# Below is to avoid unnecessary warnings before code is implemented.
-Wno-unused-parameter)
endif()

file(COPY src/videos.txt DESTINATION src/)

add_library(youtube_lib
src/commandparser.cpp
src/commandparser.h
src/helper.cpp
src/helper.h
src/video.cpp
src/video.h
src/videolibrary.cpp
src/videolibrary.h
src/videoplayer.cpp
src/videoplayer.h
src/videoplaylist.h
src/videoplaylist.cpp)

add_executable(youtube src/main.cpp)
target_link_libraries(youtube youtube_lib)

enable_testing()

add_executable(part1_test test/part1_test.cpp)
target_link_libraries(part1_test youtube_lib gmock gtest gtest_main)
gtest_discover_tests(part1_test)

add_executable(part2_test test/part2_test.cpp)
target_link_libraries(part2_test youtube_lib gmock gtest gtest_main)
gtest_discover_tests(part2_test)

add_executable(part3_test test/part3_test.cpp)
target_link_libraries(part3_test youtube_lib gmock gtest gtest_main)
gtest_discover_tests(part3_test)

add_executable(part4_test test/part4_test.cpp)
target_link_libraries(part4_test youtube_lib gmock gtest gtest_main)
gtest_discover_tests(part4_test)

add_executable(videolibrary_test test/videolibrary_test.cpp)
target_link_libraries(videolibrary_test youtube_lib gmock gtest gtest_main)
gtest_discover_tests(videolibrary_test)
97 changes: 97 additions & 0 deletions solutions/cpp/solution1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# YouTube Challenge - C++

The C++ YouTube Challenge uses C++ 11, CMake and [GTest](https://google.github.io/googletest/).

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 C++ and CMake
You need to install:

- [CMake 3.14+](https://cmake.org/install/) and a build tool like GNU make or Ninja.
- A compiler that supports C++ 11 or higher ([clang](https://clang.llvm.org/get_started.html), gcc/g++, MSVC).

On Debian-based Linux distributions you can install the dependencies with this
command:

```shell
sudo apt install cmake make clang
```

On Windows, you can install the [Microsoft Visual Studio Community
Edition](https://visualstudio.microsoft.com/downloads/) for the compiler and
build tools. Make sure to choose to install CMake as part of this.

On a Mac, you need to go to the App Store and download Xcode for free - it is Apple's IDE - Integrated Development Environment. Without Xcode, you will have no compiler (i.e. clang or gcc or g++) and no build tools, (i.e. make).
After you've installed Xcode you need to install command line tools:

```shell
xcode-select --install
```

For CMake:

- Download the latest CMake Mac binary distribution here: https://cmake.org/download/.

- Double click the downloaded .dmg file to install it. In the window that pops up, drag the CMake icon into the Application folder.

- Add this line to your .bashrc file: PATH="/Applications/CMake.app/Contents/bin":"$PATH"

- Reload your .bashrc file: source ~/.bashrc

- Verify the latest cmake version is installed: cmake --version

> Note: You can use a higher version of C++ (C++ 17 or C++ 20) if you want:
> Just change the `CMAKE_CXX_STANDARD` in `CMakeLists.txt`!

## Setting up

You can write code in the editor or IDE of your choice. However, different
editors have different ways of dealing with C++ code, so in case of doubt we
recommend you run the code and tests from the command line as shown below.

The below commands assume you are located in the `cpp/` folder of the git
repository.

## Running and Testing from the Command line

To build:

```shell script
cmake -S . -B build
```

Followed by:

```shell script
cmake --build build/
```

To run:

```shell script
./build/youtube
```

To run all the tests:

```shell script
ctest --test-dir build --output-on-failure
```

To run tests for a single Part (after building):

```shell script
./build/part1_test
./build/part2_test
./build/part3_test
./build/part4_test
```

To run a subset of the tests, in this example, all tests of part 1 that contain
`showAllVideos` in their name:

```shell script
./build/part1_test --gtest_filter='*showAllVideos*'
```

> NOTE: Don't forget to rebuild your code ater making changes for testing.
158 changes: 158 additions & 0 deletions solutions/cpp/solution1/src/commandparser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include "commandparser.h"

#include <iostream>
#include <sstream>
#include <utility>
#include <vector>

CommandParser::CommandParser(VideoPlayer&& vp) : mVideoPlayer(std::move(vp)) {}

void CommandParser::executeCommand(const std::vector<std::string>& command) {
if (command.empty()) {
std::cout << "No commands passed in to executeCommand, that is unexpected"
<< std::endl;
return;
}

if (command[0] == "NUMBER_OF_VIDEOS") {
mVideoPlayer.numberOfVideos();
} else if (command[0] == "SHOW_ALL_VIDEOS") {
mVideoPlayer.showAllVideos();
} else if (command[0] == "PLAY") {
if (command.size() != 2) {
std::cout << "Please enter PLAY command followed by video_id."
<< std::endl;
} else {
mVideoPlayer.playVideo(command[1]);
}
} else if (command[0] == "PLAY_RANDOM") {
mVideoPlayer.playRandomVideo();
} else if (command[0] == "STOP") {
mVideoPlayer.stopVideo();
} else if (command[0] == "PAUSE") {
mVideoPlayer.pauseVideo();
} else if (command[0] == "CONTINUE") {
mVideoPlayer.continueVideo();
} else if (command[0] == "SHOW_PLAYING") {
mVideoPlayer.showPlaying();
} else if (command[0] == "CREATE_PLAYLIST") {
if (command.size() != 2) {
std::cout << "Please enter CREATE_PLAYLIST command followed by video_id."
<< std::endl;
} else {
mVideoPlayer.createPlaylist(command[1]);
}
} else if (command[0] == "ADD_TO_PLAYLIST") {
if (command.size() != 3) {
std::cout << "Please enter ADD_TO_PLAYLIST command followed by playlist "
"name and video_id."
<< std::endl;
} else {
mVideoPlayer.addVideoToPlaylist(command[1], command[2]);
}
} else if (command[0] == "REMOVE_FROM_PLAYLIST") {
if (command.size() != 3) {
std::cout << "Please enter REMOVE_FROM_PLAYLIST command followed by "
"playlist name and video_id."
<< std::endl;
} else {
mVideoPlayer.removeFromPlaylist(command[1], command[2]);
}
} else if (command[0] == "CLEAR_PLAYLIST") {
if (command.size() != 2) {
std::cout
<< "Please enter CLEAR_PLAYLIST command followed by a playlist name."
<< std::endl;
} else {
mVideoPlayer.clearPlaylist(command[1]);
}
} else if (command[0] == "DELETE_PLAYLIST") {
if (command.size() != 2) {
std::cout
<< "Please enter DELETE_PLAYLIST command followed by a playlist name."
<< std::endl;
} else {
mVideoPlayer.deletePlaylist(command[1]);
}
} else if (command[0] == "SHOW_PLAYLIST") {
if (command.size() != 2) {
std::cout
<< "Please enter SHOW_PLAYLIST command followed by a playlist name."
<< std::endl;
} else {
mVideoPlayer.showPlaylist(command[1]);
}
} else if (command[0] == "SHOW_ALL_PLAYLISTS") {
mVideoPlayer.showAllPlaylists();
} else if (command[0] == "SEARCH_VIDEOS") {
if (command.size() != 2) {
std::cout
<< "Please enter SEARCH_VIDEOS command followed by a search term."
<< std::endl;
} else {
mVideoPlayer.searchVideos(command[1]);
}
} else if (command[0] == "SEARCH_VIDEOS_WITH_TAG") {
if (command.size() != 2) {
std::cout << "Please enter SEARCH_VIDEOS_WITH_TAG command followed by a "
"video tag."
<< std::endl;
} else {
mVideoPlayer.searchVideosWithTag(command[1]);
}
} else if (command[0] == "FLAG_VIDEO") {
switch (command.size()) {
case 2:
mVideoPlayer.flagVideo(command[1]);
break;
case 3:
mVideoPlayer.flagVideo(command[1], command[2]);
break;
default:
std::cout << "Please enter FLAG_VIDEO command followed by a video_id "
"and an optional flag reason."
<< std::endl;
}
} else if (command[0] == "ALLOW_VIDEO") {
if (command.size() != 2) {
std::cout << "Please enter ALLOW_VIDEO command followed by a video_id."
<< std::endl;
} else {
mVideoPlayer.allowVideo(command[1]);
}
} else if (command[0] == "HELP") {
getHelp();
} else {
std::cout << "Please enter a valid command, type HELP for a list of "
"available commands."
<< std::endl;
}
}

void CommandParser::getHelp() const {
static const char* const helpText = R"(
Available commands:
NUMBER_OF_VIDEOS - Shows how many videos are in the library.
SHOW_ALL_VIDEOS - Lists all videos from the library.
PLAY <video_id> - 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 <playlist_name> - Creates a new (empty) playlist with the provided name.
ADD_TO_PLAYLIST <playlist_name> <video_id> - Adds the requested video to the playlist.
REMOVE_FROM_PLAYLIST <playlist_name> <video_id> - Removes the specified video from the specified playlist
CLEAR_PLAYLIST <playlist_name> - Removes all the videos from the playlist.
DELETE_PLAYLIST <playlist_name> - Deletes the playlist.
SHOW_PLAYLIST <playlist_name> - List all the videos in this playlist.
SHOW_ALL_PLAYLISTS - Display all the available playlists.
SEARCH_VIDEOS <search_term> - Display all the videos whose titles contain the search_term.
SEARCH_VIDEOS_WITH_TAG <tag_name> -Display all videos whose tags contains the provided tag.
FLAG_VIDEO <video_id> <flag_reason> - Mark a video as flagged.
ALLOW_VIDEO <video_id> - Removes a flag from a video.
HELP - Displays help.
EXIT - Terminates the program execution.
)";
std::cout << helpText << std::endl;
}
30 changes: 30 additions & 0 deletions solutions/cpp/solution1/src/commandparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <string>
#include <vector>

#include "videoplayer.h"

/**
* A class used to parse and execute a user Command.
*/
class CommandParser {
private:
VideoPlayer mVideoPlayer;

void getHelp() const;

public:
CommandParser(VideoPlayer&& vp);

// This class is not copyable to avoid expensive copies.
CommandParser(const CommandParser&) = delete;
CommandParser& operator=(const CommandParser&) = delete;

// This class is movable.
CommandParser(CommandParser&&) = default;
CommandParser& operator=(CommandParser&&) = default;

// Executes the given user command.
void executeCommand(const std::vector<std::string>& command);
};
Loading