Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
postgresql_backend_test.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
16#include <gtest/gtest.h>
17#include <memory>
18#include <string>
19
22
23using namespace database;
24using namespace database::backends;
25using namespace database::core;
26
27// =============================================================================
28// Test Fixture
29// =============================================================================
30
31class PostgreSQLBackendTest : public ::testing::Test {
32protected:
33 std::unique_ptr<postgresql_backend> backend_;
35
36 void SetUp() override
37 {
38 backend_ = std::make_unique<postgresql_backend>();
39 test_config_.host = "localhost";
40 test_config_.port = 5432;
41 test_config_.database = "test_db";
42 test_config_.username = "test_user";
43 test_config_.password = "test_pass";
44 }
45
46 void TearDown() override
47 {
48 if (backend_ && backend_->is_initialized()) {
49 backend_->shutdown();
50 }
51 }
52};
53
54// =============================================================================
55// Type Identification Tests
56// =============================================================================
57
58TEST_F(PostgreSQLBackendTest, TypeReturnsPostgres)
59{
60 EXPECT_EQ(backend_->type(), database_types::postgres);
61}
62
63TEST_F(PostgreSQLBackendTest, BackendNameIsCorrect)
64{
65 EXPECT_STREQ(postgresql_backend::backend_name(), "postgresql_backend");
66}
67
68// =============================================================================
69// Initial State Tests
70// =============================================================================
71
72TEST_F(PostgreSQLBackendTest, InitiallyNotInitialized)
73{
74 EXPECT_FALSE(backend_->is_initialized());
75}
76
77TEST_F(PostgreSQLBackendTest, InitiallyNotInTransaction)
78{
79 EXPECT_FALSE(backend_->in_transaction());
80}
81
82// =============================================================================
83// Operations Without Initialization Tests
84// =============================================================================
85
86TEST_F(PostgreSQLBackendTest, SelectQueryFailsWithoutInit)
87{
88 auto result = backend_->select_query("SELECT * FROM test");
89 EXPECT_FALSE(result.is_ok());
90}
91
92TEST_F(PostgreSQLBackendTest, ExecuteQueryFailsWithoutInit)
93{
94 auto result = backend_->execute_query("CREATE TABLE test (id INT)");
95 EXPECT_FALSE(result.is_ok());
96}
97
98TEST_F(PostgreSQLBackendTest, BeginTransactionFailsWithoutInit)
99{
100 auto result = backend_->begin_transaction();
101 EXPECT_FALSE(result.is_ok());
102}
103
104TEST_F(PostgreSQLBackendTest, CommitTransactionFailsWithoutInit)
105{
106 auto result = backend_->commit_transaction();
107 EXPECT_FALSE(result.is_ok());
108}
109
110TEST_F(PostgreSQLBackendTest, RollbackTransactionFailsWithoutInit)
111{
112 auto result = backend_->rollback_transaction();
113 EXPECT_FALSE(result.is_ok());
114}
115
116// =============================================================================
117// Lifecycle Guard Tests (via backend_base)
118// =============================================================================
119
120TEST_F(PostgreSQLBackendTest, ShutdownWithoutInitIsNoOp)
121{
122 auto result = backend_->shutdown();
123 EXPECT_TRUE(result.is_ok());
124}
125
126TEST_F(PostgreSQLBackendTest, DoubleInitializationRejected)
127{
128#ifdef USE_POSTGRESQL
129 // Only test if actual PostgreSQL is available
130 auto first = backend_->initialize(test_config_);
131 if (first.is_ok()) {
132 auto second = backend_->initialize(test_config_);
133 EXPECT_FALSE(second.is_ok());
134 }
135#else
136 GTEST_SKIP() << "PostgreSQL support not compiled";
137#endif
138}
139
140// =============================================================================
141// Factory Method Tests
142// =============================================================================
143
144TEST_F(PostgreSQLBackendTest, CreateReturnsValidBackend)
145{
146 auto backend = postgresql_backend::create();
147 ASSERT_NE(backend, nullptr);
148 EXPECT_EQ(backend->type(), database_types::postgres);
149 EXPECT_FALSE(backend->is_initialized());
150}
151
152// =============================================================================
153// Connection Info Tests
154// =============================================================================
155
156TEST_F(PostgreSQLBackendTest, ConnectionInfoBeforeInit)
157{
158 auto info = backend_->connection_info();
159 // Implementation may return empty or partial info before init
160 // Just verify no crash
161 SUCCEED();
162}
163
164TEST_F(PostgreSQLBackendTest, LastErrorBeforeInit)
165{
166 // Should not crash, may return empty
167 auto error = backend_->last_error();
168 SUCCEED();
169}
170
171// =============================================================================
172// Real Connection Tests (conditional on USE_POSTGRESQL)
173// =============================================================================
174
175#ifdef USE_POSTGRESQL
176
177TEST_F(PostgreSQLBackendTest, ConnectToLocalPostgres)
178{
179 connection_config config;
180 config.host = "localhost";
181 config.port = 5432;
182 config.database = "postgres"; // Default database
183 config.username = "postgres";
184 config.password = "";
185
186 auto result = backend_->initialize(config);
187 if (!result.is_ok()) {
188 GTEST_SKIP() << "Local PostgreSQL not available: " << backend_->last_error();
189 }
190
191 EXPECT_TRUE(backend_->is_initialized());
192 auto info = backend_->connection_info();
193 EXPECT_FALSE(info.empty());
194}
195
196TEST_F(PostgreSQLBackendTest, CRUDOperationsOnPostgres)
197{
198 connection_config config;
199 config.host = "localhost";
200 config.port = 5432;
201 config.database = "postgres";
202 config.username = "postgres";
203 config.password = "";
204
205 if (!backend_->initialize(config).is_ok()) {
206 GTEST_SKIP() << "Local PostgreSQL not available";
207 }
208
209 // Create temp table
210 ASSERT_TRUE(backend_->execute_query(
211 "CREATE TEMP TABLE pg_test (id SERIAL PRIMARY KEY, name TEXT)").is_ok());
212
213 // Insert
214 auto insert_result = backend_->execute_query(
215 "INSERT INTO pg_test (name) VALUES ('test_item')");
216 EXPECT_TRUE(insert_result.is_ok());
217
218 // Select
219 auto select_result = backend_->select_query(
220 "SELECT * FROM pg_test WHERE name = 'test_item'");
221 ASSERT_TRUE(select_result.is_ok());
222 EXPECT_GE(select_result.value().size(), 1u);
223
224 // Update
225 auto update_result = backend_->execute_query(
226 "UPDATE pg_test SET name = 'updated' WHERE name = 'test_item'");
227 EXPECT_TRUE(update_result.is_ok());
228
229 // Delete
230 auto delete_result = backend_->execute_query(
231 "DELETE FROM pg_test WHERE name = 'updated'");
232 EXPECT_TRUE(delete_result.is_ok());
233}
234
235TEST_F(PostgreSQLBackendTest, TransactionsOnPostgres)
236{
237 connection_config config;
238 config.host = "localhost";
239 config.port = 5432;
240 config.database = "postgres";
241 config.username = "postgres";
242 config.password = "";
243
244 if (!backend_->initialize(config).is_ok()) {
245 GTEST_SKIP() << "Local PostgreSQL not available";
246 }
247
248 ASSERT_TRUE(backend_->execute_query(
249 "CREATE TEMP TABLE pg_tx_test (id SERIAL, val TEXT)").is_ok());
250
251 // Test commit
252 EXPECT_TRUE(backend_->begin_transaction().is_ok());
253 EXPECT_TRUE(backend_->in_transaction());
254 backend_->execute_query("INSERT INTO pg_tx_test (val) VALUES ('committed')");
255 EXPECT_TRUE(backend_->commit_transaction().is_ok());
256 EXPECT_FALSE(backend_->in_transaction());
257
258 // Test rollback
259 EXPECT_TRUE(backend_->begin_transaction().is_ok());
260 backend_->execute_query("INSERT INTO pg_tx_test (val) VALUES ('rolled_back')");
261 EXPECT_TRUE(backend_->rollback_transaction().is_ok());
262
263 // Verify rolled back data doesn't exist
264 auto result = backend_->select_query(
265 "SELECT * FROM pg_tx_test WHERE val = 'rolled_back'");
266 ASSERT_TRUE(result.is_ok());
267 EXPECT_TRUE(result.value().empty());
268}
269
270#endif // USE_POSTGRESQL
271
272int main(int argc, char** argv)
273{
274 ::testing::InitGoogleTest(&argc, argv);
275 return RUN_ALL_TESTS();
276}
std::unique_ptr< postgresql_backend > backend_
static constexpr const char * backend_name()
Backend name for error messages.
Abstract interface for database backends.
@ info
Informational messages (default)
PostgreSQL database backend plugin implementation.
TEST_F(PostgreSQLBackendTest, TypeReturnsPostgres)
Configuration for database connection.
#define ASSERT_TRUE(condition, message)