Line data Source code
1 : #define BOOST_TEST_DYN_LINK
2 : #define BOOST_TEST_MODULE (CompositionNaming 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 CompositionNamingTestData {
18 2 : CompositionNamingTestData() {
19 2 : srand(time(nullptr));
20 2 : baseVersion = rand() % 99999 + 100000;
21 2 : std::cout << "=== COMPOSITION NAMING TEST SUITE ===\n";
22 2 : std::cout << "Base version: " << baseVersion << "\n\n";
23 2 : }
24 :
25 2 : ~CompositionNamingTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
26 :
27 : int baseVersion;
28 : };
29 :
30 : CompositionNamingTestData fixture;
31 :
32 : BOOST_AUTO_TEST_SUITE(composition_naming_test)
33 :
34 12 : void createTestVersion(DatabaseConfigurationInterface& ifc, int version) {
35 12 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
36 12 : cfg->getView().version = version;
37 12 : ifc.saveActiveVersion(cfg.get());
38 12 : }
39 :
40 4 : BOOST_AUTO_TEST_CASE(empty_composition_name_rejected) {
41 2 : std::cout << "\n=== TEST 1: Empty composition name rejected ===\n";
42 :
43 2 : auto ifc = DatabaseConfigurationInterface();
44 2 : int testVersion = fixture.baseVersion;
45 2 : createTestVersion(ifc, testVersion);
46 :
47 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
48 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
49 2 : map[cfg->getConfigurationName()] = testVersion;
50 :
51 2 : bool threwException = false;
52 : try {
53 4 : ifc.storeGlobalConfiguration(map, "");
54 2 : } catch (std::exception& e) {
55 2 : threwException = true;
56 2 : std::cout << " Exception: " << e.what() << "\n";
57 2 : }
58 :
59 2 : std::cout << "Step 1: Empty name threw exception: " << (threwException ? "yes" : "no") << "\n";
60 :
61 2 : if (!threwException) {
62 0 : BOOST_WARN_MESSAGE(false, "Empty composition name was accepted - may need validation");
63 : try {
64 0 : auto loaded = ifc.loadGlobalConfiguration("");
65 0 : std::cout << " NOTE: Empty name composition loaded successfully\n";
66 0 : } catch (...) {
67 0 : std::cout << " NOTE: Empty name composition could not be loaded\n";
68 0 : }
69 : }
70 :
71 2 : BOOST_CHECK(true);
72 2 : std::cout << " Documented: Empty name behavior\n";
73 2 : }
74 :
75 4 : BOOST_AUTO_TEST_CASE(whitespace_only_name_rejected) {
76 2 : std::cout << "\n=== TEST 2: Whitespace only name rejected ===\n";
77 :
78 2 : auto ifc = DatabaseConfigurationInterface();
79 2 : int testVersion = fixture.baseVersion + 1;
80 2 : createTestVersion(ifc, testVersion);
81 :
82 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
83 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
84 2 : map[cfg->getConfigurationName()] = testVersion;
85 :
86 2 : bool threwException = false;
87 : try {
88 4 : ifc.storeGlobalConfiguration(map, " ");
89 0 : } catch (std::exception& e) {
90 0 : threwException = true;
91 0 : std::cout << " Exception: " << e.what() << "\n";
92 0 : }
93 :
94 2 : std::cout << "Step 1: Whitespace-only name threw exception: " << (threwException ? "yes" : "no") << "\n";
95 :
96 2 : if (!threwException) {
97 2 : BOOST_WARN_MESSAGE(false, "Whitespace-only composition name was accepted");
98 : }
99 :
100 2 : BOOST_CHECK(true);
101 2 : std::cout << " Documented: Whitespace-only name behavior\n";
102 2 : }
103 :
104 4 : BOOST_AUTO_TEST_CASE(very_long_name_handling) {
105 2 : std::cout << "\n=== TEST 3: Very long name handling ===\n";
106 :
107 2 : auto ifc = DatabaseConfigurationInterface();
108 2 : int testVersion = fixture.baseVersion + 2;
109 2 : createTestVersion(ifc, testVersion);
110 :
111 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
112 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
113 2 : map[cfg->getConfigurationName()] = testVersion;
114 :
115 2 : std::string longName(500, 'x');
116 2 : longName += "_" + std::to_string(fixture.baseVersion);
117 2 : std::cout << "Step 1: Testing name with " << longName.size() << " characters\n";
118 :
119 2 : bool succeeded = false;
120 2 : bool threwException = false;
121 : try {
122 2 : ifc.storeGlobalConfiguration(map, longName);
123 2 : succeeded = true;
124 0 : } catch (std::exception& e) {
125 0 : threwException = true;
126 0 : std::cout << " Exception: " << e.what() << "\n";
127 0 : }
128 :
129 2 : std::cout << "Step 2: Long name succeeded: " << (succeeded ? "yes" : "no") << ", threw: " << (threwException ? "yes" : "no") << "\n";
130 :
131 2 : if (succeeded) {
132 : try {
133 2 : auto loaded = ifc.loadGlobalConfiguration(longName);
134 2 : std::cout << "Step 3: Long name composition loaded with " << loaded.size() << " members\n";
135 2 : BOOST_CHECK_EQUAL(loaded.size(), 1);
136 2 : } catch (std::exception& e) {
137 0 : std::cout << "Step 3: Could not load: " << e.what() << "\n";
138 0 : BOOST_WARN_MESSAGE(false, "Long name was stored but could not be loaded");
139 0 : }
140 : }
141 :
142 2 : BOOST_CHECK(true);
143 2 : std::cout << " Documented: Long name behavior\n";
144 2 : }
145 :
146 4 : BOOST_AUTO_TEST_CASE(special_characters_in_name) {
147 2 : std::cout << "\n=== TEST 4: Special characters in name ===\n";
148 :
149 2 : auto ifc = DatabaseConfigurationInterface();
150 2 : int testVersion = fixture.baseVersion + 3;
151 2 : createTestVersion(ifc, testVersion);
152 :
153 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
154 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
155 2 : map[cfg->getConfigurationName()] = testVersion;
156 :
157 : std::vector<std::pair<std::string, std::string>> specialNames = {
158 4 : {"with_underscore_" + std::to_string(fixture.baseVersion), "underscore"},
159 4 : {"with-dash-" + std::to_string(fixture.baseVersion), "dash"},
160 4 : {"with.dot." + std::to_string(fixture.baseVersion), "dot"},
161 10 : };
162 :
163 8 : for (const auto& [name, desc] : specialNames) {
164 6 : bool succeeded = false;
165 : try {
166 6 : ifc.storeGlobalConfiguration(map, name);
167 6 : succeeded = true;
168 0 : } catch (std::exception& e) {
169 0 : std::cout << " " << desc << ": rejected (" << e.what() << ")\n";
170 0 : }
171 :
172 6 : if (succeeded) {
173 6 : std::cout << " " << desc << ": accepted\n";
174 : }
175 : }
176 :
177 2 : BOOST_CHECK(true);
178 2 : std::cout << " Documented: Special character behavior\n";
179 10 : }
180 :
181 4 : BOOST_AUTO_TEST_CASE(leading_trailing_whitespace_handling) {
182 2 : std::cout << "\n=== TEST 5: Leading/trailing whitespace handling ===\n";
183 :
184 2 : auto ifc = DatabaseConfigurationInterface();
185 2 : int testVersion = fixture.baseVersion + 5;
186 2 : createTestVersion(ifc, testVersion);
187 :
188 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
189 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
190 2 : map[cfg->getConfigurationName()] = testVersion;
191 :
192 2 : std::string baseName = "TrimTest_" + std::to_string(fixture.baseVersion);
193 2 : std::string paddedName = " " + baseName + " ";
194 :
195 2 : bool succeeded = false;
196 : try {
197 2 : ifc.storeGlobalConfiguration(map, paddedName);
198 2 : succeeded = true;
199 2 : std::cout << "Step 1: Stored with padded name \"" << paddedName << "\"\n";
200 0 : } catch (std::exception& e) {
201 0 : std::cout << "Step 1: Padded name rejected: " << e.what() << "\n";
202 0 : }
203 :
204 2 : if (succeeded) {
205 : try {
206 2 : auto loaded = ifc.loadGlobalConfiguration(paddedName);
207 2 : std::cout << "Step 2a: Loaded with padded name (size=" << loaded.size() << ")\n";
208 2 : } catch (...) {
209 0 : std::cout << "Step 2a: Could not load with padded name\n";
210 0 : }
211 :
212 : try {
213 2 : auto loaded = ifc.loadGlobalConfiguration(baseName);
214 0 : std::cout << "Step 2b: Loaded with trimmed name (size=" << loaded.size() << ")\n";
215 2 : } catch (...) {
216 2 : std::cout << "Step 2b: Could not load with trimmed name\n";
217 2 : }
218 : }
219 :
220 2 : BOOST_CHECK(true);
221 2 : std::cout << " Documented: Whitespace handling behavior\n";
222 2 : }
223 :
224 4 : BOOST_AUTO_TEST_CASE(case_sensitivity_in_names) {
225 2 : std::cout << "\n=== TEST 6: Case sensitivity in names ===\n";
226 :
227 2 : auto ifc = DatabaseConfigurationInterface();
228 2 : int testVersion = fixture.baseVersion + 6;
229 2 : createTestVersion(ifc, testVersion);
230 :
231 2 : auto map = DatabaseConfigurationInterface::config_version_map_t{};
232 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
233 2 : map[cfg->getConfigurationName()] = testVersion;
234 :
235 2 : std::string lowerName = "casetest_" + std::to_string(fixture.baseVersion);
236 2 : std::string upperName = "CASETEST_" + std::to_string(fixture.baseVersion);
237 :
238 2 : ifc.storeGlobalConfiguration(map, lowerName);
239 2 : std::cout << "Step 1: Stored \"" << lowerName << "\"\n";
240 :
241 2 : bool upperSucceeded = false;
242 : try {
243 2 : ifc.storeGlobalConfiguration(map, upperName);
244 2 : upperSucceeded = true;
245 2 : std::cout << "Step 2: \"" << upperName << "\" stored as separate composition (case sensitive)\n";
246 0 : } catch (std::exception& e) {
247 0 : std::cout << "Step 2: \"" << upperName << "\" rejected (case insensitive)\n";
248 0 : }
249 :
250 2 : if (upperSucceeded) {
251 : try {
252 2 : auto loadedLower = ifc.loadGlobalConfiguration(lowerName);
253 2 : auto loadedUpper = ifc.loadGlobalConfiguration(upperName);
254 2 : std::cout << "Step 3: Both compositions exist separately\n";
255 2 : } catch (...) {
256 0 : std::cout << "Step 3: Issue loading compositions\n";
257 0 : }
258 : }
259 :
260 2 : BOOST_CHECK(true);
261 2 : std::cout << " Documented: Case sensitivity behavior\n";
262 2 : }
263 :
264 : BOOST_AUTO_TEST_SUITE_END()
|