licensee 8.3.1 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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