devtools 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Gemfile +0 -2
- data/README.md +2 -2
- data/circle.yml +1 -1
- data/config/devtools.yml +2 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/mutant.yml +2 -0
- data/config/reek.yml +7 -12
- data/devtools.gemspec +20 -18
- data/lib/devtools.rb +34 -83
- data/lib/devtools/config.rb +76 -55
- data/lib/devtools/flay.rb +94 -0
- data/lib/devtools/project.rb +28 -105
- data/lib/devtools/project/initializer.rb +2 -12
- data/lib/devtools/project/initializer/rake.rb +9 -7
- data/lib/devtools/project/initializer/rspec.rb +28 -55
- data/lib/devtools/rake/flay.rb +126 -0
- data/lib/devtools/spec_helper.rb +1 -3
- data/shared/spec/shared/abstract_type_behavior.rb +0 -2
- data/shared/spec/shared/command_method_behavior.rb +0 -2
- data/shared/spec/shared/each_method_behaviour.rb +0 -2
- data/shared/spec/shared/hash_method_behavior.rb +0 -2
- data/shared/spec/shared/idempotent_method_behavior.rb +0 -2
- data/shared/spec/support/ice_nine_config.rb +0 -2
- data/spec/integration/devtools/rake/flay/verify_spec.rb +164 -0
- data/spec/spec_helper.rb +2 -8
- data/spec/unit/devtools/config/yardstick_spec.rb +17 -0
- data/spec/unit/devtools/config_spec.rb +78 -0
- data/spec/unit/devtools/flay/file_list/call_spec.rb +19 -0
- data/spec/unit/devtools/flay/scale/flay_report_spec.rb +17 -0
- data/spec/unit/devtools/flay/scale/measure_spec.rb +43 -0
- data/spec/unit/devtools/project/initializer/rake_spec.rb +21 -0
- data/spec/unit/devtools/project/initializer/rspec_spec.rb +52 -0
- data/spec/unit/devtools/project_spec.rb +34 -0
- data/spec/unit/devtools_spec.rb +14 -0
- data/tasks/metrics/ci.rake +1 -3
- data/tasks/metrics/coverage.rake +0 -2
- data/tasks/metrics/flay.rake +6 -33
- data/tasks/metrics/flog.rake +0 -2
- data/tasks/metrics/mutant.rake +31 -39
- data/tasks/metrics/reek.rake +0 -2
- data/tasks/metrics/rubocop.rake +0 -2
- data/tasks/metrics/yardstick.rake +0 -14
- data/tasks/spec.rake +0 -2
- data/tasks/yard.rake +0 -2
- metadata +96 -31
- data/.travis.yml +0 -15
- data/TODO +0 -0
- data/bin/devtools +0 -18
- data/default/config/devtools.yml +0 -2
- data/default/config/flay.yml +0 -3
- data/default/config/flog.yml +0 -2
- data/default/config/mutant.yml +0 -3
- data/default/config/reek.yml +0 -103
- data/default/config/rubocop.yml +0 -91
- data/default/config/yardstick.yml +0 -2
- data/lib/devtools/platform.rb +0 -118
- data/lib/devtools/site.rb +0 -41
- data/lib/devtools/site/initializer.rb +0 -57
data/lib/devtools/spec_helper.rb
CHANGED
@@ -0,0 +1,164 @@
|
|
1
|
+
describe Devtools::Rake::Flay, '#verify' do
|
2
|
+
let(:tempfile) { Tempfile.new(%w[file .rb], Dir.mktmpdir) }
|
3
|
+
let(:file) { Pathname(tempfile.path) }
|
4
|
+
let(:directories) { [file.dirname.to_s] }
|
5
|
+
|
6
|
+
let(:ruby) do
|
7
|
+
<<-ERUBY
|
8
|
+
def foo; end
|
9
|
+
def bar; end
|
10
|
+
ERUBY
|
11
|
+
end
|
12
|
+
|
13
|
+
around(:each) do |example|
|
14
|
+
begin
|
15
|
+
# silence other flay output
|
16
|
+
$stdout = $stderr = StringIO.new
|
17
|
+
|
18
|
+
tempfile.write(ruby)
|
19
|
+
tempfile.close
|
20
|
+
|
21
|
+
example.run
|
22
|
+
ensure
|
23
|
+
$stdout = STDOUT
|
24
|
+
$stderr = STDERR
|
25
|
+
|
26
|
+
file.unlink
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'reporting' do
|
31
|
+
let(:options) do
|
32
|
+
{ threshold: 3, total_score: 3, lib_dirs: directories, excludes: [] }.freeze
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:instance) { described_class.new(options) }
|
36
|
+
|
37
|
+
it 'measures total mass' do
|
38
|
+
allow(::Flay).to receive(:new).and_call_original
|
39
|
+
|
40
|
+
instance.verify
|
41
|
+
|
42
|
+
expect(::Flay).to have_received(:new).with(hash_including(mass: 0))
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not report the files it is processing' do
|
46
|
+
expect { instance.verify }.to_not output(/Processing #{file}/).to_stderr
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when theshold is too low' do
|
51
|
+
let(:instance) do
|
52
|
+
described_class.new(threshold: 0, total_score: 0, lib_dirs: directories, excludes: [])
|
53
|
+
end
|
54
|
+
|
55
|
+
specify do
|
56
|
+
expect { instance.verify }
|
57
|
+
.to raise_error(SystemExit)
|
58
|
+
.with_message('Flay total is now 3, but expected 0')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when threshold is too high' do
|
63
|
+
let(:instance) do
|
64
|
+
described_class.new(threshold: 1000, total_score: 0, lib_dirs: directories, excludes: [])
|
65
|
+
end
|
66
|
+
|
67
|
+
specify do
|
68
|
+
expect { instance.verify }
|
69
|
+
.to raise_error(SystemExit)
|
70
|
+
.with_message('Adjust flay threshold down to 3')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when total is too high' do
|
75
|
+
let(:instance) do
|
76
|
+
described_class.new(threshold: 3, total_score: 50, lib_dirs: directories, excludes: [])
|
77
|
+
end
|
78
|
+
|
79
|
+
specify do
|
80
|
+
expect { instance.verify }
|
81
|
+
.to raise_error(SystemExit)
|
82
|
+
.with_message('Flay total is now 3, but expected 50')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when duplicate mass is greater than 0' do
|
87
|
+
let(:ruby) do
|
88
|
+
<<-ERUBY
|
89
|
+
def foo
|
90
|
+
:hi if baz?
|
91
|
+
end
|
92
|
+
|
93
|
+
def bar
|
94
|
+
:hi if baz?
|
95
|
+
end
|
96
|
+
ERUBY
|
97
|
+
end
|
98
|
+
|
99
|
+
let(:report) do
|
100
|
+
<<-REPORT
|
101
|
+
Total score (lower is better) = 10
|
102
|
+
|
103
|
+
Similar code found in :defn (mass = 10)
|
104
|
+
#{file}:1
|
105
|
+
#{file}:5
|
106
|
+
REPORT
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:instance) do
|
110
|
+
described_class.new(threshold: 3, total_score: 5, lib_dirs: directories, excludes: [])
|
111
|
+
end
|
112
|
+
|
113
|
+
specify do
|
114
|
+
expect { instance.verify }
|
115
|
+
.to raise_error(SystemExit)
|
116
|
+
.with_message('1 chunks have a duplicate mass > 3')
|
117
|
+
end
|
118
|
+
|
119
|
+
specify do
|
120
|
+
expect { instance.verify }
|
121
|
+
.to raise_error(SystemExit)
|
122
|
+
.and output(report).to_stdout
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when multiple duplicate masses' do
|
127
|
+
let(:ruby) do
|
128
|
+
<<-ERUBY
|
129
|
+
def foo; end
|
130
|
+
def bar; end
|
131
|
+
|
132
|
+
class Foo
|
133
|
+
def initialize
|
134
|
+
@a = 1
|
135
|
+
end
|
136
|
+
end
|
137
|
+
class Bar
|
138
|
+
def initialize
|
139
|
+
@a = 1
|
140
|
+
end
|
141
|
+
end
|
142
|
+
ERUBY
|
143
|
+
end
|
144
|
+
|
145
|
+
let(:instance) do
|
146
|
+
described_class.new(threshold: 5, total_score: 8, lib_dirs: directories, excludes: [])
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'sums masses for total' do
|
150
|
+
expect { instance.verify }.to_not raise_error
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when no duplication masses' do
|
155
|
+
let(:ruby) { '' }
|
156
|
+
let(:instance) do
|
157
|
+
described_class.new(threshold: 0, total_score: 0, lib_dirs: directories, excludes: [])
|
158
|
+
end
|
159
|
+
|
160
|
+
specify do
|
161
|
+
expect { instance.verify }.to_not raise_error
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,14 +1,10 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'devtools/spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'tmpdir'
|
4
4
|
|
5
5
|
if ENV['COVERAGE'] == 'true'
|
6
|
-
require 'simplecov'
|
7
|
-
require 'coveralls'
|
8
|
-
|
9
6
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
7
|
SimpleCov::Formatter::HTMLFormatter,
|
11
|
-
Coveralls::SimpleCov::Formatter
|
12
8
|
]
|
13
9
|
|
14
10
|
SimpleCov.start do
|
@@ -22,8 +18,6 @@ if ENV['COVERAGE'] == 'true'
|
|
22
18
|
end
|
23
19
|
end
|
24
20
|
|
25
|
-
require 'devtools'
|
26
|
-
|
27
21
|
RSpec.configure do |config|
|
28
22
|
config.expect_with :rspec do |expect_with|
|
29
23
|
expect_with.syntax = :expect
|
@@ -0,0 +1,17 @@
|
|
1
|
+
RSpec.describe Devtools::Config::Yardstick do
|
2
|
+
let(:object) { described_class.new(Devtools.root.join('config')) }
|
3
|
+
|
4
|
+
describe '#options' do
|
5
|
+
subject { object.options }
|
6
|
+
|
7
|
+
specify do
|
8
|
+
should eql(
|
9
|
+
'threshold' => 100,
|
10
|
+
'rules' => nil,
|
11
|
+
'verbose' => nil,
|
12
|
+
'path' => nil,
|
13
|
+
'require_exact_threshold' => nil
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
RSpec.describe Devtools::Config do
|
2
|
+
|
3
|
+
describe '.attribute' do
|
4
|
+
let(:raw) do
|
5
|
+
{
|
6
|
+
'a' => 'bar',
|
7
|
+
'c' => []
|
8
|
+
}
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:config_path) { instance_double(Pathname) }
|
13
|
+
|
14
|
+
let(:class_under_test) do
|
15
|
+
expect(config_path).to receive(:file?)
|
16
|
+
.and_return(file?)
|
17
|
+
expect(config_path).to receive(:frozen?)
|
18
|
+
.and_return(true)
|
19
|
+
expect(config_path).to receive(:join)
|
20
|
+
.with('bar.yml')
|
21
|
+
.and_return(config_path)
|
22
|
+
|
23
|
+
Class.new(described_class) do
|
24
|
+
attribute :a, [String]
|
25
|
+
attribute :b, [Array], default: []
|
26
|
+
attribute :c, [TrueClass, FalseClass]
|
27
|
+
|
28
|
+
const_set(:FILE, 'bar.yml')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
class_under_test.new(config_path)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'on present config' do
|
37
|
+
let(:class_under_test) do
|
38
|
+
# Setup message expectation in a lasy way, not in a before
|
39
|
+
# block to make sure the around hook setting timeouts from the
|
40
|
+
# code under test is not affected.
|
41
|
+
expect(YAML).to receive(:load_file)
|
42
|
+
.with(config_path)
|
43
|
+
.and_return(raw)
|
44
|
+
|
45
|
+
expect(IceNine).to receive(:deep_freeze)
|
46
|
+
.with(raw)
|
47
|
+
.and_return(raw)
|
48
|
+
|
49
|
+
super()
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:file?) { true }
|
53
|
+
|
54
|
+
it 'allows to receive existing keys' do
|
55
|
+
expect(subject.a).to eql('bar')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows to receive absent keys with defaults' do
|
59
|
+
expect(subject.b).to eql([])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'executes checks when configured' do
|
63
|
+
expect { subject.c }.to raise_error(
|
64
|
+
Devtools::Config::TypeError,
|
65
|
+
'c: Got instance of Array expected TrueClass,FalseClass'
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'on absent config' do
|
71
|
+
let(:file?) { false }
|
72
|
+
|
73
|
+
it 'defaults to absent keys' do
|
74
|
+
expect(subject.b).to eql([])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Devtools::Flay::FileList, '.call' do
|
2
|
+
subject(:output) { described_class.call([tmpdir.to_s], [exclude]) }
|
3
|
+
|
4
|
+
let(:tmpdir) { Dir.mktmpdir }
|
5
|
+
let(:one) { Pathname(tmpdir).join('1.rb') }
|
6
|
+
let(:two) { Pathname(tmpdir).join('2.erb') }
|
7
|
+
let(:three) { Pathname(tmpdir).join('3.rb') }
|
8
|
+
let(:exclude) { Pathname(tmpdir).join('3*').to_s }
|
9
|
+
|
10
|
+
around(:each) do |example|
|
11
|
+
[one, two, three].map(&FileUtils.method(:touch))
|
12
|
+
|
13
|
+
example.run
|
14
|
+
|
15
|
+
FileUtils.rm_rf(tmpdir)
|
16
|
+
end
|
17
|
+
|
18
|
+
it { should eql(Set.new([one, two])) }
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Devtools::Flay::Scale, '#flay_report' do
|
2
|
+
subject(:instance) { described_class.new(minimum_mass: 0, files: []) }
|
3
|
+
|
4
|
+
let(:flay) do
|
5
|
+
instance_double(::Flay, process: nil, analyze: nil, masses: {})
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(::Flay).to receive(:new).with(mass: 0).and_return(flay)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify do
|
13
|
+
allow(flay).to receive(:report)
|
14
|
+
instance.flay_report
|
15
|
+
expect(flay).to have_received(:report)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
describe Devtools::Flay::Scale, '#measure' do
|
2
|
+
subject(:measure) { instance.measure }
|
3
|
+
|
4
|
+
let(:minimum_mass) { 0 }
|
5
|
+
let(:files) { [instance_double(File)] }
|
6
|
+
let(:flay_masses) { { 0 => 5, 1 => 10 } }
|
7
|
+
|
8
|
+
let(:instance) do
|
9
|
+
described_class.new(minimum_mass: minimum_mass, files: files)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:flay_hashes) do
|
13
|
+
{
|
14
|
+
0 => instance_double(Array, size: 3),
|
15
|
+
1 => instance_double(Array, size: 11)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:flay) do
|
20
|
+
instance_double(
|
21
|
+
::Flay,
|
22
|
+
analyze: nil,
|
23
|
+
masses: flay_masses,
|
24
|
+
hashes: flay_hashes
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
before do
|
29
|
+
allow(::Flay).to receive(:new).with(mass: minimum_mass).and_return(flay)
|
30
|
+
allow(flay).to receive(:process).with(*files)
|
31
|
+
end
|
32
|
+
|
33
|
+
it { should eql([Rational(5, 3), Rational(10, 11)]) }
|
34
|
+
|
35
|
+
context 'when minimum mass is not 0' do
|
36
|
+
let(:minimum_mass) { 1 }
|
37
|
+
|
38
|
+
specify do
|
39
|
+
measure
|
40
|
+
expect(::Flay).to have_received(:new).with(mass: 1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe Devtools::Project::Initializer::Rake do
|
2
|
+
describe '.call' do
|
3
|
+
subject do
|
4
|
+
described_class.call
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'performs expected rake initialization' do
|
8
|
+
path_a = instance_double(Pathname)
|
9
|
+
path_b = instance_double(Pathname)
|
10
|
+
|
11
|
+
expect(FileList).to receive(:glob)
|
12
|
+
.with(Devtools.root.join('tasks/**/*.rake').to_s)
|
13
|
+
.and_return([path_a, path_b])
|
14
|
+
|
15
|
+
expect(Rake.application).to receive(:add_import).with(path_a)
|
16
|
+
expect(Rake.application).to receive(:add_import).with(path_b)
|
17
|
+
|
18
|
+
expect(subject).to be(described_class)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|