rubycritic 0.0.5 → 1.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +593 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +45 -0
  5. data/CONTRIBUTING.md +67 -15
  6. data/README.md +105 -14
  7. data/Rakefile +9 -6
  8. data/bin/rubycritic +3 -1
  9. data/lib/rubycritic/analysers/attributes.rb +21 -0
  10. data/lib/rubycritic/analysers/churn.rb +21 -0
  11. data/lib/rubycritic/analysers/complexity.rb +22 -0
  12. data/lib/rubycritic/analysers/helpers/ast_node.rb +69 -0
  13. data/lib/rubycritic/analysers/{config.reek → helpers/config.reek} +8 -0
  14. data/lib/rubycritic/analysers/helpers/flay.rb +13 -0
  15. data/lib/rubycritic/analysers/helpers/flog.rb +17 -0
  16. data/lib/rubycritic/analysers/helpers/methods_counter.rb +25 -0
  17. data/lib/rubycritic/analysers/helpers/modules_locator.rb +43 -0
  18. data/lib/rubycritic/analysers/helpers/parser.rb +12 -0
  19. data/lib/rubycritic/analysers/helpers/reek.rb +17 -0
  20. data/lib/rubycritic/analysers/smells/flay.rb +68 -0
  21. data/lib/rubycritic/analysers/smells/flog.rb +62 -0
  22. data/lib/rubycritic/analysers/smells/reek.rb +44 -0
  23. data/lib/rubycritic/analysers_runner.rb +21 -10
  24. data/lib/rubycritic/cli/application.rb +24 -0
  25. data/lib/rubycritic/cli/options.rb +79 -0
  26. data/lib/rubycritic/commands/ci.rb +26 -0
  27. data/lib/rubycritic/commands/default.rb +28 -0
  28. data/lib/rubycritic/commands/help.rb +13 -0
  29. data/lib/rubycritic/commands/version.rb +11 -0
  30. data/lib/rubycritic/configuration.rb +33 -0
  31. data/lib/rubycritic/core/analysed_module.rb +66 -0
  32. data/lib/rubycritic/{location.rb → core/location.rb} +17 -2
  33. data/lib/rubycritic/core/rating.rb +30 -0
  34. data/lib/rubycritic/{smell.rb → core/smell.rb} +22 -13
  35. data/lib/rubycritic/generators/html/assets/javascripts/application.js +104 -0
  36. data/lib/rubycritic/generators/html/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
  37. data/lib/rubycritic/generators/html/assets/javascripts/jquery.floatThead-v1.2.7.js +754 -0
  38. data/lib/rubycritic/generators/html/assets/javascripts/jquery.scrollTo-1.4.11.js +186 -0
  39. data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.js +2089 -0
  40. data/lib/rubycritic/generators/html/assets/javascripts/jquery.timeago-v1.4.1.js +214 -0
  41. data/lib/rubycritic/generators/html/assets/stylesheets/application.css +303 -0
  42. data/lib/rubycritic/{report_generators → generators/html}/assets/stylesheets/prettify.custom_theme.css +1 -4
  43. data/lib/rubycritic/generators/html/base.rb +52 -0
  44. data/lib/rubycritic/generators/html/code_file.rb +40 -0
  45. data/lib/rubycritic/generators/html/code_index.rb +26 -0
  46. data/lib/rubycritic/generators/html/line.rb +37 -0
  47. data/lib/rubycritic/generators/html/overview.rb +27 -0
  48. data/lib/rubycritic/generators/html/smells_index.rb +38 -0
  49. data/lib/rubycritic/generators/html/templates/code_file.html.erb +38 -0
  50. data/lib/rubycritic/generators/html/templates/code_index.html.erb +30 -0
  51. data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +34 -0
  52. data/lib/rubycritic/generators/html/templates/overview.html.erb +5 -0
  53. data/lib/rubycritic/generators/html/templates/smells_index.html.erb +26 -0
  54. data/lib/rubycritic/{report_generators → generators/html}/templates/smelly_line.html.erb +1 -1
  55. data/lib/rubycritic/generators/html/turbulence.rb +17 -0
  56. data/lib/rubycritic/generators/html/view_helpers.rb +43 -0
  57. data/lib/rubycritic/generators/html_report.rb +66 -0
  58. data/lib/rubycritic/generators/json/simple.rb +30 -0
  59. data/lib/rubycritic/generators/json_report.rb +23 -0
  60. data/lib/rubycritic/reporter.rb +20 -0
  61. data/lib/rubycritic/revision_comparator.rb +27 -29
  62. data/lib/rubycritic/serializer.rb +32 -0
  63. data/lib/rubycritic/smells_status_setter.rb +7 -16
  64. data/lib/rubycritic/source_control_systems/base.rb +37 -0
  65. data/lib/rubycritic/source_control_systems/double.rb +18 -0
  66. data/lib/rubycritic/source_control_systems/git.rb +41 -37
  67. data/lib/rubycritic/source_control_systems/mercurial.rb +29 -0
  68. data/lib/rubycritic/source_locator.rb +25 -13
  69. data/lib/rubycritic/version.rb +1 -1
  70. data/lib/rubycritic.rb +17 -22
  71. data/rubycritic.gemspec +10 -7
  72. data/test/analysers_test_helper.rb +3 -0
  73. data/test/lib/rubycritic/analysers/churn_test.rb +33 -0
  74. data/test/lib/rubycritic/analysers/complexity_test.rb +16 -0
  75. data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
  76. data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
  77. data/test/lib/rubycritic/analysers/smells/flay_test.rb +39 -0
  78. data/test/lib/rubycritic/analysers/smells/flog_test.rb +26 -0
  79. data/test/lib/rubycritic/analysers/smells/reek_test.rb +33 -0
  80. data/test/lib/rubycritic/configuration_test.rb +29 -0
  81. data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
  82. data/test/lib/rubycritic/{location_test.rb → core/location_test.rb} +8 -4
  83. data/test/lib/rubycritic/core/smell_test.rb +72 -0
  84. data/test/lib/rubycritic/{smells_array_test.rb → core/smells_array_test.rb} +1 -1
  85. data/test/lib/rubycritic/report_generators/turbulence_test.rb +17 -0
  86. data/test/lib/rubycritic/report_generators/view_helpers_test.rb +83 -0
  87. data/test/lib/rubycritic/smells_status_setter_test.rb +5 -5
  88. data/test/lib/rubycritic/source_control_systems/base_test.rb +29 -0
  89. data/test/lib/rubycritic/source_control_systems/double_test.rb +11 -0
  90. data/test/lib/rubycritic/source_control_systems/git_test.rb +13 -0
  91. data/test/lib/rubycritic/source_control_systems/interfaces/basic.rb +7 -0
  92. data/test/lib/rubycritic/source_control_systems/interfaces/time_travel.rb +7 -0
  93. data/test/lib/rubycritic/source_control_systems/mercurial_test.rb +11 -0
  94. data/test/lib/rubycritic/source_locator_test.rb +42 -18
  95. data/test/lib/rubycritic/version_test.rb +1 -0
  96. data/test/samples/empty.rb +0 -0
  97. data/test/samples/flay/smelly.rb +8 -0
  98. data/test/samples/flay/smelly2.rb +8 -0
  99. data/test/samples/flog/complex.rb +11 -0
  100. data/test/samples/flog/smelly.rb +7 -2
  101. data/test/samples/location/file0_symlink.rb +0 -0
  102. data/test/samples/methods_count.rb +7 -0
  103. data/test/samples/module_names.rb +18 -0
  104. data/test/samples/reek/not_smelly.rb +31 -3
  105. data/test/samples/unparsable.rb +1 -0
  106. data/test/test_helper.rb +39 -0
  107. metadata +178 -53
  108. data/SPEC.md +0 -58
  109. data/lib/rubycritic/analysers/flog.rb +0 -20
  110. data/lib/rubycritic/analysers/reek.rb +0 -15
  111. data/lib/rubycritic/cli.rb +0 -25
  112. data/lib/rubycritic/report_generators/assets/javascripts/application.js +0 -25
  113. data/lib/rubycritic/report_generators/assets/stylesheets/application.css +0 -26
  114. data/lib/rubycritic/report_generators/base_generator.rb +0 -42
  115. data/lib/rubycritic/report_generators/file_generator.rb +0 -42
  116. data/lib/rubycritic/report_generators/index_generator.rb +0 -28
  117. data/lib/rubycritic/report_generators/line_generator.rb +0 -27
  118. data/lib/rubycritic/report_generators/reporter.rb +0 -45
  119. data/lib/rubycritic/report_generators/templates/file.html.erb +0 -3
  120. data/lib/rubycritic/report_generators/templates/index.html.erb +0 -14
  121. data/lib/rubycritic/report_generators/templates/layouts/application.html.erb +0 -19
  122. data/lib/rubycritic/report_generators/view_helpers.rb +0 -26
  123. data/lib/rubycritic/smell_adapters/flog.rb +0 -41
  124. data/lib/rubycritic/smell_adapters/reek.rb +0 -35
  125. data/lib/rubycritic/smells_aggregator.rb +0 -29
  126. data/lib/rubycritic/smelly_pathnames_serializer.rb +0 -34
  127. data/lib/rubycritic/source_control_systems/source_control_system.rb +0 -42
  128. data/test/lib/rubycritic/metric_adapters/flog_adapter_test.rb +0 -25
  129. data/test/lib/rubycritic/metric_adapters/reek_adapter_test.rb +0 -34
  130. data/test/lib/rubycritic/smell_test.rb +0 -71
  131. data/test/lib/rubycritic/smells_aggregator_test.rb +0 -47
  132. data/test/lib/rubycritic/source_control_systems/source_control_system_test.rb +0 -26
  133. /data/lib/rubycritic/{report_generators → generators/html}/assets/javascripts/jquery-2.1.0.js +0 -0
  134. /data/lib/rubycritic/{report_generators/assets/javascripts/prettify.js → generators/html/assets/javascripts/prettify-4-Mar-2013.js} +0 -0
  135. /data/lib/rubycritic/{report_generators → generators/html}/templates/line.html.erb +0 -0
@@ -1,53 +1,57 @@
1
1
  module Rubycritic
2
+ module SourceControlSystem
2
3
 
3
- class Git < SourceControlSystem
4
- register_system
4
+ class Git < Base
5
+ register_system
5
6
 
6
- def self.supported?
7
- `git branch 2>&1` && $?.success?
8
- end
7
+ def self.supported?
8
+ `git branch 2>&1` && $?.success?
9
+ end
9
10
 
10
- def self.to_s
11
- "Git"
12
- end
11
+ def self.to_s
12
+ "Git"
13
+ end
13
14
 
14
- def has_revision?
15
- head_reference && $?.success?
16
- end
15
+ def revisions_count(path)
16
+ `git log --follow --format=%h #{path.shellescape}`.count("\n")
17
+ end
17
18
 
18
- def head_reference
19
- `git rev-parse --verify HEAD`.chomp
20
- end
19
+ def date_of_last_commit(path)
20
+ `git log -1 --date=iso --format=%ad #{path.shellescape}`.chomp!
21
+ end
21
22
 
22
- def travel_to_head
23
- stash_successful = stash_changes
24
- yield
25
- ensure
26
- travel_to_original_state if stash_successful
27
- end
23
+ def revision?
24
+ head_reference && $?.success?
25
+ end
28
26
 
29
- private
27
+ def head_reference
28
+ `git rev-parse --verify HEAD`.chomp!
29
+ end
30
30
 
31
- def stash_changes
32
- return false if everything_commmited?
31
+ def travel_to_head
32
+ stash_successful = stash_changes
33
+ yield
34
+ ensure
35
+ travel_to_original_state if stash_successful
36
+ end
33
37
 
34
- stashes_count_before = stashes_count
35
- `git stash`
36
- stashes_count_after = stashes_count
37
- stashes_count_after > stashes_count_before
38
- end
38
+ private
39
39
 
40
- def everything_commmited?
41
- `git status --porcelain`.empty?
42
- end
40
+ def stash_changes
41
+ stashes_count_before = stashes_count
42
+ `git stash`
43
+ stashes_count_after = stashes_count
44
+ stashes_count_after > stashes_count_before
45
+ end
43
46
 
44
- def stashes_count
45
- `git stash list`.split("\n").length
46
- end
47
+ def stashes_count
48
+ `git stash list --format=%h`.count("\n")
49
+ end
47
50
 
48
- def travel_to_original_state
49
- `git stash pop`
51
+ def travel_to_original_state
52
+ `git stash pop`
53
+ end
50
54
  end
51
- end
52
55
 
56
+ end
53
57
  end
@@ -0,0 +1,29 @@
1
+ module Rubycritic
2
+ module SourceControlSystem
3
+
4
+ class Mercurial < Base
5
+ register_system
6
+
7
+ def self.supported?
8
+ `hg verify 2>&1` && $?.success?
9
+ end
10
+
11
+ def self.to_s
12
+ "Mercurial"
13
+ end
14
+
15
+ def revisions_count(path)
16
+ `hg log #{path.shellescape} --template '1'`.size
17
+ end
18
+
19
+ def date_of_last_commit(path)
20
+ `hg log #{path.shellescape} --template '{date|isodate}' --limit 1`.chomp
21
+ end
22
+
23
+ def revision?
24
+ false
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -7,32 +7,44 @@ module Rubycritic
7
7
  RUBY_FILES = File.join("**", "*#{RUBY_EXTENSION}")
8
8
 
9
9
  def initialize(paths)
10
- @user_paths = paths
11
- end
12
-
13
- def pathnames
14
- @pathnames ||= expand_paths
10
+ @initial_paths = Array(paths)
15
11
  end
16
12
 
17
13
  def paths
18
14
  @paths ||= pathnames.map(&:to_s)
19
15
  end
20
16
 
17
+ def pathnames
18
+ @pathnames ||= expand_paths
19
+ end
20
+
21
21
  private
22
22
 
23
+ def deduplicate_symlinks(path_list)
24
+ # sort the symlinks to the end so files are preferred
25
+ path_list.sort_by! { |path| File.symlink?(path.cleanpath) ? "z" : "a" }
26
+ if defined?(JRUBY_VERSION)
27
+ require "java"
28
+ path_list.uniq! do |path|
29
+ java.io.File.new(path.realpath.to_s).canonical_path
30
+ end
31
+ else
32
+ path_list.uniq!(&:realpath)
33
+ end
34
+ end
35
+
23
36
  def expand_paths
24
- @user_paths.map do |path|
37
+ path_list = @initial_paths.flat_map do |path|
25
38
  if File.directory?(path)
26
- Pathname.glob(files_contained_in(path))
27
- elsif File.exists?(path) && File.extname(path) == RUBY_EXTENSION
39
+ Pathname.glob(File.join(path, RUBY_FILES))
40
+ elsif File.exist?(path) && File.extname(path) == RUBY_EXTENSION
28
41
  Pathname.new(path)
29
42
  end
30
- end.flatten.compact.sort
31
- end
43
+ end.compact
44
+
45
+ deduplicate_symlinks(path_list) if Config.deduplicate_symlinks
32
46
 
33
- def files_contained_in(path)
34
- (path == ".") ? RUBY_FILES : File.join(path, RUBY_FILES)
47
+ path_list.map(&:cleanpath)
35
48
  end
36
49
  end
37
-
38
50
  end
@@ -1,3 +1,3 @@
1
1
  module Rubycritic
2
- VERSION = "0.0.5"
2
+ VERSION = "1.4.0"
3
3
  end
data/lib/rubycritic.rb CHANGED
@@ -1,27 +1,22 @@
1
- require "rubycritic/source_locator"
2
- require "rubycritic/analysers_runner"
3
- require "rubycritic/smells_aggregator"
4
- require "rubycritic/source_control_systems/source_control_system"
5
- require "rubycritic/revision_comparator"
6
- require "rubycritic/report_generators/reporter"
1
+ require "rubycritic/configuration"
7
2
 
8
3
  module Rubycritic
9
-
10
- class Rubycritic
11
- def initialize
12
- @source_control_system = SourceControlSystem.create
13
- end
14
-
15
- def critique(paths)
16
- source = SourceLocator.new(paths)
17
- if @source_control_system.has_revision?
18
- smelly_pathnames = RevisionComparator.new(source.paths, @source_control_system).compare
19
- else
20
- smell_adapters = AnalysersRunner.new(source.paths).run
21
- smelly_pathnames = SmellsAggregator.new(smell_adapters).smelly_pathnames
22
- end
23
- Reporter.new(source.pathnames, smelly_pathnames).generate_report
4
+ def self.create(options = {})
5
+ options_hash = options.to_h
6
+ Config.set(options_hash)
7
+ case Config.mode
8
+ when :version
9
+ require "rubycritic/commands/version"
10
+ Command::Version.new
11
+ when :help
12
+ require "rubycritic/commands/help"
13
+ Command::Help.new(options.help_text)
14
+ when :ci
15
+ require "rubycritic/commands/ci"
16
+ Command::Ci.new(options_hash[:paths])
17
+ else
18
+ require "rubycritic/commands/default"
19
+ Command::Default.new(options_hash[:paths])
24
20
  end
25
21
  end
26
-
27
22
  end
data/rubycritic.gemspec CHANGED
@@ -8,24 +8,27 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Rubycritic::VERSION
9
9
  spec.authors = ["Guilherme Simoes"]
10
10
  spec.email = ["guilherme.rdems@gmail.com"]
11
- spec.description = <<-EOF
12
- Ruby Critic is a tool that detects and reports smells in Ruby classes, modules and methods.
13
- EOF
14
- spec.summary = "Ruby code smell detector"
11
+ spec.description = "RubyCritic is a tool that wraps around various static analysis gems "\
12
+ "to provide a quality report of your Ruby code."
13
+ spec.summary = "RubyCritic is a Ruby code quality reporter"
15
14
  spec.homepage = "https://github.com/whitesmith/rubycritic"
16
15
  spec.license = "MIT"
16
+ spec.required_ruby_version = ">= 1.9.3"
17
17
 
18
18
  spec.files = `git ls-files`.split("\n")
19
- spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
20
20
  spec.test_files = `git ls-files -- test/*`.split("\n")
21
21
  spec.require_path = "lib"
22
22
 
23
23
  spec.add_runtime_dependency "virtus", "~> 1.0"
24
- spec.add_runtime_dependency "flog", "4.2.0"
25
- spec.add_runtime_dependency "reek", "1.3.6"
24
+ spec.add_runtime_dependency "flay", "2.4.0"
25
+ spec.add_runtime_dependency "flog", "4.2.1"
26
+ spec.add_runtime_dependency "reek", "1.6.5"
27
+ spec.add_runtime_dependency "parser", ">= 2.2.0", "< 3.0"
26
28
 
27
29
  spec.add_development_dependency "bundler", "~> 1.3"
28
30
  spec.add_development_dependency "rake"
29
31
  spec.add_development_dependency "minitest", "~> 5.3"
30
32
  spec.add_development_dependency "mocha", "~> 1.0"
33
+ spec.add_development_dependency "rubocop", "0.28.0"
31
34
  end
@@ -0,0 +1,3 @@
1
+ require "test_helper"
2
+
3
+ class AnalysedModuleDouble < OpenStruct; end
@@ -0,0 +1,33 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/churn"
3
+ require "rubycritic/source_control_systems/base"
4
+
5
+ describe Rubycritic::Analyser::Churn do
6
+ context "when analysing a file" do
7
+ before do
8
+ @analysed_module = AnalysedModuleDouble.new(:path => "path_to_some_file.rb")
9
+ analysed_modules = [@analysed_module]
10
+ analyser = Rubycritic::Analyser::Churn.new(analysed_modules)
11
+ analyser.source_control_system = SourceControlSystemDouble.new
12
+ analyser.run
13
+ end
14
+
15
+ it "calculates its churn" do
16
+ @analysed_module.churn.must_equal 1
17
+ end
18
+
19
+ it "determines the date of its last commit" do
20
+ @analysed_module.committed_at.must_equal "2013-10-09 12:52:49 +0100"
21
+ end
22
+ end
23
+ end
24
+
25
+ class SourceControlSystemDouble < Rubycritic::SourceControlSystem::Base
26
+ def revisions_count(_path)
27
+ 1 # churn
28
+ end
29
+
30
+ def date_of_last_commit(_path)
31
+ "2013-10-09 12:52:49 +0100"
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/complexity"
3
+
4
+ describe Rubycritic::Analyser::Complexity do
5
+ context "when analysing a file" do
6
+ before do
7
+ @analysed_module = AnalysedModuleDouble.new(:path => "test/samples/flog/complex.rb", :smells => [])
8
+ analysed_modules = [@analysed_module]
9
+ Rubycritic::Analyser::Complexity.new(analysed_modules).run
10
+ end
11
+
12
+ it "calculates its complexity" do
13
+ @analysed_module.complexity.must_be :>, 0
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/helpers/methods_counter"
3
+
4
+ describe Rubycritic::MethodsCounter do
5
+ describe "#count" do
6
+ context "when a file contains Ruby code" do
7
+ it "calculates the number of methods" do
8
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/methods_count.rb")
9
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 2
10
+ end
11
+ end
12
+
13
+ context "when a file is empty" do
14
+ it "returns 0 as the number of methods" do
15
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/empty.rb")
16
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 0
17
+ end
18
+ end
19
+
20
+ context "when a file is unparsable" do
21
+ it "does not blow up and returns 0 as the number of methods" do
22
+ analysed_module = AnalysedModuleDouble.new(:path => "test/samples/unparsable.rb")
23
+ capture_output_streams do
24
+ Rubycritic::MethodsCounter.new(analysed_module).count.must_equal 0
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ require "test_helper"
2
+ require "rubycritic/analysers/helpers/modules_locator"
3
+ require "rubycritic/core/analysed_module"
4
+ require "pathname"
5
+
6
+ describe Rubycritic::ModulesLocator do
7
+ describe "#names" do
8
+ context "when a file contains Ruby code" do
9
+ it "returns the names of all the classes and modules inside the file" do
10
+ analysed_module = Rubycritic::AnalysedModule.new(
11
+ :pathname => Pathname.new("test/samples/module_names.rb"),
12
+ :methods_count => 1
13
+ )
14
+ Rubycritic::ModulesLocator.new(analysed_module).names
15
+ .must_equal ["Foo", "Foo::Bar", "Foo::Baz", "Foo::Qux", "Foo::Quux::Corge"]
16
+ end
17
+ end
18
+
19
+ context "when a file is empty" do
20
+ it "returns the name of the file titleized" do
21
+ analysed_module = Rubycritic::AnalysedModule.new(
22
+ :pathname => Pathname.new("test/samples/empty.rb"),
23
+ :methods_count => 1
24
+ )
25
+ Rubycritic::ModulesLocator.new(analysed_module).names.must_equal ["Empty"]
26
+ end
27
+ end
28
+
29
+ context "when a file is unparsable" do
30
+ it "does not blow up and returns the name of the file titleized" do
31
+ analysed_module = Rubycritic::AnalysedModule.new(
32
+ :pathname => Pathname.new("test/samples/unparsable.rb"),
33
+ :methods_count => 1
34
+ )
35
+ capture_output_streams do
36
+ Rubycritic::ModulesLocator.new(analysed_module).names.must_equal ["Unparsable"]
37
+ end
38
+ end
39
+ end
40
+
41
+ context "when a file has no methods" do
42
+ it "returns the name of the file titleized" do
43
+ analysed_module = Rubycritic::AnalysedModule.new(
44
+ :pathname => Pathname.new("test/samples/no_methods.rb"),
45
+ :methods_count => 0
46
+ )
47
+ capture_output_streams do
48
+ Rubycritic::ModulesLocator.new(analysed_module).names.must_equal ["NoMethods"]
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ require "test_helper"
2
+ require "rubycritic/analysers/smells/flay"
3
+ require "rubycritic/core/analysed_module"
4
+ require "pathname"
5
+
6
+ describe Rubycritic::Analyser::FlaySmells do
7
+ context "when analysing a bunch of files with duplicate code" do
8
+ before do
9
+ @analysed_modules = [
10
+ Rubycritic::AnalysedModule.new(:pathname => Pathname.new("test/samples/flay/smelly.rb")),
11
+ Rubycritic::AnalysedModule.new(:pathname => Pathname.new("test/samples/flay/smelly2.rb"))
12
+ ]
13
+ Rubycritic::Analyser::FlaySmells.new(@analysed_modules).run
14
+ end
15
+
16
+ it "detects its smells" do
17
+ @analysed_modules.first.smells?.must_equal true
18
+ end
19
+
20
+ it "creates smells with messages" do
21
+ smell = @analysed_modules.first.smells.first
22
+ smell.message.must_be_instance_of String
23
+ end
24
+
25
+ it "creates smells with scores" do
26
+ smell = @analysed_modules.first.smells.first
27
+ smell.score.must_be_kind_of Numeric
28
+ end
29
+
30
+ it "creates smells with more than one location" do
31
+ smell = @analysed_modules.first.smells.first
32
+ smell.multiple_locations?.must_equal true
33
+ end
34
+
35
+ it "calculates the mass of duplicate code" do
36
+ @analysed_modules.first.duplication.must_be(:>, 0)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/smells/flog"
3
+
4
+ describe Rubycritic::Analyser::FlogSmells do
5
+ context "when analysing a complex file" do
6
+ before do
7
+ @analysed_module = AnalysedModuleDouble.new(:path => "test/samples/flog/smelly.rb", :smells => [])
8
+ analysed_modules = [@analysed_module]
9
+ Rubycritic::Analyser::FlogSmells.new(analysed_modules).run
10
+ end
11
+
12
+ it "detects its smells" do
13
+ @analysed_module.smells.length.must_equal 1
14
+ end
15
+
16
+ it "creates smells with messages" do
17
+ smell = @analysed_module.smells.first
18
+ smell.message.must_be_instance_of String
19
+ end
20
+
21
+ it "creates smells with scores" do
22
+ smell = @analysed_module.smells.first
23
+ smell.score.must_be :>, 0
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require "analysers_test_helper"
2
+ require "rubycritic/analysers/smells/reek"
3
+
4
+ describe Rubycritic::Analyser::ReekSmells do
5
+ context "when analysing a smelly file" do
6
+ before do
7
+ @analysed_module = AnalysedModuleDouble.new(:path => "test/samples/reek/smelly.rb", :smells => [])
8
+ analysed_modules = [@analysed_module]
9
+ Rubycritic::Analyser::ReekSmells.new(analysed_modules).run
10
+ end
11
+
12
+ it "detects its smells" do
13
+ @analysed_module.smells.length.must_equal 1
14
+ end
15
+
16
+ it "creates smells with messages" do
17
+ smell = @analysed_module.smells.first
18
+ smell.message.must_equal "has boolean parameter 'reek'"
19
+ end
20
+ end
21
+
22
+ context "when analysing a file with smells ignored in config.reek" do
23
+ before do
24
+ @analysed_module = AnalysedModuleDouble.new(:path => "test/samples/reek/not_smelly.rb", :smells => [])
25
+ analysed_modules = [@analysed_module]
26
+ Rubycritic::Analyser::ReekSmells.new(analysed_modules).run
27
+ end
28
+
29
+ it "does not detect those smells" do
30
+ @analysed_module.smells.must_be_empty
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ require "test_helper"
2
+ require "rubycritic/configuration"
3
+
4
+ describe Rubycritic::Configuration do
5
+ describe "#root" do
6
+ before do
7
+ Rubycritic::Config.set
8
+ @default = Rubycritic::Config.root
9
+ end
10
+
11
+ it "has a default" do
12
+ Rubycritic::Config.root.must_be_instance_of String
13
+ end
14
+
15
+ it "can be set to a relative path" do
16
+ Rubycritic::Config.root = "foo"
17
+ Rubycritic::Config.root.must_equal File.expand_path("foo")
18
+ end
19
+
20
+ it "can be set to an absolute path" do
21
+ Rubycritic::Config.root = "/foo"
22
+ Rubycritic::Config.root.must_equal "/foo"
23
+ end
24
+
25
+ after do
26
+ Rubycritic::Config.root = @default
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ require "test_helper"
2
+ require "rubycritic/core/analysed_module"
3
+ require "rubycritic/core/smell"
4
+
5
+ describe Rubycritic::AnalysedModule do
6
+ describe "attribute readers" do
7
+ before do
8
+ @name = "Foo"
9
+ @pathname = Pathname.new("foo.rb")
10
+ @smells = []
11
+ @churn = 1
12
+ @complexity = 2
13
+ @analysed_module = Rubycritic::AnalysedModule.new(
14
+ :name => @name,
15
+ :pathname => @pathname,
16
+ :smells => @smells,
17
+ :churn => @churn,
18
+ :complexity => @complexity
19
+ )
20
+ end
21
+
22
+ it "has a name reader" do
23
+ @analysed_module.name.must_equal @name
24
+ end
25
+
26
+ it "has a pathname reader" do
27
+ @analysed_module.pathname.must_equal @pathname
28
+ end
29
+
30
+ it "has a path reader" do
31
+ @analysed_module.path.must_equal @pathname.to_s
32
+ end
33
+
34
+ it "has a smells reader" do
35
+ @analysed_module.smells.must_equal @smells
36
+ end
37
+
38
+ it "has a churn reader" do
39
+ @analysed_module.churn.must_equal @churn
40
+ end
41
+
42
+ it "has a complexity reader" do
43
+ @analysed_module.complexity.must_equal @complexity
44
+ end
45
+ end
46
+
47
+ describe "#cost" do
48
+ it "returns the remediation cost of fixing the analysed_module" do
49
+ smells = [SmellDouble.new(:cost => 1), SmellDouble.new(:cost => 2)]
50
+ analysed_module = Rubycritic::AnalysedModule.new(:smells => smells, :complexity => 0)
51
+ analysed_module.cost.must_equal 3
52
+ end
53
+ end
54
+
55
+ describe "#complexity_per_method" do
56
+ context "when the file has no methods" do
57
+ it "returns a placeholder" do
58
+ analysed_module = Rubycritic::AnalysedModule.new(:complexity => 0, :methods_count => 0)
59
+ analysed_module.complexity_per_method.must_equal "N/A"
60
+ end
61
+ end
62
+
63
+ context "when the file has at least one method" do
64
+ it "returns the average complexity per method" do
65
+ analysed_module = Rubycritic::AnalysedModule.new(:complexity => 10, :methods_count => 2)
66
+ analysed_module.complexity_per_method.must_equal 5
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#smells?" do
72
+ it "returns true if the analysed_module has at least one smell" do
73
+ analysed_module = Rubycritic::AnalysedModule.new(:smells => [SmellDouble.new])
74
+ analysed_module.smells?.must_equal true
75
+ end
76
+ end
77
+
78
+ describe "#smells_at_location" do
79
+ it "returns the smells of an analysed_module at a certain location" do
80
+ location = Rubycritic::Location.new("./foo", "42")
81
+ smells = [Rubycritic::Smell.new(:locations => [location])]
82
+ analysed_module = Rubycritic::AnalysedModule.new(:smells => smells)
83
+ analysed_module.smells_at_location(location).must_equal smells
84
+ end
85
+ end
86
+ end
87
+
88
+ class SmellDouble < OpenStruct; end
@@ -1,11 +1,11 @@
1
1
  require "test_helper"
2
- require "rubycritic/location"
2
+ require "rubycritic/core/location"
3
3
 
4
4
  describe Rubycritic::Location do
5
5
  describe "attribute readers" do
6
6
  before do
7
- @path = "./foo"
8
- @line = 42
7
+ @path = "./foo.rb"
8
+ @line = "42"
9
9
  @location = Rubycritic::Location.new(@path, @line)
10
10
  end
11
11
 
@@ -14,7 +14,11 @@ describe Rubycritic::Location do
14
14
  end
15
15
 
16
16
  it "has a line number" do
17
- @location.line.must_equal @line
17
+ @location.line.must_equal @line.to_i
18
+ end
19
+
20
+ it "has a file name" do
21
+ @location.file_name.must_equal "foo"
18
22
  end
19
23
  end
20
24