Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
test_cli.cpp
Go to the documentation of this file.
1#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
2#include <array>
3#include <chrono>
4#include <cstdio>
5#include <curl/curl.h>
6#include <doctest.h>
7#include <functional>
8#include <iostream>
9#include <memory>
10#include <nlohmann/json.hpp>
11#include <stdexcept>
12#include <string>
13#include <thread>
14
15// Utility function to run a command and capture its output
16std::string run_command(const std::string &cmd) {
17 std::array<char, 128> buffer;
18 std::string result;
19
20 // Use std::function to manage the deleter for pclose
21 std::unique_ptr<FILE, std::function<void(FILE *)>> pipe(
22 popen(cmd.c_str(), "r"), [](FILE *f) { pclose(f); });
23
24 if (!pipe)
25 throw std::runtime_error("popen() failed");
26
27 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
28 result += buffer.data();
29 }
30
31 return result;
32}
33
34// Utility function to perform an HTTP GET request and return the response as a
35// string
36std::string http_get(const std::string &url) {
37 CURL *curl = curl_easy_init();
38 if (!curl)
39 throw std::runtime_error("Failed to init curl");
40
41 std::string response;
42 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
44 curl, CURLOPT_WRITEFUNCTION,
45 +[](char *ptr, size_t size, size_t nmemb, void *userdata) -> size_t {
46 std::string *resp = static_cast<std::string *>(userdata);
47 resp->append(ptr, size * nmemb);
48 return size * nmemb;
49 });
50 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
51
52 CURLcode res = curl_easy_perform(curl);
53 if (res != CURLE_OK) {
55 throw std::runtime_error("CURL request failed: " +
56 std::string(curl_easy_strerror(res)));
57 }
58
60 return response;
61}
62
63bool wait_for_server(int max_retries = 10) {
64 for (int i = 0; i < max_retries; ++i) {
65 try {
66 std::string res = http_get("http://localhost:1234/wycats");
67 return !res.empty();
68 } catch (...) {
69 std::this_thread::sleep_for(std::chrono::milliseconds(300));
70 }
71 }
72 return false;
73}
74
76 int ret = system("pkill -f 'github_user_fetcher --server'");
77 if (ret != 0) {
78 std::cerr << "Warning: Failed to stop server process\n";
79 }
80}
81
82TEST_CASE("Default user fetch") {
83 std::string output = run_command("./github_user_fetcher");
84
85 // Print the output for debugging purposes
86 std::cout << "Output for default user fetch:\n" << output << std::endl;
87
88 // Check if other specific information is in the output
89 CHECK(output.find("Login: izelnakri") != std::string::npos);
90 CHECK(output.find("Name: Izel Nakri") != std::string::npos);
91 CHECK(output.find("Company: Ruby, JavaScript") != std::string::npos);
92 CHECK(output.find("Location: Madrid") != std::string::npos);
93}
94
95TEST_CASE("Custom user fetch (wycats)") {
96 std::string output = run_command("./github_user_fetcher --user wycats");
97
98 std::cout << "Output for custom user fetch (wycats):\n"
99 << output << std::endl;
100
101 CHECK(output.find("Login: wycats") != std::string::npos);
102}
103
104TEST_CASE("Run server mode and fetch user data") {
105 // Run the server in a background thread
106 std::thread server_thread([]() {
107 int ret = system("./github_user_fetcher --server");
108 if (ret != 0) {
109 std::cerr << "Server exited with code: " << ret << std::endl;
110 }
111 });
112
113 // Allow the server some time to start
115
116 try {
117 // Make the HTTP request to the server for the `izelnakri` user
118 std::string url = "http://localhost:1234/izelnakri";
119 std::string json_response = http_get(url);
120
121 // Parse the JSON response
122 auto json = nlohmann::json::parse(json_response);
123
124 // Check that the response contains the expected fields
125 CHECK(json["login"] == "izelnakri");
126 CHECK(json["name"] == "Izel Nakri | izelnakri.eth");
127 CHECK(json["company"] ==
128 "Ruby, JavaScript, TS, elixir, rust, k8s, lua, nix, pkl, android");
129 CHECK(json["location"] == "Madrid | Amsterdam");
130
131 json_response = http_get("http://localhost:1234/wycats");
132 json = nlohmann::json::parse(json_response);
133
134 // Check that the response contains the expected fields for `wycats`
135 CHECK(json["login"] == "wycats");
136 } catch (const std::exception &e) {
137 // If there was an error in any of the steps, make sure the server is
138 // stopped
139 std::cerr << "Test failed: " << e.what() << std::endl;
140 stop_server();
141 MESSAGE("Test failed: ", e.what());
142 FAIL_CHECK("Exception was thrown");
143 }
144
145 // Ensure the server is stopped after the test
146 stop_server();
147
148 if (server_thread.joinable())
149 server_thread.detach(); // Don't join, since we already stopped it
150}
void CURL
Definition curl.h:117
CURLcode
Definition curl.h:509
@ CURLE_OK
Definition curl.h:510
CURL_EXTERN const char * curl_easy_strerror(CURLcode)
#define FAIL_CHECK(...)
Definition doctest.h:2959
#define CHECK(...)
Definition doctest.h:2970
#define TEST_CASE(name)
Definition doctest.h:2937
#define MESSAGE(...)
Definition doctest.h:2958
CURL_EXTERN void curl_easy_cleanup(CURL *curl)
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl)
CURL_EXTERN CURL * curl_easy_init(void)
static const char * output
void stop_server()
Definition test_cli.cpp:75
std::string run_command(const std::string &cmd)
Definition test_cli.cpp:16
bool wait_for_server(int max_retries=10)
Definition test_cli.cpp:63
std::string http_get(const std::string &url)
Definition test_cli.cpp:36
#define curl_easy_setopt(handle, option, value)