#include "curlheadercontainer.h" #include "3rd-party/catch.hpp" #include "curlhandle.h" using namespace newsboat; class CurlHeaderContainerForTesting : public CurlHeaderContainer { public: CurlHeaderContainerForTesting(CurlHandle& curlHandle) : CurlHeaderContainer(curlHandle) { } using CurlHeaderContainer::handle_header; }; TEST_CASE("CurlHeaderContainer::handle_header() stores incoming headers", "[CurlHeaderContainer]") { CurlHandle curlHandle; GIVEN("A CurlHeaderContainer") { CurlHeaderContainerForTesting curlHeaderContainer(curlHandle); WHEN("handle_header() is called repeatedly") { curlHeaderContainer.handle_header("first header"); curlHeaderContainer.handle_header("location: test"); curlHeaderContainer.handle_header(""); THEN("all headers can be retrieved") { const auto headers = curlHeaderContainer.get_header_lines(); REQUIRE(headers.size() == 3); REQUIRE(headers[0] == "first header"); REQUIRE(headers[1] == "location: test"); REQUIRE(headers[2] == ""); } } } } TEST_CASE("CurlHeaderContainer::handle_header() discards previous headers when receiving an HTTP status line", "[CurlHeaderContainer]") { CurlHandle curlHandle; GIVEN("A CurlHeaderContainer") { CurlHeaderContainerForTesting curlHeaderContainer(curlHandle); WHEN("handle_header() is called repeatedly with an HTTP status line in between") { curlHeaderContainer.handle_header("HTTP/1.1 301 Moved Permanently"); curlHeaderContainer.handle_header("header of first response"); curlHeaderContainer.handle_header("location: somewhere else"); curlHeaderContainer.handle_header(""); curlHeaderContainer.handle_header("HTTP/1.1 200 OK"); curlHeaderContainer.handle_header("header of second response"); curlHeaderContainer.handle_header(""); THEN("all headers can be retrieved") { const auto headers = curlHeaderContainer.get_header_lines(); REQUIRE(headers.size() == 3); REQUIRE(headers[0] == "HTTP/1.1 200 OK"); REQUIRE(headers[1] == "header of second response"); REQUIRE(headers[2] == ""); } } } } TEST_CASE("get_header_lines() with given key returns matched header lines (case insensitively)", "[CurlHeaderContainer]") { CurlHandle curlHandle; CurlHeaderContainerForTesting curlHeaderContainer(curlHandle); GIVEN("A few header lines as input") { curlHeaderContainer.handle_header("HTTP/1.1 200 OK"); curlHeaderContainer.handle_header("Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT"); curlHeaderContainer.handle_header("Cache-Control:no-cache"); curlHeaderContainer.handle_header("Cache-Control:no-store"); curlHeaderContainer.handle_header("whitespace-test: \tvalue with spaces\t "); curlHeaderContainer.handle_header(""); WHEN("get_header_lines() is called with a non-existent key") { const auto values = curlHeaderContainer.get_header_lines("non-existent"); THEN("Nothing is returned") { REQUIRE(values.size() == 0); } } WHEN("get_header_lines() is called with an existing key") { const auto values = curlHeaderContainer.get_header_lines("Cache-Control"); THEN("all relevant values are returned") { REQUIRE(values.size() == 2); REQUIRE(values[0] == "no-cache"); REQUIRE(values[1] == "no-store"); } } SECTION("get_header_lines() matches keys case-insensitively") { const auto values = curlHeaderContainer.get_header_lines("CACHE-CONTROL"); REQUIRE(values.size() == 2); REQUIRE(values[0] == "no-cache"); REQUIRE(values[1] == "no-store"); } SECTION("get_header_lines() removes whitespace at start and end of value") { const auto values = curlHeaderContainer.get_header_lines("whitespace-test"); REQUIRE(values.size() == 1); REQUIRE(values[0] == "value with spaces"); } } }