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  if (!db.processBulkReuser(uploadId, groupId, userId))
43  {
44  return false;
45  }
46 
47  auto reusedUploads = db.getReusedUploads(uploadId, groupId);
48  for (const auto& triple : reusedUploads)
49  {
50  ItemTreeBounds bounds;
51  if (!db.getParentItemBounds(triple.reusedUploadId, bounds))
52  continue;
53 
54  if (triple.reuseMode & REUSE_ENHANCED)
55  {
56  if (!db.processEnhancedUploadReuse(uploadId, triple.reusedUploadId,
57  groupId, triple.reusedGroupId, userId))
58  return false;
59  }
60  else
61  {
62  if (!db.processUploadReuse(uploadId, triple.reusedUploadId,
63  groupId, triple.reusedGroupId, userId))
64  return false;
65  }
66 
67  if (triple.reuseMode & REUSE_MAIN)
68  db.reuseMainLicense(uploadId, groupId, triple.reusedUploadId,
69  triple.reusedGroupId);
70 
71  if (triple.reuseMode & REUSE_CONF)
72  db.reuseConfSettings(uploadId, triple.reusedUploadId);
73 
74  if (triple.reuseMode & REUSE_COPYRIGHT)
75  db.reuseCopyrights(uploadId, triple.reusedUploadId, userId);
76  }
77  return true;
78 }
79 
80 // Test fixture
81 class ReuserScenarioTest : public CPPUNIT_NS::TestFixture
82 {
83  CPPUNIT_TEST_SUITE(ReuserScenarioTest);
84 
85  // No reuse link
88 
89  // Argument forwarding
91 
92  // Scope handling
94 
95  // Enhanced reuse
98 
99  // Multiple upload_reuse rows
101 
102  // Optional flag dispatch
103  CPPUNIT_TEST(testReuseMainLicenseFlagOnly);
104  CPPUNIT_TEST(testReuseConfFlagOnly);
105  CPPUNIT_TEST(testReuseCopyrightFlagOnly);
107 
108  CPPUNIT_TEST_SUITE_END();
109 
110 protected:
111 
119  {
121 
122  bool processUploadCalled = false;
123  db.onProcessUploadReuse =
124  [&](int, int, int, int, int) -> bool
125  { processUploadCalled = true; return true; };
126 
127  // onGetReusedUploads not set -> default returns empty vector
128  bool ok = runProcess(db, /*uploadId=*/1, /*groupId=*/3, /*userId=*/2);
129 
130  CPPUNIT_ASSERT_MESSAGE("should succeed with no reuse links", ok);
131  CPPUNIT_ASSERT_MESSAGE("processUploadReuse must not be called",
132  !processUploadCalled);
133  }
134 
143  {
145 
146  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
147  { return {{42, 3, 0}}; };
148 
149  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
150  { out = {100, "uploadtree_a", 42, 1, 100}; return true; };
151 
152  int processCalls = 0;
153  // returns true even if 0 decisions were present in the source upload
154  db.onProcessUploadReuse =
155  [&](int, int, int, int, int) -> bool
156  { ++processCalls; return true; };
157 
158  bool ok = runProcess(db, /*uploadId=*/3, /*groupId=*/3, /*userId=*/2);
159 
160  CPPUNIT_ASSERT_MESSAGE("should succeed even if source has no decisions", ok);
161  CPPUNIT_ASSERT_EQUAL_MESSAGE(
162  "processUploadReuse must be called exactly once", 1, processCalls);
163  }
164 
172  {
174 
175  const int uploadId = 3;
176  const int reusedUpload = 2;
177  const int groupId = 3;
178  const int reusedGroupId = 3;
179  const int userId = 2;
180 
181  db.onGetReusedUploads =
182  [&](int uid, int gid) -> std::vector<ReuseTriple>
183  {
184  CPPUNIT_ASSERT_EQUAL(uploadId, uid);
185  CPPUNIT_ASSERT_EQUAL(groupId, gid);
186  return {{reusedUpload, reusedGroupId, 0 /* standard reuse, ITEM scope */}};
187  };
188 
189  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
190  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
191 
192  int capturedUpload = -1;
193  int capturedReused = -1;
194  int capturedGroup = -1;
195  int capturedReusedGroup = -1;
196  int capturedUser = -1;
197 
198  db.onProcessUploadReuse =
199  [&](int u, int r, int g, int rg, int usr) -> bool
200  {
201  capturedUpload = u;
202  capturedReused = r;
203  capturedGroup = g;
204  capturedReusedGroup = rg;
205  capturedUser = usr;
206  return true;
207  };
208 
209  bool ok = runProcess(db, uploadId, groupId, userId);
210 
211  CPPUNIT_ASSERT(ok);
212  CPPUNIT_ASSERT_EQUAL(uploadId, capturedUpload);
213  CPPUNIT_ASSERT_EQUAL(reusedUpload, capturedReused);
214  CPPUNIT_ASSERT_EQUAL(groupId, capturedGroup);
215  CPPUNIT_ASSERT_EQUAL(reusedGroupId, capturedReusedGroup);
216  CPPUNIT_ASSERT_EQUAL(userId, capturedUser);
217  }
218 
227  {
229 
230  bool standardCalled = false;
231  bool enhancedCalled = false;
232 
233  // reuseMode == 0 -> no REUSE_ENHANCED -> standard path, even for REPO scope
234  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
235  { return {{2, 3, 0}}; };
236 
237  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
238  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
239 
240  db.onProcessUploadReuse =
241  [&](int, int, int, int, int) -> bool
242  { standardCalled = true; return true; };
243 
244  db.onProcessEnhancedUploadReuse =
245  [&](int, int, int, int, int) -> bool
246  { enhancedCalled = true; return true; };
247 
248  bool ok = runProcess(db, 3, 3, 2);
249 
250  CPPUNIT_ASSERT(ok);
251  CPPUNIT_ASSERT_MESSAGE("standard path for repo-scoped clearing",
252  standardCalled);
253  CPPUNIT_ASSERT_MESSAGE("enhanced path must not be used", !enhancedCalled);
254  }
255 
263  {
265 
266  bool standardCalled = false;
267  bool enhancedCalled = false;
268 
269  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
270  { return {{2, 3, REUSE_ENHANCED}}; };
271 
272  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
273  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
274 
275  db.onProcessUploadReuse =
276  [&](int, int, int, int, int) -> bool
277  { standardCalled = true; return true; };
278 
279  db.onProcessEnhancedUploadReuse =
280  [&](int, int, int, int, int) -> bool
281  { enhancedCalled = true; return true; };
282 
283  bool ok = runProcess(db, 3, 3, 2);
284 
285  CPPUNIT_ASSERT(ok);
286  CPPUNIT_ASSERT_MESSAGE("enhanced path must be taken", enhancedCalled);
287  CPPUNIT_ASSERT_MESSAGE("standard path must not be taken", !standardCalled);
288  }
289 
294  {
296 
297  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
298  { return {{2, 3, REUSE_ENHANCED}}; };
299 
300  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
301  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
302 
303  db.onProcessEnhancedUploadReuse =
304  [](int, int, int, int, int) -> bool { return false; };
305 
306  bool ok = runProcess(db, 3, 3, 2);
307 
308  CPPUNIT_ASSERT_MESSAGE("failure of enhanced reuse must propagate", !ok);
309  }
310 
318  {
320 
321  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
322  { return {{10, 3, 0}, {20, 5, 0}}; };
323 
324  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
325  { out = {1, "uploadtree_a", 0, 1, 100}; return true; };
326 
327  std::vector<int> calledWithReused;
328  db.onProcessUploadReuse =
329  [&](int, int reused, int, int, int) -> bool
330  { calledWithReused.push_back(reused); return true; };
331 
332  bool ok = runProcess(db, 1, 3, 2);
333 
334  CPPUNIT_ASSERT(ok);
335  CPPUNIT_ASSERT_EQUAL_MESSAGE("both reuse links must be processed",
336  2u, static_cast<unsigned>(calledWithReused.size()));
337  CPPUNIT_ASSERT_EQUAL(10, calledWithReused[0]);
338  CPPUNIT_ASSERT_EQUAL(20, calledWithReused[1]);
339  }
340 
347  {
349 
350  bool mainCalled = false;
351  bool confCalled = false;
352  bool copyrightCalled = false;
353 
354  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
355  { return {{2, 3, REUSE_MAIN}}; };
356 
357  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
358  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
359 
360  db.onProcessUploadReuse =
361  [](int, int, int, int, int) -> bool { return true; };
362 
363  db.onReuseMainLicense =
364  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
365 
366  db.onReuseConfSettings =
367  [&](int, int) -> bool { confCalled = true; return true; };
368 
369  db.onReuseCopyrights =
370  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
371 
372  bool ok = runProcess(db, 3, 3, 2);
373 
374  CPPUNIT_ASSERT(ok);
375  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must be called", mainCalled);
376  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
377  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
378  !copyrightCalled);
379  }
380 
387  {
389 
390  bool mainCalled = false;
391  bool confCalled = false;
392  bool copyrightCalled = false;
393 
394  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
395  { return {{2, 3, REUSE_CONF}}; };
396 
397  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
398  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
399 
400  db.onProcessUploadReuse =
401  [](int, int, int, int, int) -> bool { return true; };
402 
403  db.onReuseMainLicense =
404  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
405 
406  db.onReuseConfSettings =
407  [&](int, int) -> bool { confCalled = true; return true; };
408 
409  db.onReuseCopyrights =
410  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
411 
412  bool ok = runProcess(db, 3, 3, 2);
413 
414  CPPUNIT_ASSERT(ok);
415  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
416  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must be called", confCalled);
417  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
418  !copyrightCalled);
419  }
420 
427  {
429 
430  bool mainCalled = false;
431  bool confCalled = false;
432  bool copyrightCalled = false;
433 
434  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
435  { return {{2, 3, REUSE_COPYRIGHT}}; };
436 
437  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
438  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
439 
440  db.onProcessUploadReuse =
441  [](int, int, int, int, int) -> bool { return true; };
442 
443  db.onReuseMainLicense =
444  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
445 
446  db.onReuseConfSettings =
447  [&](int, int) -> bool { confCalled = true; return true; };
448 
449  db.onReuseCopyrights =
450  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
451 
452  bool ok = runProcess(db, 3, 3, 2);
453 
454  CPPUNIT_ASSERT(ok);
455  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
456  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
457  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must be called", copyrightCalled);
458  }
459 
467  {
469 
470  bool mainCalled = false;
471  bool confCalled = false;
472  bool copyrightCalled = false;
473  bool standardCalled = false;
474 
475  db.onGetReusedUploads = [](int, int) -> std::vector<ReuseTriple>
476  { return {{2, 3, 0 /* no flags */}}; };
477 
478  db.onGetParentItemBounds = [](int, ItemTreeBounds& out) -> bool
479  { out = {1, "uploadtree_a", 2, 1, 100}; return true; };
480 
481  db.onProcessUploadReuse =
482  [&](int, int, int, int, int) -> bool
483  { standardCalled = true; return true; };
484 
485  db.onReuseMainLicense =
486  [&](int, int, int, int) -> bool { mainCalled = true; return true; };
487 
488  db.onReuseConfSettings =
489  [&](int, int) -> bool { confCalled = true; return true; };
490 
491  db.onReuseCopyrights =
492  [&](int, int, int) -> bool { copyrightCalled = true; return true; };
493 
494  bool ok = runProcess(db, 3, 3, 2);
495 
496  CPPUNIT_ASSERT(ok);
497  CPPUNIT_ASSERT_MESSAGE("standard reuse must be called", standardCalled);
498  CPPUNIT_ASSERT_MESSAGE("reuseMainLicense must not be called", !mainCalled);
499  CPPUNIT_ASSERT_MESSAGE("reuseConfSettings must not be called", !confCalled);
500  CPPUNIT_ASSERT_MESSAGE("reuseCopyrights must not be called",
501  !copyrightCalled);
502  }
503 };
504 
505 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