test.cc 7.9 KB

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