github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/format/common/cyclonedxhelpers/licenses_test.go (about)

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