From b263f500eaaf802e90ee023c4a6c4b6aa068dd7e Mon Sep 17 00:00:00 2001 From: Simon Warren <33803336+swarren12@users.noreply.github.com> Date: Sun, 9 Jul 2023 13:16:22 +0100 Subject: [PATCH] [Fixed] Ensure licenses are recognised by `spdx_id` The recognition of licenses named by their SPDX ID is currently inconsistent; for some licenses the ID is included as an alternative name, but for some it is not. This leads to inconsistent behaviour, as seen in issue #984. Changing the matching logic to check the SPDX ID will make this more consistent and intuitive. This fixes #984 --- lib/license_finder/license.rb | 2 +- lib/license_finder/license/definitions.rb | 22 +- .../license/definitions_spec.rb | 406 ++++++++++++++++-- spec/lib/license_finder/license_spec.rb | 2 +- 4 files changed, 375 insertions(+), 57 deletions(-) diff --git a/lib/license_finder/license.rb b/lib/license_finder/license.rb index 7d9978c1..324306e0 100644 --- a/lib/license_finder/license.rb +++ b/lib/license_finder/license.rb @@ -85,7 +85,7 @@ def unrecognized_matcher? attr_reader :short_name, :pretty_name, :other_names, :spdx_id, :matcher def names - ([short_name, pretty_name] + other_names).uniq + ([short_name, pretty_name, spdx_id] + other_names).uniq end end diff --git a/lib/license_finder/license/definitions.rb b/lib/license_finder/license/definitions.rb index ac2d6b80..46a87ba4 100644 --- a/lib/license_finder/license/definitions.rb +++ b/lib/license_finder/license/definitions.rb @@ -46,12 +46,9 @@ def build_unrecognized(name) def apache1_1 License.new( short_name: 'Apache1_1', - pretty_name: 'Apache 1.1', spdx_id: 'Apache-1.1', - other_names: [ - 'Apache-1.1', - 'The Apache Software License, Version 1.1' - ], + pretty_name: 'Apache 1.1', + other_names: ['Apache Software License, Version 1.1'], url: 'http://www.apache.org/licenses/LICENSE-1.1.txt' ) end @@ -59,10 +56,9 @@ def apache1_1 def apache2 License.new( short_name: 'Apache2', - pretty_name: 'Apache 2.0', spdx_id: 'Apache-2.0', + pretty_name: 'Apache 2.0', other_names: [ - 'Apache-2.0', 'Apache Software License', 'Apache License 2.0', 'Apache License Version 2.0', @@ -83,7 +79,7 @@ def bsd License.new( short_name: 'BSD', spdx_id: 'BSD-4-Clause', - other_names: ['BSD4', 'bsd-old', '4-clause BSD', 'BSD-4-Clause', 'BSD 4-Clause', 'BSD License'], + other_names: ['BSD4', 'bsd-old', '4-clause BSD', 'BSD 4-Clause', 'BSD License'], url: 'http://en.wikipedia.org/wiki/BSD_licenses#4-clause_license_.28original_.22BSD_License.22.29' ) end @@ -118,7 +114,6 @@ def eclipse1 spdx_id: 'EPL-1.0', pretty_name: 'Eclipse Public License 1.0', other_names: [ - 'EPL-1.0', 'EPL 1.0', 'Eclipse Public License - v 1.0' ], @@ -167,7 +162,6 @@ def lgpl2_1 spdx_id: 'LGPL-2.1-only', pretty_name: 'GNU Lesser General Public License version 2.1', other_names: [ - 'LGPL-2.1-only', 'LGPL 2.1', 'LGPL v2.1', 'GNU Lesser General Public License 2.1' @@ -191,7 +185,7 @@ def mit License.new( short_name: 'MIT', spdx_id: 'MIT', - other_names: ['Expat', 'MIT license', 'MIT License', 'The MIT License (MIT)'], + other_names: ['Expat', 'MIT license', 'MIT License (MIT)'], url: 'http://opensource.org/licenses/mit-license', matcher: matcher ) @@ -213,7 +207,6 @@ def mpl1_1 spdx_id: 'MPL-1.1', pretty_name: 'Mozilla Public License 1.1', other_names: [ - 'MPL-1.1', 'Mozilla Public License, Version 1.1', 'Mozilla Public License version 1.1' ], @@ -235,7 +228,6 @@ def mpl2 spdx_id: 'MPL-2.0', pretty_name: 'Mozilla Public License 2.0', other_names: [ - 'MPL-2.0', 'Mozilla Public License, Version 2.0', 'Mozilla Public License version 2.0' ], @@ -267,7 +259,6 @@ def newbsd 'BSD-3', '3-clause BSD', '3-Clause BSD License', - 'BSD-3-Clause', 'BSD 3-Clause', 'BSD 3-Clause License', 'The 3-Clause BSD License', @@ -332,9 +323,8 @@ def simplifiedbsd other_names: [ 'FreeBSD', '2-clause BSD', - 'BSD-2-Clause', 'BSD 2-Clause', - 'The BSD 2-Clause License' + 'BSD 2-Clause License' ], url: 'http://opensource.org/licenses/bsd-license' ) diff --git a/spec/lib/license_finder/license/definitions_spec.rb b/spec/lib/license_finder/license/definitions_spec.rb index 0b545237..2fba41a1 100644 --- a/spec/lib/license_finder/license/definitions_spec.rb +++ b/spec/lib/license_finder/license/definitions_spec.rb @@ -12,51 +12,230 @@ end end +describe LicenseFinder::License, 'Apache1.1' do + subject { described_class.find_by_name 'Apache1_1' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.apache.org/licenses/LICENSE-1.1.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('Apache-1.1')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Apache 1.1')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Apache Software License, Version 1.1')).to be subject + expect(described_class.find_by_name('The Apache Software License, Version 1.1')).to be subject + end +end + describe LicenseFinder::License, 'Apache2' do - it 'should be recognized' do |_e| - expect(described_class.find_by_name('Apache2').url).to be + subject { described_class.find_by_name 'Apache2' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.apache.org/licenses/LICENSE-2.0.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('Apache-2.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Apache 2.0')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Apache License')).to be subject + expect(described_class.find_by_name('Apache Software License')).to be subject + expect(described_class.find_by_name('Apache 2')).to be subject + expect(described_class.find_by_name('Apache License, Version 2.0')).to be subject + expect(described_class.find_by_name('The Apache License, Version 2.0')).to be subject + expect(described_class.find_by_name('ASL 2.0')).to be subject + expect(described_class.find_by_name('ASF 2.0')).to be subject end end describe LicenseFinder::License, 'BSD' do - it 'should be recognized' do |_e| - expect(described_class.find_by_name('BSD').url).to be + subject { described_class.find_by_name 'BSD' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://en.wikipedia.org/wiki/BSD_licenses#4-clause_license_.28original_.22BSD_License.22.29' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('BSD-4-Clause')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('bsd-old')).to be subject + expect(described_class.find_by_name('BSD 4-Clause')).to be subject + expect(described_class.find_by_name('BSD License')).to be subject + expect(described_class.find_by_name('The BSD License')).to be subject end end describe LicenseFinder::License, 'cc01' do - it 'should be recognized' do |_e| - expect(described_class.find_by_name('CC0 1.0').url).to be + subject { described_class.find_by_name 'CC01' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://creativecommons.org/publicdomain/zero/1.0' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('CC0-1.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('CC0 1.0 Universal')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('CC0 1.0')).to be subject + end +end + +describe LicenseFinder::License, 'CDDL1' do + subject { described_class.find_by_name 'CDDL1' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://spdx.org/licenses/CDDL-1.0.html' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('CDDL-1.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Common Development and Distribution License 1.0')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('CDDL-1.0')).to be subject + expect(described_class.find_by_name('Common Development and Distribution License (CDDL) v1.0')).to be subject + expect(described_class.find_by_name('COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0')).to be subject + end +end + +describe LicenseFinder::License, 'EPL1' do + subject { described_class.find_by_name 'EPL1' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://www.eclipse.org/legal/epl-v10.html' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('EPL-1.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Eclipse Public License 1.0')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('EPL 1.0')).to be subject + expect(described_class.find_by_name('Eclipse Public License - v 1.0')).to be subject end end describe LicenseFinder::License, 'GPLv2' do - it 'should be recognized' do - expect(described_class.find_by_name('GPLv2').url).to be + subject { described_class.find_by_name 'GPLv2' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.gnu.org/licenses/gpl-2.0.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('GPL-2.0-only')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('GPL V2')).to be subject + expect(described_class.find_by_name('gpl-v2')).to be subject + expect(described_class.find_by_name('GNU GENERAL PUBLIC LICENSE Version 2')).to be subject end end describe LicenseFinder::License, 'GPLv3' do - it 'should be recognized' do - expect(described_class.find_by_name('GPLv3').url).to be + subject { described_class.find_by_name 'GPLv3' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.gnu.org/licenses/gpl-3.0.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('GPL-3.0-only')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('GPL V3')).to be subject + expect(described_class.find_by_name('gpl-v3')).to be subject + expect(described_class.find_by_name('GNU GENERAL PUBLIC LICENSE Version 3')).to be subject end end describe LicenseFinder::License, 'ISC' do - it 'should be recognized' do - expect(described_class.find_by_name('ISC').url).to be + subject { described_class.find_by_name 'ISC' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://en.wikipedia.org/wiki/ISC_license' end end describe LicenseFinder::License, 'LGPL' do - it 'should be recognized' do - expect(described_class.find_by_name('LGPL').url).to be + subject { described_class.find_by_name 'LGPL' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.gnu.org/licenses/lgpl.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('LGPL-3.0-only')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('LGPL-3')).to be subject + expect(described_class.find_by_name('LGPLv3')).to be subject + expect(described_class.find_by_name('LGPL-3.0')).to be subject + end +end + +describe LicenseFinder::License, 'LGPL2.1' do + subject { described_class.find_by_name 'LGPL2_1' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://opensource.org/licenses/LGPL-2.1' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('LGPL-2.1-only')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('LGPL 2.1')).to be subject + expect(described_class.find_by_name('LGPL v2.1')).to be subject + expect(described_class.find_by_name('GNU Lesser General Public License 2.1')).to be subject end end describe LicenseFinder::License, 'MIT' do subject { described_class.find_by_name 'MIT' } + it 'should have correct license url' do + expect(subject.url).to be 'http://opensource.org/licenses/mit-license' + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Expat')).to be subject + expect(described_class.find_by_name('MIT license')).to be subject + expect(described_class.find_by_name('MIT License')).to be subject + expect(described_class.find_by_name('MIT License (MIT)')).to be subject + expect(described_class.find_by_name('The MIT License (MIT)')).to be subject + end + describe '#matches_text?' do it 'should return true if the text contains the MIT url' do expect(subject).to be_matches_text 'MIT License is awesome http://opensource.org/licenses/mit-license' @@ -85,17 +264,34 @@ describe LicenseFinder::License, 'MPL1_1' do subject { described_class.find_by_name 'MPL1_1' } - it 'should be recognized' do - expect(subject).to be + it 'should have correct license url' do + expect(subject.url).to be 'https://www.mozilla.org/media/MPL/1.1/index.0c5913925d40.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('MPL-1.1')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Mozilla Public License 1.1')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Mozilla Public License, Version 1.1')).to be subject + expect(described_class.find_by_name('Mozilla Public License version 1.1')).to be subject end describe '#matches_text?' do it "should return true if the text begins with 'Mozilla Public License Version 1.1'" do expect(subject).to be_matches_text 'Mozilla Public License Version 1.1' + expect(subject).to be_matches_text 'Mozilla Public License, Version 1.1' + expect(subject).to be_matches_text 'Mozilla Public Licence Version 1.1' end it "should return false if the text beings with 'Mozilla Public License, version 2.0'" do + expect(subject).not_to be_matches_text 'Mozilla Public License version 2.0' expect(subject).not_to be_matches_text 'Mozilla Public License, version 2.0' + expect(subject).not_to be_matches_text 'Mozilla Public Licence version 2.0' end end end @@ -103,6 +299,23 @@ describe LicenseFinder::License, 'MPL2' do subject { described_class.find_by_name 'MPL2' } + it 'should have correct license url' do + expect(subject.url).to be 'https://www.mozilla.org/media/MPL/2.0/index.815ca599c9df.txt' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('MPL-2.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Mozilla Public License 2.0')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Mozilla Public License, Version 2.0')).to be subject + expect(described_class.find_by_name('Mozilla Public License version 2.0')).to be subject + end + describe '#matches_text?' do it "should return true if the text begins with 'The Mozilla Public License, version 2.0'" do expect(subject).to be_matches_text 'Mozilla Public License, version 2.0' @@ -115,6 +328,34 @@ describe LicenseFinder::License, 'NewBSD' do subject { described_class.find_by_name 'NewBSD' } + it 'should have correct license url' do + expect(subject.url).to be 'http://opensource.org/licenses/BSD-3-Clause' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('BSD-3-Clause')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('New BSD')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('Modified BSD')).to be subject + expect(described_class.find_by_name('BSD3')).to be subject + expect(described_class.find_by_name('BSD 3')).to be subject + expect(described_class.find_by_name('BSD-3')).to be subject + expect(described_class.find_by_name('3-clause BSD')).to be subject + expect(described_class.find_by_name('3-Clause BSD License')).to be subject + expect(described_class.find_by_name('BSD 3-Clause')).to be subject + expect(described_class.find_by_name('BSD 3-Clause License')).to be subject + expect(described_class.find_by_name('The 3-Clause BSD License')).to be subject + expect(described_class.find_by_name('BSD 3-clause New License')).to be subject + expect(described_class.find_by_name('New BSD License')).to be subject + expect(described_class.find_by_name('BSD New license')).to be subject + expect(described_class.find_by_name('BSD Licence 3')).to be subject + end + it 'should match regardless of organization or copyright holder names' do license = <<-LICENSE Redistribution and use in source and binary forms, with or without @@ -173,20 +414,58 @@ end describe LicenseFinder::License, 'OFL' do - it 'should be recognized' do - expect(described_class.find_by_name('OFL').url).to be + subject { described_class.find_by_name 'OFL' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://opensource.org/licenses/OFL-1.1' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('OFL-1.1')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('SIL OPEN FONT LICENSE Version 1.1')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('OPEN FONT LICENSE Version 1.1')).to be subject end end describe LicenseFinder::License, 'Python' do - it 'should be recognized' do - expect(described_class.find_by_name('Python').url).to be + subject { described_class.find_by_name 'Python' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://hg.python.org/cpython/raw-file/89ce323357db/LICENSE' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('PSF-2.0')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Python Software Foundation License')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('PSF')).to be subject + expect(described_class.find_by_name('PSFL')).to be subject + expect(described_class.find_by_name('PSF License')).to be subject end end describe LicenseFinder::License, 'Ruby' do subject { described_class.find_by_name 'Ruby' } + it 'should have correct license url' do + expect(subject.url).to be 'http://www.ruby-lang.org/en/LICENSE.txt' + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('ruby')).to be subject + end + describe '#matches?' do it 'should return true when the Ruby license URL is present' do expect(subject).to be_matches_text "This gem is available under the following license:\nhttp://www.ruby-lang.org/en/LICENSE.txt\nOkay?" @@ -203,39 +482,88 @@ end describe LicenseFinder::License, 'SimplifiedBSD' do - it 'should be recognized' do - expect(described_class.find_by_name('SimplifiedBSD').url).to be + subject { described_class.find_by_name 'SimplifiedBSD' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://opensource.org/licenses/bsd-license' + end + + it 'should be recognized by spdx_id' do + expect(described_class.find_by_name('BSD-2-Clause')).to be subject + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('Simplified BSD')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('FreeBSD')).to be subject + expect(described_class.find_by_name('2-clause BSD')).to be subject + expect(described_class.find_by_name('BSD 2-Clause')).to be subject + expect(described_class.find_by_name('BSD 2-Clause License')).to be subject + expect(described_class.find_by_name('The BSD 2-Clause License')).to be subject end end describe LicenseFinder::License, 'Unlicense' do - it 'should be recognized' do - expect(described_class.find_by_name('Unlicense').name).to eq('The Unlicense') - expect(described_class.find_by_name('Unlicense').url).to be + subject { described_class.find_by_name 'Unlicense' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://unlicense.org/' + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('The Unlicense')).to be subject end end describe LicenseFinder::License, 'WTFPL' do - it 'should be recognized' do - expect(described_class.find_by_name('WTFPL').name).to eq('WTFPL') - expect(described_class.find_by_name('WTFPL').url).to be - expect(described_class.find_by_name('WTFPL V2').url).to be - expect(described_class.find_by_name('Do What The Fuck You Want To Public License').url).to be + subject { described_class.find_by_name 'WTFPL' } + + it 'should have correct license url' do + expect(subject.url).to be 'http://www.wtfpl.net/' + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('WTFPL V2')).to be subject + expect(described_class.find_by_name('Do What The Fuck You Want To Public License')).to be subject end end describe LicenseFinder::License, '0BSD' do - it 'should be recognized' do - expect(described_class.find_by_name('0BSD').url).to be - expect(described_class.find_by_name('Zero-Clause BSD').url).to be + subject { described_class.find_by_name '0BSD' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://opensource.org/licenses/0BSD' + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('BSD Zero Clause License')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('0-Clause BSD')).to be subject + expect(described_class.find_by_name('Zero-Clause BSD')).to be subject + expect(described_class.find_by_name('BSD-0-Clause')).to be subject + expect(described_class.find_by_name('BSD-Zero-Clause')).to be subject + expect(described_class.find_by_name('BSD 0-Clause')).to be subject + expect(described_class.find_by_name('BSD Zero-Clause')).to be subject end end describe LicenseFinder::License, 'Zlib' do - it 'should be recognized' do - expect(described_class.find_by_name('Zlib').url).to be - expect(described_class.find_by_name('zlib/libpng license').url).to be - expect(described_class.find_by_name('zlib License').url).to be + subject { described_class.find_by_name 'Zlib' } + + it 'should have correct license url' do + expect(subject.url).to be 'https://opensource.org/licenses/Zlib' + end + + it 'should be recognized by pretty name' do + expect(described_class.find_by_name('zlib/libpng license')).to be subject + end + + it 'should be recognised by other names' do + expect(described_class.find_by_name('zlib License')).to be subject end it 'should match regardless of year or copyright holder names' do @@ -263,7 +591,7 @@ source distribution. LICENSE - expect(described_class.find_by_name('Zlib')).to be_matches_text license - expect(described_class.find_by_name('Zlib')).not_to be_matches_text 'SOME OTHER LICENSE' + expect(subject).to be_matches_text license + expect(subject).not_to be_matches_text 'SOME OTHER LICENSE' end end diff --git a/spec/lib/license_finder/license_spec.rb b/spec/lib/license_finder/license_spec.rb index 90ddd24f..03760735 100644 --- a/spec/lib/license_finder/license_spec.rb +++ b/spec/lib/license_finder/license_spec.rb @@ -13,7 +13,7 @@ module LicenseFinder it 'should create populate sub licenses for compound AND' do license = License.find_by_name('(MIT AND CC0-1.0)') expect(license.sub_licenses[0].name).to eq 'MIT' - expect(license.sub_licenses[1].name).to eq 'CC0-1.0' + expect(license.sub_licenses[1].name).to eq 'CC0 1.0 Universal' end end end