test.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include <gtest/gtest.h>
  2. #include <httplib.h>
  3. //#include <future>
  4. #include <iostream>
  5. #ifdef _WIN32
  6. #include <process.h>
  7. #endif
  8. using namespace std;
  9. using namespace httplib;
  10. const char* HOST = "localhost";
  11. const int PORT = 8080;
  12. class thread
  13. {
  14. public:
  15. thread(std::function<void ()> fn);
  16. ~thread();
  17. void join();
  18. private:
  19. thread();
  20. #ifdef _WIN32
  21. HANDLE thread_;
  22. static unsigned int __stdcall TreadFunc(void* arg);
  23. #else
  24. pthread_t thread_;
  25. static void* TreadFunc(void* arg);
  26. #endif
  27. static std::map<void*, std::function<void ()>> tasks_;
  28. };
  29. std::map<void*, std::function<void ()>> thread::tasks_;
  30. inline thread::thread(std::function<void ()> fn)
  31. : thread_(NULL)
  32. {
  33. tasks_[this] = fn;
  34. #ifdef _WIN32
  35. thread_ = (HANDLE)_beginthreadex(NULL, 0, TreadFunc, this, 0, NULL);
  36. #else
  37. pthread_create(&thread_, NULL, TreadFunc, this);
  38. #endif
  39. }
  40. inline thread::~thread()
  41. {
  42. #ifdef _WIN32
  43. CloseHandle(thread_);
  44. #endif
  45. }
  46. inline void thread::join()
  47. {
  48. #ifdef _WIN32
  49. ::WaitForSingleObject(thread_, INFINITE);
  50. #else
  51. pthread_join(thread_, NULL);
  52. #endif
  53. }
  54. #ifdef _WIN32
  55. unsigned int __stdcall thread::TreadFunc(void* arg)
  56. #else
  57. void* thread::TreadFunc(void* arg)
  58. #endif
  59. {
  60. thread* pThis = static_cast<thread*>(arg);
  61. tasks_[pThis]();
  62. tasks_.erase(pThis);
  63. return 0;
  64. }
  65. #ifdef _WIN32
  66. TEST(StartupTest, WSAStartup)
  67. {
  68. WSADATA wsaData;
  69. int ret = WSAStartup(0x0002, &wsaData);
  70. ASSERT_EQ(0, ret);
  71. }
  72. #endif
  73. TEST(SplitTest, ParseQueryString)
  74. {
  75. string s = "key1=val1&key2=val2&key3=val3";
  76. map<string, string> dic;
  77. detail::split(s.c_str(), s.c_str() + s.size(), '&', [&](const char* b, const char* e) {
  78. string key, val;
  79. detail::split(b, e, '=', [&](const char* b, const char* e) {
  80. if (key.empty()) {
  81. key.assign(b, e);
  82. } else {
  83. val.assign(b, e);
  84. }
  85. });
  86. dic[key] = val;
  87. });
  88. EXPECT_EQ("val1", dic["key1"]);
  89. EXPECT_EQ("val2", dic["key2"]);
  90. EXPECT_EQ("val3", dic["key3"]);
  91. }
  92. TEST(ParseQueryTest, ParseQueryString)
  93. {
  94. string s = "key1=val1&key2=val2&key3=val3";
  95. map<string, string> dic;
  96. detail::parse_query_text(s, dic);
  97. EXPECT_EQ("val1", dic["key1"]);
  98. EXPECT_EQ("val2", dic["key2"]);
  99. EXPECT_EQ("val3", dic["key3"]);
  100. }
  101. TEST(SocketTest, OpenClose)
  102. {
  103. socket_t sock = detail::create_server_socket(HOST, PORT);
  104. ASSERT_NE(-1, sock);
  105. auto ret = detail::close_socket(sock);
  106. EXPECT_EQ(0, ret);
  107. }
  108. TEST(GetHeaderValueTest, DefaultValue)
  109. {
  110. //MultiMap map = {{"Dummy","Dummy"}};
  111. MultiMap map;
  112. map.insert(std::make_pair("Dummy", "Dummy"));
  113. auto val = detail::get_header_value_text(map, "Content-Type", "text/plain");
  114. ASSERT_STREQ("text/plain", val);
  115. }
  116. TEST(GetHeaderValueTest, DefaultValueInt)
  117. {
  118. //MultiMap map = {{"Dummy","Dummy"}};
  119. MultiMap map;
  120. map.insert(std::make_pair("Dummy", "Dummy"));
  121. auto val = detail::get_header_value_int(map, "Content-Length", 100);
  122. EXPECT_EQ(100, val);
  123. }
  124. TEST(GetHeaderValueTest, RegularValue)
  125. {
  126. //MultiMap map = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
  127. MultiMap map;
  128. map.insert(std::make_pair("Content-Type","text/html"));
  129. map.insert(std::make_pair("Dummy", "Dummy"));
  130. auto val = detail::get_header_value_text(map, "Content-Type", "text/plain");
  131. ASSERT_STREQ("text/html", val);
  132. }
  133. TEST(GetHeaderValueTest, RegularValueInt)
  134. {
  135. //MultiMap map = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
  136. MultiMap map;
  137. map.insert(std::make_pair("Content-Length", "100"));
  138. map.insert(std::make_pair("Dummy", "Dummy"));
  139. auto val = detail::get_header_value_int(map, "Content-Length", 0);
  140. EXPECT_EQ(100, val);
  141. }
  142. class ServerTest : public ::testing::Test {
  143. protected:
  144. ServerTest() : svr_(HOST, PORT), cli_(HOST, PORT) {
  145. }
  146. virtual void SetUp() {
  147. svr_.get("/hi", [&](Connection& c) {
  148. c.response.set_content("Hello World!", "text/plain");
  149. });
  150. svr_.get("/", [&](httplib::Connection& c) {
  151. c.response.set_redirect("/hi");
  152. });
  153. svr_.post("/person", [&](Connection& c) {
  154. const auto& req = c.request;
  155. if (req.has_param("name") && req.has_param("note")) {
  156. persons_[req.params.at("name")] = req.params.at("note");
  157. } else {
  158. c.response.status = 400;
  159. }
  160. });
  161. svr_.get("/person/(.*)", [&](Connection& c) {
  162. const auto& req = c.request;
  163. std::string name = req.matches[1];
  164. if (persons_.find(name) != persons_.end()) {
  165. auto note = persons_[name];
  166. c.response.set_content(note, "text/plain");
  167. } else {
  168. c.response.status = 404;
  169. }
  170. });
  171. svr_.get("/stop", [&](Connection& c) {
  172. svr_.stop();
  173. });
  174. persons_["john"] = "programmer";
  175. //f_ = async([&](){ svr_.run(); });
  176. t_ = std::make_shared<thread>([&](){ svr_.run(); });
  177. }
  178. virtual void TearDown() {
  179. //svr_.stop(); // NOTE: This causes dead lock on Windows.
  180. cli_.get("/stop");
  181. //f_.get();
  182. t_->join();
  183. }
  184. std::map<std::string, std::string> persons_;
  185. Server svr_;
  186. Client cli_;
  187. //std::future<void> f_;
  188. std::shared_ptr<thread> t_;
  189. };
  190. TEST_F(ServerTest, GetMethod200)
  191. {
  192. auto res = cli_.get("/hi");
  193. ASSERT_TRUE(res != nullptr);
  194. EXPECT_EQ(200, res->status);
  195. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  196. EXPECT_EQ("Hello World!", res->body);
  197. }
  198. TEST_F(ServerTest, GetMethod302)
  199. {
  200. auto res = cli_.get("/");
  201. ASSERT_TRUE(res != nullptr);
  202. EXPECT_EQ(302, res->status);
  203. EXPECT_EQ("/hi", res->get_header_value("Location"));
  204. }
  205. TEST_F(ServerTest, GetMethod404)
  206. {
  207. auto res = cli_.get("/invalid");
  208. ASSERT_TRUE(res != nullptr);
  209. EXPECT_EQ(404, res->status);
  210. }
  211. TEST_F(ServerTest, GetMethodPersonJohn)
  212. {
  213. auto res = cli_.get("/person/john");
  214. ASSERT_TRUE(res != nullptr);
  215. EXPECT_EQ(200, res->status);
  216. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  217. EXPECT_EQ("programmer", res->body);
  218. }
  219. TEST_F(ServerTest, PostMethod1)
  220. {
  221. auto res = cli_.get("/person/john1");
  222. ASSERT_TRUE(res != nullptr);
  223. ASSERT_EQ(404, res->status);
  224. res = cli_.post("/person", "name=john1&note=coder", "application/x-www-form-urlencoded");
  225. ASSERT_TRUE(res != nullptr);
  226. ASSERT_EQ(200, res->status);
  227. res = cli_.get("/person/john1");
  228. ASSERT_TRUE(res != nullptr);
  229. ASSERT_EQ(200, res->status);
  230. ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
  231. ASSERT_EQ("coder", res->body);
  232. }
  233. TEST_F(ServerTest, PostMethod2)
  234. {
  235. auto res = cli_.get("/person/john2");
  236. ASSERT_TRUE(res != nullptr);
  237. ASSERT_EQ(404, res->status);
  238. Map params;
  239. params["name"] = "john2";
  240. params["note"] = "coder";
  241. res = cli_.post("/person", params);
  242. ASSERT_TRUE(res != nullptr);
  243. ASSERT_EQ(200, res->status);
  244. res = cli_.get("/person/john2");
  245. ASSERT_TRUE(res != nullptr);
  246. ASSERT_EQ(200, res->status);
  247. ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
  248. ASSERT_EQ("coder", res->body);
  249. }
  250. #ifdef _WIN32
  251. TEST(CleanupTest, WSACleanup)
  252. {
  253. int ret = WSACleanup();
  254. ASSERT_EQ(0, ret);
  255. }
  256. #endif
  257. // vim: et ts=4 sw=4 cin cino={1s ff=unix