licensee 8.7.0 → 8.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,6 +37,22 @@ RSpec.describe 'integration test' do
37
37
  end
38
38
  end
39
39
 
40
+ context 'with CC-BY-NC-SA' do
41
+ let(:fixture) { 'cc-by-nc-sa' }
42
+
43
+ it 'matches nothing' do
44
+ expect(subject.license).to eql(nil)
45
+ end
46
+ end
47
+
48
+ context 'with CC-BY-ND' do
49
+ let(:fixture) { 'cc-by-nd' }
50
+
51
+ it 'matches nothing' do
52
+ expect(subject.license).to eql(nil)
53
+ end
54
+ end
55
+
40
56
  context 'MPL with HRs removed' do
41
57
  let(:license) { Licensee::License.find('mpl-2.0') }
42
58
  let(:fixture) { 'mpl-without-hrs' }
@@ -45,6 +61,15 @@ RSpec.describe 'integration test' do
45
61
  expect(subject.license).to eql(license)
46
62
  end
47
63
  end
64
+
65
+ context 'GPL3 with instructions removed' do
66
+ let(:license) { Licensee::License.find('gpl-3.0') }
67
+ let(:fixture) { 'gpl3-without-instructions' }
68
+
69
+ it 'matches to GPL3' do
70
+ expect(subject.license).to eql(license)
71
+ end
72
+ end
48
73
  end
49
74
 
50
75
  context 'with the license file stubbed' do
@@ -3,6 +3,8 @@ class ContentHelperTestHelper
3
3
  attr_accessor :content
4
4
 
5
5
  DEFAULT_CONTENT = <<-EOS.freeze
6
+ The MIT License
7
+
6
8
  Copyright 2016 Ben Balter
7
9
 
8
10
  The made
@@ -32,12 +34,12 @@ RSpec.describe Licensee::ContentHelper do
32
34
  end
33
35
 
34
36
  it 'knows the length delta' do
35
- expect(subject.length_delta(mit)).to eql(1012)
37
+ expect(subject.length_delta(mit)).to eql(1000)
36
38
  expect(subject.length_delta(subject)).to eql(0)
37
39
  end
38
40
 
39
41
  it 'knows the similarity' do
40
- expect(subject.similarity(mit)).to be_within(1).of(4)
42
+ expect(subject.similarity(mit)).to be_within(1).of(2)
41
43
  expect(subject.similarity(subject)).to eql(100.0)
42
44
  end
43
45
 
@@ -70,6 +72,33 @@ RSpec.describe Licensee::ContentHelper do
70
72
  expect(normalized_content).to_not match(/\n/)
71
73
  end
72
74
 
75
+ Licensee::License.all(hidden: true).each do |license|
76
+ context license.name do
77
+ it 'strips the title' do
78
+ regex = /\A#{license.name_without_version}/i
79
+ expect(license.content_normalized).to_not match(regex)
80
+ end
81
+
82
+ it 'strips the version' do
83
+ expect(license.content_normalized).to_not match(/\Aversion/i)
84
+ end
85
+
86
+ it 'strips the copyright' do
87
+ expect(license.content_normalized).to_not match(/\Acopyright/i)
88
+ end
89
+
90
+ it 'strips the implementation instructions' do
91
+ end_terms_regex = /END OF TERMS AND CONDITIONS/i
92
+ expect(license.content_normalized).to_not match(end_terms_regex)
93
+ expect(license.content_normalized).to_not match(/How to apply/i)
94
+ end
95
+ end
96
+ end
97
+
98
+ it 'strips the title' do
99
+ expect(normalized_content).to_not match('MIT')
100
+ end
101
+
73
102
  it 'normalize the content' do
74
103
  expect(normalized_content).to eql 'the made up license.'
75
104
  end
@@ -168,6 +168,11 @@ RSpec.describe Licensee::License do
168
168
  expect(mit).to_not be_gpl
169
169
  expect(gpl).to be_gpl
170
170
  end
171
+
172
+ it 'knows if a license is CC' do
173
+ expect(gpl).to_not be_creative_commons
174
+ expect(cc_by).to be_creative_commons
175
+ end
171
176
  end
172
177
 
173
178
  context 'content' do
@@ -180,7 +185,7 @@ RSpec.describe Licensee::License do
180
185
  end
181
186
 
182
187
  it 'computes the hash' do
183
- expect(mit.hash).to eql('750260c322080bab4c19fd55eb78bc73e1ae8f11')
188
+ expect(mit.hash).to eql('d64f3bb4282a97b37454b5bb96a8a264a3363dc3')
184
189
  end
185
190
 
186
191
  context 'with content stubbed' do
@@ -25,14 +25,15 @@ RSpec.describe Licensee::Matchers::Copyright do
25
25
  'UTF-8 Encoded' => 'Copyright (c) 2010-2014 Simon Hürlimann',
26
26
  'Comma-separated date' => 'Copyright (c) 2003, 2004 Ben Balter',
27
27
  'Hyphen-separated date' => 'Copyright (c) 2003-2004 Ben Balter',
28
- 'ASCII-8BIT encoded' => "Copyright \xC2\xA92015 Ben Balter`"
28
+ 'ASCII-8BIT encoded' => "Copyright \xC2\xA92015 Ben Balter`",
29
+ 'No year' => 'Copyright Ben Balter'
29
30
  .force_encoding('ASCII-8BIT')
30
31
  }.each do |description, notice|
31
32
  context "with a #{description} notice" do
32
33
  let(:content) { notice }
33
34
 
34
35
  it 'matches' do
35
- expect(subject.match).to eql(no_license)
36
+ expect(content).to be_detected_as(no_license)
36
37
  end
37
38
  end
38
39
  end
@@ -1,6 +1,9 @@
1
1
  RSpec.describe Licensee::Matchers::Dice do
2
+ let(:mit) { Licensee::License.find('mit') }
2
3
  let(:gpl) { Licensee::License.find('gpl-3.0') }
3
4
  let(:agpl) { Licensee::License.find('agpl-3.0') }
5
+ let(:cc_by) { Licensee::License.find('cc-by-4.0') }
6
+ let(:cc_by_sa) { Licensee::License.find('cc-by-sa-4.0') }
4
7
  let(:content) { sub_copyright_info(gpl.content) }
5
8
  let(:file) { Licensee::Project::LicenseFile.new(content, 'LICENSE.txt') }
6
9
  subject { described_class.new(file) }
@@ -19,12 +22,12 @@ RSpec.describe Licensee::Matchers::Dice do
19
22
 
20
23
  it 'sorts licenses by similarity' do
21
24
  expect(subject.licenses_by_similiarity[0]).to eql([gpl, 100.0])
22
- expect(subject.licenses_by_similiarity[1]).to eql([agpl, 94.06571848945562])
25
+ expect(subject.licenses_by_similiarity[1]).to eql([agpl, 95.73361082206036])
23
26
  end
24
27
 
25
28
  it 'returns a list of licenses above the confidence threshold' do
26
29
  expect(subject.licenses_by_similiarity[0]).to eql([gpl, 100.0])
27
- expect(subject.licenses_by_similiarity[1]).to eql([agpl, 94.06571848945562])
30
+ expect(subject.licenses_by_similiarity[1]).to eql([agpl, 95.73361082206036])
28
31
  end
29
32
 
30
33
  it 'returns the match confidence' do
@@ -40,4 +43,42 @@ RSpec.describe Licensee::Matchers::Dice do
40
43
  expect(subject.confidence).to eql(0)
41
44
  end
42
45
  end
46
+
47
+ context 'stacked licenses' do
48
+ let(:content) do
49
+ sub_copyright_info(mit.content) + "\n\n" + sub_copyright_info(gpl.content)
50
+ end
51
+
52
+ it "doesn't match" do
53
+ skip 'Stacked MIT + GPL not properly detected'
54
+ expect(content).to_not be_detected_as(gpl)
55
+ expect(subject.match).to eql(nil)
56
+ expect(subject.matches).to be_empty
57
+ expect(subject.confidence).to eql(0)
58
+ end
59
+ end
60
+
61
+ context 'CC false positive' do
62
+ context 'CC-BY' do
63
+ let(:content) { cc_by.content }
64
+
65
+ it 'matches' do
66
+ expect(content).to be_detected_as(cc_by)
67
+ end
68
+ end
69
+
70
+ context 'CC-ND' do
71
+ let(:project_path) { fixture_path('cc-by-nd') }
72
+ let(:license_path) { File.expand_path('LICENSE', project_path) }
73
+ let(:content) { File.read(license_path) }
74
+
75
+ it "doesn't match" do
76
+ expect(content).to_not be_detected_as(cc_by)
77
+ expect(content).to_not be_detected_as(cc_by_sa)
78
+ expect(subject.match).to be_nil
79
+ expect(subject.matches).to be_empty
80
+ expect(subject.confidence).to eql(0)
81
+ end
82
+ end
83
+ end
43
84
  end
@@ -0,0 +1,32 @@
1
+ RSpec.describe Licensee::Matchers::DistZilla do
2
+ let(:mit) { Licensee::License.find('mit') }
3
+ let(:content) { 'license = MIT' }
4
+ let(:file) { Licensee::Project::LicenseFile.new(content, 'dist.ini') }
5
+ subject { described_class.new(file) }
6
+
7
+ it 'stores the file' do
8
+ expect(subject.file).to eql(file)
9
+ end
10
+
11
+ it 'has confidence' do
12
+ expect(subject.confidence).to eql(90)
13
+ end
14
+
15
+ it 'matches' do
16
+ expect(subject.match).to eql(mit)
17
+ end
18
+
19
+ {
20
+ 'spdx name' => ['license = MIT', 'mit'],
21
+ 'non spdx name' => ['license = Mozilla_2_0', 'mpl-2.0']
22
+ }.each do |description, license_declaration_and_key|
23
+ context "with a #{description}" do
24
+ let(:content) { license_declaration_and_key[0] }
25
+ let(:license) { Licensee::License.find(license_declaration_and_key[1]) }
26
+
27
+ it 'matches' do
28
+ expect(subject.match).to eql(license)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -9,7 +9,7 @@ RSpec.describe Licensee::Matchers::Exact do
9
9
  end
10
10
 
11
11
  it 'matches' do
12
- expect(subject.match).to eql(mit)
12
+ expect(content).to be_detected_as(mit)
13
13
  end
14
14
 
15
15
  it 'is confident' do
@@ -18,12 +18,12 @@ RSpec.describe Licensee::Project::LicenseFile do
18
18
  end
19
19
 
20
20
  it 'creates the wordset' do
21
- expect(subject.wordset.count).to eql(93)
22
- expect(subject.wordset.first).to eql('mit')
21
+ expect(subject.wordset.count).to eql(91)
22
+ expect(subject.wordset.first).to eql('permission')
23
23
  end
24
24
 
25
25
  it 'creates the hash' do
26
- expect(subject.hash).to eql('750260c322080bab4c19fd55eb78bc73e1ae8f11')
26
+ expect(subject.hash).to eql('d64f3bb4282a97b37454b5bb96a8a264a3363dc3')
27
27
  end
28
28
 
29
29
  context 'filename scoring' do
@@ -119,4 +119,40 @@ RSpec.describe Licensee::Project::LicenseFile do
119
119
  end
120
120
  end
121
121
  end
122
+
123
+ context 'CC false positives' do
124
+ let(:regex) { Licensee::Project::LicenseFile::CC_FALSE_POSITIVE_REGEX }
125
+
126
+ it "knows MIT isn't a potential false positive" do
127
+ expect(subject.content).to_not match(regex)
128
+ expect(subject).to_not be_a_potential_false_positive
129
+ end
130
+
131
+ context 'a CC false positive without creative commons in the title' do
132
+ let(:content) { 'Creative Commons Attribution-NonCommercial 4.0' }
133
+
134
+ it "knows it's a potential false positive" do
135
+ expect(subject.content).to match(regex)
136
+ expect(subject).to be_a_potential_false_positive
137
+ end
138
+ end
139
+
140
+ context 'a CC false positive without creative commons in the title' do
141
+ let(:content) { 'Attribution-NonCommercial 4.0 International' }
142
+
143
+ it "knows it's a potential false positive" do
144
+ expect(subject.content).to match(regex)
145
+ expect(subject).to be_a_potential_false_positive
146
+ end
147
+ end
148
+
149
+ context 'CC-BY-ND' do
150
+ let(:content) { 'Attribution-NoDerivatives 4.0 International' }
151
+
152
+ it "knows it's a potential false positive" do
153
+ expect(subject.content).to match(regex)
154
+ expect(subject).to be_a_potential_false_positive
155
+ end
156
+ end
157
+ end
122
158
  end
@@ -8,6 +8,7 @@ RSpec.describe Licensee::Project::PackageInfo do
8
8
  'licensee.gemspec' => 1.0,
9
9
  'package.json' => 1.0,
10
10
  'DESCRIPTION' => 0.9,
11
+ 'dist.ini' => 0.8,
11
12
  'bower.json' => 0.75,
12
13
  'README.md' => 0.0
13
14
  }.each do |filename, expected_score|
@@ -39,6 +40,14 @@ RSpec.describe Licensee::Project::PackageInfo do
39
40
  end
40
41
  end
41
42
 
43
+ context 'with dist.ini' do
44
+ let(:filename) { 'dist.ini' }
45
+
46
+ it 'returns the DistZilla matcher' do
47
+ expect(possible_matchers).to eql([Licensee::Matchers::DistZilla])
48
+ end
49
+ end
50
+
42
51
  context 'with DESCRIPTION' do
43
52
  let(:filename) { 'DESCRIPTION' }
44
53
  let(:content) { 'Package: test' }
data/spec/spec_helper.rb CHANGED
@@ -38,10 +38,6 @@ end
38
38
 
39
39
  def wrap(text, line_width = 80)
40
40
  text = text.clone
41
- copyright = /^#{Licensee::Matchers::Copyright::REGEX}$/i.match(text)
42
- if copyright
43
- text.gsub!(/^#{Licensee::Matchers::Copyright::REGEX}$/i, '[COPYRIGHT]')
44
- end
45
41
  text.gsub!(/([^\n])\n([^\n])/, '\1 \2')
46
42
 
47
43
  text = text.split("\n").collect do |line|
@@ -51,7 +47,7 @@ def wrap(text, line_width = 80)
51
47
  line
52
48
  end
53
49
  end * "\n"
54
- text.gsub! '[COPYRIGHT]', "\n#{copyright}\n" if copyright
50
+
55
51
  text.strip
56
52
  end
57
53
 
@@ -65,14 +61,52 @@ def add_random_words(string, count = 5)
65
61
  string
66
62
  end
67
63
 
64
+ # Init git dir
65
+ # Note: we disable gpgsign and restore it to its original setting to avoid
66
+ # Signing commits during tests and slowing down / breaking specs
68
67
  def git_init(path)
69
68
  Dir.chdir path do
70
69
  `git init`
70
+ gpgsign = `git config --local commit.gpgsign`
71
+ `git config --local commit.gpgsign false`
71
72
  `git add .`
72
73
  `git commit -m 'initial commit'`
74
+ `git config --local commit.gpgsign #{gpgsign}`
73
75
  end
74
76
  end
75
77
 
78
+ def format_percent(float)
79
+ "#{format('%.2f', float)}%"
80
+ end
81
+
76
82
  RSpec::Matchers.define :be_an_existing_file do
77
83
  match { |path| File.exist?(path) }
78
84
  end
85
+
86
+ RSpec::Matchers.define :be_detected_as do |expected|
87
+ match do |actual|
88
+ @expected_as_array = [expected.content]
89
+ license_file = Licensee::Project::LicenseFile.new(actual, 'LICENSE')
90
+ return false unless license_file.license
91
+ values_match? expected, license_file.license
92
+ end
93
+
94
+ failure_message do |actual|
95
+ license_file = Licensee::Project::LicenseFile.new(actual, 'LICENSE')
96
+ license_name = expected.meta['spdx-id'] || expected.key
97
+ similarity = expected.similarity(license_file)
98
+ msg = "Expected the content to match the #{license_name} license"
99
+ msg << " (#{format_percent(similarity)} similarity"
100
+ msg << "using the #{license_file.matcher} matcher)"
101
+ end
102
+
103
+ failure_message_when_negated do |actual|
104
+ license_file = Licensee::Project::LicenseFile.new(actual, 'LICENSE')
105
+ license_name = expected.meta['spdx-id'] || expected.key
106
+ similarity = expected.similarity(license_file)
107
+ msg = "Expected the content to *not* match the #{license_name} license"
108
+ msg << " (#{format_percent(similarity)} similarity)"
109
+ end
110
+
111
+ diffable
112
+ end
@@ -1,7 +1,7 @@
1
1
  RSpec.describe 'vendored licenes' do
2
2
  let(:filename) { 'LICENSE.txt' }
3
3
  let(:license_file) { Licensee::Project::LicenseFile.new(content, filename) }
4
- let(:detected_license) { license_file.license }
4
+ let(:detected_license) { license_file.license if license_file }
5
5
  let(:wtfpl) { Licensee::License.find('wtfpl') }
6
6
 
7
7
  Licensee.licenses(hidden: true).each do |license|
@@ -12,11 +12,11 @@ RSpec.describe 'vendored licenes' do
12
12
  let(:content) { content_with_copyright }
13
13
 
14
14
  it 'detects the license' do
15
- expect(detected_license).to eql(license)
15
+ expect(content).to be_detected_as(license)
16
16
  end
17
17
 
18
18
  context 'when modified' do
19
- let(:line_length) { 50 }
19
+ let(:line_length) { 60 }
20
20
  let(:random_words) { 3 }
21
21
  let(:content_rewrapped) { wrap(content_with_copyright, line_length) }
22
22
  let(:content_with_random_words) do
@@ -24,23 +24,21 @@ RSpec.describe 'vendored licenes' do
24
24
  end
25
25
 
26
26
  context 'without the title' do
27
- let(:content) do
28
- content = content_with_copyright.sub(/\A.*license\n/i, '')
29
- content.sub(/\A#{license.name}/i, '')
30
- end
27
+ let(:content) { wtfpl.send :strip_title, content_with_copyright }
31
28
 
32
29
  it 'detects the license' do
33
- # WTFPL is too short to be mofifed and still be detected
34
- expect(detected_license).to eql(license) unless license == wtfpl
30
+ skip 'The WTFPL is too short to be modified' if license == wtfpl
31
+ expect(content).to be_detected_as(license)
35
32
  end
36
33
  end
37
34
 
38
35
  context 'with a double title' do
39
- let(:content) { "#{license.name}\n\n#{content_with_copyright}" }
36
+ let(:content) do
37
+ "#{license.name.sub('*', 'u')}\n\n#{content_with_copyright}"
38
+ end
40
39
 
41
40
  it 'detects the license' do
42
- # WTFPL is too short to be mofifed and still be detected
43
- expect(detected_license).to eql(license) unless license == wtfpl
41
+ expect(content).to be_detected_as(license)
44
42
  end
45
43
  end
46
44
 
@@ -48,7 +46,7 @@ RSpec.describe 'vendored licenes' do
48
46
  let(:content) { content_rewrapped }
49
47
 
50
48
  it 'detects the license' do
51
- expect(detected_license).to eql(license)
49
+ expect(content).to be_detected_as(license)
52
50
  end
53
51
  end
54
52
 
@@ -56,8 +54,8 @@ RSpec.describe 'vendored licenes' do
56
54
  let(:content) { content_with_random_words }
57
55
 
58
56
  it 'detects the license' do
59
- # WTFPL is too short to be mofifed and still be detected
60
- expect(detected_license).to eql(license) unless license == wtfpl
57
+ skip 'The WTFPL is too short to be modified' if license == wtfpl
58
+ expect(content).to be_detected_as(license)
61
59
  end
62
60
  end
63
61
 
@@ -65,8 +63,8 @@ RSpec.describe 'vendored licenes' do
65
63
  let(:content) { wrap(content_with_random_words, line_length) }
66
64
 
67
65
  it 'detects the license' do
68
- # WTFPL is too short to be mofifed and still be detected
69
- expect(detected_license).to eql(license) unless license == wtfpl
66
+ skip 'The WTFPL is too short to be modified' if license == wtfpl
67
+ expect(content).to be_detected_as(license)
70
68
  end
71
69
  end
72
70
  end