github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/license_test.go (about)

     1  package pkg
     2  
     3  import (
     4  	"sort"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/anchore/syft/syft/artifact"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/license"
    13  )
    14  
    15  func Test_Hash(t *testing.T) {
    16  
    17  	loc1 := file.NewLocation("place!")
    18  	loc1.FileSystemID = "fs1"
    19  	loc2 := file.NewLocation("place!")
    20  	loc2.FileSystemID = "fs2" // important! there is a different file system ID
    21  
    22  	lic1 := NewLicenseFromFields("MIT", "foo", &loc1)
    23  	lic2 := NewLicenseFromFields("MIT", "bar", &loc2)
    24  
    25  	hash1, err := artifact.IDByHash(lic1)
    26  	require.NoError(t, err)
    27  
    28  	hash2, err := artifact.IDByHash(lic2)
    29  	require.NoError(t, err)
    30  
    31  	assert.Equal(t, hash1, hash2)
    32  }
    33  
    34  func Test_Sort(t *testing.T) {
    35  	tests := []struct {
    36  		name     string
    37  		licenses Licenses
    38  		expected Licenses
    39  	}{
    40  		{
    41  			name:     "empty",
    42  			licenses: []License{},
    43  			expected: []License{},
    44  		},
    45  		{
    46  			name: "single",
    47  			licenses: []License{
    48  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    49  			},
    50  			expected: []License{
    51  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    52  			},
    53  		},
    54  		{
    55  			name: "multiple",
    56  			licenses: []License{
    57  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    58  				NewLicenseFromURLs("MIT", "https://github.com/anchore/syft/blob/main/LICENSE"),
    59  				NewLicenseFromLocations("Apache", file.NewLocation("area!")),
    60  				NewLicenseFromLocations("gpl2+", file.NewLocation("area!")),
    61  			},
    62  			expected: Licenses{
    63  				NewLicenseFromLocations("Apache", file.NewLocation("area!")),
    64  				NewLicenseFromURLs("MIT", "https://github.com/anchore/syft/blob/main/LICENSE"),
    65  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    66  				NewLicenseFromLocations("gpl2+", file.NewLocation("area!")),
    67  			},
    68  		},
    69  		{
    70  			name: "multiple with location variants",
    71  			licenses: []License{
    72  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    73  				NewLicenseFromLocations("MIT", file.NewLocation("park!")),
    74  				NewLicense("MIT"),
    75  				NewLicense("AAL"),
    76  				NewLicense("Adobe-2006"),
    77  				NewLicenseFromLocations("Apache", file.NewLocation("area!")),
    78  			},
    79  			expected: Licenses{
    80  				NewLicense("AAL"),
    81  				NewLicense("Adobe-2006"),
    82  				NewLicenseFromLocations("Apache", file.NewLocation("area!")),
    83  				NewLicense("MIT"),
    84  				NewLicenseFromLocations("MIT", file.NewLocation("park!")),
    85  				NewLicenseFromLocations("MIT", file.NewLocation("place!")),
    86  			},
    87  		},
    88  	}
    89  
    90  	for _, test := range tests {
    91  		t.Run(test.name, func(t *testing.T) {
    92  			sort.Sort(test.licenses)
    93  			assert.Equal(t, test.expected, test.licenses)
    94  		})
    95  
    96  	}
    97  }
    98  
    99  func TestLicense_Merge(t *testing.T) {
   100  	locA := file.NewLocation("a")
   101  	locB := file.NewLocation("b")
   102  
   103  	tests := []struct {
   104  		name    string
   105  		subject License
   106  		other   License
   107  		want    License
   108  		wantErr require.ErrorAssertionFunc
   109  	}{
   110  		{
   111  			name: "valid merge",
   112  			subject: License{
   113  				Value:          "MIT",
   114  				SPDXExpression: "MIT",
   115  				Type:           license.Declared,
   116  				URLs: []string{
   117  					"b", "a",
   118  				},
   119  				Locations: file.NewLocationSet(locA),
   120  			},
   121  			other: License{
   122  				Value:          "MIT",
   123  				SPDXExpression: "MIT",
   124  				Type:           license.Declared,
   125  				URLs: []string{
   126  					"c", "d",
   127  				},
   128  				Locations: file.NewLocationSet(locB),
   129  			},
   130  			want: License{
   131  				Value:          "MIT",
   132  				SPDXExpression: "MIT",
   133  				Type:           license.Declared,
   134  				URLs: []string{
   135  					"a", "b", "c", "d",
   136  				},
   137  				Locations: file.NewLocationSet(locA, locB),
   138  			},
   139  		},
   140  		{
   141  			name: "mismatched value",
   142  			subject: License{
   143  				Value:          "DIFFERENT!!",
   144  				SPDXExpression: "MIT",
   145  				Type:           license.Declared,
   146  				URLs: []string{
   147  					"b", "a",
   148  				},
   149  				Locations: file.NewLocationSet(locA),
   150  			},
   151  			other: License{
   152  				Value:          "MIT",
   153  				SPDXExpression: "MIT",
   154  				Type:           license.Declared,
   155  				URLs: []string{
   156  					"c", "d",
   157  				},
   158  				Locations: file.NewLocationSet(locB),
   159  			},
   160  			wantErr: require.Error,
   161  		},
   162  		{
   163  			name: "mismatched spdx expression",
   164  			subject: License{
   165  				Value:          "MIT",
   166  				SPDXExpression: "DIFFERENT!!",
   167  				Type:           license.Declared,
   168  				URLs: []string{
   169  					"b", "a",
   170  				},
   171  				Locations: file.NewLocationSet(locA),
   172  			},
   173  			other: License{
   174  				Value:          "MIT",
   175  				SPDXExpression: "MIT",
   176  				Type:           license.Declared,
   177  				URLs: []string{
   178  					"c", "d",
   179  				},
   180  				Locations: file.NewLocationSet(locB),
   181  			},
   182  			wantErr: require.Error,
   183  		},
   184  		{
   185  			name: "mismatched type",
   186  			subject: License{
   187  				Value:          "MIT",
   188  				SPDXExpression: "MIT",
   189  				Type:           license.Concluded,
   190  				URLs: []string{
   191  					"b", "a",
   192  				},
   193  				Locations: file.NewLocationSet(locA),
   194  			},
   195  			other: License{
   196  				Value:          "MIT",
   197  				SPDXExpression: "MIT",
   198  				Type:           license.Declared,
   199  				URLs: []string{
   200  					"c", "d",
   201  				},
   202  				Locations: file.NewLocationSet(locB),
   203  			},
   204  			wantErr: require.Error,
   205  		},
   206  	}
   207  	for _, tt := range tests {
   208  		t.Run(tt.name, func(t *testing.T) {
   209  			if tt.wantErr == nil {
   210  				tt.wantErr = require.NoError
   211  			}
   212  
   213  			subjectLocationLen := len(tt.subject.Locations.ToSlice())
   214  			subjectURLLen := len(tt.subject.URLs)
   215  
   216  			got, err := tt.subject.Merge(tt.other)
   217  			tt.wantErr(t, err)
   218  			if err != nil {
   219  				return
   220  			}
   221  			require.NotNilf(t, got, "expected a non-nil license")
   222  			assert.Equal(t, tt.want, *got)
   223  			// prove we don't modify the subject
   224  			assert.Equal(t, subjectLocationLen, len(tt.subject.Locations.ToSlice()))
   225  			assert.Equal(t, subjectURLLen, len(tt.subject.URLs))
   226  		})
   227  	}
   228  }