licensee 8.3.1 → 8.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/licensee/content_helper.rb +29 -1
  4. data/lib/licensee/license.rb +4 -0
  5. data/lib/licensee/matchers/copyright_matcher.rb +2 -1
  6. data/lib/licensee/matchers/dice_matcher.rb +10 -35
  7. data/lib/licensee/matchers/exact_matcher.rb +3 -1
  8. data/lib/licensee/project.rb +36 -2
  9. data/lib/licensee/project_files/license_file.rb +5 -0
  10. data/lib/licensee/projects/fs_project.rb +14 -9
  11. data/lib/licensee/projects/git_project.rb +14 -13
  12. data/lib/licensee/version.rb +1 -1
  13. data/lib/licensee.rb +7 -1
  14. data/test/fixtures/lgpl.git/HEAD +1 -0
  15. data/test/fixtures/lgpl.git/config +5 -0
  16. data/test/fixtures/lgpl.git/objects/1a/cd060ebbbeac294200008657d9502130f93465 +2 -0
  17. data/test/fixtures/lgpl.git/objects/4b/1f98c1e95b6d4dae0b0a160f554be97e5afece +2 -0
  18. data/test/fixtures/lgpl.git/objects/a4/cfa42bc8e1d432fa851c5c4e3f294f01e05fd3 +0 -0
  19. data/test/fixtures/lgpl.git/objects/b7/de6e186bd02935030f5d42867ea7043fb1c27c +0 -0
  20. data/test/fixtures/lgpl.git/objects/dd/d0e017b1bf39218a6ea4f2fadd29a7ea8ebe03 +0 -0
  21. data/test/fixtures/lgpl.git/objects/eb/d853e83a2d317422c52f3922f4c9c5bb4a10b7 +0 -0
  22. data/test/fixtures/lgpl.git/refs/heads/master +1 -0
  23. data/test/functions.rb +16 -9
  24. data/test/{test_licensee_copyright_matcher.rb → licensee/matchers/test_copyright_matcher.rb} +6 -0
  25. data/test/{test_licensee_dice_matcher.rb → licensee/matchers/test_dice_matcher.rb} +11 -2
  26. data/test/{test_licensee_exact_matcher.rb → licensee/matchers/test_exact_matcher.rb} +8 -0
  27. data/test/{test_licensee_gemspec_matcher.rb → licensee/matchers/test_gemspec_matcher.rb} +1 -1
  28. data/test/{test_licensee_npm_bower_matcher.rb → licensee/matchers/test_npm_bower_matcher.rb} +0 -0
  29. data/test/licensee/matchers/test_package_matcher.rb +27 -0
  30. data/test/{test_licensee_license_file.rb → licensee/project_files/test_license_file.rb} +15 -0
  31. data/test/{test_licensee_package_info.rb → licensee/project_files/test_package_info.rb} +0 -0
  32. data/test/{test_licensee_readme.rb → licensee/project_files/test_readme.rb} +0 -0
  33. data/test/licensee/test_content_helper.rb +56 -0
  34. data/test/{test_licensee_license.rb → licensee/test_license.rb} +11 -0
  35. data/test/{test_licensee_project.rb → licensee/test_project.rb} +5 -0
  36. data/test/{test_licensee_project_file.rb → licensee/test_project_file.rb} +0 -0
  37. data/test/test_licensee.rb +6 -2
  38. data/vendor/choosealicense.com/_licenses/afl-3.0.txt +5 -4
  39. data/vendor/choosealicense.com/_licenses/agpl-3.0.txt +8 -7
  40. data/vendor/choosealicense.com/_licenses/apache-2.0.txt +5 -4
  41. data/vendor/choosealicense.com/_licenses/artistic-2.0.txt +6 -5
  42. data/vendor/choosealicense.com/_licenses/bsd-2-clause.txt +4 -3
  43. data/vendor/choosealicense.com/_licenses/bsd-3-clause-clear.txt +5 -5
  44. data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +4 -3
  45. data/vendor/choosealicense.com/_licenses/cc-by-4.0.txt +5 -4
  46. data/vendor/choosealicense.com/_licenses/cc-by-sa-4.0.txt +6 -5
  47. data/vendor/choosealicense.com/_licenses/cc0-1.0.txt +1 -0
  48. data/vendor/choosealicense.com/_licenses/epl-1.0.txt +6 -5
  49. data/vendor/choosealicense.com/_licenses/eupl-1.1.txt +8 -7
  50. data/vendor/choosealicense.com/_licenses/gpl-2.0.txt +7 -6
  51. data/vendor/choosealicense.com/_licenses/gpl-3.0.txt +7 -6
  52. data/vendor/choosealicense.com/_licenses/isc.txt +4 -3
  53. data/vendor/choosealicense.com/_licenses/lgpl-2.1.txt +7 -6
  54. data/vendor/choosealicense.com/_licenses/lgpl-3.0.txt +7 -7
  55. data/vendor/choosealicense.com/_licenses/lppl-1.3c.txt +6 -5
  56. data/vendor/choosealicense.com/_licenses/mit.txt +4 -3
  57. data/vendor/choosealicense.com/_licenses/mpl-2.0.txt +6 -5
  58. data/vendor/choosealicense.com/_licenses/ms-pl.txt +4 -4
  59. data/vendor/choosealicense.com/_licenses/ms-rl.txt +7 -7
  60. data/vendor/choosealicense.com/_licenses/ofl-1.1.txt +4 -4
  61. data/vendor/choosealicense.com/_licenses/osl-3.0.txt +7 -7
  62. data/vendor/choosealicense.com/_licenses/unlicense.txt +6 -1
  63. data/vendor/choosealicense.com/_licenses/wtfpl.txt +2 -2
  64. data/vendor/choosealicense.com/_licenses/zlib.txt +5 -4
  65. metadata +24 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b3f800aaf46c58f74814dc25a5f9121985b619c
4
- data.tar.gz: fbe2299058f5b7108e1f05462ced09f24cd9c13e
3
+ metadata.gz: 0ea7d783ce6fc8e59946877a34fc32d84b01f449
4
+ data.tar.gz: 65142dc4101a66360d080b7eede89977d5ca10c6
5
5
  SHA512:
6
- metadata.gz: 841d87d6848ec806dd1ecf8d557c67f2e1f7cfbf76f9dbe5175cf2363efed2e1b6f373db9831990c0884d19bdea9e2bd826b4e493169c4b71bf66a3c137a85f5
7
- data.tar.gz: 624464f0ccbd8bac06df571a31bdc8be1996a426b041ac1064f88d2aee3b57b52b9d6eb567bcce244a68bfa5c08a5f157c40360545e26c0916dcf55e1bab1a5e
6
+ metadata.gz: 9b93a5da892c334a4e3bce03be2ef7342ffda08ae64b6db412216f691af53ee9d8a7d54596c9aadaff6cd6d02038c04da21f4d4e98af222283788fdb77a340cc
7
+ data.tar.gz: d066ee5ed370b2c840cd5282f19fccf525f26cde2469a6205039ab886b5b1f2ca5e63e9ac88fc2888fa1c4657cda2b50d2f57f4da79632ac22ad4f96779bc33a
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rake/testtask'
3
3
 
4
4
  Rake::TestTask.new(:test) do |test|
5
5
  test.libs << 'lib' << 'test'
6
- test.pattern = 'test/**/test_licensee*.rb'
6
+ test.pattern = 'test/**/test_*.rb'
7
7
  end
8
8
 
9
9
  desc 'Open console with Licensee loaded'
@@ -5,22 +5,50 @@ module Licensee
5
5
  module ContentHelper
6
6
  DIGEST = Digest::SHA1
7
7
 
8
+ # A set of each word in the license, without duplicates
8
9
  def wordset
9
10
  @wordset ||= if content_normalized
10
11
  content_normalized.scan(/[\w']+/).to_set
11
12
  end
12
13
  end
13
14
 
15
+ # Number of characteres in the normalized content
16
+ def length
17
+ return 0 unless content_normalized
18
+ content_normalized.length
19
+ end
20
+
21
+ # Number of characters that could be added/removed to still be
22
+ # considered a potential match
23
+ def max_delta
24
+ (length * Licensee.inverse_confidence_threshold).to_i
25
+ end
26
+
27
+ # Given another license or project file, calculates the difference in length
28
+ def length_delta(other)
29
+ (length - other.length).abs
30
+ end
31
+
32
+ # Given another license or project file, calculates the similarity
33
+ # as a percentage of words in common
34
+ def similarity(other)
35
+ overlap = (wordset & other.wordset).size
36
+ total = wordset.size + other.wordset.size
37
+ 100.0 * (overlap * 2.0 / total)
38
+ end
39
+
40
+ # SHA1 of the normalized content
14
41
  def hash
15
42
  @hash ||= DIGEST.hexdigest content_normalized
16
43
  end
17
44
 
45
+ # Content with copyright header and linebreaks removed
18
46
  def content_normalized
19
47
  return unless content
20
48
  @content_normalized ||= begin
21
49
  content_normalized = content.downcase.strip
22
50
  content_normalized.gsub!(/^#{Matchers::Copyright::REGEX}$/i, '')
23
- content_normalized.tr("\n", ' ').squeeze(' ')
51
+ content_normalized.tr("\n", ' ').squeeze(' ').strip
24
52
  end
25
53
  end
26
54
  end
@@ -111,6 +111,10 @@ module Licensee
111
111
  meta['hidden']
112
112
  end
113
113
 
114
+ def gpl?
115
+ key == 'gpl-2.0' || key == 'gpl-3.0'
116
+ end
117
+
114
118
  # The license body (e.g., contents - frontmatter)
115
119
  def content
116
120
  @content ||= parts[2] if parts && parts[2]
@@ -2,7 +2,8 @@
2
2
  module Licensee
3
3
  module Matchers
4
4
  class Copyright
5
- REGEX = /\s*Copyright (©|\(c\)|\xC2\xA9)? ?(\d{4}|\[year\])(.*)?\s*/i
5
+ # rubocop:disable Metrics/LineLength
6
+ REGEX = /\s*(Copyright|\(c\)) (©|\(c\)|\xC2\xA9)? ?(\d{4}|\[year\])(.*)?\s*/i
6
7
 
7
8
  def initialize(file)
8
9
  @file = file
@@ -1,6 +1,8 @@
1
1
  module Licensee
2
2
  module Matchers
3
3
  class Dice
4
+ attr_reader :file
5
+
4
6
  def initialize(file)
5
7
  @file = file
6
8
  end
@@ -10,9 +12,8 @@ module Licensee
10
12
  def match
11
13
  return @match if defined? @match
12
14
  matches = potential_licenses.map do |license|
13
- if (sim = similarity(license)) >= Licensee.confidence_threshold
14
- [license, sim]
15
- end
15
+ similarity = license.similarity(file)
16
+ [license, similarity] if similarity >= Licensee.confidence_threshold
16
17
  end
17
18
  matches.compact!
18
19
  @match = if matches.empty?
@@ -22,46 +23,20 @@ module Licensee
22
23
  end
23
24
  end
24
25
 
25
- # Sort all licenses, in decending order, by difference in
26
- # length to the file
27
- # Difference in lengths cannot exceed the file's length *
28
- # the confidence threshold / 100
26
+ # Licenses that may be a match for this file.
27
+ # To avoid false positives, the percentage change in file length
28
+ # may not exceed the inverse of the confidence threshold
29
29
  def potential_licenses
30
30
  @potential_licenses ||= begin
31
- licenses = Licensee.licenses(hidden: true)
32
- licenses = licenses.select do |license|
33
- license.wordset && length_delta(license) <= max_delta
31
+ Licensee.licenses(hidden: true).select do |license|
32
+ license.wordset && license.length_delta(file) <= license.max_delta
34
33
  end
35
- licenses.sort_by { |l| length_delta(l) }
36
34
  end
37
35
  end
38
36
 
39
- # Calculate the difference between the file length and a given
40
- # license's length
41
- def length_delta(license)
42
- (@file.wordset.size - license.wordset.size).abs
43
- end
44
-
45
- # Maximum possible difference between file length and license length
46
- # for a license to be a potential license to be matched
47
- def max_delta
48
- @max_delta ||= (
49
- @file.wordset.size * (Licensee.confidence_threshold / 100.0)
50
- )
51
- end
52
-
53
37
  # Confidence that the matched license is a match
54
38
  def confidence
55
- @confidence ||= match ? similarity(match) : 0
56
- end
57
-
58
- private
59
-
60
- # Calculate percent changed between file and potential license
61
- def similarity(license)
62
- overlap = (@file.wordset & license.wordset).size
63
- total = @file.wordset.size + license.wordset.size
64
- 100.0 * (overlap * 2.0 / total)
39
+ @confidence ||= match ? file.similarity(match) : 0
65
40
  end
66
41
  end
67
42
  end
@@ -6,7 +6,9 @@ module Licensee
6
6
  end
7
7
 
8
8
  def match
9
- Licensee.licenses(hidden: true).find { |l| l.wordset == @file.wordset }
9
+ Licensee.licenses(hidden: true).find do |license|
10
+ license.length == @file.length && license.wordset == @file.wordset
11
+ end
10
12
  end
11
13
 
12
14
  def confidence
@@ -23,8 +23,16 @@ module Licensee
23
23
  def license_file
24
24
  return @license_file if defined? @license_file
25
25
  @license_file = begin
26
- content, name = find_file { |n| LicenseFile.name_score(n) }
27
- LicenseFile.new(content, name) if content && name
26
+ license_file = license_from_file { |n| LicenseFile.name_score(n) }
27
+ return license_file unless license_file && license_file.license
28
+
29
+ # Special case LGPL, which actuall lives in LICENSE.lesser, per the
30
+ # license instructions. See https://git.io/viwyK
31
+ lesser = if license_file.license.gpl?
32
+ license_from_file { |file| LicenseFile.lesser_gpl_score(file) }
33
+ end
34
+
35
+ lesser || license_file
28
36
  end
29
37
  end
30
38
 
@@ -46,5 +54,31 @@ module Licensee
46
54
  PackageInfo.new(content, name) if content && name
47
55
  end
48
56
  end
57
+
58
+ private
59
+
60
+ # Given a block, passes each filename to that block, and expects a numeric
61
+ # score in response. Returns an array of all files with a score > 0,
62
+ # sorted by file score descending
63
+ def find_files
64
+ return [] if files.empty? || files.nil?
65
+ found = files.each { |file| file[:score] = yield(file[:name]) }
66
+ found.select! { |file| file[:score] > 0 }
67
+ found.sort { |a, b| b[:score] <=> a[:score] }
68
+ end
69
+
70
+ # Given a block, passes each filename to that block, and expects a numeric
71
+ # score in response. Returns a hash representing the top scoring file
72
+ # or nil, if no file scored > 0
73
+ def find_file(&block)
74
+ return if files.empty? || files.nil?
75
+ file = find_files(&block).first
76
+ [load_file(file), file[:name]] if file
77
+ end
78
+
79
+ def license_from_file(&block)
80
+ content, name = find_file(&block)
81
+ LicenseFile.new(content, name) if content && name
82
+ end
49
83
  end
50
84
  end
@@ -20,6 +20,11 @@ module Licensee
20
20
  return 0.5 if filename =~ /licen[sc]e/i
21
21
  0.0
22
22
  end
23
+
24
+ # case-insensitive block to determine if the given file is LICENSE.lesser
25
+ def self.lesser_gpl_score(filename)
26
+ filename.casecmp('copying.lesser').zero? ? 1 : 0
27
+ end
23
28
  end
24
29
  end
25
30
  end
@@ -12,7 +12,9 @@ module Licensee
12
12
 
13
13
  private
14
14
 
15
- def find_file
15
+ # Returns an array of hashes representing the project's files.
16
+ # Hashes will have the :name key, with the relative path to the file
17
+ def files
16
18
  files = []
17
19
 
18
20
  if ::File.file?(path)
@@ -24,17 +26,20 @@ module Licensee
24
26
 
25
27
  Dir.glob(::File.join(path, pattern)) do |file|
26
28
  next unless ::File.file?(file)
27
- file = ::File.basename(file)
28
- if (score = yield file) > 0
29
- files.push(name: file, score: score)
30
- end
29
+ files.push(name: ::File.basename(file))
31
30
  end
32
31
 
33
- return if files.empty?
34
- files.sort! { |a, b| b[:score] <=> a[:score] }
32
+ files
33
+ end
35
34
 
36
- f = files.first
37
- [::File.read(::File.join(path, f[:name])), f[:name]]
35
+ # Retrieve a file's content from disk
36
+ #
37
+ # file - the file hash, with the :name key as the file's relative path
38
+ # path - the base path to the project
39
+ #
40
+ # Returns the fiel contents as a string
41
+ def load_file(file)
42
+ ::File.read(::File.join(path, file[:name]))
38
43
  end
39
44
  end
40
45
  end
@@ -36,24 +36,25 @@ module Licensee
36
36
 
37
37
  MAX_LICENSE_SIZE = 64 * 1024
38
38
 
39
- def load_blob_data(oid)
40
- data, = Rugged::Blob.to_buffer(repository, oid, MAX_LICENSE_SIZE)
39
+ # Retrieve a file's content from the Git database
40
+ #
41
+ # file - the file hash, including the file's OID
42
+ #
43
+ # Returns a string representing the file's contents
44
+ def load_file(file)
45
+ data, = Rugged::Blob.to_buffer(repository, file[:oid], MAX_LICENSE_SIZE)
41
46
  data
42
47
  end
43
48
 
44
- def find_file
45
- files = commit.tree.map do |entry|
49
+ # Returns an array of hashes representing the project's files.
50
+ # Hashes will have the the following keys:
51
+ # :name - the file's path relative to the repo root
52
+ # :oid - the file's OID
53
+ def files
54
+ commit.tree.map do |entry|
46
55
  next unless entry[:type] == :blob
47
- if (score = yield entry[:name]) > 0
48
- { name: entry[:name], oid: entry[:oid], score: score }
49
- end
56
+ { name: entry[:name], oid: entry[:oid] }
50
57
  end.compact
51
-
52
- return if files.empty?
53
- files.sort! { |a, b| b[:score] <=> a[:score] }
54
-
55
- f = files.first
56
- [load_blob_data(f[:oid]), f[:name]]
57
58
  end
58
59
  end
59
60
  end
@@ -1,3 +1,3 @@
1
1
  module Licensee
2
- VERSION = '8.3.1'.freeze
2
+ VERSION = '8.4.0'.freeze
3
3
  end
data/lib/licensee.rb CHANGED
@@ -23,7 +23,7 @@ require_relative 'licensee/matchers/npm_bower_matcher'
23
23
 
24
24
  module Licensee
25
25
  # Over which percent is a match considered a match by default
26
- CONFIDENCE_THRESHOLD = 90
26
+ CONFIDENCE_THRESHOLD = 95
27
27
 
28
28
  # Base domain from which to build license URLs
29
29
  DOMAIN = 'http://choosealicense.com'.freeze
@@ -50,5 +50,11 @@ module Licensee
50
50
  def confidence_threshold
51
51
  @confidence_threshold ||= CONFIDENCE_THRESHOLD
52
52
  end
53
+
54
+ # Inverse of the confidence threshold, represented as a float
55
+ # By default this will be 0.1
56
+ def inverse_confidence_threshold
57
+ @inverse ||= (1 - Licensee.confidence_threshold / 100.0).round(2)
58
+ end
53
59
  end
54
60
  end
@@ -0,0 +1 @@
1
+ ref: refs/heads/master
@@ -0,0 +1,5 @@
1
+ [core]
2
+ repositoryformatversion = 0
3
+ filemode = true
4
+ bare = true
5
+ ignorecase = true
@@ -0,0 +1,2 @@
1
+ x��Qj�0D��S�b${�HPJ�MV�c��`+��>N� �7o�
2
+
@@ -0,0 +1,2 @@
1
+ x��[
2
+ �0E��*f��C�B�Nf��
@@ -0,0 +1 @@
1
+ 1acd060ebbbeac294200008657d9502130f93465
data/test/functions.rb CHANGED
@@ -19,9 +19,11 @@ def license_from_path(path)
19
19
  license
20
20
  end
21
21
 
22
- def chaos_monkey(string)
23
- Random.rand(3).times do
24
- string[Random.rand(string.length)] = SecureRandom.base64(Random.rand(3))
22
+ # Add random words to the end of a license to test similarity tollerances
23
+ def chaos_monkey(string, count: 5)
24
+ ipsum = %w[lorem ipsum dolor sit amet consectetur adipiscing elit]
25
+ Random.rand(count).times do
26
+ string << " #{ipsum[Random.rand(ipsum.length)]}"
25
27
  end
26
28
  string
27
29
  end
@@ -35,15 +37,20 @@ def verify_license_file(license, chaos = false, wrap = false)
35
37
 
36
38
  license_file = Licensee::Project::LicenseFile.new(text)
37
39
 
38
- actual = license_file.license
39
- msg = "No match for #{expected}."
40
-
41
- assert actual, msg
40
+ detected = license_file.license
41
+ msg = "No match for #{expected}.\n"
42
+ matcher = Licensee::Matchers::Dice.new(license_file)
43
+ matcher.potential_licenses.each do |potential_license|
44
+ msg << "Potential license: #{potential_license.key}\n"
45
+ msg << "Potential similiarity: #{potential_license.similarity(license_file)}\n"
46
+ end
47
+ msg << "Text: #{license_file.content_normalized}"
48
+ assert detected, msg
42
49
 
43
- msg = "Expeceted #{expected} but got #{actual.key} for .match. "
50
+ msg = "Expeceted #{expected} but got #{detected.key} for .match. "
44
51
  msg << "Confidence: #{license_file.confidence}. "
45
52
  msg << "Method: #{license_file.matcher.class}"
46
- assert_equal expected, actual.key, msg
53
+ assert_equal expected, detected.key, msg
47
54
  end
48
55
 
49
56
  def wrap(text, line_width = 80)
@@ -26,6 +26,12 @@ class TestLicenseeCopyrightMatchers < Minitest::Test
26
26
  assert_equal 'no-license', Licensee::Matchers::Copyright.new(file).match.key
27
27
  end
28
28
 
29
+ should 'match (c) copyright notices' do
30
+ text = '(C) 2015 Ben Balter'
31
+ file = Licensee::Project::LicenseFile.new(text)
32
+ assert_equal 'no-license', Licensee::Matchers::Copyright.new(file).match.key
33
+ end
34
+
29
35
  should 'not false positive' do
30
36
  path = Licensee::License.find('mit').path
31
37
  text = File.read(path, encoding: 'utf-8').split('---').last
@@ -6,6 +6,12 @@ class TestLicenseeDiceMatchers < Minitest::Test
6
6
  @mit = Licensee::Project::LicenseFile.new(text)
7
7
  end
8
8
 
9
+ def concat_licenses(*args)
10
+ args.map do |license|
11
+ license_from_path(Licensee::License.find(license).path)
12
+ end.join("\n")
13
+ end
14
+
9
15
  should 'match the license' do
10
16
  assert_equal 'mit', Licensee::Matchers::Dice.new(@mit).match.key
11
17
  end
@@ -15,7 +21,10 @@ class TestLicenseeDiceMatchers < Minitest::Test
15
21
  assert matcher.confidence > 95, "#{matcher.confidence} < 95"
16
22
  end
17
23
 
18
- should 'calculate max delta' do
19
- assert_equal 83.7, Licensee::Matchers::Dice.new(@mit).max_delta
24
+ should 'know when two licenses have be concatenated' do
25
+ text = concat_licenses('mit', 'gpl-2.0')
26
+ license = Licensee::Project::LicenseFile.new(text)
27
+ matcher = Licensee::Matchers::Dice.new(license)
28
+ refute matcher.match
20
29
  end
21
30
  end
@@ -14,4 +14,12 @@ class TestLicenseeExactMatchers < Minitest::Test
14
14
  should 'know the match confidence' do
15
15
  assert_equal 100, Licensee::Matchers::Exact.new(@mit).confidence
16
16
  end
17
+
18
+ should 'require the file to be the same length' do
19
+ path = Licensee::License.find('mit').path
20
+ text = File.read(path, encoding: 'utf-8').split('---').last
21
+ text << ' MIT'
22
+ license = Licensee::Project::LicenseFile.new(text)
23
+ refute Licensee::Matchers::Exact.new(license).match
24
+ end
17
25
  end
@@ -2,7 +2,7 @@ require 'helper'
2
2
 
3
3
  class TestLicenseeGemspecMatchers < Minitest::Test
4
4
  should 'detect its own license' do
5
- root = File.expand_path '../', File.dirname(__FILE__)
5
+ root = File.expand_path '../../../', File.dirname(__FILE__)
6
6
  project = Licensee::GitProject.new(root, detect_packages: true)
7
7
  matcher = Licensee::Matchers::Gemspec.new(project.package_file)
8
8
  assert_equal 'mit', matcher.send(:license_property)
@@ -0,0 +1,27 @@
1
+ require 'helper'
2
+
3
+ class PackageMatcherTestHelper < Licensee::Matchers::Package
4
+ attr_accessor :license_property, :file
5
+ end
6
+
7
+ class TestLicenseePackageMatcher < Minitest::Test
8
+ def setup
9
+ pkg = File.read fixture_path('npm/package.json')
10
+ @file = Licensee::Project::PackageInfo.new(pkg)
11
+ @matcher = PackageMatcherTestHelper.new(@file)
12
+ @matcher.license_property = 'mit'
13
+ end
14
+
15
+ should 'store the file' do
16
+ assert_equal @matcher.file, @file
17
+ end
18
+
19
+ should 'match' do
20
+ assert @matcher.match
21
+ assert_equal 'mit', @matcher.match.key
22
+ end
23
+
24
+ should 'return the confidence' do
25
+ assert_equal 90, @matcher.confidence
26
+ end
27
+ end
@@ -55,4 +55,19 @@ class TestLicenseeLicenseFile < Minitest::Test
55
55
  end
56
56
  end
57
57
  end
58
+
59
+ context 'LGPL scoring' do
60
+ {
61
+ 'COPYING.lesser' => 1,
62
+ 'copying.lesser' => 1,
63
+ 'license.lesser' => 0,
64
+ 'LICENSE.md' => 0,
65
+ 'FOO.md' => 0
66
+ }.each do |filename, expected|
67
+ should "score a license named `#{filename}` as `#{expected}`" do
68
+ score = Licensee::Project::LicenseFile.lesser_gpl_score(filename)
69
+ assert_equal expected, score
70
+ end
71
+ end
72
+ end
58
73
  end
@@ -0,0 +1,56 @@
1
+ require 'helper'
2
+
3
+ class ContentHelperTestHelper
4
+ include Licensee::ContentHelper
5
+ attr_accessor :content
6
+
7
+ DEFAULT_CONTENT = <<-EOS.freeze
8
+ Copyright 2016 Ben Balter
9
+
10
+ The made
11
+ up license.
12
+ EOS
13
+
14
+ def initialize(content = nil)
15
+ @content = content || DEFAULT_CONTENT
16
+ end
17
+ end
18
+
19
+ class TestLicenseeContentHelper < Minitest::Test
20
+ def setup
21
+ @helper = ContentHelperTestHelper.new
22
+ end
23
+
24
+ should 'normalize the content' do
25
+ assert_equal 'the made up license.', @helper.content_normalized
26
+ end
27
+
28
+ should 'generate the hash' do
29
+ assert_equal '3c59634b9fae4396a76a978f3f6aa718ed790a9a', @helper.hash
30
+ end
31
+
32
+ should 'calculate the length' do
33
+ assert_equal 20, @helper.length
34
+ end
35
+
36
+ should 'know the max delta' do
37
+ assert_equal 1, @helper.max_delta
38
+ end
39
+
40
+ should 'build the wordset' do
41
+ assert_equal %w(the made up license).to_set, @helper.wordset
42
+ end
43
+
44
+ should 'calculate the length delta' do
45
+ other = ContentHelperTestHelper.new 'asdf'
46
+ assert_equal 16, @helper.length_delta(other)
47
+ end
48
+
49
+ should 'calculate the similarity' do
50
+ other = ContentHelperTestHelper.new 'asdf'
51
+ assert_equal 0, @helper.similarity(other)
52
+
53
+ other = ContentHelperTestHelper.new 'Not really the made up license'
54
+ assert_equal 80.0, @helper.similarity(other)
55
+ end
56
+ end
@@ -117,6 +117,17 @@ class TestLicenseeLicense < Minitest::Test
117
117
  assert_equal '750260c322080bab4c19fd55eb78bc73e1ae8f11', @license.hash
118
118
  end
119
119
 
120
+ should "recognize GPL'd licenses" do
121
+ license = Licensee::License.new 'gpl-2.0'
122
+ assert license.gpl?
123
+
124
+ license = Licensee::License.new 'gpl-3.0'
125
+ assert license.gpl?
126
+
127
+ license = Licensee::License.new 'mit'
128
+ refute license.gpl?
129
+ end
130
+
120
131
  describe 'name without version' do
121
132
  should 'strip the version from the license name' do
122
133
  expected = 'GNU Affero General Public License'
@@ -72,6 +72,11 @@ class TestLicenseeProject < Minitest::Test
72
72
  project = make_project 'no-license.git'
73
73
  assert_equal nil, project.license
74
74
  end
75
+
76
+ should 'detect an LGPL licensed project with LICENSE.lesser' do
77
+ project = make_project 'lgpl.git'
78
+ assert_equal 'lgpl-3.0', project.license.key
79
+ end
75
80
  end
76
81
  end
77
82
 
@@ -24,13 +24,17 @@ class TestLicensee < Minitest::Test
24
24
 
25
25
  context 'confidence threshold' do
26
26
  should 'return the confidence threshold' do
27
- assert_equal 90, Licensee.confidence_threshold
27
+ assert_equal 95, Licensee.confidence_threshold
28
28
  end
29
29
 
30
30
  should 'let the user override the confidence threshold' do
31
31
  Licensee.confidence_threshold = 50
32
32
  assert_equal 50, Licensee.confidence_threshold
33
- Licensee.confidence_threshold = 90
33
+ Licensee.confidence_threshold = 95
34
+ end
35
+
36
+ should 'return the inverse of the confidence threshold' do
37
+ assert_equal 0.05, Licensee.inverse_confidence_threshold
34
38
  end
35
39
  end
36
40
  end