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.4', $report['specVersion'] === '1.4');
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 vendor is FOSSology', $report['metadata']['tools'][0]['vendor'] === 'FOSSology');
167  assert_test('Tool version is 4.5.0', $report['metadata']['tools'][0]['version'] === '4.5.0');
168  assert_test('Metadata has main component', isset($report['metadata']['component']));
169  assert_test('Main component has copyright', isset($report['metadata']['component']['copyright']));
170  assert_test('Report has components array', is_array($report['components']));
171  assert_test('Components count is 1', count($report['components']) === 1);
172  assert_test('File component has copyright', isset($report['components'][0]['copyright']));
173  assert_test('Report has no externalReferences when not provided', !isset($report['externalReferences']));
174 
175  echo "\n";
176 
177  echo "Test 7: JSON validity\n";
178  $json = json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
179  assert_test('JSON encodes without error', json_last_error() === JSON_ERROR_NONE);
180  assert_test('JSON is not empty', strlen($json) > 100);
181 
182  $decoded = json_decode($json, true);
183  assert_test('JSON round-trip preserves bomFormat', $decoded['bomFormat'] === 'CycloneDX');
184  assert_test('JSON round-trip preserves license text',
185  isset($decoded['metadata']['component']['licenses'][0]['license']['text']['content']));
186 
187  echo "\n";
188 
189  echo "Test 8: Component with version\n";
190  $compWithVersion = $generator->createComponent(array(
191  'type' => 'library',
192  'name' => 'busybox',
193  'version' => '1.36.1'
194  ));
195 
196  assert_test('Component has version', isset($compWithVersion['version']));
197  assert_test('Version value is correct', $compWithVersion['version'] === '1.36.1');
198 
199  $compNoVersion = $generator->createComponent(array(
200  'type' => 'library',
201  'name' => 'busybox',
202  'version' => ''
203  ));
204  assert_test('Empty version is not included', !isset($compNoVersion['version']));
205 
206  echo "\n";
207 
208  echo "Test 9: Component with purl\n";
209  $compWithPurl = $generator->createComponent(array(
210  'type' => 'library',
211  'name' => 'busybox',
212  'purl' => 'pkg:deb/debian/busybox@1.36.1'
213  ));
214 
215  assert_test('Component has purl', isset($compWithPurl['purl']));
216  assert_test('PURL value is correct', $compWithPurl['purl'] === 'pkg:deb/debian/busybox@1.36.1');
217 
218  $compNoPurl = $generator->createComponent(array(
219  'type' => 'library',
220  'name' => 'busybox',
221  'purl' => ''
222  ));
223  assert_test('Empty purl is not included', !isset($compNoPurl['purl']));
224 
225  echo "\n";
226 
227  echo "Test 10: Component with description\n";
228  $compWithDesc = $generator->createComponent(array(
229  'type' => 'library',
230  'name' => 'openssl',
231  'description' => 'Open source SSL/TLS toolkit'
232  ));
233 
234  assert_test('Component has description', isset($compWithDesc['description']));
235  assert_test('Description value is correct', $compWithDesc['description'] === 'Open source SSL/TLS toolkit');
236 
237  $compNoDesc = $generator->createComponent(array(
238  'type' => 'library',
239  'name' => 'openssl',
240  'description' => ''
241  ));
242  assert_test('Empty description is not included', !isset($compNoDesc['description']));
243 
244  echo "\n";
245 
246  echo "Test 11: Component with properties (acknowledgements + comments)\n";
247  $compWithProps = $generator->createComponent(array(
248  'type' => 'file',
249  'name' => 'src/main.c',
250  'acknowledgements' => "Thanks to the OpenSSL team\nThanks to contributors",
251  'comments' => 'Reviewed and approved by legal team'
252  ));
253 
254  assert_test('Component has properties', isset($compWithProps['properties']));
255  assert_test('Properties has 2 entries', count($compWithProps['properties']) === 2);
256  assert_test('First property is acknowledgement',
257  $compWithProps['properties'][0]['name'] === 'fossology:acknowledgement');
258  assert_test('Acknowledgement value is correct',
259  strpos($compWithProps['properties'][0]['value'], 'OpenSSL') !== false);
260  assert_test('Second property is comment',
261  $compWithProps['properties'][1]['name'] === 'fossology:comment');
262  assert_test('Comment value is correct',
263  $compWithProps['properties'][1]['value'] === 'Reviewed and approved by legal team');
264 
265  $compOnlyAck = $generator->createComponent(array(
266  'type' => 'file',
267  'name' => 'src/util.c',
268  'acknowledgements' => 'Thanks to maintainers',
269  'comments' => ''
270  ));
271  assert_test('Only acknowledgement property when comments empty', count($compOnlyAck['properties']) === 1);
272  assert_test('Single property is acknowledgement',
273  $compOnlyAck['properties'][0]['name'] === 'fossology:acknowledgement');
274 
275  $compNoProps = $generator->createComponent(array(
276  'type' => 'file',
277  'name' => 'src/test.c',
278  'acknowledgements' => '',
279  'comments' => ''
280  ));
281  assert_test('No properties when both empty', !isset($compNoProps['properties']));
282 
283  echo "\n";
284 
285  echo "Test 12: Component with externalReferences\n";
286  $compWithExtRef = $generator->createComponent(array(
287  'type' => 'library',
288  'name' => 'openssl',
289  'externalReferences' => [
290  ['type' => 'distribution', 'url' => 'https://www.openssl.org/source/openssl-3.0.12.tar.gz'],
291  ['type' => 'vcs', 'url' => 'https://github.com/openssl/openssl']
292  ]
293  ));
294 
295  assert_test('Component has externalReferences', isset($compWithExtRef['externalReferences']));
296  assert_test('ExternalReferences has 2 entries', count($compWithExtRef['externalReferences']) === 2);
297  assert_test('First ref type is distribution',
298  $compWithExtRef['externalReferences'][0]['type'] === 'distribution');
299  assert_test('First ref url is correct',
300  $compWithExtRef['externalReferences'][0]['url'] === 'https://www.openssl.org/source/openssl-3.0.12.tar.gz');
301 
302  $compNoExtRef = $generator->createComponent(array(
303  'type' => 'library',
304  'name' => 'openssl',
305  'externalReferences' => []
306  ));
307  assert_test('Empty externalReferences is not included', !isset($compNoExtRef['externalReferences']));
308 
309  echo "\n";
310 
311  echo "Test 13: Full report with externalReferences\n";
312  $reportWithExtRef = $generator->generateReport(array(
313  'tool-version' => '4.5.0',
314  'maincomponent' => $comp,
315  'components' => array($fileComponent),
316  'externalReferences' => [
317  ['type' => 'website', 'url' => 'https://www.fossology.org']
318  ]
319  ));
320 
321  assert_test('Report has externalReferences', isset($reportWithExtRef['externalReferences']));
322  assert_test('Report externalReferences has 1 entry', count($reportWithExtRef['externalReferences']) === 1);
323  assert_test('Report externalRef type is website',
324  $reportWithExtRef['externalReferences'][0]['type'] === 'website');
325 
326  echo "\n";
327 
328  echo "Test 14: Full component with all new fields\n";
329  $fullComp = $generator->createComponent(array(
330  'type' => 'library',
331  'name' => 'busybox',
332  'version' => '1.36.1',
333  'bomref' => '99',
334  'scope' => 'required',
335  'mimeType' => 'application/x-tar',
336  'copyright' => 'Copyright 2023 BusyBox Authors',
337  'description' => 'Tiny utilities for small and embedded systems',
338  'purl' => 'pkg:generic/busybox@1.36.1',
339  'hashes' => array($generator->createHash('SHA-256', 'abc123def456')),
340  'licenses' => array($result),
341  'externalReferences' => [
342  ['type' => 'vcs', 'url' => 'https://git.busybox.net/busybox/']
343  ],
344  'acknowledgements' => 'Thanks to Denys Vlasenko',
345  'comments' => 'Primary build dependency'
346  ));
347 
348  assert_test('Full component has type', $fullComp['type'] === 'library');
349  assert_test('Full component has name', $fullComp['name'] === 'busybox');
350  assert_test('Full component has version', $fullComp['version'] === '1.36.1');
351  assert_test('Full component has bom-ref', $fullComp['bom-ref'] === '99');
352  assert_test('Full component has purl', $fullComp['purl'] === 'pkg:generic/busybox@1.36.1');
353  assert_test('Full component has description',
354  $fullComp['description'] === 'Tiny utilities for small and embedded systems');
355  assert_test('Full component has copyright', isset($fullComp['copyright']));
356  assert_test('Full component has hashes', count($fullComp['hashes']) === 1);
357  assert_test('Full component has licenses', count($fullComp['licenses']) === 1);
358  assert_test('Full component has externalReferences', count($fullComp['externalReferences']) === 1);
359  assert_test('Full component has properties', count($fullComp['properties']) === 2);
360 
361  echo "\n";
362 
363  echo "=== Results ===\n";
364  echo "Passed: $passed | Failed: $failed\n";
365 
366  if ($failed > 0) {
367  echo "\nSome tests FAILED!\n";
368  exit(1);
369  } else {
370  echo "\nAll tests passed!\n";
371  exit(0);
372  }
373 
374 } // end namespace