Line data Source code
1 : #define BOOST_TEST_DYN_LINK
2 : #define BOOST_TEST_MODULE (SearchPatterns test)
3 :
4 : #include <boost/test/unit_test.hpp>
5 :
6 : #include <cstdlib>
7 : #include <ctime>
8 : #include <iostream>
9 : #include <memory>
10 : #include <string>
11 : #include <vector>
12 :
13 : #include "../DatabaseConfigurationInterface.h"
14 :
15 : using namespace ots;
16 :
17 : struct SearchPatternsTestData {
18 2 : SearchPatternsTestData() {
19 2 : srand(time(nullptr));
20 2 : baseVersion = rand() % 99999 + 100000;
21 2 : std::cout << "=== SEARCH PATTERNS TEST SUITE ===\n";
22 2 : std::cout << "Base version: " << baseVersion << "\n\n";
23 2 : }
24 :
25 2 : ~SearchPatternsTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
26 :
27 : int baseVersion;
28 : };
29 :
30 : SearchPatternsTestData fixture;
31 :
32 : BOOST_AUTO_TEST_SUITE(search_patterns_test)
33 :
34 6 : void createSearchTestData(DatabaseConfigurationInterface& ifc, int version, const std::string& prefix) {
35 6 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
36 6 : cfg->getView().version = version;
37 6 : ifc.saveActiveVersion(cfg.get());
38 :
39 6 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
40 6 : map[cfg->getConfigurationName()] = version;
41 :
42 36 : for (int i = 0; i < 5; i++) {
43 30 : std::string compName = prefix + "_" + std::to_string(i);
44 30 : ifc.storeGlobalConfiguration(map, compName);
45 30 : }
46 6 : }
47 :
48 4 : BOOST_AUTO_TEST_CASE(wildcard_only_search) {
49 2 : std::cout << "\n=== TEST 1: Wildcard only search ===\n";
50 :
51 2 : auto ifc = DatabaseConfigurationInterface();
52 :
53 2 : auto results = ifc.findAllGlobalConfigurations("*");
54 2 : std::cout << "Step 1: findAllGlobalConfigurations(\"*\") returned " << results.size() << " results\n";
55 :
56 2 : BOOST_CHECK_GE(results.size(), 0);
57 :
58 2 : std::cout << " Verified: Wildcard search returns valid results\n";
59 2 : }
60 :
61 4 : BOOST_AUTO_TEST_CASE(multiple_wildcards) {
62 2 : std::cout << "\n=== TEST 2: Multiple wildcards ===\n";
63 :
64 2 : auto ifc = DatabaseConfigurationInterface();
65 2 : int testVersion = fixture.baseVersion;
66 :
67 2 : std::string prefix = "MultiWild_" + std::to_string(fixture.baseVersion);
68 2 : createSearchTestData(ifc, testVersion, prefix);
69 2 : std::cout << "Step 1: Created compositions with prefix: " << prefix << "\n";
70 :
71 2 : std::string pattern = "*Wild*" + std::to_string(fixture.baseVersion) + "*";
72 :
73 : try {
74 2 : auto results = ifc.findAllGlobalConfigurations(pattern);
75 1 : std::cout << "Step 2: Search pattern \"" << pattern << "\" returned " << results.size() << " results\n";
76 1 : BOOST_CHECK_GE(results.size(), 0);
77 2 : } catch (std::exception& e) {
78 1 : std::cout << "Step 2: Multiple wildcards threw exception (may be provider limitation)\n";
79 1 : std::cout << " Exception: " << e.what() << "\n";
80 1 : BOOST_WARN_MESSAGE(false, "Multiple wildcards not supported by provider");
81 1 : }
82 :
83 2 : BOOST_CHECK(true);
84 2 : std::cout << " Documented: Multiple wildcards behavior\n";
85 2 : }
86 :
87 4 : BOOST_AUTO_TEST_CASE(prefix_search) {
88 2 : std::cout << "\n=== TEST 3: Prefix search ===\n";
89 :
90 2 : auto ifc = DatabaseConfigurationInterface();
91 2 : int testVersion = fixture.baseVersion + 100;
92 :
93 2 : std::string prefix = "PrefixSearch_" + std::to_string(fixture.baseVersion);
94 2 : createSearchTestData(ifc, testVersion, prefix);
95 2 : std::cout << "Step 1: Created 5 compositions with prefix: " << prefix << "\n";
96 :
97 2 : std::string pattern = prefix + "*";
98 2 : auto results = ifc.findAllGlobalConfigurations(pattern);
99 2 : std::cout << "Step 2: Search pattern \"" << pattern << "\" returned " << results.size() << " results\n";
100 :
101 2 : BOOST_CHECK_GE(results.size(), 5);
102 :
103 2 : std::cout << " Verified: Prefix search works correctly\n";
104 2 : }
105 :
106 4 : BOOST_AUTO_TEST_CASE(regex_special_chars_escaped) {
107 2 : std::cout << "\n=== TEST 4: Regex special chars escaped ===\n";
108 :
109 2 : auto ifc = DatabaseConfigurationInterface();
110 :
111 4 : std::vector<std::string> regexPatterns = {"config.name", "config[1]", "config(test)", "config^start", "config$end"};
112 :
113 2 : int safeCount = 0;
114 12 : for (const auto& pattern : regexPatterns) {
115 10 : bool handled = false;
116 : try {
117 10 : auto results = ifc.findAllGlobalConfigurations(pattern);
118 10 : handled = true;
119 10 : std::cout << " \"" << pattern << "\": returned " << results.size() << " results\n";
120 10 : } catch (std::exception& e) {
121 0 : handled = true;
122 0 : std::cout << " \"" << pattern << "\": threw (acceptable)\n";
123 0 : }
124 10 : if (handled) safeCount++;
125 : }
126 :
127 2 : std::cout << "Step 1: Handled " << safeCount << "/" << regexPatterns.size() << " patterns safely\n";
128 :
129 2 : BOOST_CHECK_EQUAL(safeCount, regexPatterns.size());
130 2 : std::cout << " Verified: Regex special characters handled safely\n";
131 2 : }
132 :
133 4 : BOOST_AUTO_TEST_CASE(sql_injection_like_patterns) {
134 2 : std::cout << "\n=== TEST 5: SQL injection like patterns ===\n";
135 :
136 2 : auto ifc = DatabaseConfigurationInterface();
137 2 : int testVersion = fixture.baseVersion + 200;
138 :
139 2 : std::string prefix = "SafeTest_" + std::to_string(fixture.baseVersion);
140 2 : createSearchTestData(ifc, testVersion, prefix);
141 :
142 : std::vector<std::string> injectionPatterns = {"'; DROP TABLE configs; --", "config' OR '1'='1", "config\"; DELETE FROM *; --", "$(rm -rf /)",
143 4 : "`ls -la`"};
144 :
145 2 : int safeCount = 0;
146 12 : for (const auto& pattern : injectionPatterns) {
147 : try {
148 10 : auto results = ifc.findAllGlobalConfigurations(pattern);
149 8 : safeCount++;
150 8 : std::cout << " \"" << pattern.substr(0, 20) << "...\": returned " << results.size() << " results (safe)\n";
151 10 : } catch (std::exception& e) {
152 2 : safeCount++;
153 2 : std::cout << " \"" << pattern.substr(0, 20) << "...\": threw (safe)\n";
154 2 : }
155 : }
156 :
157 2 : auto safeResults = ifc.findAllGlobalConfigurations(prefix + "*");
158 2 : bool dbStillWorks = (safeResults.size() >= 5);
159 2 : std::cout << "Step 1: Database still working: " << (dbStillWorks ? "yes" : "NO!") << "\n";
160 :
161 2 : BOOST_CHECK_EQUAL(safeCount, injectionPatterns.size());
162 2 : BOOST_CHECK(dbStillWorks);
163 :
164 2 : std::cout << " Verified: Injection patterns handled safely\n";
165 2 : }
166 :
167 4 : BOOST_AUTO_TEST_CASE(empty_search_behavior) {
168 2 : std::cout << "\n=== TEST 6: Empty search behavior ===\n";
169 :
170 2 : auto ifc = DatabaseConfigurationInterface();
171 :
172 4 : auto emptyResults = ifc.findAllGlobalConfigurations("");
173 2 : auto wildcardResults = ifc.findAllGlobalConfigurations("*");
174 :
175 2 : std::cout << "Step 1: Empty search returned " << emptyResults.size() << " results\n";
176 2 : std::cout << "Step 2: Wildcard search returned " << wildcardResults.size() << " results\n";
177 :
178 2 : if (emptyResults.size() == wildcardResults.size()) {
179 2 : std::cout << " Behavior: Empty search = wildcard search\n";
180 0 : } else if (emptyResults.size() == 0) {
181 0 : std::cout << " Behavior: Empty search returns no results\n";
182 : } else {
183 0 : std::cout << " Behavior: Empty search is different from wildcard\n";
184 : }
185 :
186 2 : BOOST_CHECK(true);
187 2 : std::cout << " Documented: Empty search behavior\n";
188 2 : }
189 :
190 : BOOST_AUTO_TEST_SUITE_END()
|