FOSSology  4.7.1
Open Source License Compliance by Open Source Software
test_scenarios.cc
Go to the documentation of this file.
1 /*
2  SPDX-License-Identifier: GPL-2.0-only
3  Author: Dietmar Helmut Leher <helmut.leher.ext@vaillant-group.com>
4  SPDX-FileCopyrightText: © 2026 Vaillant GmbH
5 */
29 #include <cppunit/TestFixture.h>
30 #include <cppunit/extensions/HelperMacros.h>
31 
33 #include "ReuserState.hpp"
34 #include "ReuserTypes.hpp"
35 
36 // Minimal replica of processUploadId without scheduler dependency
37 // Accepts groupId / userId explicitly so tests remain self-contained.
38 // Mirrors the helper defined in test_worker.cc.
39 static bool runProcess(ReuserDatabaseHandler& db, int uploadId,
40  int groupId, int userId)
41 {
42  auto reusedUploads = db.getReusedUploads(uploadId, groupId);
43  for (const auto& triple : reusedUploads)
44  {
45  ItemTreeBounds bounds;
46  if (!db.getParentItemBounds(triple.reusedUploadId, bounds))
47  continue;
48 
49  if (triple.reuseMode & REUSE_ENHANCED)
50  {
51  if (!db.processEnhancedUploadReuse(uploadId, triple.reusedUploadId,
52  groupId, triple.reusedGroupId, userId))
53  return false;
54  }
55  else
56  {
57  if (!db.processUploadReuse(uploadId, triple.reusedUploadId,
58  groupId, triple.reusedGroupId, userId))
59  return false;
60  }
61 
62  if (triple.reuseMode & REUSE_MAIN)
63  db.reuseMainLicense(uploadId, groupId, triple.reusedUploadId,
64  triple.reusedGroupId);
65 
66  if (triple.reuseMode & REUSE_CONF)
67  db.reuseConfSettings(uploadId, triple.reusedUploadId);
68 
69  if (triple.reuseMode & REUSE_COPYRIGHT)
70  db.reuseCopyrights(uploadId, triple.reusedUploadId, userId);
71  }
72  return true;
73 }
74 
75 // Test fixture
76 class ReuserScenarioTest : public CPPUNIT_NS::TestFixture
77 {
78  CPPUNIT_TEST_SUITE(ReuserScenarioTest);
79 
80  // No reuse link
83 
84  // Argument forwarding
86 
87  // Scope handling
89 
90  // Enhanced reuse
93 
94  // Multiple upload_reuse rows
96 
97  // Optional flag dispatch
98  CPPUNIT_TEST(testReuseMainLicenseFlagOnly);
99  CPPUNIT_TEST(testReuseConfFlagOnly);
100  CPPUNIT_TEST(testReuseCopyrightFlagOnly);
102 
103  CPPUNIT_TEST_SUITE_END();
104 
105 protected:
106 
114  {
116 
117  bool processUploadCalled = false;
118  db.onProcessUploadReuse =
119  [&](int, int, int, int, int) -> bool
120  { processUploadCalled = true; return true; };
121 
122  // onGetReusedUploads not set -> default returns empty vector
123  bool ok = runProcess(db, /*uploadId=*/1, /*groupId=*/3, /*userId=*/2);
124 
125  CPPUNIT_ASSERT_MESSAGE("should succeed with no reuse links", ok);
126  CPPUNIT_ASSERT_MESSAGE("processUploadReuse must not be called",
127  !processUploadCalled);
128  }
129 
138  {
140 
141  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
142  { return {{42, 3, 0}}; };
143 
144  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
145  { out = {100, "uploadtree_a", 42, 1, 100}; return true; };
146 
147  int processCalls = 0;
148  // returns true even if 0 decisions were present in the source upload
149  db.onProcessUploadReuse =
150  [&](int, int, int, int, int) -> bool
151  { ++processCalls; return true; };
152 
153  bool ok = runProcess(db, /*uploadId=*/3, /*groupId=*/3, /*userId=*/2);
154 
155  CPPUNIT_ASSERT_MESSAGE("should succeed even if source has no decisions", ok);
156  CPPUNIT_ASSERT_EQUAL_MESSAGE(
157  "processUploadReuse must be called exactly once", 1, processCalls);
158  }
159 
167  {
169 
170  const int uploadId = 3;
171  const int reusedUpload = 2;
172  const int groupId = 3;
173  const int reusedGroupId = 3;
174  const int userId = 2;
175 
176  db.onGetReusedUploads =
177  [&](int uid, int gid) -> std::vector<ReuseTriple>
178  {
179  CPPUNIT_ASSERT_EQUAL(uploadId, uid);
180  CPPUNIT_ASSERT_EQUAL(groupId, gid);
181  return {{reusedUpload, reusedGroupId, 0 /* standard reuse, ITEM scope */}};
182  };
183 
184  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
185  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
186 
187  int capturedUpload = -1;
188  int capturedReused = -1;
189  int capturedGroup = -1;
190  int capturedReusedGroup = -1;
191  int capturedUser = -1;
192 
193  db.onProcessUploadReuse =
194  [&](int u, int r, int g, int rg, int usr) -> bool
195  {
196  capturedUpload = u;
197  capturedReused = r;
198  capturedGroup = g;
199  capturedReusedGroup = rg;
200  capturedUser = usr;
201  return true;
202  };
203 
204  bool ok = runProcess(db, uploadId, groupId, userId);
205 
206  CPPUNIT_ASSERT(ok);
207  CPPUNIT_ASSERT_EQUAL(uploadId, capturedUpload);
208  CPPUNIT_ASSERT_EQUAL(reusedUpload, capturedReused);
209  CPPUNIT_ASSERT_EQUAL(groupId, capturedGroup);
210  CPPUNIT_ASSERT_EQUAL(reusedGroupId, capturedReusedGroup);
211  CPPUNIT_ASSERT_EQUAL(userId, capturedUser);
212  }
213 
222  {
224 
225  bool standardCalled = false;
226  bool enhancedCalled = false;
227 
228  // reuseMode == 0 -> no REUSE_ENHANCED -> standard path, even for REPO scope
229  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
230  { return {{2, 3, 0}}; };
231 
232  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
233  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
234 
235  db.onProcessUploadReuse =
236  [&](int, int, int, int, int) -> bool
237  { standardCalled = true; return true; };
238 
239  db.onProcessEnhancedUploadReuse =
240  [&](int, int, int, int, int) -> bool
241  { enhancedCalled = true; return true; };
242 
243  bool ok = runProcess(db, 3, 3, 2);
244 
245  CPPUNIT_ASSERT(ok);
246  CPPUNIT_ASSERT_MESSAGE("standard path for repo-scoped clearing",
247  standardCalled);
248  CPPUNIT_ASSERT_MESSAGE("enhanced path must not be used", !enhancedCalled);
249  }
250 
258  {
260 
261  bool standardCalled = false;
262  bool enhancedCalled = false;
263 
264  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
265  { return {{2, 3, REUSE_ENHANCED}}; };
266 
267  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
268  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
269 
270  db.onProcessUploadReuse =
271  [&](int, int, int, int, int) -> bool
272  { standardCalled = true; return true; };
273 
274  db.onProcessEnhancedUploadReuse =
275  [&](int, int, int, int, int) -> bool
276  { enhancedCalled = true; return true; };
277 
278  bool ok = runProcess(db, 3, 3, 2);
279 
280  CPPUNIT_ASSERT(ok);
281  CPPUNIT_ASSERT_MESSAGE("enhanced path must be taken", enhancedCalled);
282  CPPUNIT_ASSERT_MESSAGE("standard path must not be taken", !standardCalled);
283  }
284 
289  {
291 
292  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
293  { return {{2, 3, REUSE_ENHANCED}}; };
294 
295  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
296  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
297 
298  db.onProcessEnhancedUploadReuse =
299  [](int, int, int, int, int) -> bool { return false; };
300 
301  bool ok = runProcess(db, 3, 3, 2);
302 
303  CPPUNIT_ASSERT_MESSAGE("failure of enhanced reuse must propagate", !ok);
304  }
305 
313  {
315 
316  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
317  { return {{10, 3, 0}, {20, 5, 0}}; };
318 
319  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
320  { out = {1, "uploadtree_a", 0, 1, 100}; return true; };
321 
322  std::vector<int> calledWithReused;
323  db.onProcessUploadReuse =
324  [&](int, int reused, int, int, int) -> bool
325  { calledWithReused.push_back(reused); return true; };
326 
327  bool ok = runProcess(db, 1, 3, 2);
328 
329  CPPUNIT_ASSERT(ok);
330  CPPUNIT_ASSERT_EQUAL_MESSAGE("both reuse links must be processed",
331  2u, static_cast<unsigned>(calledWithReused.size()));
332  CPPUNIT_ASSERT_EQUAL(10, calledWithReused[0]);
333  CPPUNIT_ASSERT_EQUAL(20, calledWithReused[1]);
334  }
335 
342  {
344 
345  bool mainCalled = false;
346  bool confCalled = false;
347  bool copyrightCalled = false;
348 
349  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
350  { return {{2, 3, REUSE_MAIN}}; };
351 
352  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
353  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
354 
355  db.onProcessUploadReuse =
356  [](int, int, int, int, int) -> bool { return true; };
357 
358  db.onReuseMainLicense =
359  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
360 
361  db.onReuseConfSettings =
362  [&](int, int) -> bool { confCalled = true; return true; };
363 
364  db.onReuseCopyrights =
365  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
366 
367  bool ok = runProcess(db, 3, 3, 2);
368 
369  CPPUNIT_ASSERT(ok);
370  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must be called", mainCalled);
371  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
372  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
373  !copyrightCalled);
374  }
375 
382  {
384 
385  bool mainCalled = false;
386  bool confCalled = false;
387  bool copyrightCalled = false;
388 
389  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
390  { return {{2, 3, REUSE_CONF}}; };
391 
392  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
393  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
394 
395  db.onProcessUploadReuse =
396  [](int, int, int, int, int) -> bool { return true; };
397 
398  db.onReuseMainLicense =
399  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
400 
401  db.onReuseConfSettings =
402  [&](int, int) -> bool { confCalled = true; return true; };
403 
404  db.onReuseCopyrights =
405  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
406 
407  bool ok = runProcess(db, 3, 3, 2);
408 
409  CPPUNIT_ASSERT(ok);
410  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
411  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must be called", confCalled);
412  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
413  !copyrightCalled);
414  }
415 
422  {
424 
425  bool mainCalled = false;
426  bool confCalled = false;
427  bool copyrightCalled = false;
428 
429  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
430  { return {{2, 3, REUSE_COPYRIGHT}}; };
431 
432  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
433  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
434 
435  db.onProcessUploadReuse =
436  [](int, int, int, int, int) -> bool { return true; };
437 
438  db.onReuseMainLicense =
439  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
440 
441  db.onReuseConfSettings =
442  [&](int, int) -> bool { confCalled = true; return true; };
443 
444  db.onReuseCopyrights =
445  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
446 
447  bool ok = runProcess(db, 3, 3, 2);
448 
449  CPPUNIT_ASSERT(ok);
450  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
451  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
452  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must be called", copyrightCalled);
453  }
454 
462  {
464 
465  bool mainCalled = false;
466  bool confCalled = false;
467  bool copyrightCalled = false;
468  bool standardCalled = false;
469 
470  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
471  { return {{2, 3, 0 /* no flags */}}; };
472 
473  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
474  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
475 
476  db.onProcessUploadReuse =
477  [&](int, int, int, int, int) -> bool
478  { standardCalled = true; return true; };
479 
480  db.onReuseMainLicense =
481  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
482 
483  db.onReuseConfSettings =
484  [&](int, int) -> bool { confCalled = true; return true; };
485 
486  db.onReuseCopyrights =
487  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
488 
489  bool ok = runProcess(db, 3, 3, 2);
490 
491  CPPUNIT_ASSERT(ok);
492  CPPUNIT_ASSERT_MESSAGE("standard reuse must be called", standardCalled);
493  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
494  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
495  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
496  !copyrightCalled);
497  }
498 };
499 
500 CPPUNIT_TEST_SUITE_REGISTRATION(ReuserScenarioTest);
Mock ReuserDatabaseHandler for unit tests.
Test double for ReuserDatabaseHandler.
Database handler for the reuser agent.
void testMultipleReuseLinksAllProcessed()
All upload_reuse rows for an upload are processed in order.
void testCorrectArgumentsForwardedToProcessUploadReuse()
All five arguments are forwarded correctly to processUploadReuse.
void testOptionalFlagsNotCalledWithoutBits()
reuseMode == 0 -> only processUploadReuse is called, no optional extras.
void testEnhancedReuseUsesEnhancedPath()
REUSE_ENHANCED bit routes to processEnhancedUploadReuse.
void testNoReuseLinkSucceedsWithoutProcessing()
No upload_reuse row exists for this upload.
void testEnhancedReuseFailurePropagates()
A false return from processEnhancedUploadReuse propagates to the caller.
void testReuseMainLicenseFlagOnly()
REUSE_MAIN bit causes only reuseMainLicense to be called.
void testReuseExistsButSourceHasNoClearings()
upload_reuse row exists but the source upload has no clearing decisions.
void testRepoClearingUsesStandardReusePath()
reuseMode == 0 always takes the standard reuse path.
void testReuseConfFlagOnly()
REUSE_CONF bit causes only reuseConfSettings to be called.
void testReuseCopyrightFlagOnly()
REUSE_COPYRIGHT bit causes only reuseCopyrights to be called.
Definition: db.php:28
Bounds of an item within an uploadtree table.
Definition: ReuserTypes.hpp:14