github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/formats/common/cyclonedxhelpers/licenses_test.go (about)

     1  package cyclonedxhelpers
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/CycloneDX/cyclonedx-go"
     7  	"github.com/nextlinux/gosbom/gosbom/license"
     8  	"github.com/nextlinux/gosbom/gosbom/pkg"
     9  	"github.com/nextlinux/gosbom/internal"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func Test_encodeLicense(t *testing.T) {
    14  	tests := []struct {
    15  		name     string
    16  		input    pkg.Package
    17  		expected *cyclonedx.Licenses
    18  	}{
    19  		{
    20  			name:  "no licenses",
    21  			input: pkg.Package{},
    22  		},
    23  		{
    24  			name: "no SPDX licenses",
    25  			input: pkg.Package{
    26  				Licenses: pkg.NewLicenseSet(
    27  					pkg.NewLicense("RandomLicense"),
    28  				),
    29  			},
    30  			expected: &cyclonedx.Licenses{
    31  				{
    32  					License: &cyclonedx.License{
    33  						Name: "RandomLicense",
    34  					},
    35  				},
    36  			},
    37  		},
    38  		{
    39  			name: "single SPDX ID and Non SPDX ID",
    40  			input: pkg.Package{
    41  				Licenses: pkg.NewLicenseSet(
    42  					pkg.NewLicense("mit"),
    43  					pkg.NewLicense("FOOBAR"),
    44  				),
    45  			},
    46  			expected: &cyclonedx.Licenses{
    47  				{
    48  					License: &cyclonedx.License{
    49  						ID: "MIT",
    50  					},
    51  				},
    52  				{
    53  					License: &cyclonedx.License{
    54  						Name: "FOOBAR",
    55  					},
    56  				},
    57  			},
    58  		},
    59  		{
    60  			name: "with complex SPDX license expression",
    61  			input: pkg.Package{
    62  				Licenses: pkg.NewLicenseSet(
    63  					pkg.NewLicense("MIT AND GPL-3.0-only"),
    64  				),
    65  			},
    66  			expected: &cyclonedx.Licenses{
    67  				{
    68  					Expression: "MIT AND GPL-3.0-only",
    69  				},
    70  			},
    71  		},
    72  		{
    73  			name: "with multiple complex SPDX license expression",
    74  			input: pkg.Package{
    75  				Licenses: pkg.NewLicenseSet(
    76  					pkg.NewLicense("MIT AND GPL-3.0-only"),
    77  					pkg.NewLicense("MIT AND GPL-3.0-only WITH Classpath-exception-2.0"),
    78  				),
    79  			},
    80  			expected: &cyclonedx.Licenses{
    81  				{
    82  					Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)",
    83  				},
    84  			},
    85  		},
    86  		{
    87  			name: "with multiple URLs and expressions",
    88  			input: pkg.Package{
    89  				Licenses: pkg.NewLicenseSet(
    90  					pkg.NewLicenseFromURLs("MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"),
    91  					pkg.NewLicense("MIT AND GPL-3.0-only"),
    92  					pkg.NewLicenseFromURLs("FakeLicense", "htts://someurl.com"),
    93  				),
    94  			},
    95  			expected: &cyclonedx.Licenses{
    96  				{
    97  					License: &cyclonedx.License{
    98  						ID:  "MIT",
    99  						URL: "https://opensource.org/licenses/MIT",
   100  					},
   101  				},
   102  				{
   103  					License: &cyclonedx.License{
   104  						ID:  "MIT",
   105  						URL: "https://spdx.org/licenses/MIT.html",
   106  					},
   107  				},
   108  				{
   109  					License: &cyclonedx.License{
   110  						Name: "FakeLicense",
   111  						URL:  "htts://someurl.com",
   112  					},
   113  				},
   114  				{
   115  					License: &cyclonedx.License{
   116  						Name: "MIT AND GPL-3.0-only",
   117  					},
   118  				},
   119  			},
   120  		},
   121  		{
   122  			name: "with multiple values licenses are deduplicated",
   123  			input: pkg.Package{
   124  				Licenses: pkg.NewLicenseSet(
   125  					pkg.NewLicense("Apache-2"),
   126  					pkg.NewLicense("Apache-2.0"),
   127  				),
   128  			},
   129  			expected: &cyclonedx.Licenses{
   130  				{
   131  					License: &cyclonedx.License{
   132  						ID: "Apache-2.0",
   133  					},
   134  				},
   135  			},
   136  		},
   137  		{
   138  			name: "with multiple URLs and single with no URLs",
   139  			input: pkg.Package{
   140  				Licenses: pkg.NewLicenseSet(
   141  					pkg.NewLicense("MIT"),
   142  					pkg.NewLicenseFromURLs("MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"),
   143  					pkg.NewLicense("MIT AND GPL-3.0-only"),
   144  				),
   145  			},
   146  			expected: &cyclonedx.Licenses{
   147  				{
   148  					License: &cyclonedx.License{
   149  						ID:  "MIT",
   150  						URL: "https://opensource.org/licenses/MIT",
   151  					},
   152  				},
   153  				{
   154  					License: &cyclonedx.License{
   155  						ID:  "MIT",
   156  						URL: "https://spdx.org/licenses/MIT.html",
   157  					},
   158  				},
   159  				{
   160  					License: &cyclonedx.License{
   161  						Name: "MIT AND GPL-3.0-only",
   162  					},
   163  				},
   164  			},
   165  		},
   166  		// TODO: do we drop the non SPDX ID license and do a single expression
   167  		// OR do we keep the non SPDX ID license and do multiple licenses where the complex
   168  		// expressions are set as the NAME field?
   169  		//{
   170  		//	name: "with multiple complex SPDX license expression and a non spdx id",
   171  		//	input: pkg.Package{
   172  		//		Licenses: []pkg.License{
   173  		//			{
   174  		//				SPDXExpression: "MIT AND GPL-3.0-only",
   175  		//			},
   176  		//			{
   177  		//				SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
   178  		//			},
   179  		//			{
   180  		//				Value: "FOOBAR",
   181  		//			},
   182  		//		},
   183  		//	},
   184  		//	expected: &cyclonedx.Licenses{
   185  		//		{
   186  		//			Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)",
   187  		//		},
   188  		//	},
   189  		//},
   190  	}
   191  	for _, test := range tests {
   192  		t.Run(test.name, func(t *testing.T) {
   193  			assert.Equal(t, test.expected, encodeLicenses(test.input))
   194  		})
   195  	}
   196  }
   197  
   198  func TestDecodeLicenses(t *testing.T) {
   199  	tests := []struct {
   200  		name     string
   201  		input    *cyclonedx.Component
   202  		expected []pkg.License
   203  	}{
   204  		{
   205  			name:     "no licenses",
   206  			input:    &cyclonedx.Component{},
   207  			expected: []pkg.License{},
   208  		},
   209  		{
   210  			name: "no SPDX license ID or expression",
   211  			input: &cyclonedx.Component{
   212  				Licenses: &cyclonedx.Licenses{
   213  					{
   214  						License: &cyclonedx.License{
   215  							Name: "RandomLicense",
   216  						},
   217  					},
   218  				},
   219  			},
   220  			expected: []pkg.License{
   221  				{
   222  					Value: "RandomLicense",
   223  					// CycloneDX specification doesn't give a field for determining the license type
   224  					Type: license.Declared,
   225  					URLs: internal.NewStringSet(),
   226  				},
   227  			},
   228  		},
   229  		{
   230  			name: "with SPDX license ID",
   231  			input: &cyclonedx.Component{
   232  				Licenses: &cyclonedx.Licenses{
   233  					{
   234  						License: &cyclonedx.License{
   235  							ID: "MIT",
   236  						},
   237  					},
   238  				},
   239  			},
   240  			expected: []pkg.License{
   241  				{
   242  					Value:          "MIT",
   243  					SPDXExpression: "MIT",
   244  					Type:           license.Declared,
   245  					URLs:           internal.NewStringSet(),
   246  				},
   247  			},
   248  		},
   249  		{
   250  			name: "with complex SPDX license expression",
   251  			input: &cyclonedx.Component{
   252  				Licenses: &cyclonedx.Licenses{
   253  					{
   254  						License:    &cyclonedx.License{},
   255  						Expression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
   256  					},
   257  				},
   258  			},
   259  			expected: []pkg.License{
   260  				{
   261  					Value:          "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
   262  					SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
   263  					Type:           license.Declared,
   264  					URLs:           internal.NewStringSet(),
   265  				},
   266  			},
   267  		},
   268  	}
   269  	for _, test := range tests {
   270  		t.Run(test.name, func(t *testing.T) {
   271  			assert.Equal(t, test.expected, decodeLicenses(test.input))
   272  		})
   273  	}
   274  }