rubycritic 3.4.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -2
  3. data/README.md +12 -10
  4. data/lib/rubycritic/cli/options.rb +25 -3
  5. data/lib/rubycritic/command_factory.rb +3 -0
  6. data/lib/rubycritic/commands/ci.rb +2 -8
  7. data/lib/rubycritic/commands/compare.rb +105 -0
  8. data/lib/rubycritic/commands/utils/build_number_file.rb +35 -0
  9. data/lib/rubycritic/configuration.rb +18 -1
  10. data/lib/rubycritic/core/analysed_modules_collection.rb +23 -3
  11. data/lib/rubycritic/generators/html/assets/stylesheets/application.css +20 -0
  12. data/lib/rubycritic/generators/html/base.rb +1 -1
  13. data/lib/rubycritic/generators/html/code_file.rb +11 -0
  14. data/lib/rubycritic/generators/html/code_index.rb +7 -0
  15. data/lib/rubycritic/generators/html/overview.rb +7 -0
  16. data/lib/rubycritic/generators/html/smells_index.rb +7 -0
  17. data/lib/rubycritic/generators/html/templates/code_index.html.erb +10 -0
  18. data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +7 -0
  19. data/lib/rubycritic/generators/html/view_helpers.rb +10 -1
  20. data/lib/rubycritic/source_control_systems/git.rb +27 -1
  21. data/lib/rubycritic/version.rb +1 -1
  22. metadata +7 -131
  23. data/.gitignore +0 -23
  24. data/.rubocop.yml +0 -37
  25. data/.rubocop_todo.yml +0 -45
  26. data/.todo.reek +0 -142
  27. data/.travis.yml +0 -29
  28. data/.yardopts +0 -5
  29. data/docs/building-own-code-climate.md +0 -156
  30. data/docs/core-metrics.md +0 -72
  31. data/docs/jenkins-pr-reviews.md +0 -64
  32. data/features/command_line_interface/minimum_score.feature +0 -39
  33. data/features/command_line_interface/options.feature +0 -37
  34. data/features/rake_task.feature +0 -65
  35. data/features/step_definitions/rake_task_steps.rb +0 -5
  36. data/features/step_definitions/rubycritic_steps.rb +0 -33
  37. data/features/step_definitions/sample_file_steps.rb +0 -32
  38. data/features/support/env.rb +0 -43
  39. data/images/churn-vs-complexity.png +0 -0
  40. data/images/code.png +0 -0
  41. data/images/logo.png +0 -0
  42. data/images/overview.png +0 -0
  43. data/images/rating.png +0 -0
  44. data/images/reek.png +0 -0
  45. data/images/smell-details.png +0 -0
  46. data/images/smells.png +0 -0
  47. data/images/whitesmith.png +0 -0
  48. data/rubycritic.gemspec +0 -45
  49. data/test/analysers_test_helper.rb +0 -12
  50. data/test/lib/rubycritic/analysers/churn_test.rb +0 -35
  51. data/test/lib/rubycritic/analysers/complexity_test.rb +0 -18
  52. data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +0 -31
  53. data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +0 -55
  54. data/test/lib/rubycritic/analysers/smells/flay_test.rb +0 -41
  55. data/test/lib/rubycritic/analysers/smells/flog_test.rb +0 -28
  56. data/test/lib/rubycritic/analysers/smells/reek_test.rb +0 -32
  57. data/test/lib/rubycritic/analysis_summary_test.rb +0 -30
  58. data/test/lib/rubycritic/browser_test.rb +0 -18
  59. data/test/lib/rubycritic/commands/status_reporter_test.rb +0 -81
  60. data/test/lib/rubycritic/configuration_test.rb +0 -31
  61. data/test/lib/rubycritic/core/analysed_module_test.rb +0 -90
  62. data/test/lib/rubycritic/core/analysed_modules_collection_test.rb +0 -111
  63. data/test/lib/rubycritic/core/location_test.rb +0 -39
  64. data/test/lib/rubycritic/core/smell_test.rb +0 -105
  65. data/test/lib/rubycritic/core/smells_array_test.rb +0 -30
  66. data/test/lib/rubycritic/generators/console_report_test.rb +0 -83
  67. data/test/lib/rubycritic/generators/json_report_test.rb +0 -38
  68. data/test/lib/rubycritic/generators/lint_report_test.rb +0 -37
  69. data/test/lib/rubycritic/generators/turbulence_test.rb +0 -19
  70. data/test/lib/rubycritic/generators/view_helpers_test.rb +0 -85
  71. data/test/lib/rubycritic/revision_comparator_test.rb +0 -66
  72. data/test/lib/rubycritic/smells_status_setter_test.rb +0 -24
  73. data/test/lib/rubycritic/source_control_systems/base_test.rb +0 -31
  74. data/test/lib/rubycritic/source_control_systems/double_test.rb +0 -13
  75. data/test/lib/rubycritic/source_control_systems/git_test.rb +0 -15
  76. data/test/lib/rubycritic/source_control_systems/interfaces/basic.rb +0 -9
  77. data/test/lib/rubycritic/source_control_systems/interfaces/time_travel.rb +0 -9
  78. data/test/lib/rubycritic/source_control_systems/mercurial_test.rb +0 -13
  79. data/test/lib/rubycritic/source_control_systems/perforce_test.rb +0 -176
  80. data/test/lib/rubycritic/source_locator_test.rb +0 -80
  81. data/test/lib/rubycritic/version_test.rb +0 -10
  82. data/test/samples/empty.rb +0 -0
  83. data/test/samples/flay/smelly.rb +0 -8
  84. data/test/samples/flay/smelly2.rb +0 -8
  85. data/test/samples/flog/complex.rb +0 -11
  86. data/test/samples/flog/smelly.rb +0 -11
  87. data/test/samples/location/dir1/file1.rb +0 -0
  88. data/test/samples/location/file0.rb +0 -0
  89. data/test/samples/location/file0_symlink.rb +0 -1
  90. data/test/samples/location/file_with_different_extension.py +0 -0
  91. data/test/samples/location/file_with_no_extension +0 -0
  92. data/test/samples/methods_count.rb +0 -7
  93. data/test/samples/module_names.rb +0 -18
  94. data/test/samples/no_methods.rb +0 -4
  95. data/test/samples/reek/not_smelly.rb +0 -35
  96. data/test/samples/reek/smelly.rb +0 -17
  97. data/test/samples/unparsable.rb +0 -1
  98. data/test/test_helper.rb +0 -64
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/analysers/smells/flay'
5
- require 'rubycritic/core/analysed_module'
6
- require 'pathname'
7
-
8
- describe RubyCritic::Analyser::FlaySmells do
9
- context 'when analysing a bunch of files with duplicate code' do
10
- before do
11
- @analysed_modules = [
12
- RubyCritic::AnalysedModule.new(pathname: Pathname.new('test/samples/flay/smelly.rb')),
13
- RubyCritic::AnalysedModule.new(pathname: Pathname.new('test/samples/flay/smelly2.rb'))
14
- ]
15
- RubyCritic::Analyser::FlaySmells.new(@analysed_modules).run
16
- end
17
-
18
- it 'detects its smells' do
19
- @analysed_modules.first.smells?.must_equal true
20
- end
21
-
22
- it 'creates smells with messages' do
23
- smell = @analysed_modules.first.smells.first
24
- smell.message.must_be_instance_of String
25
- end
26
-
27
- it 'creates smells with scores' do
28
- smell = @analysed_modules.first.smells.first
29
- smell.score.must_be_kind_of Numeric
30
- end
31
-
32
- it 'creates smells with more than one location' do
33
- smell = @analysed_modules.first.smells.first
34
- smell.multiple_locations?.must_equal true
35
- end
36
-
37
- it 'calculates the mass of duplicate code' do
38
- @analysed_modules.first.duplication.must_be(:>, 0)
39
- end
40
- end
41
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'analysers_test_helper'
4
- require 'rubycritic/analysers/smells/flog'
5
-
6
- describe RubyCritic::Analyser::FlogSmells do
7
- context 'when analysing a complex file' do
8
- before do
9
- @analysed_module = AnalysedModuleDouble.new(path: 'test/samples/flog/smelly.rb', smells: [])
10
- analysed_modules = [@analysed_module]
11
- RubyCritic::Analyser::FlogSmells.new(analysed_modules).run
12
- end
13
-
14
- it 'detects its smells' do
15
- @analysed_module.smells.length.must_equal 1
16
- end
17
-
18
- it 'creates smells with messages' do
19
- smell = @analysed_module.smells.first
20
- smell.message.must_be_instance_of String
21
- end
22
-
23
- it 'creates smells with scores' do
24
- smell = @analysed_module.smells.first
25
- smell.score.must_be :>, 0
26
- end
27
- end
28
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'analysers_test_helper'
4
- require 'rubycritic/analysers/smells/reek'
5
-
6
- describe RubyCritic::Analyser::ReekSmells do
7
- context 'when analysing a smelly file' do
8
- before do
9
- pathname = Pathname.new('test/samples/reek/smelly.rb')
10
- @analysed_module = AnalysedModuleDouble.new(pathname: pathname, smells: [])
11
- analysed_modules = [@analysed_module]
12
- RubyCritic::Analyser::ReekSmells.new(analysed_modules).run
13
- end
14
-
15
- it 'detects its smells' do
16
- @analysed_module.smells.length.must_equal 2
17
- end
18
-
19
- it 'respects the .reek file' do
20
- messages = @analysed_module.smells.map(&:message)
21
- messages.wont_include "has the parameter name 'a'"
22
- end
23
-
24
- it 'creates smells with messages' do
25
- first_smell = @analysed_module.smells.first
26
- first_smell.message.must_equal "has boolean parameter 'reek'"
27
-
28
- last_smell = @analysed_module.smells.last
29
- last_smell.message.must_equal 'has no descriptive comment'
30
- end
31
- end
32
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/analysis_summary'
5
-
6
- module RubyCritic
7
- describe AnalysisSummary do
8
- before do
9
- analysed_modules = AnalysedModulesCollectionDouble.new(
10
- [
11
- AnalysedModuleDouble.new(rating: 'A', churn: 2, smells: %i[a b c]),
12
- AnalysedModuleDouble.new(rating: 'A', churn: 3, smells: [:b]),
13
- AnalysedModuleDouble.new(rating: 'A', churn: 4, smells: %i[x y]),
14
- AnalysedModuleDouble.new(rating: 'B', churn: 5, smells: %i[a z])
15
- ]
16
- )
17
- @summary = RubyCritic::AnalysisSummary.generate(analysed_modules)
18
- end
19
-
20
- describe '.root' do
21
- it 'computes correct summary' do
22
- @summary['A'].to_a.must_equal({ files: 3, churns: 9, smells: 6 }.to_a)
23
- @summary['B'].to_a.must_equal({ files: 1, churns: 5, smells: 2 }.to_a)
24
- @summary['C'].to_a.must_equal({ files: 0, churns: 0, smells: 0 }.to_a)
25
- @summary['D'].to_a.must_equal({ files: 0, churns: 0, smells: 0 }.to_a)
26
- @summary['F'].to_a.must_equal({ files: 0, churns: 0, smells: 0 }.to_a)
27
- end
28
- end
29
- end
30
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/browser'
5
-
6
- describe RubyCritic::Browser do
7
- before do
8
- @report_path = 'tmp/rubycritic/overview.html'
9
- @browser = RubyCritic::Browser.new @report_path
10
- end
11
-
12
- describe '#open' do
13
- it 'should be open report with launch browser' do
14
- Launchy.stubs(:open).returns(true)
15
- @browser.open.must_equal true
16
- end
17
- end
18
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/commands/status_reporter'
5
- require 'rubycritic/cli/options'
6
-
7
- describe RubyCritic::Command::StatusReporter do
8
- let(:success_status) { RubyCritic::Command::StatusReporter::SUCCESS }
9
- let(:score_below_minimum) { RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM }
10
-
11
- describe 'with default options' do
12
- before do
13
- @options = RubyCritic::Cli::Options.new([])
14
- @options.parse
15
- @reporter = RubyCritic::Command::StatusReporter.new(@options.to_h)
16
- end
17
-
18
- it 'has a default' do
19
- @reporter.status.must_equal success_status
20
- @reporter.status_message.must_be_nil
21
- end
22
-
23
- it 'accept a score' do
24
- @reporter.score = 50.0
25
- @reporter.status.must_equal success_status
26
- @reporter.status_message.must_equal 'Score: 50.0'
27
- end
28
-
29
- it 'should format the score' do
30
- @reporter.score = 98.95258620689656
31
- @reporter.status.must_equal success_status
32
- @reporter.status_message.must_equal 'Score: 98.95'
33
- end
34
- end
35
-
36
- describe 'with minimum-score option' do
37
- before do
38
- @options = RubyCritic::Cli::Options.new(['-s', '99'])
39
- @options.parse
40
- @reporter = RubyCritic::Command::StatusReporter.new(@options.to_h)
41
- end
42
-
43
- it 'has a default' do
44
- @reporter.status.must_equal success_status
45
- @reporter.status_message.must_be_nil
46
- end
47
-
48
- describe 'when score is below minimum' do
49
- let(:score) { 98.0 }
50
- it 'should return the correct status' do
51
- @reporter.score = score
52
- @reporter.status.must_equal score_below_minimum
53
- @reporter.status_message.must_equal 'Score (98.0) is below the minimum 99.0'
54
- end
55
-
56
- it 'should format the score' do
57
- @reporter.score = 98.95258620689656
58
- @reporter.status.must_equal score_below_minimum
59
- @reporter.status_message.must_equal 'Score (98.95) is below the minimum 99.0'
60
- end
61
- end
62
-
63
- describe 'when score is equal the minimum' do
64
- let(:score) { 99.0 }
65
- it 'should return the correct status' do
66
- @reporter.score = score
67
- @reporter.status.must_equal success_status
68
- @reporter.status_message.must_equal 'Score: 99.0'
69
- end
70
- end
71
-
72
- describe 'when score is above the minimum' do
73
- let(:score) { 100.0 }
74
- it 'should return the correct status' do
75
- @reporter.score = score
76
- @reporter.status.must_equal success_status
77
- @reporter.status_message.must_equal 'Score: 100.0'
78
- end
79
- end
80
- end
81
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/configuration'
5
-
6
- describe RubyCritic::Configuration do
7
- describe '#root' do
8
- before do
9
- RubyCritic::Config.set
10
- @default = RubyCritic::Config.root
11
- end
12
-
13
- it 'has a default' do
14
- RubyCritic::Config.root.must_be_instance_of String
15
- end
16
-
17
- it 'can be set to a relative path' do
18
- RubyCritic::Config.root = 'foo'
19
- RubyCritic::Config.root.must_equal File.expand_path('foo')
20
- end
21
-
22
- it 'can be set to an absolute path' do
23
- RubyCritic::Config.root = '/foo'
24
- RubyCritic::Config.root.must_equal '/foo'
25
- end
26
-
27
- after do
28
- RubyCritic::Config.root = @default
29
- end
30
- end
31
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/core/analysed_module'
5
- require 'rubycritic/core/smell'
6
-
7
- describe RubyCritic::AnalysedModule do
8
- describe 'attribute readers' do
9
- before do
10
- @name = 'Foo'
11
- @pathname = Pathname.new('foo.rb')
12
- @smells = []
13
- @churn = 1
14
- @complexity = 2
15
- @analysed_module = RubyCritic::AnalysedModule.new(
16
- name: @name,
17
- pathname: @pathname,
18
- smells: @smells,
19
- churn: @churn,
20
- complexity: @complexity
21
- )
22
- end
23
-
24
- it 'has a name reader' do
25
- @analysed_module.name.must_equal @name
26
- end
27
-
28
- it 'has a pathname reader' do
29
- @analysed_module.pathname.must_equal @pathname
30
- end
31
-
32
- it 'has a path reader' do
33
- @analysed_module.path.must_equal @pathname.to_s
34
- end
35
-
36
- it 'has a smells reader' do
37
- @analysed_module.smells.must_equal @smells
38
- end
39
-
40
- it 'has a churn reader' do
41
- @analysed_module.churn.must_equal @churn
42
- end
43
-
44
- it 'has a complexity reader' do
45
- @analysed_module.complexity.must_equal @complexity
46
- end
47
- end
48
-
49
- describe '#cost' do
50
- it 'returns the remediation cost of fixing the analysed_module' do
51
- smells = [SmellDouble.new(cost: 1), SmellDouble.new(cost: 2)]
52
- analysed_module = RubyCritic::AnalysedModule.new(smells: smells, complexity: 0)
53
- analysed_module.cost.must_equal 3
54
- end
55
- end
56
-
57
- describe '#complexity_per_method' do
58
- context 'when the file has no methods' do
59
- it 'returns a placeholder' do
60
- analysed_module = RubyCritic::AnalysedModule.new(complexity: 0, methods_count: 0)
61
- analysed_module.complexity_per_method.must_equal 'N/A'
62
- end
63
- end
64
-
65
- context 'when the file has at least one method' do
66
- it 'returns the average complexity per method' do
67
- analysed_module = RubyCritic::AnalysedModule.new(complexity: 10, methods_count: 2)
68
- analysed_module.complexity_per_method.must_equal 5
69
- end
70
- end
71
- end
72
-
73
- describe '#smells?' do
74
- it 'returns true if the analysed_module has at least one smell' do
75
- analysed_module = RubyCritic::AnalysedModule.new(smells: [SmellDouble.new])
76
- analysed_module.smells?.must_equal true
77
- end
78
- end
79
-
80
- describe '#smells_at_location' do
81
- it 'returns the smells of an analysed_module at a certain location' do
82
- location = RubyCritic::Location.new('./foo', '42')
83
- smells = [RubyCritic::Smell.new(locations: [location])]
84
- analysed_module = RubyCritic::AnalysedModule.new(smells: smells)
85
- analysed_module.smells_at_location(location).must_equal smells
86
- end
87
- end
88
- end
89
-
90
- class SmellDouble < OpenStruct; end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rubycritic/core/analysed_modules_collection'
5
-
6
- describe RubyCritic::AnalysedModulesCollection do
7
- subject { RubyCritic::AnalysedModulesCollection.new(paths) }
8
-
9
- describe '.new' do
10
- context 'with an empty path' do
11
- let(:paths) { '' }
12
-
13
- it 'returns an empty collection' do
14
- subject.count.must_equal 0
15
- end
16
- end
17
-
18
- context 'with a list of files' do
19
- let(:paths) { %w[test/samples/doesnt_exist.rb test/samples/unparsable.rb test/samples/empty.rb] }
20
-
21
- it 'registers one AnalysedModule element per existent file' do
22
- subject.count.must_equal 2
23
- subject.all? { |a| a.is_a?(RubyCritic::AnalysedModule) }.must_equal true
24
- end
25
- end
26
-
27
- context 'with a directory' do
28
- let(:paths) { 'test/samples/' }
29
-
30
- it 'recursively registers all files' do
31
- subject.count.must_equal Dir['test/samples/**/*.rb'].count
32
- end
33
- end
34
-
35
- context 'with redundant paths' do
36
- let(:paths) { %w[test/samples/flog test/samples/flog/complex.rb] }
37
-
38
- it 'returns a redundant collection' do
39
- subject.count.must_equal 3
40
- end
41
- end
42
- end
43
-
44
- describe '#score' do
45
- context 'with no modules' do
46
- let(:paths) { '' }
47
-
48
- it 'returns zero' do
49
- subject.score.must_equal 0.0
50
- end
51
- end
52
-
53
- context 'with not analysed modules' do
54
- let(:paths) { 'test/samples/flog' }
55
-
56
- it 'returns zero' do
57
- subject.score.must_equal 0.0
58
- end
59
- end
60
-
61
- context 'with analysed modules' do
62
- before do
63
- subject.each_with_index do |mod, i|
64
- mod.expects(:cost).returns costs[i]
65
- end
66
- end
67
-
68
- let(:paths) { %w[test/samples/flog test/samples/flay] }
69
-
70
- context 'with perfect modules' do
71
- let(:costs) { [0.0, 0.0, 0.0, 0.0] }
72
-
73
- it 'returns the maximum score' do
74
- subject.score.must_equal 100.0
75
- end
76
- end
77
-
78
- context 'with very bad modules' do
79
- let(:costs) { [16.0, 16.0, 16.0, 16.0] }
80
-
81
- it 'returns zero' do
82
- subject.score.must_equal 0.0
83
- end
84
- end
85
-
86
- context 'with horrible modules' do
87
- let(:costs) { [32.0, 32.0, 32.0, 32.0] }
88
-
89
- it 'returns zero' do
90
- subject.score.must_equal 0.0
91
- end
92
- end
93
-
94
- context 'with mixed modules' do
95
- let(:costs) { [32.0, 2.0, 0.0, 2.0] }
96
-
97
- it 'properly calculates the score' do
98
- subject.score.must_equal 43.75
99
- end
100
- end
101
-
102
- context 'with a module above the cost limit' do
103
- let(:costs) { [220.0, 2.0, 0.0, 2.0] }
104
-
105
- it 'reduces the impact in the result' do
106
- subject.score.must_equal 43.75
107
- end
108
- end
109
- end
110
- end
111
- end