Skip to content

Commit

Permalink
add satisfies for license comparisons
Browse files Browse the repository at this point in the history
* start of satisfies translation from js to go
* add comparator code to determine >, <, = for two licenses
* add ranges for licenses
* normalize -or-later, -only, + in license identifier

Known direct license comparisons that fail in go, but pass in js

```
satisfies(“Apache-3.0”, “Apache-2.0+”) // Apache-3.0 doesn’t exist
satisfies(“Apache-1.0+”, “Apache-2.0+”) // not in same range
satisfies(“GPL-2.0”, “GPL-2.0+”) // not in same range
satisfies(“GPL-2.0”, “GPL-2.0-or-later”) // not in same range
```
  • Loading branch information
elrayle committed Aug 29, 2022
1 parent ec3679e commit 3472631
Show file tree
Hide file tree
Showing 12 changed files with 843 additions and 73 deletions.
38 changes: 38 additions & 0 deletions spdxexp/compare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package spdxexp

func compareGT(first *Node, second *Node) bool {
firstRange := GetLicenseRange(*first.License())
secondRange := GetLicenseRange(*second.License())

if !sameLicenseGroup(firstRange, secondRange) {
return false
}
return firstRange.Location[VERSION_GROUP] > secondRange.Location[VERSION_GROUP]
}

func compareLT(first *Node, second *Node) bool {
firstRange := GetLicenseRange(*first.License())
secondRange := GetLicenseRange(*second.License())

if !sameLicenseGroup(firstRange, secondRange) {
return false
}
return firstRange.Location[VERSION_GROUP] < secondRange.Location[VERSION_GROUP]
}

func compareEQ(first *Node, second *Node) bool {
firstRange := GetLicenseRange(*first.License())
secondRange := GetLicenseRange(*second.License())

if !sameLicenseGroup(firstRange, secondRange) {
return false
}
return firstRange.Location[VERSION_GROUP] == secondRange.Location[VERSION_GROUP]
}

func sameLicenseGroup(firstRange *LicenseRange, secondRange *LicenseRange) bool {
if firstRange == nil || secondRange == nil || firstRange.Location[LICENSE_GROUP] != secondRange.Location[LICENSE_GROUP] {
return false
}
return true
}
94 changes: 94 additions & 0 deletions spdxexp/compare_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package spdxexp

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCompareGT(t *testing.T) {
tests := []struct {
name string
first *Node
second *Node
result bool
}{
{"expect greater than: GPL-3.0 > GPL-2.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-2.0", false), true},
{"expect greater than: GPL-3.0-only > GPL-2.0-only", getLicenseNode("GPL-3.0-only", false), getLicenseNode("GPL-2.0-only", false), true},
{"expect greater than: LPPL-1.3a > LPPL-1.0", getLicenseNode("LPPL-1.3a", false), getLicenseNode("LPPL-1.0", false), true},
{"expect greater than: LPPL-1.3c > LPPL-1.3a", getLicenseNode("LPPL-1.3c", false), getLicenseNode("LPPL-1.3a", false), true},
{"expect greater than: AGPL-3.0 > AGPL-1.0", getLicenseNode("AGPL-3.0", false), getLicenseNode("AGPL-1.0", false), true},
{"expect greater than: GPL-2.0-or-later > GPL-2.0-only", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0-only", false), true}, // TODO: Double check that -or-later and -only should be true for GT
{"expect greater than: GPL-2.0-or-later > GPL-2.0", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0", false), true},
{"expect equal: GPL-3.0 > GPL-3.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-3.0", false), false},
{"expect less than: MPL-1.0 > MPL-2.0", getLicenseNode("MPL-1.0", false), getLicenseNode("MPL-2.0", false), false},
{"incompatible: MIT > ISC", getLicenseNode("MIT", false), getLicenseNode("ISC", false), false},
{"incompatible: OSL-1.0 > OPL-1.0", getLicenseNode("OSL-1.0", false), getLicenseNode("OPL-1.0", false), false},
{"not simple license: (MIT OR ISC) > GPL-3.0", getLicenseNode("(MIT OR ISC)", false), getLicenseNode("GPL-3.0", false), false}, // TODO: should it raise error?
}

for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.result, compareGT(test.first, test.second))
})
}
}

func TestCompareEQ(t *testing.T) {
tests := []struct {
name string
first *Node
second *Node
result bool
}{
{"expect greater than: GPL-3.0 == GPL-2.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-2.0", false), false},
{"expect greater than: GPL-3.0-only == GPL-2.0-only", getLicenseNode("GPL-3.0-only", false), getLicenseNode("GPL-2.0-only", false), false},
{"expect greater than: LPPL-1.3a == LPPL-1.0", getLicenseNode("LPPL-1.3a", false), getLicenseNode("LPPL-1.0", false), false},
{"expect greater than: LPPL-1.3c == LPPL-1.3a", getLicenseNode("LPPL-1.3c", false), getLicenseNode("LPPL-1.3a", false), false},
{"expect greater than: AGPL-3.0 == AGPL-1.0", getLicenseNode("AGPL-3.0", false), getLicenseNode("AGPL-1.0", false), false},
{"expect greater than: GPL-2.0-or-later == GPL-2.0-only", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0-only", false), false},
{"expect greater than: GPL-2.0-or-later == GPL-2.0", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0", false), false},
{"expect equal: GPL-3.0 == GPL-3.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-3.0", false), true},
{"expect less than: MPL-1.0 == MPL-2.0", getLicenseNode("MPL-1.0", false), getLicenseNode("MPL-2.0", false), false},
{"incompatible: MIT == ISC", getLicenseNode("MIT", false), getLicenseNode("ISC", false), false},
{"incompatible: OSL-1.0 == OPL-1.0", getLicenseNode("OSL-1.0", false), getLicenseNode("OPL-1.0", false), false},
{"not simple license: (MIT OR ISC) == GPL-3.0", getLicenseNode("(MIT OR ISC)", false), getLicenseNode("GPL-3.0", false), false}, // TODO: should it raise error?
}

for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.result, compareEQ(test.first, test.second))
})
}
}

func TestCompareLT(t *testing.T) {
tests := []struct {
name string
first *Node
second *Node
result bool
}{
{"expect greater than: GPL-3.0 < GPL-2.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-2.0", false), false},
{"expect greater than: GPL-3.0-only < GPL-2.0-only", getLicenseNode("GPL-3.0-only", false), getLicenseNode("GPL-2.0-only", false), false},
{"expect greater than: LPPL-1.3a < LPPL-1.0", getLicenseNode("LPPL-1.3a", false), getLicenseNode("LPPL-1.0", false), false},
{"expect greater than: LPPL-1.3c < LPPL-1.3a", getLicenseNode("LPPL-1.3c", false), getLicenseNode("LPPL-1.3a", false), false},
{"expect greater than: AGPL-3.0 < AGPL-1.0", getLicenseNode("AGPL-3.0", false), getLicenseNode("AGPL-1.0", false), false},
{"expect greater than: GPL-2.0-or-later < GPL-2.0-only", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0-only", false), false},
{"expect greater than: GPL-2.0-or-later == GPL-2.0", getLicenseNode("GPL-2.0-or-later", true), getLicenseNode("GPL-2.0", false), false},
{"expect equal: GPL-3.0 < GPL-3.0", getLicenseNode("GPL-3.0", false), getLicenseNode("GPL-3.0", false), false},
{"expect less than: MPL-1.0 < MPL-2.0", getLicenseNode("MPL-1.0", false), getLicenseNode("MPL-2.0", false), true},
{"incompatible: MIT < ISC", getLicenseNode("MIT", false), getLicenseNode("ISC", false), false},
{"incompatible: OSL-1.0 < OPL-1.0", getLicenseNode("OSL-1.0", false), getLicenseNode("OPL-1.0", false), false},
{"not simple license: (MIT OR ISC) < GPL-3.0", getLicenseNode("(MIT OR ISC)", false), getLicenseNode("GPL-3.0", false), false}, // TODO: should it raise error?
}

for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.result, compareLT(test.first, test.second))
})
}
}
Loading

0 comments on commit 3472631

Please sign in to comment.