Line data Source code
1 : #define BOOST_TEST_DYN_LINK
2 : #define BOOST_TEST_MODULE (VersionEdgeCases test)
3 :
4 : #include <boost/test/unit_test.hpp>
5 :
6 : #include <climits>
7 : #include <cstdlib>
8 : #include <ctime>
9 : #include <iostream>
10 : #include <memory>
11 : #include <string>
12 : #include <vector>
13 :
14 : #include "../DatabaseConfigurationInterface.h"
15 :
16 : using namespace ots;
17 :
18 : struct VersionEdgeCasesTestData {
19 2 : VersionEdgeCasesTestData() {
20 2 : srand(time(nullptr));
21 2 : baseVersion = rand() % 99999 + 100000;
22 2 : std::cout << "=== VERSION EDGE CASES TEST SUITE ===\n";
23 2 : std::cout << "Base version: " << baseVersion << "\n\n";
24 2 : }
25 :
26 2 : ~VersionEdgeCasesTestData() { std::cout << "\n=== TEST SUITE COMPLETE ===\n"; }
27 :
28 : int baseVersion;
29 : };
30 :
31 : VersionEdgeCasesTestData fixture;
32 :
33 : BOOST_AUTO_TEST_SUITE(version_edge_cases_test)
34 :
35 4 : BOOST_AUTO_TEST_CASE(version_zero_is_valid) {
36 2 : std::cout << "\n=== TEST 1: Version zero is valid ===\n";
37 :
38 2 : auto ifc = DatabaseConfigurationInterface();
39 :
40 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
41 2 : cfg->getView().version = 0;
42 :
43 2 : auto result = ifc.saveActiveVersion(cfg.get());
44 2 : std::cout << "Step 1: Save version 0 returned: " << result << "\n";
45 :
46 2 : if (result != 0) {
47 0 : std::cout << " NOTE: Version 0 may already exist from previous test runs\n";
48 0 : std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
49 0 : auto fillResult = ifc.fill(readCfg.get(), 0);
50 0 : if (fillResult == 0) {
51 0 : std::cout << " Version 0 already exists and is loadable\n";
52 0 : BOOST_CHECK(true);
53 : } else {
54 0 : std::cout << " Version 0 is rejected by the system\n";
55 0 : BOOST_WARN_MESSAGE(false, "Version 0 may not be supported");
56 : }
57 0 : } else {
58 2 : auto versions = ifc.getVersions(cfg.get());
59 2 : bool found = (versions.find(0) != versions.end());
60 2 : std::cout << "Step 2: Version 0 found in getVersions: " << (found ? "yes" : "no") << "\n";
61 2 : BOOST_CHECK(found);
62 2 : }
63 :
64 2 : std::cout << " Documented: Version 0 behavior\n";
65 2 : }
66 :
67 4 : BOOST_AUTO_TEST_CASE(negative_version_handling) {
68 2 : std::cout << "\n=== TEST 2: Negative version handling ===\n";
69 :
70 2 : auto ifc = DatabaseConfigurationInterface();
71 :
72 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
73 2 : cfg->getView().version = -1;
74 :
75 2 : auto result = ifc.saveActiveVersion(cfg.get());
76 2 : std::cout << "Step 1: Save version -1 returned: " << result << "\n";
77 :
78 2 : if (result == 0) {
79 2 : std::cout << " NOTE: Negative versions are accepted by the system\n";
80 2 : BOOST_WARN_MESSAGE(false, "Negative versions are accepted - may need validation");
81 :
82 2 : auto versions = ifc.getVersions(cfg.get());
83 2 : bool found = (versions.find(-1) != versions.end());
84 2 : std::cout << "Step 2: Version -1 found in getVersions: " << (found ? "yes" : "no") << "\n";
85 2 : } else {
86 0 : std::cout << " OK: Negative versions are rejected\n";
87 : }
88 :
89 2 : BOOST_CHECK(true);
90 2 : std::cout << " Documented: Negative version behavior\n";
91 2 : }
92 :
93 4 : BOOST_AUTO_TEST_CASE(max_int_version) {
94 2 : std::cout << "\n=== TEST 3: Maximum integer version ===\n";
95 :
96 2 : auto ifc = DatabaseConfigurationInterface();
97 :
98 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
99 2 : cfg->getView().version = INT_MAX;
100 2 : std::cout << "Using INT_MAX = " << INT_MAX << "\n";
101 :
102 2 : auto result = ifc.saveActiveVersion(cfg.get());
103 2 : std::cout << "Step 1: Save version INT_MAX returned: " << result << "\n";
104 :
105 2 : if (result == 0) {
106 2 : std::cout << " INT_MAX version accepted\n";
107 2 : auto versions = ifc.getVersions(cfg.get());
108 2 : bool found = (versions.find(INT_MAX) != versions.end());
109 2 : std::cout << "Step 2: INT_MAX found in getVersions: " << (found ? "yes" : "no") << "\n";
110 2 : } else {
111 0 : std::cout << " INT_MAX version rejected (acceptable)\n";
112 : }
113 :
114 2 : BOOST_CHECK(true);
115 2 : std::cout << " Verified: INT_MAX handled without crash\n";
116 2 : }
117 :
118 4 : BOOST_AUTO_TEST_CASE(version_gap_findlatest_correct) {
119 2 : std::cout << "\n=== TEST 4: Version gap findLatest correct ===\n";
120 :
121 2 : auto ifc = DatabaseConfigurationInterface();
122 2 : int baseV = fixture.baseVersion + 1000;
123 :
124 4 : std::vector<int> versions = {baseV + 1, baseV + 5, baseV + 10, baseV + 100};
125 :
126 10 : for (int v : versions) {
127 8 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
128 8 : cfg->getView().version = v;
129 8 : auto result = ifc.saveActiveVersion(cfg.get());
130 8 : BOOST_REQUIRE_EQUAL(result, 0);
131 8 : }
132 2 : std::cout << "Step 1: Created versions with gaps: " << versions[0] << ", " << versions[1] << ", " << versions[2] << ", " << versions[3] << "\n";
133 :
134 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
135 2 : auto latest = ifc.findLatestVersion(cfg.get());
136 2 : std::cout << "Step 2: findLatestVersion returned: " << latest << "\n";
137 :
138 2 : BOOST_CHECK_GE(latest, baseV + 100);
139 2 : std::cout << " Verified: findLatestVersion works correctly with gaps\n";
140 2 : }
141 :
142 4 : BOOST_AUTO_TEST_CASE(version_ordering_not_insertion_order) {
143 2 : std::cout << "\n=== TEST 5: Version ordering not insertion order ===\n";
144 :
145 2 : auto ifc = DatabaseConfigurationInterface();
146 2 : int baseV = fixture.baseVersion + 2000;
147 :
148 4 : std::vector<int> insertOrder = {baseV + 50, baseV + 10, baseV + 30, baseV + 20};
149 :
150 10 : for (int v : insertOrder) {
151 8 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
152 8 : cfg->getView().version = v;
153 8 : auto result = ifc.saveActiveVersion(cfg.get());
154 8 : BOOST_REQUIRE_EQUAL(result, 0);
155 8 : }
156 2 : std::cout << "Step 1: Inserted versions in order: " << insertOrder[0] << ", " << insertOrder[1] << ", " << insertOrder[2] << ", " << insertOrder[3]
157 2 : << "\n";
158 :
159 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
160 2 : auto latest = ifc.findLatestVersion(cfg.get());
161 2 : std::cout << "Step 2: findLatestVersion returned: " << latest << " (expected >= " << baseV + 50 << ")\n";
162 :
163 2 : BOOST_CHECK_GE(latest, baseV + 50);
164 2 : std::cout << " Verified: findLatestVersion uses numeric ordering, not insertion order\n";
165 2 : }
166 :
167 4 : BOOST_AUTO_TEST_CASE(getversions_returns_sorted) {
168 2 : std::cout << "\n=== TEST 6: getVersions returns sorted ===\n";
169 :
170 2 : auto ifc = DatabaseConfigurationInterface();
171 2 : int baseV = fixture.baseVersion + 3000;
172 :
173 4 : std::vector<int> insertOrder = {baseV + 100, baseV + 1, baseV + 50, baseV + 25, baseV + 75};
174 :
175 12 : for (int v : insertOrder) {
176 10 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
177 10 : cfg->getView().version = v;
178 10 : auto result = ifc.saveActiveVersion(cfg.get());
179 10 : BOOST_REQUIRE_EQUAL(result, 0);
180 10 : }
181 2 : std::cout << "Step 1: Inserted " << insertOrder.size() << " versions in random order\n";
182 :
183 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
184 2 : auto versions = ifc.getVersions(cfg.get());
185 :
186 2 : std::vector<int> foundVersions;
187 12 : for (int v : insertOrder) {
188 10 : if (versions.find(v) != versions.end()) {
189 10 : foundVersions.push_back(v);
190 : }
191 : }
192 :
193 2 : std::cout << "Step 2: Found " << foundVersions.size() << "/" << insertOrder.size() << " inserted versions\n";
194 2 : BOOST_CHECK_EQUAL(foundVersions.size(), insertOrder.size());
195 :
196 2 : int prev = INT_MIN;
197 2 : bool isSorted = true;
198 34 : for (int v : versions) {
199 32 : if (v < prev) {
200 0 : isSorted = false;
201 0 : break;
202 : }
203 32 : prev = v;
204 : }
205 :
206 2 : std::cout << "Step 3: All versions sorted: " << (isSorted ? "yes" : "no") << "\n";
207 2 : BOOST_CHECK(isSorted);
208 :
209 2 : std::cout << " Verified: getVersions returns sorted set\n";
210 2 : }
211 :
212 4 : BOOST_AUTO_TEST_CASE(same_version_different_data_overwrite) {
213 2 : std::cout << "\n=== TEST 7: Same version different data overwrite ===\n";
214 :
215 2 : auto ifc = DatabaseConfigurationInterface();
216 2 : int testVersion = fixture.baseVersion + 4000;
217 :
218 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
219 2 : cfg->getView().version = testVersion;
220 4 : cfg->getView().fillFromJSON("{\"data\": \"original_value_12345\"}");
221 2 : auto result1 = ifc.saveActiveVersion(cfg.get());
222 2 : BOOST_REQUIRE_EQUAL(result1, 0);
223 2 : std::cout << "Step 1: Saved version " << testVersion << " with original data\n";
224 :
225 4 : cfg->getView().fillFromJSON("{\"data\": \"updated_value_67890\"}");
226 2 : auto result2 = ifc.saveActiveVersion(cfg.get(), true);
227 2 : BOOST_CHECK_EQUAL(result2, 0);
228 2 : std::cout << "Step 2: Overwrote with updated data, result: " << result2 << "\n";
229 :
230 2 : std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
231 2 : auto fillResult = ifc.fill(readCfg.get(), testVersion);
232 2 : BOOST_REQUIRE_EQUAL(fillResult, 0);
233 :
234 2 : bool hasUpdated = (readCfg->getView()._json.find("updated_value_67890") != std::string::npos);
235 2 : bool hasOriginal = (readCfg->getView()._json.find("original_value_12345") != std::string::npos);
236 2 : std::cout << "Step 3: Loaded data contains updated: " << (hasUpdated ? "yes" : "no") << ", original: " << (hasOriginal ? "yes" : "no") << "\n";
237 :
238 2 : BOOST_CHECK(hasUpdated);
239 2 : BOOST_CHECK(!hasOriginal);
240 2 : std::cout << " Verified: Overwrite replaces data correctly\n";
241 2 : }
242 :
243 4 : BOOST_AUTO_TEST_CASE(version_one_million) {
244 2 : std::cout << "\n=== TEST 8: Version one million ===\n";
245 :
246 2 : auto ifc = DatabaseConfigurationInterface();
247 :
248 2 : int largeVersion = fixture.baseVersion + 1000000;
249 2 : std::cout << "Using version: " << largeVersion << "\n";
250 :
251 2 : std::shared_ptr<ConfigurationBase> cfg = std::make_shared<TestConfiguration001>();
252 2 : cfg->getView().version = largeVersion;
253 :
254 2 : auto result = ifc.saveActiveVersion(cfg.get());
255 2 : std::cout << "Step 1: Save version " << largeVersion << " returned: " << result << "\n";
256 2 : BOOST_CHECK_EQUAL(result, 0);
257 :
258 2 : std::shared_ptr<ConfigurationBase> readCfg = std::make_shared<TestConfiguration001>();
259 2 : auto fillResult = ifc.fill(readCfg.get(), largeVersion);
260 2 : std::cout << "Step 2: fill() for version " << largeVersion << " returned: " << fillResult << "\n";
261 2 : BOOST_CHECK_EQUAL(fillResult, 0);
262 :
263 2 : std::cout << " Verified: Large version numbers work correctly\n";
264 2 : }
265 :
266 : BOOST_AUTO_TEST_SUITE_END()
|