github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/gentoo/license_test.go (about) 1 package gentoo 2 3 import ( 4 "bytes" 5 "os" 6 "strings" 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 // you can get a good sense of test fixtures with: 15 // docker run --rm -it gentoo/stage3 bash -c 'find var/db/pkg/ | grep LICENSE | xargs cat' 16 17 func Test_extractLicenses(t *testing.T) { 18 19 tests := []struct { 20 name string 21 license string 22 wantExpression string 23 }{ 24 { 25 name: "empty", 26 license: "", 27 wantExpression: "", 28 }, 29 { 30 name: "single", 31 license: "GPL-2", 32 wantExpression: "GPL-2", 33 }, 34 { 35 name: "multiple", 36 license: "GPL-2 GPL-3 ", // note the extra space 37 wantExpression: "GPL-2 AND GPL-3", 38 }, 39 { 40 name: "license choices", 41 license: "|| ( GPL-2 GPL-3 )\n", // note the newline 42 wantExpression: "GPL-2 OR GPL-3", 43 }, 44 { 45 // this might not be correct behavior, but we do our best with missing info 46 name: "license choices with missing useflag suffix", 47 license: "GPL-3+ LGPL-3+ || ( GPL-3+ libgcc libstdc++ gcc-runtime-library-exception-3.1 ) FDL-1.3+", // no use flag so what do we do with FDL here? 48 wantExpression: "GPL-3+ AND LGPL-3+ AND (GPL-3+ OR libgcc OR libstdc++ OR gcc-runtime-library-exception-3.1 OR FDL-1.3+)", // "OR FDL-1.3+" is probably wrong at the end... 49 }, 50 } 51 for _, tt := range tests { 52 t.Run(tt.name, func(t *testing.T) { 53 raw, expression := extractLicenses(nil, nil, strings.NewReader(tt.license)) 54 assert.Equalf(t, tt.wantExpression, expression, "unexpected expression for %v", tt.license) 55 assert.Equalf(t, strings.TrimSpace(tt.license), raw, "unexpected raw for %v", tt.license) 56 }) 57 } 58 } 59 60 func TestParseLicenseGroups(t *testing.T) { 61 tests := []struct { 62 name string 63 input string 64 expected map[string][]string 65 expectError require.ErrorAssertionFunc 66 }{ 67 { 68 name: "basic nesting example", 69 input: "test-fixtures/license-groups/example1", 70 expected: map[string][]string{ 71 "FSF-APPROVED": { 72 "Apache-2.0", "BSD", "BSD-2", "GPL-2", "GPL-3", "LGPL-2.1", "LGPL-3", "X11", "ZLIB", 73 "Apache-1.1", "BSD-4", "MPL-1.0", "MPL-1.1", "PSF-2.0", 74 }, 75 "GPL-COMPATIBLE": { 76 "Apache-2.0", "BSD", "BSD-2", "GPL-2", "GPL-3", "LGPL-2.1", "LGPL-3", "X11", "ZLIB", 77 }, 78 }, 79 }, 80 { 81 name: "error on cycles", 82 input: "test-fixtures/license-groups/cycle", 83 expectError: require.Error, 84 }, 85 { 86 name: "error on self references", 87 input: "test-fixtures/license-groups/self", 88 expectError: require.Error, 89 }, 90 { 91 name: "error on missing reference", 92 input: "test-fixtures/license-groups/missing", 93 expectError: require.Error, 94 }, 95 } 96 97 for _, tc := range tests { 98 t.Run(tc.name, func(t *testing.T) { 99 if tc.expectError == nil { 100 tc.expectError = require.NoError 101 } 102 103 contents, err := os.ReadFile(tc.input) 104 require.NoError(t, err) 105 106 actual, err := parseLicenseGroups(bytes.NewReader(contents)) 107 tc.expectError(t, err) 108 if err != nil { 109 return 110 } 111 112 if d := cmp.Diff(tc.expected, actual); d != "" { 113 t.Errorf("unexpected license groups (-want +got):\n%s", d) 114 } 115 }) 116 } 117 } 118 119 func TestReplaceLicenseGroups(t *testing.T) { 120 tests := []struct { 121 name string 122 licenses []string 123 groups map[string][]string 124 expected []string 125 }{ 126 { 127 name: "nil groups", 128 licenses: []string{"MIT", "Apache-2.0", "@GPL"}, 129 groups: nil, 130 expected: []string{"MIT", "Apache-2.0", "@GPL"}, 131 }, 132 { 133 name: "empty groups", 134 licenses: []string{"MIT", "Apache-2.0", "@GPL"}, 135 groups: map[string][]string{}, 136 expected: []string{"MIT", "Apache-2.0", "@GPL"}, 137 }, 138 { 139 name: "no group references", 140 licenses: []string{"MIT", "Apache-2.0", "GPL-2.0"}, 141 groups: map[string][]string{"GPL": {"GPL-2.0", "GPL-3.0"}}, 142 expected: []string{"MIT", "Apache-2.0", "GPL-2.0"}, 143 }, 144 { 145 name: "single group reference", 146 licenses: []string{"MIT", "@GPL", "Apache-2.0"}, 147 groups: map[string][]string{"GPL": {"GPL-2.0", "GPL-3.0"}}, 148 expected: []string{"MIT", "GPL-2.0", "GPL-3.0", "Apache-2.0"}, 149 }, 150 { 151 name: "multiple group references", 152 licenses: []string{"@MIT-LIKE", "@GPL", "BSD-3"}, 153 groups: map[string][]string{ 154 "MIT-LIKE": {"MIT", "ISC"}, 155 "GPL": {"GPL-2.0", "GPL-3.0"}, 156 }, 157 expected: []string{"MIT", "ISC", "GPL-2.0", "GPL-3.0", "BSD-3"}, 158 }, 159 { 160 name: "unknown group reference", 161 licenses: []string{"MIT", "@UNKNOWN", "Apache-2.0"}, 162 groups: map[string][]string{"GPL": {"GPL-2.0", "GPL-3.0"}}, 163 expected: []string{"MIT", "@UNKNOWN", "Apache-2.0"}, 164 }, 165 { 166 name: "reference at end", 167 licenses: []string{"MIT", "Apache-2.0", "@GPL"}, 168 groups: map[string][]string{"GPL": {"GPL-2.0", "GPL-3.0"}}, 169 expected: []string{"MIT", "Apache-2.0", "GPL-2.0", "GPL-3.0"}, 170 }, 171 } 172 173 for _, tc := range tests { 174 t.Run(tc.name, func(t *testing.T) { 175 inputLicenses := make([]string, len(tc.licenses)) 176 copy(inputLicenses, tc.licenses) 177 178 actual := replaceLicenseGroups(inputLicenses, tc.groups) 179 180 assert.Equal(t, tc.expected, actual) 181 }) 182 } 183 }