Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
test_connection_string_builder.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11
12#include <iostream>
13#include <string>
14
15using namespace database::integrated;
16
17// Test counters
18static int tests_passed = 0;
19static int tests_failed = 0;
20
21// Test helpers
22#define TEST_START(name) \
23 std::cout << "\n[TEST] " << name << "...\n"
24
25#define ASSERT_TRUE(condition, message) \
26 do { \
27 if (!(condition)) { \
28 std::cout << " FAILED: " << message << "\n"; \
29 std::cout << " at " << __FILE__ << ":" << __LINE__ << "\n"; \
30 tests_failed++; \
31 return false; \
32 } \
33 } while(0)
34
35#define ASSERT_FALSE(condition, message) \
36 ASSERT_TRUE(!(condition), message)
37
38#define ASSERT_EQ(expected, actual, message) \
39 do { \
40 if ((expected) != (actual)) { \
41 std::cout << " FAILED: " << message << "\n"; \
42 std::cout << " Expected: \"" << (expected) << "\"\n"; \
43 std::cout << " Actual: \"" << (actual) << "\"\n"; \
44 std::cout << " at " << __FILE__ << ":" << __LINE__ << "\n"; \
45 tests_failed++; \
46 return false; \
47 } \
48 } while(0)
49
50#define TEST_END() \
51 do { \
52 std::cout << " PASSED\n"; \
53 tests_passed++; \
54 return true; \
55 } while(0)
56
57//==============================================================================
58// PostgreSQL Tests
59//==============================================================================
60
62 TEST_START("PostgreSQL - Basic Connection String");
63
64 auto result = connection_string_builder()
65 .host("localhost")
66 .port(5432)
67 .database("mydb")
68 .user("admin")
69 .password("secret")
70 .build(backend_type::postgres);
71
72 ASSERT_TRUE(result.is_ok(), "Build should succeed");
73
74 auto conn_str = result.value();
75 ASSERT_TRUE(conn_str.find("host=localhost") != std::string::npos, "Should contain host");
76 ASSERT_TRUE(conn_str.find("port=5432") != std::string::npos, "Should contain port");
77 ASSERT_TRUE(conn_str.find("dbname=mydb") != std::string::npos, "Should contain dbname");
78 ASSERT_TRUE(conn_str.find("user=admin") != std::string::npos, "Should contain user");
79 ASSERT_TRUE(conn_str.find("password=secret") != std::string::npos, "Should contain password");
80
81 TEST_END();
82}
83
85 TEST_START("PostgreSQL - SSL Mode");
86
87 auto result = connection_string_builder()
88 .host("localhost")
89 .database("mydb")
90 .ssl_mode(ssl_mode::require)
91 .build(backend_type::postgres);
92
93 ASSERT_TRUE(result.is_ok(), "Build should succeed");
94 ASSERT_TRUE(result.value().find("sslmode=require") != std::string::npos, "Should contain sslmode");
95
96 TEST_END();
97}
98
100 TEST_START("PostgreSQL - SSL Verify CA");
101
102 auto result = connection_string_builder()
103 .host("localhost")
104 .ssl_mode(ssl_mode::verify_ca)
105 .build(backend_type::postgres);
106
107 ASSERT_TRUE(result.is_ok(), "Build should succeed");
108 ASSERT_TRUE(result.value().find("sslmode=verify-ca") != std::string::npos, "Should contain verify-ca");
109
110 TEST_END();
111}
112
114 TEST_START("PostgreSQL - Connection Timeout");
115
116 auto result = connection_string_builder()
117 .host("localhost")
118 .connect_timeout(30)
119 .build(backend_type::postgres);
120
121 ASSERT_TRUE(result.is_ok(), "Build should succeed");
122 ASSERT_TRUE(result.value().find("connect_timeout=30") != std::string::npos, "Should contain timeout");
123
124 TEST_END();
125}
126
128 TEST_START("PostgreSQL - Application Name");
129
130 auto result = connection_string_builder()
131 .host("localhost")
132 .application_name("my_app")
133 .build(backend_type::postgres);
134
135 ASSERT_TRUE(result.is_ok(), "Build should succeed");
136 ASSERT_TRUE(result.value().find("application_name=my_app") != std::string::npos, "Should contain app name");
137
138 TEST_END();
139}
140
142 TEST_START("PostgreSQL - Custom Option");
143
144 auto result = connection_string_builder()
145 .host("localhost")
146 .option("client_encoding", "UTF8")
147 .build(backend_type::postgres);
148
149 ASSERT_TRUE(result.is_ok(), "Build should succeed");
150 ASSERT_TRUE(result.value().find("client_encoding=UTF8") != std::string::npos, "Should contain custom option");
151
152 TEST_END();
153}
154
156 TEST_START("PostgreSQL - Empty Builder");
157
158 auto result = connection_string_builder()
159 .build(backend_type::postgres);
160
161 ASSERT_TRUE(result.is_ok(), "Build should succeed even with empty builder");
162 ASSERT_EQ("", result.value(), "Empty builder should produce empty string");
163
164 TEST_END();
165}
166
167//==============================================================================
168// SQLite Tests
169//==============================================================================
170
172 TEST_START("SQLite - File Database");
173
174 auto result = connection_string_builder()
175 .database("mydb.db")
176 .build(backend_type::sqlite);
177
178 ASSERT_TRUE(result.is_ok(), "Build should succeed");
179 ASSERT_EQ("mydb.db", result.value(), "Should return file path");
180
181 TEST_END();
182}
183
185 TEST_START("SQLite - In-Memory Database");
186
187 auto result = connection_string_builder()
188 .in_memory()
189 .build(backend_type::sqlite);
190
191 ASSERT_TRUE(result.is_ok(), "Build should succeed");
192 ASSERT_EQ(":memory:", result.value(), "Should return :memory:");
193
194 TEST_END();
195}
196
198 TEST_START("SQLite - No Database Set");
199
200 auto result = connection_string_builder()
201 .build(backend_type::sqlite);
202
203 ASSERT_TRUE(result.is_err(), "Build should fail without database");
204
205 TEST_END();
206}
207
209 TEST_START("SQLite - In-Memory Overrides File");
210
211 auto result = connection_string_builder()
212 .database("mydb.db")
213 .in_memory()
214 .build(backend_type::sqlite);
215
216 ASSERT_TRUE(result.is_ok(), "Build should succeed");
217 ASSERT_EQ(":memory:", result.value(), "In-memory should override file");
218
219 TEST_END();
220}
221
222//==============================================================================
223// MongoDB Tests
224//==============================================================================
225
227 TEST_START("MongoDB - Basic Connection String");
228
229 auto result = connection_string_builder()
230 .host("localhost")
231 .port(27017)
232 .database("mydb")
233 .build(backend_type::mongodb);
234
235 ASSERT_TRUE(result.is_ok(), "Build should succeed");
236 ASSERT_EQ("mongodb://localhost:27017/mydb", result.value(), "Should return MongoDB URI");
237
238 TEST_END();
239}
240
242 TEST_START("MongoDB - With Authentication");
243
244 auto result = connection_string_builder()
245 .host("localhost")
246 .user("admin")
247 .password("secret")
248 .database("mydb")
249 .build(backend_type::mongodb);
250
251 ASSERT_TRUE(result.is_ok(), "Build should succeed");
252 ASSERT_EQ("mongodb://admin:secret@localhost/mydb", result.value(), "Should include credentials");
253
254 TEST_END();
255}
256
258 TEST_START("MongoDB - Default Host");
259
260 auto result = connection_string_builder()
261 .database("mydb")
262 .build(backend_type::mongodb);
263
264 ASSERT_TRUE(result.is_ok(), "Build should succeed");
265 ASSERT_TRUE(result.value().find("localhost") != std::string::npos, "Should default to localhost");
266
267 TEST_END();
268}
269
271 TEST_START("MongoDB - SSL Option");
272
273 auto result = connection_string_builder()
274 .host("localhost")
275 .ssl_mode(ssl_mode::require)
276 .build(backend_type::mongodb);
277
278 ASSERT_TRUE(result.is_ok(), "Build should succeed");
279 ASSERT_TRUE(result.value().find("ssl=true") != std::string::npos, "Should include SSL option");
280
281 TEST_END();
282}
283
284//==============================================================================
285// Redis Tests
286//==============================================================================
287
289 TEST_START("Redis - Basic Connection String");
290
291 auto result = connection_string_builder()
292 .host("localhost")
293 .port(6379)
294 .build(backend_type::redis);
295
296 ASSERT_TRUE(result.is_ok(), "Build should succeed");
297 ASSERT_EQ("redis://localhost:6379", result.value(), "Should return Redis URI");
298
299 TEST_END();
300}
301
303 TEST_START("Redis - With Password Only");
304
305 auto result = connection_string_builder()
306 .host("localhost")
307 .password("secret")
308 .build(backend_type::redis);
309
310 ASSERT_TRUE(result.is_ok(), "Build should succeed");
311 ASSERT_EQ("redis://:secret@localhost", result.value(), "Should include password");
312
313 TEST_END();
314}
315
317 TEST_START("Redis - With Database Number");
318
319 auto result = connection_string_builder()
320 .host("localhost")
321 .database("0")
322 .build(backend_type::redis);
323
324 ASSERT_TRUE(result.is_ok(), "Build should succeed");
325 ASSERT_EQ("redis://localhost/0", result.value(), "Should include database number");
326
327 TEST_END();
328}
329
330//==============================================================================
331// Builder Behavior Tests
332//==============================================================================
333
335 TEST_START("Builder - Reset");
336
338 builder.host("localhost")
339 .port(5432)
340 .database("mydb");
341
342 auto result1 = builder.build(backend_type::postgres);
343 ASSERT_TRUE(result1.is_ok(), "First build should succeed");
344 ASSERT_TRUE(result1.value().find("localhost") != std::string::npos, "Should contain host");
345
346 builder.reset();
347
348 auto result2 = builder.build(backend_type::postgres);
349 ASSERT_TRUE(result2.is_ok(), "Build after reset should succeed");
350 ASSERT_EQ("", result2.value(), "After reset should be empty");
351
352 TEST_END();
353}
354
356 TEST_START("Builder - Method Chaining");
357
358 auto result = connection_string_builder()
359 .host("db.example.com")
360 .port(5432)
361 .database("production")
362 .user("app_user")
363 .password("app_secret")
364 .ssl_mode(ssl_mode::verify_full)
365 .connect_timeout(10)
366 .application_name("my_service")
367 .option("target_session_attrs", "read-write")
368 .build(backend_type::postgres);
369
370 ASSERT_TRUE(result.is_ok(), "Chained build should succeed");
371
372 auto conn_str = result.value();
373 ASSERT_TRUE(conn_str.find("host=db.example.com") != std::string::npos, "Should have host");
374 ASSERT_TRUE(conn_str.find("sslmode=verify-full") != std::string::npos, "Should have SSL mode");
375 ASSERT_TRUE(conn_str.find("target_session_attrs=read-write") != std::string::npos, "Should have custom option");
376
377 TEST_END();
378}
379
381 TEST_START("Builder - Reuse for Multiple Connections");
382
384 builder.host("localhost")
385 .user("admin")
386 .password("secret");
387
388 // Build for PostgreSQL
389 builder.database("pg_db").port(5432);
390 auto pg_result = builder.build(backend_type::postgres);
391 ASSERT_TRUE(pg_result.is_ok(), "PostgreSQL build should succeed");
392
393 // Reset and build for SQLite
394 builder.reset()
395 .database("test.db");
396 auto sqlite_result = builder.build(backend_type::sqlite);
397 ASSERT_TRUE(sqlite_result.is_ok(), "SQLite build should succeed");
398
399 TEST_END();
400}
401
403 TEST_START("Builder - Copy Semantics");
404
406 builder1.host("localhost").port(5432);
407
408 connection_string_builder builder2 = builder1;
409 builder2.database("mydb");
410
411 auto result1 = builder1.build(backend_type::postgres);
412 auto result2 = builder2.build(backend_type::postgres);
413
414 ASSERT_TRUE(result1.is_ok(), "Original build should succeed");
415 ASSERT_TRUE(result2.is_ok(), "Copy build should succeed");
416
417 // Original should not have database
418 ASSERT_TRUE(result1.value().find("dbname") == std::string::npos, "Original should not have database");
419 // Copy should have database
420 ASSERT_TRUE(result2.value().find("dbname=mydb") != std::string::npos, "Copy should have database");
421
422 TEST_END();
423}
424
425//==============================================================================
426// Main Test Runner
427//==============================================================================
428
429int main() {
430 std::cout << "\n";
431 std::cout << "========================================\n";
432 std::cout << "Connection String Builder Tests\n";
433 std::cout << "========================================\n";
434
435 // PostgreSQL tests
443
444 // SQLite tests
449
450 // MongoDB tests
455
456 // Redis tests
460
461 // Builder behavior tests
466
467 // Print summary
468 std::cout << "\n";
469 std::cout << "========================================\n";
470 std::cout << "Test Summary\n";
471 std::cout << "========================================\n";
472 std::cout << "Passed: " << tests_passed << "\n";
473 std::cout << "Failed: " << tests_failed << "\n";
474
475 if (tests_failed == 0) {
476 std::cout << "\nAll tests passed!\n\n";
477 return 0;
478 } else {
479 std::cout << "\nSome tests failed!\n\n";
480 return 1;
481 }
482}
Fluent builder for constructing database connection strings.
connection_string_builder & database(std::string_view db)
Set the database name.
connection_string_builder & user(std::string_view u)
Set the username for authentication.
connection_string_builder & port(uint16_t p)
Set the database port.
connection_string_builder & host(std::string_view h)
Set the database host.
connection_string_builder & ssl_mode(enum ssl_mode mode)
Set the SSL connection mode.
connection_string_builder & application_name(std::string_view name)
Set the application name (for PostgreSQL)
connection_string_builder & reset()
Reset the builder to initial state.
connection_string_builder & option(std::string_view key, std::string_view value)
Add a custom option.
connection_string_builder & in_memory()
Configure SQLite to use in-memory database.
connection_string_builder & password(std::string_view p)
Set the password for authentication.
connection_string_builder & connect_timeout(uint32_t seconds)
Set the connection timeout.
kcenon::common::Result< std::string > build(backend_type type) const
Build the connection string for the specified backend.
Fluent builder for constructing type-safe database connection strings.
#define ASSERT_EQ(expected, actual, message)
bool test_mongodb_default_host()
bool test_postgres_app_name()
#define ASSERT_TRUE(condition, message)
bool test_postgres_verify_ca()
bool test_postgres_custom_option()
bool test_redis_with_database()
bool test_sqlite_no_database()
static int tests_passed
static int tests_failed
bool test_redis_with_password()
#define TEST_START(name)
bool test_mongodb_with_auth()
bool test_sqlite_memory_overrides_file()