mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
--------- Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
317 lines
7.7 KiB
Go
317 lines
7.7 KiB
Go
package helpers
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/CycloneDX/cyclonedx-go"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/anchore/syft/syft/license"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
)
|
|
|
|
func Test_encodeLicense(t *testing.T) {
|
|
ctx := context.TODO()
|
|
tests := []struct {
|
|
name string
|
|
input pkg.Package
|
|
expected *cyclonedx.Licenses
|
|
}{
|
|
{
|
|
name: "no licenses",
|
|
input: pkg.Package{},
|
|
},
|
|
{
|
|
name: "no SPDX licenses",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "RandomLicense"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "RandomLicense",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "single SPDX ID and Non SPDX ID",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "mit"),
|
|
pkg.NewLicenseWithContext(ctx, "FOOBAR"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "FOOBAR",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with complex SPDX license expression",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "MIT AND GPL-3.0-only"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
Expression: "MIT AND GPL-3.0-only",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with multiple complex SPDX license expression",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "MIT AND GPL-3.0-only"),
|
|
pkg.NewLicenseWithContext(ctx, "MIT AND GPL-3.0-only WITH Classpath-exception-2.0"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with multiple URLs and expressions",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseFromURLsWithContext(ctx, "MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"),
|
|
pkg.NewLicenseWithContext(ctx, "MIT AND GPL-3.0-only"),
|
|
pkg.NewLicenseFromURLsWithContext(ctx, "FakeLicense", "htts://someurl.com"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
URL: "https://opensource.org/licenses/MIT",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
URL: "https://spdx.org/licenses/MIT.html",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "FakeLicense",
|
|
URL: "htts://someurl.com",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "MIT AND GPL-3.0-only",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with URL only and no name or SPDX ID",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseFromURLsWithContext(ctx, "", "http://jaxen.codehaus.org/license.html"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "http://jaxen.codehaus.org/license.html",
|
|
URL: "http://jaxen.codehaus.org/license.html",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with multiple values licenses are deduplicated",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "Apache-2"),
|
|
pkg.NewLicenseWithContext(ctx, "Apache-2.0"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "Apache-2.0",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with multiple URLs and single with no URLs",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(
|
|
pkg.NewLicenseWithContext(ctx, "MIT"),
|
|
pkg.NewLicenseFromURLsWithContext(ctx, "MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"),
|
|
pkg.NewLicenseWithContext(ctx, "MIT AND GPL-3.0-only"),
|
|
),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
URL: "https://opensource.org/licenses/MIT",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
URL: "https://spdx.org/licenses/MIT.html",
|
|
},
|
|
},
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "MIT AND GPL-3.0-only",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "single parenthesized SPDX expression",
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, "(MIT OR Apache-2.0)")...),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
Expression: "MIT OR Apache-2.0",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "single license AND to parenthesized SPDX expression",
|
|
// (LGPL-3.0-or-later OR GPL-2.0-or-later OR (LGPL-3.0-or-later AND GPL-2.0-or-later)) AND GFDL-1.3-invariants-or-later
|
|
input: pkg.Package{
|
|
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromValuesWithContext(ctx, "(LGPL-3.0-or-later OR GPL-2.0-or-later OR (LGPL-3.0-or-later AND GPL-2.0-or-later)) AND GFDL-1.3-invariants-or-later")...),
|
|
},
|
|
expected: &cyclonedx.Licenses{
|
|
{
|
|
Expression: "(LGPL-3.0-or-later OR GPL-2.0-or-later OR (LGPL-3.0-or-later AND GPL-2.0-or-later)) AND GFDL-1.3-invariants-or-later",
|
|
},
|
|
},
|
|
},
|
|
// TODO: do we drop the non SPDX ID license and do a single expression
|
|
// OR do we keep the non SPDX ID license and do multiple licenses where the complex
|
|
// expressions are set as the NAME field?
|
|
//{
|
|
// name: "with multiple complex SPDX license expression and a non spdx id",
|
|
// input: pkg.Package{
|
|
// Licenses: []pkg.License{
|
|
// {
|
|
// SPDXExpression: "MIT AND GPL-3.0-only",
|
|
// },
|
|
// {
|
|
// SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
|
|
// },
|
|
// {
|
|
// Value: "FOOBAR",
|
|
// },
|
|
// },
|
|
// },
|
|
// expected: &cyclonedx.Licenses{
|
|
// {
|
|
// Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)",
|
|
// },
|
|
// },
|
|
//},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if d := cmp.Diff(test.expected, encodeLicenses(test.input)); d != "" {
|
|
t.Errorf("unexpected license (-want +got):\n%s", d)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeLicenses(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input *cyclonedx.Component
|
|
expected []pkg.License
|
|
}{
|
|
{
|
|
name: "no licenses",
|
|
input: &cyclonedx.Component{},
|
|
expected: []pkg.License{},
|
|
},
|
|
{
|
|
name: "no SPDX license ID or expression",
|
|
input: &cyclonedx.Component{
|
|
Licenses: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
Name: "RandomLicense",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []pkg.License{
|
|
{
|
|
Value: "RandomLicense",
|
|
// CycloneDX specification doesn't give a field for determining the license type
|
|
Type: license.Declared,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with SPDX license ID",
|
|
input: &cyclonedx.Component{
|
|
Licenses: &cyclonedx.Licenses{
|
|
{
|
|
License: &cyclonedx.License{
|
|
ID: "MIT",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []pkg.License{
|
|
{
|
|
Value: "MIT",
|
|
SPDXExpression: "MIT",
|
|
Type: license.Declared,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with complex SPDX license expression",
|
|
input: &cyclonedx.Component{
|
|
Licenses: &cyclonedx.Licenses{
|
|
{
|
|
// CycloneDX specification doesn't allow to provide License if Expression is provided
|
|
License: nil,
|
|
Expression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
|
|
},
|
|
},
|
|
},
|
|
expected: []pkg.License{
|
|
{
|
|
Value: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
|
|
SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0",
|
|
Type: license.Declared,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
assert.Equal(t, test.expected, decodeLicenses(test.input))
|
|
})
|
|
}
|
|
}
|