#include "rss/parser.h" #include #include "3rd-party/catch.hpp" #include "curlhandle.h" #include "rss/exception.h" #include "strprintf.h" #include "test_helpers/exceptionwithmsg.h" #include "test_helpers/httptestserver.h" #include "test_helpers/misc.h" #include "utils.h" TEST_CASE("Throws exception if file doesn't exist", "[rsspp::Parser]") { using test_helpers::ExceptionWithMsg; rsspp::Parser p; REQUIRE_THROWS_MATCHES(p.parse_file("data/non-existent.xml"), rsspp::Exception, ExceptionWithMsg("could not parse file")); } TEST_CASE("Throws exception if file can't be parsed", "[rsspp::Parser]") { using test_helpers::ExceptionWithMsg; rsspp::Parser p; REQUIRE_THROWS_MATCHES(p.parse_file("data/empty.xml"), rsspp::Exception, ExceptionWithMsg("could not parse file")); } TEST_CASE("Extracts data from RSS 0.91", "[rsspp::Parser]") { rsspp::Parser p; rsspp::Feed f; REQUIRE_NOTHROW(f = p.parse_file("data/rss091_1.xml")); REQUIRE(f.rss_version == rsspp::Feed::RSS_0_91); REQUIRE(f.title == "Example Channel"); REQUIRE(f.description == "an example feed"); REQUIRE(f.link == "http://example.com/"); REQUIRE(f.language == "en"); REQUIRE(f.items.size() == 1u); REQUIRE(f.items[0].title == "1 < 2"); REQUIRE(f.items[0].link == "http://example.com/1_less_than_2.html"); REQUIRE(f.items[0].description == "1 < 2, 3 < 4.\nIn HTML, starts a bold phrase\nand you " "start a link with )" R"()" R"(tag:example.com)" R"(%s)" R"(2008-12-30T18:26:15Z)" R"()" R"(tag:example.com,2008-12-30:/atom_testing)" R"(regular title)" R"(2008-12-30T20:04:15Z)" R"()" R"()"; TEST_CASE("parse_url() converts data if specified in xml encoding attribute", "[rsspp::Parser]") { using namespace newsboat; constexpr auto title_utf8 = u8"タイトル"; // Japanese for "title" auto feed_xml_utf8 = strprintf::fmt(atom_feed_with_encoding, "utf-16", title_utf8); auto feed_xml_utf16 = utils::convert_text(feed_xml_utf8, "utf-16", "utf-8"); auto feed_xml = std::vector(feed_xml_utf16.begin(), feed_xml_utf16.end()); auto& test_server = test_helpers::HttpTestServer::get_instance(); auto mock_registration = test_server.add_endpoint("/feed", {}, 200, { {"content-type", "text/xml"}, }, feed_xml); const auto address = test_server.get_address(); const auto url = strprintf::fmt("http://%s/feed", address); rsspp::Parser parser; CurlHandle easyhandle; auto parsed_feed = parser.parse_url(url, easyhandle); REQUIRE(parsed_feed.items.size() == 1); REQUIRE(parsed_feed.title == title_utf8); } TEST_CASE("parse_url() only converts once even when encoding specified twice (xml encoding and http header)", "[rsspp::Parser]") { using namespace newsboat; constexpr auto title_utf8 = u8"Prøve"; // Danish for "test" auto feed_xml_utf8 = strprintf::fmt(atom_feed_with_encoding, "iso-8859-1", title_utf8); auto feed_xml_iso8859_1 = utils::convert_text(feed_xml_utf8, "iso-8859-1", "utf-8"); auto feed_xml = std::vector(feed_xml_iso8859_1.begin(), feed_xml_iso8859_1.end()); auto& test_server = test_helpers::HttpTestServer::get_instance(); auto mock_registration = test_server.add_endpoint("/feed", {}, 200, { {"content-type", "text/xml; charset=iso-8859-1"}, }, feed_xml); const auto address = test_server.get_address(); const auto url = strprintf::fmt("http://%s/feed", address); rsspp::Parser parser; CurlHandle easyhandle; auto parsed_feed = parser.parse_url(url, easyhandle); REQUIRE(parsed_feed.items.size() == 1); REQUIRE(parsed_feed.title == title_utf8); } TEST_CASE("parse_url() uses xml encoding if specified encodings conflict (xml encoding vs http header)", "[rsspp::Parser]") { using namespace newsboat; constexpr auto title_utf8 = u8"Prøve"; // Danish for "test" auto feed_xml_utf8 = strprintf::fmt(atom_feed_with_encoding, "iso-8859-1", title_utf8); auto feed_xml_iso8859_1 = utils::convert_text(feed_xml_utf8, "iso-8859-1", "utf-8"); auto feed_xml = std::vector(feed_xml_iso8859_1.begin(), feed_xml_iso8859_1.end()); auto& test_server = test_helpers::HttpTestServer::get_instance(); auto mock_registration = test_server.add_endpoint("/feed", {}, 200, { {"content-type", "text/xml; charset=utf-16"}, // Expected to be ignored }, feed_xml); const auto address = test_server.get_address(); const auto url = strprintf::fmt("http://%s/feed", address); rsspp::Parser parser; CurlHandle easyhandle; auto parsed_feed = parser.parse_url(url, easyhandle); REQUIRE(parsed_feed.items.size() == 1); REQUIRE(parsed_feed.title == title_utf8); } // Placeholders: // %s: feed title constexpr auto atom_feed_without_encoding = R"()" R"()" R"(tag:example.com)" R"(%s)" R"(2008-12-30T18:26:15Z)" R"()" R"(tag:example.com,2008-12-30:/atom_testing)" R"(regular title)" R"(2008-12-30T20:04:15Z)" R"()" R"()"; TEST_CASE("parse_url() applies encoding specified in http header if no xml encoding specified", "[rsspp::Parser]") { using namespace newsboat; constexpr auto title_utf8 = u8"Prøve"; // Danish for "test" auto feed_xml_utf8 = strprintf::fmt(atom_feed_without_encoding, title_utf8); auto feed_xml_iso8859_1 = utils::convert_text(feed_xml_utf8, "iso-8859-1", "utf-8"); auto feed_xml = std::vector(feed_xml_iso8859_1.begin(), feed_xml_iso8859_1.end()); auto& test_server = test_helpers::HttpTestServer::get_instance(); auto mock_registration = test_server.add_endpoint("/feed", {}, 200, { {"content-type", "text/xml; charset=iso-8859-1"}, }, feed_xml); const auto address = test_server.get_address(); const auto url = strprintf::fmt("http://%s/feed", address); rsspp::Parser parser; CurlHandle easyhandle; auto parsed_feed = parser.parse_url(url, easyhandle); REQUIRE(parsed_feed.items.size() == 1); REQUIRE(parsed_feed.title == title_utf8); } TEST_CASE("parse_url() assumes utf-8 if no encoding specified and replaces invalid code units", "[rsspp::Parser]") { using namespace newsboat; constexpr auto title_utf8 = u8"Prøve"; // Danish for "test" constexpr auto expected_title = u8"Pr�ve"; auto feed_xml_utf8 = strprintf::fmt(atom_feed_without_encoding, title_utf8); auto feed_xml_iso8859_1 = utils::convert_text(feed_xml_utf8, "iso-8859-1", "utf-8"); auto feed_xml = std::vector(feed_xml_iso8859_1.begin(), feed_xml_iso8859_1.end()); auto& test_server = test_helpers::HttpTestServer::get_instance(); auto mock_registration = test_server.add_endpoint("/feed", {}, 200, {}, feed_xml); const auto address = test_server.get_address(); const auto url = strprintf::fmt("http://%s/feed", address); rsspp::Parser parser; CurlHandle easyhandle; auto parsed_feed = parser.parse_url(url, easyhandle); REQUIRE(parsed_feed.items.size() == 1); REQUIRE(parsed_feed.title == expected_title); }