Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
mock_backend.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
5#include "mock_backend.h"
6#include <algorithm>
7
8namespace database::testing {
9
10// mock_backend implementation
12 : db_type_(database_types::none)
13 , initialized_(false)
14 , init_result_(true)
15 , default_rows_affected_(1)
16 , in_transaction_(false)
17{
18}
19
21 : db_type_(other.db_type_)
22 , initialized_(other.initialized_)
23 , init_result_(other.init_result_)
24 , init_error_(std::move(other.init_error_))
25 , connection_string_(std::move(other.connection_string_))
26 , default_result_(std::move(other.default_result_))
27 , default_rows_affected_(other.default_rows_affected_)
28 , last_error_(std::move(other.last_error_))
29 , in_transaction_(other.in_transaction_)
30 , expectations_(std::move(other.expectations_))
31 , executed_queries_(std::move(other.executed_queries_))
32{
33 other.initialized_ = false;
34 other.in_transaction_ = false;
35}
36
38 if (this != &other) {
39 db_type_ = other.db_type_;
40 initialized_ = other.initialized_;
41 init_result_ = other.init_result_;
42 init_error_ = std::move(other.init_error_);
43 connection_string_ = std::move(other.connection_string_);
44 default_result_ = std::move(other.default_result_);
45 default_rows_affected_ = other.default_rows_affected_;
46 last_error_ = std::move(other.last_error_);
47 in_transaction_ = other.in_transaction_;
48 expectations_ = std::move(other.expectations_);
49 executed_queries_ = std::move(other.executed_queries_);
50 other.initialized_ = false;
51 other.in_transaction_ = false;
52 }
53 return *this;
54}
55
59
60kcenon::common::VoidResult mock_backend::initialize(const core::connection_config& config) {
61 std::lock_guard<std::mutex> lock(mutex_);
62 connection_string_ = config.host + ":" + std::to_string(config.port) + "/" + config.database;
63 if (init_result_) {
64 initialized_ = true;
65 return kcenon::common::VoidResult(std::monostate{});
66 }
67 last_error_ = init_error_.empty() ? "Mock initialization failed" : init_error_;
68 return kcenon::common::VoidResult(kcenon::common::error_info{-1, last_error_});
69}
70
71kcenon::common::VoidResult mock_backend::shutdown() {
72 std::lock_guard<std::mutex> lock(mutex_);
73 initialized_ = false;
74 in_transaction_ = false;
75 return kcenon::common::VoidResult(std::monostate{});
76}
77
79 return initialized_;
80}
81
82kcenon::common::Result<core::database_result> mock_backend::select_query(const std::string& query_string) {
83 std::lock_guard<std::mutex> lock(mutex_);
84 record_query(query_string);
85
86 if (auto* exp = find_expectation(query_string)) {
87 return exp->get_select_result();
88 }
89 return kcenon::common::Result<core::database_result>::ok(default_result_);
90}
91
92kcenon::common::VoidResult mock_backend::execute_query(const std::string& query_string) {
93 std::lock_guard<std::mutex> lock(mutex_);
94 record_query(query_string);
95
96 if (auto* exp = find_expectation(query_string)) {
97 return exp->get_execute_result();
98 }
99 return kcenon::common::VoidResult(std::monostate{});
100}
101
102kcenon::common::VoidResult mock_backend::begin_transaction() {
103 std::lock_guard<std::mutex> lock(mutex_);
104 if (in_transaction_) {
105 last_error_ = "Transaction already in progress";
106 return kcenon::common::VoidResult(kcenon::common::error_info{-1, last_error_});
107 }
108 in_transaction_ = true;
109 return kcenon::common::VoidResult(std::monostate{});
110}
111
112kcenon::common::VoidResult mock_backend::commit_transaction() {
113 std::lock_guard<std::mutex> lock(mutex_);
114 if (!in_transaction_) {
115 last_error_ = "No transaction in progress";
116 return kcenon::common::VoidResult(kcenon::common::error_info{-1, last_error_});
117 }
118 in_transaction_ = false;
119 return kcenon::common::VoidResult(std::monostate{});
120}
121
122kcenon::common::VoidResult mock_backend::rollback_transaction() {
123 std::lock_guard<std::mutex> lock(mutex_);
124 if (!in_transaction_) {
125 last_error_ = "No transaction in progress";
126 return kcenon::common::VoidResult(kcenon::common::error_info{-1, last_error_});
127 }
128 in_transaction_ = false;
129 return kcenon::common::VoidResult(std::monostate{});
130}
131
133 return in_transaction_;
134}
135
136std::string mock_backend::last_error() const {
137 return last_error_;
138}
139
140std::map<std::string, std::string> mock_backend::connection_info() const {
141 return {
142 {"type", "mock"},
143 {"connection_string", connection_string_},
144 {"initialized", initialized_ ? "true" : "false"}
145 };
146}
147
152
153mock_backend& mock_backend::set_initialize_result(bool result, const std::string& error) {
154 init_result_ = result;
155 init_error_ = error;
156 return *this;
157}
158
163
166 return *this;
167}
168
172 return backend_expectation_builder(this, std::move(exp));
173}
174
177 exp.for_pattern(regex_pattern);
178 return backend_expectation_builder(this, std::move(exp));
179}
180
186
188 init_result_ = false;
189 init_error_ = error;
190 return *this;
191}
192
194 initialized_ = false;
195 return *this;
196}
197
199 std::lock_guard<std::mutex> lock(mutex_);
200 return std::all_of(expectations_.begin(), expectations_.end(),
201 [](const backend_expectation& exp) { return exp.is_satisfied(); });
202}
203
204std::vector<std::string> mock_backend::get_executed_queries() const {
205 std::lock_guard<std::mutex> lock(mutex_);
206 return executed_queries_;
207}
208
210 std::lock_guard<std::mutex> lock(mutex_);
211 return executed_queries_.size();
212}
213
214size_t mock_backend::get_query_count(const std::string& pattern) const {
215 std::lock_guard<std::mutex> lock(mutex_);
216 std::regex re(pattern);
217 return std::count_if(executed_queries_.begin(), executed_queries_.end(),
218 [&re](const std::string& q) { return std::regex_search(q, re); });
219}
220
222 std::lock_guard<std::mutex> lock(mutex_);
223 expectations_.clear();
224 executed_queries_.clear();
225 initialized_ = false;
226 in_transaction_ = false;
227 connection_string_.clear();
228 last_error_.clear();
229}
230
232 std::lock_guard<std::mutex> lock(mutex_);
233 expectations_.clear();
234}
235
237 std::lock_guard<std::mutex> lock(mutex_);
238 executed_queries_.clear();
239}
240
242 return connection_string_;
243}
244
245void mock_backend::record_query(const std::string& query) {
246 executed_queries_.push_back(query);
247}
248
250 for (auto& exp : expectations_) {
251 if (exp.matches(query) && exp.can_be_invoked()) {
252 return &exp;
253 }
254 }
255 return nullptr;
256}
257
258// mock_backend_builder implementation
260 : mock_(std::make_unique<mock_backend>())
261{
262}
263
267
268mock_backend mock_backend_builder::with_data(const std::string& table_name, const core::database_result& data) {
269 mock_backend db;
270 db.expect_pattern("SELECT.*FROM.*" + table_name).will_return(data);
271 return db;
272}
273
275 mock_backend db;
276 db.expect_any().will_fail(error);
277 return db;
278}
279
281 mock_->set_database_type(type);
282 return *this;
283}
284
286 mock_->set_default_select_result(result);
287 return *this;
288}
289
291 mock_->simulate_initialization_failure();
292 return *this;
293}
294
296 return std::move(*mock_);
297}
298
299} // namespace database::testing
Fluent builder for backend expectations.
backend_expectation_builder & will_fail(const std::string &error_message)
backend_expectation_builder & will_return(const core::database_result &result)
Single query expectation with configurable behavior for database_backend.
backend_expectation & for_query(const std::string &query, backend_match_type type=backend_match_type::EXACT)
backend_expectation & for_pattern(const std::string &pattern)
Builder for common mock configurations.
std::unique_ptr< mock_backend > mock_
mock_backend_builder & with_type(database_types type)
static mock_backend failing_database(const std::string &error="Mock database error")
static mock_backend with_data(const std::string &table_name, const core::database_result &data)
mock_backend_builder & with_default_result(const core::database_result &result)
mock_backend_builder & that_fails_on_initialize()
Configurable mock for database_backend interface.
mock_backend & set_initialize_result(bool result, const std::string &error="")
kcenon::common::VoidResult commit_transaction() override
Commit the current transaction.
std::vector< backend_expectation > expectations_
std::vector< std::string > get_executed_queries() const
kcenon::common::VoidResult shutdown() override
Shutdown the database backend gracefully.
std::string last_error() const override
Get last error message from backend.
backend_expectation * find_expectation(const std::string &query)
std::vector< std::string > executed_queries_
std::string get_connection_string() const
core::database_result default_result_
backend_expectation_builder expect_pattern(const std::string &regex_pattern)
mock_backend & operator=(const mock_backend &)=delete
bool in_transaction() const override
Check if backend is currently in a transaction.
bool is_initialized() const override
Check if backend is initialized and ready.
mock_backend & simulate_initialization_failure(const std::string &error="Mock initialization failed")
mock_backend & set_default_rows_affected(uint64_t rows)
void record_query(const std::string &query)
kcenon::common::VoidResult initialize(const core::connection_config &config) override
Initialize the database backend.
std::map< std::string, std::string > connection_info() const override
Get backend-specific connection information.
kcenon::common::VoidResult begin_transaction() override
Begin a transaction.
mock_backend & set_database_type(database_types type)
database_types type() const override
Get the database type of this backend.
backend_expectation_builder expect_any()
kcenon::common::Result< core::database_result > select_query(const std::string &query_string) override
Execute a SELECT query.
kcenon::common::VoidResult execute_query(const std::string &query_string) override
Execute a general SQL query (DDL, DML)
mock_backend & set_default_select_result(const core::database_result &result)
backend_expectation_builder expect_query(const std::string &query)
kcenon::common::VoidResult rollback_transaction() override
Rollback the current transaction.
std::vector< database_row > database_result
database_types
Represents various database backends or modes.
@ none
No specific database type is set.
Configuration for database connection.