license_finder 0.7.3 → 0.8.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.
- data/.gitignore +4 -3
- data/.travis.yml +1 -8
- data/bin/license_finder +31 -1
- data/db/migrate/201303290935_create_dependencies.rb +14 -0
- data/db/migrate/201303291155_create_licenses.rb +13 -0
- data/db/migrate/201303291402_create_approvals.rb +13 -0
- data/db/migrate/201303291456_create_ancestries.rb +9 -0
- data/db/migrate/201303291519_create_bundler_groups.rb +13 -0
- data/db/migrate/201303291720_move_manual_from_approvals_to_licenses.rb +11 -0
- data/db/migrate/201303291753_allow_null_license_names.rb +7 -0
- data/db/migrate/201304011027_allow_null_dependency_version.rb +7 -0
- data/db/migrate/201304020947_change_table_name_licenses_to_license_aliases.rb +5 -0
- data/features/approve_dependencies.feature +0 -45
- data/features/html_report.feature +1 -11
- data/features/license_finder.feature +13 -27
- data/features/license_finder_rake_task.feature +2 -1
- data/features/set_license.feature +2 -4
- data/features/step_definitions/license_finder_steps.rb +25 -0
- data/features/step_definitions/steps.rb +40 -26
- data/features/text_report.feature +2 -2
- data/files/license_finder.yml +1 -1
- data/lib/license_finder.rb +14 -6
- data/lib/license_finder/bundle.rb +4 -17
- data/lib/license_finder/bundle_syncer.rb +2 -3
- data/lib/license_finder/bundled_gem.rb +4 -47
- data/lib/license_finder/cli.rb +9 -16
- data/lib/license_finder/configuration.rb +55 -3
- data/lib/license_finder/dependency_report.rb +1 -1
- data/lib/license_finder/gem_saver.rb +69 -0
- data/lib/license_finder/html_report.rb +2 -2
- data/lib/license_finder/license.rb +60 -58
- data/lib/license_finder/license_files.rb +36 -0
- data/lib/license_finder/license_url.rb +8 -6
- data/lib/license_finder/platform.rb +32 -0
- data/lib/license_finder/possible_license_file.rb +1 -1
- data/lib/license_finder/tables.rb +7 -0
- data/lib/license_finder/tables/approval.rb +4 -0
- data/lib/license_finder/tables/bundler_group.rb +4 -0
- data/lib/license_finder/tables/dependency.rb +31 -0
- data/lib/license_finder/tables/license_alias.rb +22 -0
- data/lib/license_finder/yml_to_sql.rb +127 -0
- data/lib/tasks/license_finder.rake +3 -0
- data/lib/templates/html_report.erb +50 -32
- data/lib/templates/text_report.erb +3 -2
- data/license_finder.gemspec +14 -5
- data/readme.md +10 -50
- data/spec/lib/license_finder/bundle_spec.rb +22 -19
- data/spec/lib/license_finder/bundle_syncer_spec.rb +4 -10
- data/spec/lib/license_finder/bundled_gem_spec.rb +40 -108
- data/spec/lib/license_finder/cli_spec.rb +3 -3
- data/spec/lib/license_finder/configuration_spec.rb +53 -21
- data/spec/lib/license_finder/gem_saver_spec.rb +155 -0
- data/spec/lib/license_finder/html_report_spec.rb +32 -15
- data/spec/lib/license_finder/license_files_spec.rb +50 -0
- data/spec/lib/license_finder/tables/dependency_spec.rb +102 -0
- data/spec/lib/license_finder/tables/license_alias_spec.rb +54 -0
- data/spec/lib/license_finder/text_report_spec.rb +6 -4
- data/spec/lib/license_finder/yml_to_sql_spec.rb +99 -0
- data/spec/lib/license_finder_spec.rb +5 -5
- data/spec/spec_helper.rb +17 -1
- metadata +79 -32
- data/lib/license_finder/dependency.rb +0 -50
- data/lib/license_finder/persistence.rb +0 -1
- data/lib/license_finder/persistence/yaml.rb +0 -7
- data/lib/license_finder/persistence/yaml/configuration.rb +0 -34
- data/lib/license_finder/persistence/yaml/dependency.rb +0 -127
- data/lib/license_finder/source_syncer.rb +0 -40
- data/lib/templates/dependency.html.erb +0 -54
- data/spec/lib/license_finder/dependency_spec.rb +0 -188
- data/spec/lib/license_finder/persistence/yaml/dependency_spec.rb +0 -5
- data/spec/lib/license_finder/source_syncer_spec.rb +0 -37
- data/spec/support/shared_examples/persistence/configuration.rb +0 -28
- data/spec/support/shared_examples/persistence/dependency.rb +0 -138
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
describe GemSaver do
|
5
|
+
let(:gemspec) do
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'spec_name'
|
8
|
+
s.version = '2.1.3'
|
9
|
+
s.summary = 'summary'
|
10
|
+
s.description = 'description'
|
11
|
+
s.homepage = 'homepage'
|
12
|
+
|
13
|
+
s.add_dependency 'foo'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#save" do
|
18
|
+
let(:bundled_gem) { BundledGem.new(gemspec) }
|
19
|
+
subject { described_class.find_or_initialize_by_name('spec_name', bundled_gem).save }
|
20
|
+
|
21
|
+
context "when the dependency is new" do
|
22
|
+
it "persists gem data" do
|
23
|
+
subject.id.should be
|
24
|
+
subject.name.should == "spec_name"
|
25
|
+
subject.version.should == "2.1.3"
|
26
|
+
subject.summary.should == "summary"
|
27
|
+
subject.description.should == "description"
|
28
|
+
subject.homepage.should == "homepage"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "associates children" do
|
32
|
+
subject.children.map(&:name).should == ['foo']
|
33
|
+
end
|
34
|
+
|
35
|
+
it "marks depenency as unapproved by default" do
|
36
|
+
subject.approval.state.should == nil
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with a bundler dependency" do
|
40
|
+
let(:bundled_gem) { BundledGem.new(gemspec, stub(:bundler_dependency, groups: %w[1 2 3]))}
|
41
|
+
|
42
|
+
it "saves the bundler groups" do
|
43
|
+
subject.bundler_groups.map(&:name).should =~ %w[1 2 3]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the dependency already existed" do
|
49
|
+
let!(:old_copy) do
|
50
|
+
Dependency.create(
|
51
|
+
name: 'spec_name',
|
52
|
+
version: '0.1.2',
|
53
|
+
summary: 'old summary',
|
54
|
+
description: 'old desription',
|
55
|
+
homepage: 'old homepage'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "merges in the latest data" do
|
60
|
+
subject.id.should == old_copy.id
|
61
|
+
subject.name.should == old_copy.name
|
62
|
+
subject.version.should == "2.1.3"
|
63
|
+
subject.summary.should == "summary"
|
64
|
+
subject.description.should == "description"
|
65
|
+
subject.homepage.should == "homepage"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "keeps a manually assigned license" do
|
69
|
+
old_copy.license = LicenseAlias.create(name: 'foo', manual: true)
|
70
|
+
old_copy.save
|
71
|
+
subject.license.name.should == 'foo'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "keeps approval" do
|
75
|
+
old_copy.approval = Approval.create(state: true)
|
76
|
+
old_copy.save
|
77
|
+
subject.approval.state.should == true
|
78
|
+
end
|
79
|
+
|
80
|
+
it "ensures correct children are associated" do
|
81
|
+
old_copy.add_child Dependency.new(name: 'bob')
|
82
|
+
old_copy.add_child Dependency.new(name: 'joe')
|
83
|
+
old_copy.children.each(&:save)
|
84
|
+
subject.children.map(&:name).should =~ ['foo']
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with a bundler dependency" do
|
88
|
+
let(:bundled_gem) { BundledGem.new(gemspec, stub(:bundler_dependency, groups: %w[1 2 3]))}
|
89
|
+
|
90
|
+
before do
|
91
|
+
old_copy.add_bundler_group BundlerGroup.find_or_create(name: 'a')
|
92
|
+
old_copy.add_bundler_group BundlerGroup.find_or_create(name: 'b')
|
93
|
+
end
|
94
|
+
|
95
|
+
it "ensures the correct bundler groups are associated" do
|
96
|
+
subject.bundler_groups.map(&:name).should =~ %w[1 2 3]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "license changes to something other than 'other'" do
|
101
|
+
before do
|
102
|
+
old_copy.license = LicenseAlias.create(name: 'other')
|
103
|
+
old_copy.save
|
104
|
+
gemspec.license = "new license"
|
105
|
+
end
|
106
|
+
|
107
|
+
context "new license is whitelisted" do
|
108
|
+
before { LicenseFinder.config.stub(:whitelist).and_return [gemspec.license] }
|
109
|
+
|
110
|
+
it "should set the approval to true" do
|
111
|
+
subject.should be_approved
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "new license is not whitelisted" do
|
116
|
+
it "should set the approval to false" do
|
117
|
+
subject.should_not be_approved
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "license changes to unknown (i.e., 'other')" do
|
123
|
+
before do
|
124
|
+
old_copy.license = LicenseAlias.create(name: 'MIT')
|
125
|
+
old_copy.approval = Approval.create(state: false)
|
126
|
+
old_copy.save
|
127
|
+
gemspec.license = "other"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should not change the license" do
|
131
|
+
subject.license.name.should == 'MIT'
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should not change the approval" do
|
135
|
+
subject.should_not be_approved
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "license does not change" do
|
140
|
+
before do
|
141
|
+
old_copy.license = LicenseAlias.create(name: 'MIT')
|
142
|
+
old_copy.approval = Approval.create(state: false)
|
143
|
+
old_copy.save
|
144
|
+
gemspec.license = "MIT"
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should not change the license or approval" do
|
148
|
+
subject.should_not be_approved
|
149
|
+
subject.license.name.should == "MIT"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -1,65 +1,82 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "capybara"
|
2
3
|
|
3
4
|
module LicenseFinder
|
4
5
|
describe HtmlReport do
|
5
6
|
describe "#to_s" do
|
6
|
-
let(:dependency)
|
7
|
-
|
7
|
+
let(:dependency) do
|
8
|
+
dep = Dependency.new name: "the-name"
|
9
|
+
dep.license = LicenseAlias.create name: 'MIT'
|
10
|
+
dep.approval = Approval.create state: true
|
11
|
+
dep
|
12
|
+
end
|
13
|
+
|
14
|
+
subject { Capybara.string(HtmlReport.new([dependency]).to_s) }
|
8
15
|
|
9
16
|
context "when the dependency is approved" do
|
10
17
|
it "should add an approved class to dependency's container" do
|
11
|
-
should
|
18
|
+
should have_selector ".approved"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not list the dependency in the action items" do
|
22
|
+
should_not have_selector ".action-items"
|
12
23
|
end
|
13
24
|
end
|
14
25
|
|
15
26
|
context "when the dependency is not approved" do
|
16
|
-
before { dependency.
|
27
|
+
before { dependency.approval.state = false }
|
17
28
|
|
18
29
|
it "should not add an approved class to he dependency's container" do
|
19
|
-
should
|
30
|
+
should have_selector ".unapproved"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "lists the dependency in the action items" do
|
34
|
+
should have_selector ".action-items li"
|
20
35
|
end
|
21
36
|
end
|
22
37
|
|
23
38
|
context "when the gem has at least one bundler group" do
|
24
|
-
before { dependency.bundler_groups
|
39
|
+
before { dependency.stub(bundler_groups: [stub(name: "group")]) }
|
25
40
|
it "should show the bundler group(s) in parens" do
|
26
|
-
should
|
41
|
+
should have_text "(group)"
|
27
42
|
end
|
28
43
|
end
|
29
44
|
|
30
45
|
context "when the gem has no bundler groups" do
|
31
|
-
before { dependency.bundler_groups
|
46
|
+
before { dependency.stub(bundler_groups: []) }
|
32
47
|
|
33
48
|
it "should not show any parens or bundler group info" do
|
34
|
-
should_not
|
49
|
+
should_not have_text "()"
|
35
50
|
end
|
36
51
|
|
37
52
|
end
|
38
53
|
|
39
54
|
context "when the gem has at least one parent" do
|
40
|
-
before { dependency.parents
|
55
|
+
before { dependency.stub(parents: [stub(:name => "foo parent")]) }
|
41
56
|
it "should include a parents section" do
|
42
|
-
should
|
57
|
+
should have_text "Parents"
|
58
|
+
should have_text "foo parent"
|
43
59
|
end
|
44
60
|
end
|
45
61
|
|
46
62
|
context "when the gem has no parents" do
|
47
63
|
it "should not include any parents section in the output" do
|
48
|
-
should_not
|
64
|
+
should_not have_text "Parents"
|
49
65
|
end
|
50
66
|
end
|
51
67
|
|
52
68
|
context "when the gem has at least one child" do
|
53
|
-
before { dependency.children
|
69
|
+
before { dependency.stub(children: [stub(:name => "foo child")]) }
|
54
70
|
|
55
71
|
it "should include a Children section" do
|
56
|
-
should
|
72
|
+
should have_text "Children"
|
73
|
+
should have_text "foo child"
|
57
74
|
end
|
58
75
|
end
|
59
76
|
|
60
77
|
context "when the gem has no children" do
|
61
78
|
it "should not include any Children section in the output" do
|
62
|
-
should_not
|
79
|
+
should_not have_text "Children"
|
63
80
|
end
|
64
81
|
end
|
65
82
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
describe LicenseFiles do
|
5
|
+
def fixture_path(fixture)
|
6
|
+
Pathname.new(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec', 'fixtures', fixture)).realpath.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#files" do
|
10
|
+
it "is empty if there aren't any license files" do
|
11
|
+
subject = described_class.new('/not/a/dir')
|
12
|
+
subject.files.should == []
|
13
|
+
end
|
14
|
+
|
15
|
+
it "includes files with names like LICENSE, License or COPYING" do
|
16
|
+
subject = described_class.new(fixture_path('license_names'))
|
17
|
+
|
18
|
+
subject.files.map(&:file_name).should =~
|
19
|
+
%w[COPYING.txt LICENSE Mit-License README.rdoc Licence.rdoc]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "includes files deep in the hierarchy" do
|
23
|
+
subject = described_class.new(fixture_path('nested_gem'))
|
24
|
+
|
25
|
+
subject.files.map { |f| [f.file_name, f.file_path] }.should =~ [
|
26
|
+
%w[LICENSE vendor/LICENSE]
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "includes both files nested inside LICENSE directory and top level files" do
|
31
|
+
subject = described_class.new(fixture_path('license_directory'))
|
32
|
+
found_license_files = subject.files
|
33
|
+
|
34
|
+
found_license_files.map { |f| [f.file_name, f.file_path] }.should =~ [
|
35
|
+
%w[BSD-2-Clause.txt LICENSE/BSD-2-Clause.txt],
|
36
|
+
%w[GPL-2.0.txt LICENSE/GPL-2.0.txt],
|
37
|
+
%w[MIT.txt LICENSE/MIT.txt],
|
38
|
+
%w[RUBY.txt LICENSE/RUBY.txt],
|
39
|
+
%w[COPYING COPYING],
|
40
|
+
%w[LICENSE LICENSE/LICENSE]
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles non UTF8 encodings" do
|
45
|
+
subject = described_class.new(fixture_path('utf8_gem'))
|
46
|
+
expect { subject.files }.not_to raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
describe Dependency do
|
5
|
+
let(:attributes) do
|
6
|
+
{
|
7
|
+
'name' => "spec_name",
|
8
|
+
'version' => "2.1.3",
|
9
|
+
'license' => "GPLv2",
|
10
|
+
'approved' => false,
|
11
|
+
'notes' => 'some notes',
|
12
|
+
'homepage' => 'homepage',
|
13
|
+
'license_files' => ['/Users/pivotal/foo/lic1', '/Users/pivotal/bar/lic2'],
|
14
|
+
'bundler_groups' => ["test"]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:config) { Configuration.new }
|
19
|
+
|
20
|
+
before do
|
21
|
+
LicenseFinder.stub(:config).and_return config
|
22
|
+
config.whitelist = ["MIT", "other"]
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ".destroy_obsolete" do
|
26
|
+
it "destroys every dependency except for the ones provided as 'current'" do
|
27
|
+
cur1 = Dependency.create(name: "current dependency 1")
|
28
|
+
cur2 = Dependency.create(name: "current dependency 2")
|
29
|
+
Dependency.create(name: "old dependency 1")
|
30
|
+
Dependency.create(name: "old dependency 2")
|
31
|
+
|
32
|
+
Dependency.destroy_obsolete([cur1, cur2])
|
33
|
+
Dependency.all.should =~ [cur1, cur2]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.unapproved' do
|
38
|
+
it "should return all unapproved dependencies" do
|
39
|
+
dependency = Dependency.create(name: "unapproved dependency", version: '0.0.1')
|
40
|
+
dependency.approval = Approval.create(state: false)
|
41
|
+
dependency.save
|
42
|
+
approved = Dependency.create(name: "approved dependency", version: '0.0.1')
|
43
|
+
approved.approval = Approval.create(state: true)
|
44
|
+
approved.save
|
45
|
+
whitelisted = Dependency.create(name: "approved dependency", version: '0.0.1')
|
46
|
+
whitelisted.license = LicenseAlias.create(name: 'MIT')
|
47
|
+
whitelisted.approval = Approval.create(state: false)
|
48
|
+
whitelisted.save
|
49
|
+
|
50
|
+
unapproved = Dependency.unapproved
|
51
|
+
unapproved.count.should == 1
|
52
|
+
unapproved.should_not be_any(&:approved?)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#approve!' do
|
57
|
+
it "should update the database to show the dependency is approved" do
|
58
|
+
dependency = Dependency.create(name: "foo", version: '0.0.1')
|
59
|
+
dependency.approval = Approval.create(state: false)
|
60
|
+
dependency.save
|
61
|
+
dependency.approve!
|
62
|
+
dependency.reload.should be_approved
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#approved?" do
|
67
|
+
let(:dependency) { Dependency.create(name: 'some gem') }
|
68
|
+
|
69
|
+
it "is true if its license is whitelisted" do
|
70
|
+
dependency.stub_chain(:license, whitelisted?: true)
|
71
|
+
dependency.should be_approved
|
72
|
+
end
|
73
|
+
|
74
|
+
it "is true if it has been approved" do
|
75
|
+
dependency.stub_chain(:license, whitelisted?: false)
|
76
|
+
dependency.stub_chain(:approval, state: true)
|
77
|
+
dependency.should be_approved
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is false otherwise" do
|
81
|
+
dependency.stub_chain(:license, whitelisted?: false)
|
82
|
+
dependency.stub_chain(:approval, state: false)
|
83
|
+
dependency.should_not be_approved
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#set_license_manually" do
|
88
|
+
let(:gem) do
|
89
|
+
dependency = Dependency.new(name: "bob", version: '0.0.1')
|
90
|
+
dependency.license = LicenseAlias.create(name: 'Original')
|
91
|
+
dependency.save
|
92
|
+
dependency
|
93
|
+
end
|
94
|
+
|
95
|
+
it "delegates to the license" do
|
96
|
+
gem.license.should_receive(:set_manually).with('Updated')
|
97
|
+
gem.set_license_manually('Updated')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
describe LicenseAlias do
|
5
|
+
describe 'initializes' do
|
6
|
+
it "delegates to LicenseUrl.find_by_name for the url" do
|
7
|
+
LicenseUrl.stub(:find_by_name).with("MIT").and_return "http://license-url.com"
|
8
|
+
license = described_class.new(name: 'MIT')
|
9
|
+
license.url.should == "http://license-url.com"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#set_manually" do
|
14
|
+
subject do
|
15
|
+
described_class.create(name: 'Original')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "modifies the license" do
|
19
|
+
subject.set_manually('Updated')
|
20
|
+
subject.reload.name.should == 'Updated'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "marks the approval as manual" do
|
24
|
+
subject.set_manually('Updated')
|
25
|
+
subject.reload.manual.should be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#whitelisted?" do
|
30
|
+
let(:config) { Configuration.new }
|
31
|
+
|
32
|
+
before do
|
33
|
+
LicenseFinder.stub(:config).and_return config
|
34
|
+
config.whitelist = ["MIT", "other"]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return true when the license is whitelisted" do
|
38
|
+
described_class.new(name: 'MIT').should be_whitelisted
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return true when the license is an alternative name of a whitelisted license" do
|
42
|
+
described_class.new(name: 'Expat').should be_whitelisted
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return true when the license has no matching license class, but is whitelisted anyways" do
|
46
|
+
described_class.new(name: 'other').should be_whitelisted
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return false when the license is not whitelisted" do
|
50
|
+
described_class.new(name: 'GPL').should_not be_whitelisted
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|