From e93ccd18d4ae28fa2ea4cc9fb994413e05a70a53 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 30 Jan 2022 13:00:24 +0400 Subject: [PATCH 1/2] Robust test data in ServerTest.404WithBodyTesting Before this change the meaning of test data in the ServerTest.404WithBodyTesting unit test entirely depended on the number of entries: - 2 entries: url, expected body - 4 entries: url, book name, book title and expected body This was fragile and non scalable (if other combinations of expected response data are needed). This commit defines a mini-DSL taking advantage of operator overloading that allows to define test data in a robust way with the help of the compiler. Some code in `TestContentIn404HtmlResponse` is obsoleted by this change however it is not removed in this commit so that the change is easier to understand. That will be done next. --- test/server.cpp | 98 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 20 deletions(-) diff --git a/test/server.cpp b/test/server.cpp index 600b171ae..34646e4b7 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -322,9 +322,64 @@ TEST_F(ServerTest, 404) EXPECT_EQ(404, zfs1_->GET(url)->status) << "url: " << url; } +namespace TestingOfHtmlResponses +{ + +struct ExpectedResponseData +{ + const std::string bookName, bookTitle, expectedBody; +}; + +enum ExpectedResponseDataType +{ + book_name, + book_title, + expected_body +}; + +// Operator overloading is used as a means of defining a mini-DSL for +// defining test data in a concise way (see usage in +// TEST_F(ServerTest, 404WithBodyTesting)) +ExpectedResponseData operator==(ExpectedResponseDataType t, std::string s) +{ + switch (t) + { + case book_name: return ExpectedResponseData{s, "", ""}; + case book_title: return ExpectedResponseData{"", s, ""}; + case expected_body: return ExpectedResponseData{"", "", s}; + default: assert(false); return ExpectedResponseData{}; + } +} + +std::string selectNonEmpty(const std::string& a, const std::string& b) +{ + if ( a.empty() ) return b; + + assert(b.empty()); + return a; +} + +ExpectedResponseData operator&&(const ExpectedResponseData& a, + const ExpectedResponseData& b) +{ + return ExpectedResponseData{ + selectNonEmpty(a.bookName, b.bookName), + selectNonEmpty(a.bookTitle, b.bookTitle), + selectNonEmpty(a.expectedBody, b.expectedBody) + }; +} + class TestContentIn404HtmlResponse { public: + TestContentIn404HtmlResponse(const std::string& url, + const ExpectedResponseData& erd) + : url(url) + , bookName(erd.bookName) + , bookTitle(erd.bookTitle) + , expectedBody(erd.expectedBody) + {} + TestContentIn404HtmlResponse(const std::string& url, const std::string& expectedBody) : url(url) @@ -445,11 +500,14 @@ std::string TestContentIn404HtmlResponse::taskbarLinks() const + R"(">)"; } +} // namespace TestingOfHtmlResponses + TEST_F(ServerTest, 404WithBodyTesting) { + using namespace TestingOfHtmlResponses; const std::vector testData{ { /* url */ "/ROOT/random?content=non-existent-book", - /* expected body */ R"( + expected_body==R"(

Not Found

//EOLWHITESPACEMARKER

@@ -458,7 +516,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/suggest?content=no-such-book&term=whatever", - /* expected body */ R"( + expected_body==R"(

Not Found

//EOLWHITESPACEMARKER

@@ -467,7 +525,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/catalog/", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/catalog/" was not found on this server. @@ -478,7 +536,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/catalog/invalid_endpoint", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/catalog/invalid_endpoint" was not found on this server. @@ -489,7 +547,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/invalid-book/whatever", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/invalid-book/whatever" was not found on this server. @@ -500,9 +558,9 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/zimfile/invalid-article", - /* book name */ "zimfile", - /* book title */ "Ray Charles", - /* expected body */ R"( + book_name=="zimfile" && + book_title=="Ray Charles" && + expected_body==R"(

Not Found

The requested URL "/ROOT/zimfile/invalid-article" was not found on this server. @@ -513,7 +571,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ R"(/ROOT/">)", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/"><svg onload=alert(1)>" was not found on this server. @@ -524,9 +582,9 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ R"(/ROOT/zimfile/">)", - /* book name */ "zimfile", - /* book title */ "Ray Charles", - /* expected body */ R"( + book_name=="zimfile" && + book_title=="Ray Charles" && + expected_body==R"(

Not Found

The requested URL "/ROOT/zimfile/"><svg onload=alert(1)>" was not found on this server. @@ -537,7 +595,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/raw/no-such-book/meta/Title", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/raw/no-such-book/meta/Title" was not found on this server. @@ -548,7 +606,7 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/raw/zimfile/XYZ", - /* expected body */ R"( + expected_body==R"(

Not Found

The requested URL "/ROOT/raw/zimfile/XYZ" was not found on this server. @@ -559,9 +617,9 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/raw/zimfile/meta/invalid-metadata", - /* book name */ "zimfile", - /* book title */ "Ray Charles", - /* expected body */ R"( + book_name=="zimfile" && + book_title=="Ray Charles" && + expected_body==R"(

Not Found

The requested URL "/ROOT/raw/zimfile/meta/invalid-metadata" was not found on this server. @@ -572,9 +630,9 @@ TEST_F(ServerTest, 404WithBodyTesting) )" }, { /* url */ "/ROOT/raw/zimfile/content/invalid-article", - /* book name */ "zimfile", - /* book title */ "Ray Charles", - /* expected body */ R"( + book_name=="zimfile" && + book_title=="Ray Charles" && + expected_body==R"(

Not Found

The requested URL "/ROOT/raw/zimfile/content/invalid-article" was not found on this server. From ed46541b6f2a0db272d365b5aa0e0e42aa9ba8c0 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 30 Jan 2022 13:10:57 +0400 Subject: [PATCH 2/2] Clean-up promised in the previous commit --- test/server.cpp | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/test/server.cpp b/test/server.cpp index 34646e4b7..bff14f654 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -369,34 +369,16 @@ ExpectedResponseData operator&&(const ExpectedResponseData& a, }; } -class TestContentIn404HtmlResponse +class TestContentIn404HtmlResponse : public ExpectedResponseData { public: TestContentIn404HtmlResponse(const std::string& url, const ExpectedResponseData& erd) - : url(url) - , bookName(erd.bookName) - , bookTitle(erd.bookTitle) - , expectedBody(erd.expectedBody) + : ExpectedResponseData(erd) + , url(url) {} - TestContentIn404HtmlResponse(const std::string& url, - const std::string& expectedBody) - : url(url) - , expectedBody(expectedBody) - {} - - TestContentIn404HtmlResponse(const std::string& url, - const std::string& bookName, - const std::string& bookTitle, - const std::string& expectedBody) - : url(url) - , bookName(bookName) - , bookTitle(bookTitle) - , expectedBody(expectedBody) - {} - - const std::string url, bookName, bookTitle, expectedBody; + const std::string url; std::string expectedResponse() const;