diff --git a/CMakeLists.txt b/CMakeLists.txt index 02413b5..fbbddda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,3 +20,6 @@ IF(GCRYPT_FOUND) add_compile_definitions(DROPOUT_DL_GCRYPT) ENDIF() +# IF(DROPOUT_BUILD_TESTS) + add_subdirectory(tests) +# ENDIF() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..8ffbb9c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.23) +project(dropout-dl-tests) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(episode-test test.cpp episode.cpp ../src/episode.cpp) + +target_link_libraries(episode-test curl sqlite3 gcrypt) + +message(STATUS "Building Tests") + +include_directories(episode ../src) diff --git a/tests/episode.cpp b/tests/episode.cpp new file mode 100644 index 0000000..ecf738d --- /dev/null +++ b/tests/episode.cpp @@ -0,0 +1,322 @@ +// +// Created by moss on 9/30/22. +// +#include "episode.h" +#include "test.h" + +namespace dropout_dl { + tests test_episode_name_parsing() { + bool success; + + std::string (*test_function)(const std::string&) = episode::get_episode_name; + + std::string base_test_solution = "Base Test Title"; + std::string base_test = "

\n" + " " + base_test_solution + "\n" + "

"; + + test base("Basic Episode Name Parsing", test_function, base_test, base_test_solution); + + + std::string multiple_header_test_solution = "Multi Header Test Title"; + std::string multiple_header_test = "

\n" + "Header without class or strong\n" + "

\n" + "

\n" + "Header with incorrect classes" + "

\n" + "

\n" + "Header with strong" + "

\n" + "

\n" + " " + multiple_header_test_solution + "\n" + "

\n" + "

\n" + " Valid Header and Strong After Correct Title \n" + "

"; + + + test multiple_header("Multiple Header Episode Name Parsing", test_function, multiple_header_test, multiple_header_test_solution); + + std::string no_valid_header_test_solution = "ERROR"; + std::string no_valid_header_test = "

\n" + "Header without class or Strong\n" + "

\n" + "

\n" + "Header with incorrect classes" + "

\n" + "

\n" + "Header with strong" + "

\n"; + + test no_valid_header("No Valid Header Episode Name Parsing", test_function, no_valid_header_test, no_valid_header_test_solution); + + + std::string html_character_test_solution = "'&;"; + std::string html_character_test = "

\n" + " '&;\n" + "

"; + + test html_character_code("Html Character Code Episode Name Parsing", test_function, html_character_test, html_character_test_solution); + + + return tests("Episode Name Parsing", {base, multiple_header, no_valid_header, html_character_code}); + } + + tests test_episode_number_parsing() { + bool success; + + std::string (*test_function)(const std::string&) = episode::get_episode_number; + + std::string base_test_solution = "1"; + std::string base_test = "\n" + " Season 1, Episode 1\n" + ""; + + test base("Basic Episode Number Parsing", test_function, base_test, base_test_solution); + + + std::string multiple_link_test_solution = "1"; + std::string multiple_link_test = "\n" + "asjdhgaorihg\n" + "\n" + "\n" + " Season 1, Episode 1\n" + "\n" + "\n" + " Season 1, Episode 2\n"; + + + test multiple_link("Multiple Link Episode Number Parsing", test_function, multiple_link_test, multiple_link_test_solution); + + std::string no_valid_number_test_solution = "-1"; + std::string no_valid_number_test = "\n" + "816\n" + "\n" + "\n" + "157" + "\n" + "\n" + "Episode" + "\n"; + + test no_valid_number("No Valid Episode Number Parsing", test_function, no_valid_number_test, no_valid_number_test_solution); + + + std::string earlier_episode_text_test_solution = "15"; + std::string earlier_episode_text_test = "

\n" + " Episode Wrong\n" + "

\n" + "\n" + " Season 1, Episode 15\n" + ""; + + test earlier_episode_text("Earlier Episode Text Number Parsing", test_function, earlier_episode_text_test, earlier_episode_text_test_solution); + + return tests("Episode Name Parsing", {base, multiple_link, no_valid_number, earlier_episode_text}); + } + + tests test_episode_series_name_parsing() { + bool success; + + std::string (*test_function)(const std::string&) = episode::get_series_name; + + std::string base_test_solution = "Base Test Title"; + std::string base_test = "

\n" + " \n" + " Base Test Title\n" + " \n" + "

"; + + test base("Basic Episode Series Name Parsing", test_function, base_test, base_test_solution); + + + std::string multiple_header_test_solution = "Multi Header Test Title"; + std::string multiple_header_test = "

\n" + "Header without class or link\n" + "

\n" + "

\n" + "Header with incorrect classes" + "

\n" + "

\n" + "Header with strong" + "

\n" + "

\n" + " " + multiple_header_test_solution + "\n" + "

\n" + "

\n" + " Valid Header and Link After Correct Title \n" + "

"; + + + test multiple_header("Multiple Header Episode Series Name Parsing", test_function, multiple_header_test, multiple_header_test_solution); + + std::string no_valid_header_test_solution = "ERROR"; + std::string no_valid_header_test = "

\n" + "Header without class or link\n" + "

\n" + "

\n" + "Header with incorrect classes" + "

\n" + "

\n" + "Header with strong" + "

\n"; + + test no_valid_header("No Valid Header Episode Series Name Parsing", test_function, no_valid_header_test, no_valid_header_test_solution); + + + std::string html_character_test_solution = "'&;"; + std::string html_character_test = "

\n" + " '&;\n" + "

"; + + test html_character("Html Character Code Episode Series Name Parsing", test_function, html_character_test, html_character_test_solution); + + return tests("Episode Name Parsing", {base, multiple_header, no_valid_header, html_character}); + } + + tests test_episode_embedded_url_parsing() { + bool success; + + std::string (*test_function)(const std::string&) = episode::get_embed_url; + + std::string base_test_solution = "Base Test URL"; + std::string base_test = " window.VHX.config = {\n" + " embed_url: \"" + base_test_solution + "\"\n" + " };"; + + test base("Basic Episode Embedded URL Parsing", test_function, base_test, base_test_solution); + + + std::string multiple_script_test_solution = "Multi Header Test Title"; + std::string multiple_script_test = " " + "" + "" + "" + "" + "" + ""; + + + test multiple_script("Multiple Script Embedded URL Parsing", test_function, multiple_script_test, multiple_script_test_solution); + + std::string no_valid_URL_test_solution = ""; + std::string no_valid_URL_test = " "; + + test no_valid_URL("No Valid Embedded URL Parsing", test_function, no_valid_URL_test, no_valid_URL_test_solution); + + return tests("Episode Name Parsing", {base, multiple_script, no_valid_URL}); + } + + tests test_episode_config_url_parsing() { + bool success; + + std::string (*test_function)(const std::string&) = episode::get_config_url; + + std::string base_test_solution = "Base Test URL"; + std::string base_test = R"(window.OTTData = {"config_url":")" + base_test_solution + "\"};"; + + test base("Basic Episode Config URL Parsing", test_function, base_test, base_test_solution); + + + std::string no_valid_URL_test_solution = ""; + std::string no_valid_URL_test = R"(window.OTTData = {"api_data":{"api_host":"","api_token":"","user_auth_token":{"auth_user_token":"","embed_referrer_host":""}},"buy_button":{"label":null,"url":null},"collection":{"id":null},"product":{"id":null},"":{"label":"","url":""},"site":{"id":null,"subdomain":"","twitter_name":""},"video":{"duration":null,"id":null,"is_trailer":"","title":"","is_live_video":false,"live_event_id":null},"google_cast_app_id":"","hide_chrome":null,"initial_time":null,"js_api_enabled":null,"locale":"","show_share_actions":null,"user":{"id":,"email":""},"analytics_url":""})"; + + test no_valid_URL("No Valid Config URL Parsing", test_function, no_valid_URL_test, no_valid_URL_test_solution); + + return tests("Episode Name Parsing", {base, no_valid_URL}); + } +} + +int main() { + + dropout_dl::tests name_tests = dropout_dl::test_episode_name_parsing(); + + + dropout_dl::tests number_tests = dropout_dl::test_episode_number_parsing(); + + + dropout_dl::tests series_tests = dropout_dl::test_episode_series_name_parsing(); + + + dropout_dl::tests embedded_tests = dropout_dl::test_episode_embedded_url_parsing(); + + + dropout_dl::tests config_tests = dropout_dl::test_episode_config_url_parsing(); + + + if (name_tests.success && number_tests.success && series_tests.success && embedded_tests.success && config_tests.success) { + std::cout << TESTNAME << BOLDRED << "Episode Tests" << RESET << std::endl; + } + else { + std::cout << TESTNAME << BOLDGREEN << "Episode Tests" << RESET << std::endl; + } + + name_tests.display(); + + number_tests.display(); + + series_tests.display(); + + embedded_tests.display(); + + config_tests.display(); +} \ No newline at end of file diff --git a/tests/test.cpp b/tests/test.cpp new file mode 100644 index 0000000..0338903 --- /dev/null +++ b/tests/test.cpp @@ -0,0 +1,26 @@ +// +// Created by moss on 9/30/22. +// +#include "test.h" + +template +void dropout_dl::test::display_result() { + if (!this->success) { + std::cout << RED << name << ": \"" << result << "\" =/= \"" << expected_result << '"' << RESET << std::endl; + } else { + std::cout << GREEN << name << RESET << std::endl; + } +} + +void dropout_dl::tests::display() { + + if (!this->success) { + std::cout << '\n' << TESTNAME << BOLDRED << name << RESET << std::endl; + } else { + std::cout << '\n' << TESTNAME << BOLDGREEN << name << RESET << std::endl; + } + + for (auto& test : tests_vector) { + test.display_result(); + } +} \ No newline at end of file diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..af9f94d --- /dev/null +++ b/tests/test.h @@ -0,0 +1,83 @@ +// +// Created by moss on 9/30/22. +// +#pragma once + +#include +#include "iostream" + +namespace dropout_dl { + +#define RESET "\033[0m" +#define BLACK "\033[30m" /* Black */ +#define RED "\033[31m" /* Red */ +#define GREEN "\033[32m" /* Green */ +#define YELLOW "\033[33m" /* Yellow */ +#define BLUE "\033[34m" /* Blue */ +#define MAGENTA "\033[35m" /* Magenta */ +#define CYAN "\033[36m" /* Cyan */ +#define WHITE "\033[37m" /* White */ +#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ +#define BOLDRED "\033[1m\033[31m" /* Bold Red */ +#define FAIL "\033[31mFAIL: \033[0m" // Test Failure +#define BOLDFAIL "\033[1m\033[31mFAIL: \033[0m" // Test Failure +#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ +#define SUCCESS "\033[32mSUCCESS: \033[0m" /* Test Success */ +#define BOLDSUCCESS "\033[1m\033[32mSUCCESS: \033[0m" /* Test Success */ +#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ +#define WARN "\033[1m\033[33mWARNING: \033[0m" /* Test Warning */ +#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ +#define TESTNAME "\033[1m\033[34mTEST: \033[0m" /* Bold Blue */ +#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ +#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ +#define BOLDWHITE "\033[1m\033[37m" /* Bold White */ + + + template class test { + public: + std::string name; + t result; + t expected_result; + bool success; + + test(const std::string& name, const t& result, const t& expected_result) { + this->name = name; + this->result = result; + this->expected_result = expected_result; + this->success = (result == expected_result); + } + + test(const std::string& test_name, t (*function)(const t &), const t &argument, const t& expected_result) { + t test_result = function(argument); + this->name = test_name; + this->result = test_result; + this->expected_result = expected_result; + this->success = test_result == expected_result; + } + + void display_result(); + + + }; + + + class tests { + public: + std::vector> tests_vector; + std::string name; + bool success; + + tests(const std::string& name, const std::vector>& tests) { + this->name = name; + this->tests_vector = tests; + this->success = tests_vector.front().success; + for (const auto& test : tests_vector) { + success = success && test.success; + } + } + + void display(); + }; + + +} \ No newline at end of file