FOSSology  4.7.1
Open Source License Compliance by Open Source Software
test_report_output.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2026 Krrish Biswas <krrishbiswas175@gmail.com>
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
13 namespace Fossology\Lib\Data {
14  class LicenseRef
15  {
16  const SPDXREF_PREFIX = "LicenseRef-";
17  }
18 }
19 
20 namespace {
21 
22  if (!function_exists('uuid_create')) {
23  define('UUID_TYPE_TIME', 1);
24  function uuid_create($type = UUID_TYPE_TIME)
25  {
26  return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
27  mt_rand(0, 0xffff), mt_rand(0, 0xffff),
28  mt_rand(0, 0xffff),
29  mt_rand(0, 0x0fff) | 0x4000,
30  mt_rand(0, 0x3fff) | 0x8000,
31  mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
32  );
33  }
34  }
35 
36  require_once __DIR__ . '/../agent/reportgenerator.php';
37 
39 
40  $generator = new BomReportGenerator();
41  $passed = 0;
42  $failed = 0;
43 
44  function assert_test($name, $condition, $detail = '')
45  {
46  global $passed, $failed;
47  if ($condition) {
48  echo " PASS: $name\n";
49  $passed++;
50  } else {
51  echo " FAIL: $name" . ($detail ? " -- $detail" : "") . "\n";
52  $failed++;
53  }
54  }
55 
56  echo "\n=== CycloneDX BomReportGenerator Tests ===\n\n";
57 
58  echo "Test 1: License with text content\n";
59  $licenseData = array(
60  'id' => 'MIT',
61  'name' => 'MIT License',
62  'url' => 'https://opensource.org/licenses/MIT',
63  'textContent' => base64_encode('Permission is hereby granted, free of charge...'),
64  'textContentType' => 'text/plain'
65  );
66  $result = $generator->createLicense($licenseData);
67 
68  assert_test('License has license key', isset($result['license']));
69  assert_test('License id is MIT', $result['license']['id'] === 'MIT');
70  assert_test('License has url', $result['license']['url'] === 'https://opensource.org/licenses/MIT');
71  assert_test('License has text block', isset($result['license']['text']));
72  assert_test('License text has content', isset($result['license']['text']['content']));
73  assert_test('License text contentType is text/plain', $result['license']['text']['contentType'] === 'text/plain');
74  assert_test('License text encoding is base64', $result['license']['text']['encoding'] === 'base64');
75  assert_test('License text decodes correctly',
76  base64_decode($result['license']['text']['content']) === 'Permission is hereby granted, free of charge...');
77 
78  echo "\n";
79 
80  echo "Test 2: License without text content\n";
81  $licenseDataNoText = array(
82  'id' => 'Apache-2.0',
83  'name' => 'Apache License 2.0',
84  'url' => 'https://www.apache.org/licenses/LICENSE-2.0'
85  );
86  $result2 = $generator->createLicense($licenseDataNoText);
87 
88  assert_test('License has license key', isset($result2['license']));
89  assert_test('License id is Apache-2.0', $result2['license']['id'] === 'Apache-2.0');
90  assert_test('License has NO text block', !isset($result2['license']['text']));
91 
92  echo "\n";
93 
94  echo "Test 3: LicenseRef expression\n";
95  $licenseRef = array(
96  'id' => 'LicenseRef-fossology-custom',
97  'name' => 'Custom License'
98  );
99  $result3 = $generator->createLicense($licenseRef);
100 
101  assert_test('LicenseRef returns expression', isset($result3['expression']));
102  assert_test('Expression value correct', $result3['expression'] === 'LicenseRef-fossology-custom');
103  assert_test('LicenseRef has NO license key', !isset($result3['license']));
104 
105  echo "\n";
106 
107  echo "Test 4: Component with copyright\n";
108  $componentData = array(
109  'type' => 'library',
110  'name' => 'openssl-3.0.12.tar.gz',
111  'bomref' => '42',
112  'scope' => 'required',
113  'mimeType' => 'application/gzip',
114  'copyright' => "Copyright 2000-2023 The OpenSSL Project Authors\nCopyright 1995-2023 Eric A. Young, Tim J. Hudson",
115  'hashes' => array(
116  $generator->createHash('SHA-1', 'abc123'),
117  $generator->createHash('MD5', 'def456')
118  ),
119  'licenses' => array($result)
120  );
121  $comp = $generator->createComponent($componentData);
122 
123  assert_test('Component has type', $comp['type'] === 'library');
124  assert_test('Component has name', $comp['name'] === 'openssl-3.0.12.tar.gz');
125  assert_test('Component has bom-ref', $comp['bom-ref'] === '42');
126  assert_test('Component has copyright', isset($comp['copyright']));
127  assert_test('Copyright contains OpenSSL', strpos($comp['copyright'], 'OpenSSL') !== false);
128  assert_test('Copyright contains both entries', strpos($comp['copyright'], 'Eric A. Young') !== false);
129  assert_test('Component has hashes', count($comp['hashes']) === 2);
130  assert_test('Component has licenses', count($comp['licenses']) === 1);
131 
132  echo "\n";
133 
134  echo "Test 5: Component without copyright\n";
135  $compNoCopyright = $generator->createComponent(array(
136  'type' => 'file',
137  'name' => 'README.md'
138  ));
139 
140  assert_test('Component without copyright has no copyright key', !isset($compNoCopyright['copyright']));
141 
142  echo "\n";
143 
144  echo "Test 6: Full report structure\n";
145  $fileComponent = $generator->createComponent(array(
146  'type' => 'file',
147  'name' => 'src/main.c',
148  'bomref' => '42-100',
149  'copyright' => 'Copyright 2023 Test Author',
150  'hashes' => array($generator->createHash('SHA-1', 'aaa')),
151  'licenses' => array($result)
152  ));
153 
154  $report = $generator->generateReport(array(
155  'tool-version' => '4.5.0',
156  'maincomponent' => $comp,
157  'components' => array($fileComponent)
158  ));
159 
160  assert_test('Report bomFormat is CycloneDX', $report['bomFormat'] === 'CycloneDX');
161  assert_test('Report specVersion is 1.7', $report['specVersion'] === '1.7');
162  assert_test('Report version is integer 1', $report['version'] === 1);
163  assert_test('Report has serialNumber', !empty($report['serialNumber']));
164  assert_test('Report has metadata', isset($report['metadata']));
165  assert_test('Report metadata has tools', isset($report['metadata']['tools']));
166  assert_test('Tool manufacturer is FOSSology',
167  $report['metadata']['tools']['components'][0]['manufacturer']['name'] === 'FOSSology');
168  assert_test('Tool has no vendor', !isset($report['metadata']['tools']['components'][0]['vendor']));
169  assert_test('Tool version is 4.5.0', $report['metadata']['tools']['components'][0]['version'] === '4.5.0');
170  assert_test('Metadata has main component', isset($report['metadata']['component']));
171  assert_test('Main component has copyright', isset($report['metadata']['component']['copyright']));
172  assert_test('Report has components array', is_array($report['components']));
173  assert_test('Components count is 1', count($report['components']) === 1);
174  assert_test('File component has copyright', isset($report['components'][0]['copyright']));
175  assert_test('Report has no externalReferences when not provided', !isset($report['externalReferences']));
176 
177  echo "\n";
178 
179  echo "Test 7: JSON validity\n";
180  $json = json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
181  assert_test('JSON encodes without error', json_last_error() === JSON_ERROR_NONE);
182  assert_test('JSON is not empty', strlen($json) > 100);
183 
184  $decoded = json_decode($json, true);
185  assert_test('JSON round-trip preserves bomFormat', $decoded['bomFormat'] === 'CycloneDX');
186  assert_test('JSON round-trip preserves license text',
187  isset($decoded['metadata']['component']['licenses'][0]['license']['text']['content']));
188 
189  echo "\n";
190 
191  echo "Test 8: Component with version\n";
192  $compWithVersion = $generator->createComponent(array(
193  'type' => 'library',
194  'name' => 'busybox',
195  'version' => '1.36.1'
196  ));
197 
198  assert_test('Component has version', isset($compWithVersion['version']));
199  assert_test('Version value is correct', $compWithVersion['version'] === '1.36.1');
200 
201  $compNoVersion = $generator->createComponent(array(
202  'type' => 'library',
203  'name' => 'busybox',
204  'version' => ''
205  ));
206  assert_test('Empty version is not included', !isset($compNoVersion['version']));
207 
208  echo "\n";
209 
210  echo "Test 9: Component with purl\n";
211  $compWithPurl = $generator->createComponent(array(
212  'type' => 'library',
213  'name' => 'busybox',
214  'purl' => 'pkg:deb/debian/busybox@1.36.1'
215  ));
216 
217  assert_test('Component has purl', isset($compWithPurl['purl']));
218  assert_test('PURL value is correct', $compWithPurl['purl'] === 'pkg:deb/debian/busybox@1.36.1');
219 
220  $compNoPurl = $generator->createComponent(array(
221  'type' => 'library',
222  'name' => 'busybox',
223  'purl' => ''
224  ));
225  assert_test('Empty purl is not included', !isset($compNoPurl['purl']));
226 
227  echo "\n";
228 
229  echo "Test 10: Component with description\n";
230  $compWithDesc = $generator->createComponent(array(
231  'type' => 'library',
232  'name' => 'openssl',
233  'description' => 'Open source SSL/TLS toolkit'
234  ));
235 
236  assert_test('Component has description', isset($compWithDesc['description']));
237  assert_test('Description value is correct', $compWithDesc['description'] === 'Open source SSL/TLS toolkit');
238 
239  $compNoDesc = $generator->createComponent(array(
240  'type' => 'library',
241  'name' => 'openssl',
242  'description' => ''
243  ));
244  assert_test('Empty description is not included', !isset($compNoDesc['description']));
245 
246  echo "\n";
247 
248  echo "Test 11: Component with properties (acknowledgements + comments)\n";
249  $compWithProps = $generator->createComponent(array(
250  'type' => 'file',
251  'name' => 'src/main.c',
252  'acknowledgements' => "Thanks to the OpenSSL team\nThanks to contributors",
253  'comments' => 'Reviewed and approved by legal team'
254  ));
255 
256  assert_test('Component has properties', isset($compWithProps['properties']));
257  assert_test('Properties has 2 entries', count($compWithProps['properties']) === 2);
258  assert_test('First property is acknowledgement',
259  $compWithProps['properties'][0]['name'] === 'fossology:acknowledgement');
260  assert_test('Acknowledgement value is correct',
261  strpos($compWithProps['properties'][0]['value'], 'OpenSSL') !== false);
262  assert_test('Second property is comment',
263  $compWithProps['properties'][1]['name'] === 'fossology:comment');
264  assert_test('Comment value is correct',
265  $compWithProps['properties'][1]['value'] === 'Reviewed and approved by legal team');
266 
267  $compOnlyAck = $generator->createComponent(array(
268  'type' => 'file',
269  'name' => 'src/util.c',
270  'acknowledgements' => 'Thanks to maintainers',
271  'comments' => ''
272  ));
273  assert_test('Only acknowledgement property when comments empty', count($compOnlyAck['properties']) === 1);
274  assert_test('Single property is acknowledgement',
275  $compOnlyAck['properties'][0]['name'] === 'fossology:acknowledgement');
276 
277  $compNoProps = $generator->createComponent(array(
278  'type' => 'file',
279  'name' => 'src/test.c',
280  'acknowledgements' => '',
281  'comments' => ''
282  ));
283  assert_test('No properties when both empty', !isset($compNoProps['properties']));
284 
285  echo "\n";
286 
287  echo "Test 12: Component with externalReferences\n";
288  $compWithExtRef = $generator->createComponent(array(
289  'type' => 'library',
290  'name' => 'openssl',
291  'externalReferences' => [
292  ['type' => 'distribution', 'url' => 'https://www.openssl.org/source/openssl-3.0.12.tar.gz'],
293  ['type' => 'vcs', 'url' => 'https://github.com/openssl/openssl']
294  ]
295  ));
296 
297  assert_test('Component has externalReferences', isset($compWithExtRef['externalReferences']));
298  assert_test('ExternalReferences has 2 entries', count($compWithExtRef['externalReferences']) === 2);
299  assert_test('First ref type is distribution',
300  $compWithExtRef['externalReferences'][0]['type'] === 'distribution');
301  assert_test('First ref url is correct',
302  $compWithExtRef['externalReferences'][0]['url'] === 'https://www.openssl.org/source/openssl-3.0.12.tar.gz');
303 
304  $compNoExtRef = $generator->createComponent(array(
305  'type' => 'library',
306  'name' => 'openssl',
307  'externalReferences' => []
308  ));
309  assert_test('Empty externalReferences is not included', !isset($compNoExtRef['externalReferences']));
310 
311  echo "\n";
312 
313  echo "Test 13: Full report with externalReferences\n";
314  $reportWithExtRef = $generator->generateReport(array(
315  'tool-version' => '4.5.0',
316  'maincomponent' => $comp,
317  'components' => array($fileComponent),
318  'externalReferences' => [
319  ['type' => 'website', 'url' => 'https://www.fossology.org']
320  ]
321  ));
322 
323  assert_test('Report has externalReferences', isset($reportWithExtRef['externalReferences']));
324  assert_test('Report externalReferences has 1 entry', count($reportWithExtRef['externalReferences']) === 1);
325  assert_test('Report externalRef type is website',
326  $reportWithExtRef['externalReferences'][0]['type'] === 'website');
327 
328  echo "\n";
329 
330  echo "Test 14: Full component with all new fields\n";
331  $fullComp = $generator->createComponent(array(
332  'type' => 'library',
333  'name' => 'busybox',
334  'version' => '1.36.1',
335  'bomref' => '99',
336  'scope' => 'required',
337  'mimeType' => 'application/x-tar',
338  'copyright' => 'Copyright 2023 BusyBox Authors',
339  'description' => 'Tiny utilities for small and embedded systems',
340  'purl' => 'pkg:generic/busybox@1.36.1',
341  'hashes' => array($generator->createHash('SHA-256', 'abc123def456')),
342  'licenses' => array($result),
343  'externalReferences' => [
344  ['type' => 'vcs', 'url' => 'https://git.busybox.net/busybox/']
345  ],
346  'acknowledgements' => 'Thanks to Denys Vlasenko',
347  'comments' => 'Primary build dependency'
348  ));
349 
350  assert_test('Full component has type', $fullComp['type'] === 'library');
351  assert_test('Full component has name', $fullComp['name'] === 'busybox');
352  assert_test('Full component has version', $fullComp['version'] === '1.36.1');
353  assert_test('Full component has bom-ref', $fullComp['bom-ref'] === '99');
354  assert_test('Full component has purl', $fullComp['purl'] === 'pkg:generic/busybox@1.36.1');
355  assert_test('Full component has description',
356  $fullComp['description'] === 'Tiny utilities for small and embedded systems');
357  assert_test('Full component has copyright', isset($fullComp['copyright']));
358  assert_test('Full component has hashes', count($fullComp['hashes']) === 1);
359  assert_test('Full component has licenses', count($fullComp['licenses']) === 1);
360  assert_test('Full component has externalReferences', count($fullComp['externalReferences']) === 1);
361  assert_test('Full component has properties', count($fullComp['properties']) === 2);
362 
363  echo "\n";
364 
365  echo "Test 15: LicenseRef expression with bom-ref and acknowledgement\n";
366  $licenseRefWithRef = $generator->createLicense(array(
367  'id' => 'LicenseRef-fossology-BSD-style',
368  'bom-ref' => 'lic-scanner-320-42',
369  'acknowledgement' => 'declared'
370  ));
371 
372  assert_test('Expression value correct',
373  $licenseRefWithRef['expression'] === 'LicenseRef-fossology-BSD-style');
374  assert_test('Expression has bom-ref', $licenseRefWithRef['bom-ref'] === 'lic-scanner-320-42');
375  assert_test('Expression has acknowledgement', $licenseRefWithRef['acknowledgement'] === 'declared');
376  assert_test('Expression has only schema keys',
377  array_keys($licenseRefWithRef) === array('expression', 'bom-ref', 'acknowledgement'));
378 
379  echo "\n";
380 
381  echo "=== Results ===\n";
382  echo "Passed: $passed | Failed: $failed\n";
383 
384  if ($failed > 0) {
385  echo "\nSome tests FAILED!\n";
386  exit(1);
387  } else {
388  echo "\nAll tests passed!\n";
389  exit(0);
390  }
391 
392 } // end namespace