reek 4.6.0 → 5.0.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -12
- data/.rubocop.yml +79 -26
- data/.simplecov +1 -0
- data/.travis.yml +3 -9
- data/.yardopts +1 -1
- data/CHANGELOG.md +76 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +5 -5
- data/README.md +138 -107
- data/Rakefile +16 -3
- data/bin/code_climate_reek +1 -0
- data/bin/reek +2 -3
- data/docs/API.md +2 -9
- data/docs/Basic-Smell-Options.md +51 -11
- data/docs/Code-Smells.md +1 -1
- data/docs/Command-Line-Options.md +14 -4
- data/docs/Duplicate-Method-Call.md +49 -1
- data/docs/Feature-Envy.md +44 -0
- data/docs/How-To-Write-New-Detectors.md +7 -7
- data/docs/Instance-Variable-Assumption.md +1 -1
- data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
- data/docs/Rake-Task.md +1 -1
- data/docs/Reek-4-to-Reek-5-migration.md +193 -0
- data/docs/Reek-Driven-Development.md +1 -1
- data/docs/Uncommunicative-Method-Name.md +45 -6
- data/docs/Uncommunicative-Module-Name.md +49 -7
- data/docs/Uncommunicative-Parameter-Name.md +43 -5
- data/docs/Uncommunicative-Variable-Name.md +73 -2
- data/docs/Unused-Private-Method.md +3 -3
- data/docs/defaults.reek.yml +129 -0
- data/docs/yard_plugin.rb +1 -0
- data/features/command_line_interface/basic_usage.feature +2 -2
- data/features/command_line_interface/options.feature +46 -4
- data/features/command_line_interface/show_progress.feature +4 -4
- data/features/command_line_interface/smell_selection.feature +1 -1
- data/features/command_line_interface/smells_count.feature +6 -6
- data/features/command_line_interface/stdin.feature +31 -5
- data/features/configuration_files/accept_setting.feature +45 -28
- data/features/configuration_files/directory_specific_directives.feature +80 -75
- data/features/configuration_files/exclude_directives.feature +11 -10
- data/features/configuration_files/exclude_paths_directives.feature +4 -4
- data/features/configuration_files/masking_smells.feature +38 -9
- data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
- data/features/configuration_files/reject_setting.feature +52 -41
- data/features/configuration_files/schema_validation.feature +59 -0
- data/features/configuration_files/unused_private_method.feature +18 -16
- data/features/configuration_loading.feature +53 -10
- data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
- data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
- data/features/locales.feature +32 -0
- data/features/rake_task/rake_task.feature +58 -18
- data/features/reports/codeclimate.feature +59 -0
- data/features/reports/json.feature +3 -3
- data/features/reports/reports.feature +34 -34
- data/features/reports/yaml.feature +3 -3
- data/features/rspec_matcher.feature +40 -0
- data/features/samples.feature +287 -287
- data/features/step_definitions/reek_steps.rb +14 -2
- data/features/step_definitions/sample_file_steps.rb +9 -4
- data/features/support/env.rb +2 -11
- data/features/todo_list.feature +26 -23
- data/lib/reek/ast/ast_node_class_map.rb +1 -0
- data/lib/reek/ast/builder.rb +16 -0
- data/lib/reek/ast/node.rb +50 -58
- data/lib/reek/ast/object_refs.rb +2 -1
- data/lib/reek/ast/reference_collector.rb +3 -4
- data/lib/reek/ast/sexp_extensions/arguments.rb +1 -0
- data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +1 -0
- data/lib/reek/ast/sexp_extensions/begin.rb +17 -0
- data/lib/reek/ast/sexp_extensions/block.rb +1 -0
- data/lib/reek/ast/sexp_extensions/case.rb +2 -1
- data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
- data/lib/reek/ast/sexp_extensions/if.rb +9 -1
- data/lib/reek/ast/sexp_extensions/lambda.rb +1 -0
- data/lib/reek/ast/sexp_extensions/literal.rb +1 -0
- data/lib/reek/ast/sexp_extensions/logical_operators.rb +2 -1
- data/lib/reek/ast/sexp_extensions/methods.rb +5 -6
- data/lib/reek/ast/sexp_extensions/module.rb +55 -8
- data/lib/reek/ast/sexp_extensions/nested_assignables.rb +1 -0
- data/lib/reek/ast/sexp_extensions/self.rb +1 -0
- data/lib/reek/ast/sexp_extensions/send.rb +1 -4
- data/lib/reek/ast/sexp_extensions/super.rb +1 -0
- data/lib/reek/ast/sexp_extensions/symbols.rb +1 -0
- data/lib/reek/ast/sexp_extensions/variables.rb +1 -0
- data/lib/reek/ast/sexp_extensions/when.rb +1 -0
- data/lib/reek/ast/sexp_extensions/yield.rb +1 -0
- data/lib/reek/ast/sexp_extensions.rb +2 -0
- data/lib/reek/cli/application.rb +5 -3
- data/lib/reek/cli/command/base_command.rb +1 -0
- data/lib/reek/cli/command/report_command.rb +2 -2
- data/lib/reek/cli/command/todo_list_command.rb +9 -8
- data/lib/reek/cli/options.rb +32 -16
- data/lib/reek/cli/silencer.rb +15 -3
- data/lib/reek/cli/status.rb +1 -0
- data/lib/reek/code_comment.rb +14 -16
- data/lib/reek/configuration/app_configuration.rb +34 -28
- data/lib/reek/configuration/configuration_converter.rb +110 -0
- data/lib/reek/configuration/configuration_file_finder.rb +17 -41
- data/lib/reek/configuration/configuration_validator.rb +13 -23
- data/lib/reek/configuration/default_directive.rb +18 -3
- data/lib/reek/configuration/directory_directives.rb +18 -11
- data/lib/reek/configuration/excluded_paths.rb +2 -1
- data/lib/reek/configuration/rake_task_converter.rb +29 -0
- data/lib/reek/configuration/schema.yml +210 -0
- data/lib/reek/configuration/schema_validator.rb +38 -0
- data/lib/reek/context/attribute_context.rb +4 -3
- data/lib/reek/context/class_context.rb +1 -0
- data/lib/reek/context/code_context.rb +49 -44
- data/lib/reek/context/ghost_context.rb +1 -2
- data/lib/reek/context/method_context.rb +26 -18
- data/lib/reek/context/module_context.rb +11 -11
- data/lib/reek/context/root_context.rb +1 -4
- data/lib/reek/context/send_context.rb +3 -2
- data/lib/reek/context/singleton_attribute_context.rb +1 -0
- data/lib/reek/context/singleton_method_context.rb +1 -0
- data/lib/reek/context/statement_counter.rb +1 -0
- data/lib/reek/context/visibility_tracker.rb +1 -0
- data/lib/reek/context_builder.rb +44 -44
- data/lib/reek/detector_repository.rb +12 -11
- data/lib/reek/documentation_link.rb +28 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +15 -13
- data/lib/reek/errors/bad_detector_in_comment_error.rb +13 -11
- data/lib/reek/errors/base_error.rb +3 -0
- data/lib/reek/errors/config_file_error.rb +11 -0
- data/lib/reek/errors/encoding_error.rb +43 -0
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +14 -12
- data/lib/reek/errors/incomprehensible_source_error.rb +23 -24
- data/lib/reek/errors/syntax_error.rb +41 -0
- data/lib/reek/examiner.rb +24 -22
- data/lib/reek/logging_error_handler.rb +8 -5
- data/lib/reek/rake/task.rb +8 -5
- data/lib/reek/report/base_report.rb +9 -12
- data/lib/reek/report/code_climate/code_climate_configuration.rb +2 -1
- data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -6
- data/lib/reek/report/code_climate/code_climate_fingerprint.rb +1 -0
- data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -0
- data/lib/reek/report/code_climate/code_climate_report.rb +1 -0
- data/lib/reek/report/code_climate.rb +1 -0
- data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
- data/lib/reek/report/heading_formatter.rb +54 -0
- data/lib/reek/report/html_report.rb +1 -0
- data/lib/reek/report/json_report.rb +2 -1
- data/lib/reek/report/location_formatter.rb +40 -0
- data/lib/reek/report/progress_formatter.rb +79 -0
- data/lib/reek/report/simple_warning_formatter.rb +34 -0
- data/lib/reek/report/text_report.rb +2 -2
- data/lib/reek/report/xml_report.rb +4 -3
- data/lib/reek/report/yaml_report.rb +2 -1
- data/lib/reek/report.rb +16 -10
- data/lib/reek/smell_configuration.rb +3 -2
- data/lib/reek/smell_detectors/attribute.rb +6 -11
- data/lib/reek/smell_detectors/base_detector.rb +31 -26
- data/lib/reek/smell_detectors/boolean_parameter.rb +4 -5
- data/lib/reek/smell_detectors/class_variable.rb +6 -14
- data/lib/reek/smell_detectors/control_parameter.rb +19 -33
- data/lib/reek/smell_detectors/data_clump.rb +16 -9
- data/lib/reek/smell_detectors/duplicate_method_call.rb +24 -17
- data/lib/reek/smell_detectors/feature_envy.rb +10 -7
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +15 -23
- data/lib/reek/smell_detectors/irresponsible_module.rb +6 -12
- data/lib/reek/smell_detectors/long_parameter_list.rb +11 -7
- data/lib/reek/smell_detectors/long_yield_list.rb +11 -7
- data/lib/reek/smell_detectors/manual_dispatch.rb +5 -5
- data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +21 -20
- data/lib/reek/smell_detectors/module_initialize.rb +4 -5
- data/lib/reek/smell_detectors/nested_iterators.rb +17 -24
- data/lib/reek/smell_detectors/nil_check.rb +9 -15
- data/lib/reek/smell_detectors/repeated_conditional.rb +14 -11
- data/lib/reek/smell_detectors/subclassed_from_core_class.rb +8 -8
- data/lib/reek/smell_detectors/too_many_constants.rb +11 -9
- data/lib/reek/smell_detectors/too_many_instance_variables.rb +11 -6
- data/lib/reek/smell_detectors/too_many_methods.rb +12 -7
- data/lib/reek/smell_detectors/too_many_statements.rb +11 -6
- data/lib/reek/smell_detectors/uncommunicative_method_name.rb +11 -11
- data/lib/reek/smell_detectors/uncommunicative_module_name.rb +15 -18
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +18 -22
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +27 -27
- data/lib/reek/smell_detectors/unused_parameters.rb +5 -6
- data/lib/reek/smell_detectors/unused_private_method.rb +14 -20
- data/lib/reek/smell_detectors/utility_function.rb +13 -16
- data/lib/reek/smell_detectors.rb +2 -1
- data/lib/reek/smell_warning.rb +16 -8
- data/lib/reek/source/source_code.rb +65 -46
- data/lib/reek/source/source_locator.rb +9 -8
- data/lib/reek/spec/should_reek.rb +3 -2
- data/lib/reek/spec/should_reek_of.rb +13 -26
- data/lib/reek/spec/should_reek_only_of.rb +5 -4
- data/lib/reek/spec/smell_matcher.rb +2 -1
- data/lib/reek/spec.rb +7 -6
- data/lib/reek/tree_dresser.rb +9 -8
- data/lib/reek/version.rb +2 -1
- data/lib/reek.rb +1 -0
- data/reek.gemspec +5 -6
- data/samples/checkstyle.xml +1 -1
- data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
- data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
- data/samples/configuration/full_configuration.reek +8 -4
- data/samples/configuration/full_mask.reek +5 -4
- data/samples/configuration/partial_mask.reek +3 -2
- data/samples/configuration/regular_configuration/.reek.yml +4 -0
- data/samples/paths.rb +5 -4
- data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
- data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
- data/spec/factories/factories.rb +2 -13
- data/spec/reek/ast/node_spec.rb +103 -10
- data/spec/reek/ast/reference_collector_spec.rb +1 -1
- data/spec/reek/ast/sexp_extensions_spec.rb +15 -34
- data/spec/reek/cli/application_spec.rb +52 -42
- data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
- data/spec/reek/cli/silencer_spec.rb +28 -0
- data/spec/reek/code_comment_spec.rb +31 -38
- data/spec/reek/configuration/app_configuration_spec.rb +46 -33
- data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
- data/spec/reek/configuration/default_directive_spec.rb +1 -1
- data/spec/reek/configuration/directory_directives_spec.rb +6 -7
- data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
- data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
- data/spec/reek/configuration/schema_validator_spec.rb +165 -0
- data/spec/reek/context/code_context_spec.rb +70 -106
- data/spec/reek/context/ghost_context_spec.rb +9 -9
- data/spec/reek/context/method_context_spec.rb +2 -2
- data/spec/reek/context/module_context_spec.rb +3 -3
- data/spec/reek/context/root_context_spec.rb +1 -1
- data/spec/reek/context/statement_counter_spec.rb +1 -0
- data/spec/reek/context_builder_spec.rb +20 -0
- data/spec/reek/documentation_link_spec.rb +20 -0
- data/spec/reek/errors/base_error_spec.rb +13 -0
- data/spec/reek/examiner_spec.rb +137 -29
- data/spec/reek/rake/task_spec.rb +25 -2
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -78
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
- data/spec/reek/report/code_climate/code_climate_report_spec.rb +22 -22
- data/spec/reek/report/json_report_spec.rb +13 -46
- data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
- data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
- data/spec/reek/report/text_report_spec.rb +4 -4
- data/spec/reek/report/xml_report_spec.rb +3 -3
- data/spec/reek/report/yaml_report_spec.rb +17 -46
- data/spec/reek/report_spec.rb +3 -3
- data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
- data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
- data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
- data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
- data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
- data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
- data/spec/reek/smell_detectors/irresponsible_module_spec.rb +59 -21
- data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
- data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
- data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
- data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
- data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
- data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
- data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
- data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
- data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
- data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
- data/spec/reek/smell_warning_spec.rb +12 -8
- data/spec/reek/source/source_code_spec.rb +27 -38
- data/spec/reek/source/source_locator_spec.rb +42 -12
- data/spec/reek/spec/should_reek_of_spec.rb +25 -30
- data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
- data/spec/reek/spec/should_reek_spec.rb +8 -8
- data/spec/reek/spec/smell_matcher_spec.rb +23 -23
- data/spec/reek/tree_dresser_spec.rb +12 -17
- data/spec/spec_helper.rb +7 -17
- data/tasks/configuration.rake +8 -5
- metadata +77 -40
- data/defaults.reek +0 -128
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
- data/lib/reek/errors/parse_error.rb +0 -19
- data/lib/reek/report/formatter/heading_formatter.rb +0 -51
- data/lib/reek/report/formatter/location_formatter.rb +0 -41
- data/lib/reek/report/formatter/progress_formatter.rb +0 -80
- data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
- data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -35
- data/lib/reek/report/formatter.rb +0 -32
- data/samples/configuration/non_public_modifiers_mask.reek +0 -3
- data/samples/smelly_with_inline_mask.rb +0 -8
- data/samples/smelly_with_modifiers.rb +0 -12
- data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
- data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
- /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
- /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
- /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
- /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
- /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
- /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
- /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
- /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
- /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
- /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
|
@@ -3,8 +3,8 @@ require_lib 'reek/context/method_context'
|
|
|
3
3
|
require_lib 'reek/context/module_context'
|
|
4
4
|
|
|
5
5
|
RSpec.describe Reek::Context::CodeContext do
|
|
6
|
-
|
|
7
|
-
let(:ctx) { described_class.new(
|
|
6
|
+
describe '#full_name' do
|
|
7
|
+
let(:ctx) { described_class.new(exp) }
|
|
8
8
|
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode') }
|
|
9
9
|
let(:exp_name) { 'random_name' }
|
|
10
10
|
let(:full_name) { "::::::::::::::::::::#{exp_name}" }
|
|
@@ -14,9 +14,54 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
14
14
|
allow(exp).to receive(:full_name).and_return(full_name)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
it 'creates the correct full name' do
|
|
18
|
+
expect(ctx.full_name).to eq(full_name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when there is an outer' do
|
|
22
|
+
let(:outer_name) { 'another_random sting' }
|
|
23
|
+
let(:outer) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
24
|
+
|
|
25
|
+
before do
|
|
26
|
+
ctx.register_with_parent outer
|
|
27
|
+
allow(outer).to receive(:full_name).at_least(:once).and_return(outer_name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'creates the correct full name' do
|
|
31
|
+
expect(ctx.full_name).to eq(full_name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'passes the outer name to exp#full_name' do
|
|
35
|
+
ctx.full_name
|
|
36
|
+
expect(exp).to have_received(:full_name).with outer_name
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe '#name' do
|
|
42
|
+
let(:ctx) { described_class.new(exp) }
|
|
43
|
+
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode') }
|
|
44
|
+
let(:exp_name) { 'random_name' }
|
|
45
|
+
|
|
46
|
+
before do
|
|
47
|
+
allow(exp).to receive(:name).and_return(exp_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
17
50
|
it 'gets its short name from the exp' do
|
|
18
51
|
expect(ctx.name).to eq(exp_name)
|
|
19
52
|
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#matches?' do
|
|
56
|
+
let(:ctx) { described_class.new(exp) }
|
|
57
|
+
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode') }
|
|
58
|
+
let(:exp_name) { 'random_name' }
|
|
59
|
+
let(:full_name) { "::::::::::::::::::::#{exp_name}" }
|
|
60
|
+
|
|
61
|
+
before do
|
|
62
|
+
allow(exp).to receive(:name).and_return(exp_name)
|
|
63
|
+
allow(exp).to receive(:full_name).and_return(full_name)
|
|
64
|
+
end
|
|
20
65
|
|
|
21
66
|
it 'does not match an empty list' do
|
|
22
67
|
expect(ctx.matches?([])).to eq(false)
|
|
@@ -31,31 +76,38 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
31
76
|
end
|
|
32
77
|
|
|
33
78
|
it 'recognises its own short name' do
|
|
79
|
+
expect(ctx.matches?([exp_name])).to eq(true)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'recognises its own short name in a list' do
|
|
34
83
|
expect(ctx.matches?(['banana', exp_name])).to eq(true)
|
|
35
84
|
end
|
|
36
85
|
|
|
37
86
|
it 'recognises its short name as a regex' do
|
|
38
|
-
expect(ctx.matches?([
|
|
87
|
+
expect(ctx.matches?([/#{exp_name}/])).to eq(true)
|
|
39
88
|
end
|
|
40
89
|
|
|
41
90
|
it 'does not blow up on []-ended Strings' do
|
|
42
91
|
expect(ctx.matches?(['banana[]', exp_name])).to eq(true)
|
|
43
92
|
end
|
|
44
93
|
|
|
94
|
+
it 'recognises its own full name' do
|
|
95
|
+
expect(ctx.matches?(['banana', full_name])).to eq(true)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'recognises its full name as a regex' do
|
|
99
|
+
expect(ctx.matches?([/banana/, /#{full_name}/])).to eq(true)
|
|
100
|
+
end
|
|
101
|
+
|
|
45
102
|
context 'when there is an outer' do
|
|
46
|
-
let(:ctx) { described_class.new(outer, exp) }
|
|
47
103
|
let(:outer_name) { 'another_random sting' }
|
|
48
|
-
let(:outer) { described_class.new(
|
|
104
|
+
let(:outer) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
49
105
|
|
|
50
106
|
before do
|
|
51
107
|
ctx.register_with_parent outer
|
|
52
108
|
allow(outer).to receive(:full_name).at_least(:once).and_return(outer_name)
|
|
53
109
|
end
|
|
54
110
|
|
|
55
|
-
it 'creates the correct full name' do
|
|
56
|
-
expect(ctx.full_name).to eq(full_name)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
111
|
it 'recognises its own full name' do
|
|
60
112
|
expect(ctx.matches?(['banana', full_name])).to eq(true)
|
|
61
113
|
end
|
|
@@ -66,98 +118,10 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
66
118
|
end
|
|
67
119
|
end
|
|
68
120
|
|
|
69
|
-
context 'enumerating syntax elements' do
|
|
70
|
-
context 'in an empty module' do
|
|
71
|
-
let(:ctx) do
|
|
72
|
-
src = 'module Emptiness; end'
|
|
73
|
-
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
74
|
-
described_class.new(nil, ast)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'yields no calls' do
|
|
78
|
-
ctx.each_node(:send, []) { |exp| raise "#{exp} yielded by empty module!" }
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'yields one module' do
|
|
82
|
-
mods = 0
|
|
83
|
-
ctx.each_node(:module, []) { |_exp| mods += 1 }
|
|
84
|
-
expect(mods).to eq(1)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "yields the module's full AST" do
|
|
88
|
-
ctx.each_node(:module, []) do |exp|
|
|
89
|
-
expect(exp).to eq(sexp(:module, sexp(:const, nil, :Emptiness), nil))
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it 'returns an empty array of ifs when no block is passed' do
|
|
94
|
-
expect(ctx.each_node(:if, [])).to be_empty
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
context 'with a nested element' do
|
|
99
|
-
let(:ctx) do
|
|
100
|
-
src = "module Loneliness; def calloo; puts('hello') end; end"
|
|
101
|
-
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
102
|
-
described_class.new(nil, ast)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it 'yields no ifs' do
|
|
106
|
-
ctx.each_node(:if, []) { |exp| raise "#{exp} yielded by empty module!" }
|
|
107
|
-
end
|
|
108
|
-
it 'yields one module' do
|
|
109
|
-
expect(ctx.each_node(:module, []).length).to eq(1)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it "yields the module's full AST" do
|
|
113
|
-
ctx.each_node(:module, []) do |exp|
|
|
114
|
-
expect(exp).to eq sexp(:module,
|
|
115
|
-
sexp(:const, nil, :Loneliness),
|
|
116
|
-
sexp(:def, :calloo,
|
|
117
|
-
sexp(:args),
|
|
118
|
-
sexp(:send, nil, :puts, sexp(:str, 'hello'))))
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it 'yields one method' do
|
|
123
|
-
expect(ctx.each_node(:def, []).length).to eq(1)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it "yields the method's full AST" do
|
|
127
|
-
ctx.each_node(:def, []) { |exp| expect(exp.children.first).to eq(:calloo) }
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
it 'ignores the call inside the method if the traversal is pruned' do
|
|
131
|
-
expect(ctx.each_node(:send, [:def])).to be_empty
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
it 'finds 3 ifs in a class' do
|
|
136
|
-
src = <<-EOS
|
|
137
|
-
class Scrunch
|
|
138
|
-
def first
|
|
139
|
-
return @field == :sym ? 0 : 3;
|
|
140
|
-
end
|
|
141
|
-
def second
|
|
142
|
-
if @field == :sym
|
|
143
|
-
@other += " quarts"
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
def third
|
|
147
|
-
raise 'flu!' unless @field == :sym
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
EOS
|
|
151
|
-
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
152
|
-
ctx = described_class.new(nil, ast)
|
|
153
|
-
expect(ctx.each_node(:if, []).length).to eq(3)
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
121
|
describe '#config_for' do
|
|
158
122
|
let(:src) do
|
|
159
123
|
<<-EOS
|
|
160
|
-
# :reek:DuplicateMethodCall
|
|
124
|
+
# :reek:DuplicateMethodCall { allow_calls: [ puts ] }')
|
|
161
125
|
def repeated_greeting
|
|
162
126
|
puts 'Hello!'
|
|
163
127
|
puts 'Hello!'
|
|
@@ -166,7 +130,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
166
130
|
end
|
|
167
131
|
let(:expression) { Reek::Source::SourceCode.from(src).syntax_tree }
|
|
168
132
|
let(:outer) { nil }
|
|
169
|
-
let(:context) { described_class.new(
|
|
133
|
+
let(:context) { described_class.new(expression) }
|
|
170
134
|
let(:sniffer) { class_double('Reek::SmellDetectors::BaseDetector') }
|
|
171
135
|
|
|
172
136
|
before do
|
|
@@ -181,7 +145,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
181
145
|
end
|
|
182
146
|
|
|
183
147
|
context 'when there is an outer context' do
|
|
184
|
-
let(:outer) { described_class.new(
|
|
148
|
+
let(:outer) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
185
149
|
|
|
186
150
|
before do
|
|
187
151
|
allow(outer).to receive(:config_for).with(sniffer).and_return(
|
|
@@ -196,9 +160,9 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
196
160
|
end
|
|
197
161
|
|
|
198
162
|
describe '#register_with_parent' do
|
|
199
|
-
let(:context) { described_class.new(
|
|
200
|
-
let(:first_child) { described_class.new(
|
|
201
|
-
let(:second_child) { described_class.new(
|
|
163
|
+
let(:context) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
164
|
+
let(:first_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
165
|
+
let(:second_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
202
166
|
|
|
203
167
|
it "appends the element to the parent context's list of children" do
|
|
204
168
|
first_child.register_with_parent context
|
|
@@ -209,9 +173,9 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
209
173
|
end
|
|
210
174
|
|
|
211
175
|
describe '#each' do
|
|
212
|
-
let(:context) { described_class.new(
|
|
213
|
-
let(:first_child) { described_class.new(
|
|
214
|
-
let(:second_child) { described_class.new(
|
|
176
|
+
let(:context) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
177
|
+
let(:first_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
178
|
+
let(:second_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
215
179
|
|
|
216
180
|
it 'yields each child' do
|
|
217
181
|
first_child.register_with_parent context
|
|
@@ -4,53 +4,53 @@ require_lib 'reek/context/ghost_context'
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe Reek::Context::GhostContext do
|
|
6
6
|
let(:exp) { instance_double('Reek::AST::Node') }
|
|
7
|
-
let(:parent) { Reek::Context::CodeContext.new(
|
|
7
|
+
let(:parent) { Reek::Context::CodeContext.new(exp) }
|
|
8
8
|
|
|
9
9
|
describe '#register_with_parent' do
|
|
10
10
|
it 'does not append itself to its parent' do
|
|
11
|
-
ghost = described_class.new(
|
|
11
|
+
ghost = described_class.new(nil)
|
|
12
12
|
ghost.register_with_parent(parent)
|
|
13
13
|
expect(parent.children).not_to include ghost
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
describe '#append_child_context' do
|
|
18
|
-
let(:ghost) { described_class.new(
|
|
18
|
+
let(:ghost) { described_class.new(nil) }
|
|
19
19
|
|
|
20
20
|
before do
|
|
21
21
|
ghost.register_with_parent(parent)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'appends the child to the grandparent context' do
|
|
25
|
-
child = Reek::Context::CodeContext.new(
|
|
25
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
26
26
|
child.register_with_parent(ghost)
|
|
27
27
|
|
|
28
28
|
expect(parent.children).to include child
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "sets the child's parent to the grandparent context" do
|
|
32
|
-
child = Reek::Context::CodeContext.new(
|
|
32
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
33
33
|
child.register_with_parent(ghost)
|
|
34
34
|
|
|
35
35
|
expect(child.parent).to eq parent
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
it 'appends the child to the list of children' do
|
|
39
|
-
child = Reek::Context::CodeContext.new(
|
|
39
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
40
40
|
child.register_with_parent(ghost)
|
|
41
41
|
|
|
42
42
|
expect(ghost.children).to include child
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
context '
|
|
46
|
-
let(:child_ghost) { described_class.new(
|
|
45
|
+
context 'when the grandparent is also a ghost' do
|
|
46
|
+
let(:child_ghost) { described_class.new(nil) }
|
|
47
47
|
|
|
48
48
|
before do
|
|
49
49
|
child_ghost.register_with_parent(ghost)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it 'sets the childs parent to its remote ancestor' do
|
|
53
|
-
child = Reek::Context::CodeContext.new(
|
|
53
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
54
54
|
child.register_with_parent(child_ghost)
|
|
55
55
|
|
|
56
56
|
expect(child.parent).to eq parent
|
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
|
2
2
|
require_lib 'reek/context/method_context'
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::Context::MethodContext do
|
|
5
|
-
let(:method_context) { described_class.new(
|
|
5
|
+
let(:method_context) { described_class.new(exp, nil) }
|
|
6
6
|
|
|
7
7
|
describe '#matches?' do
|
|
8
8
|
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode').as_null_object }
|
|
@@ -31,7 +31,7 @@ RSpec.describe Reek::Context::MethodContext do
|
|
|
31
31
|
describe '#default_assignments' do
|
|
32
32
|
def assignments_from(src)
|
|
33
33
|
exp = Reek::Source::SourceCode.from(src).syntax_tree
|
|
34
|
-
ctx = Reek::Context::MethodContext.new(
|
|
34
|
+
ctx = Reek::Context::MethodContext.new(exp, nil)
|
|
35
35
|
ctx.default_assignments
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -32,9 +32,9 @@ RSpec.describe Reek::Context::ModuleContext do
|
|
|
32
32
|
let(:first_def) { instance_double('Reek::AST::SexpExtensions::DefNode', name: :foo) }
|
|
33
33
|
let(:second_def) { instance_double('Reek::AST::SexpExtensions::DefNode') }
|
|
34
34
|
|
|
35
|
-
let(:context) { described_class.new(
|
|
36
|
-
let(:first_child) { Reek::Context::MethodContext.new(
|
|
37
|
-
let(:second_child) { Reek::Context::MethodContext.new(
|
|
35
|
+
let(:context) { described_class.new(main_exp) }
|
|
36
|
+
let(:first_child) { Reek::Context::MethodContext.new(first_def, main_exp) }
|
|
37
|
+
let(:second_child) { Reek::Context::MethodContext.new(second_def, main_exp) }
|
|
38
38
|
|
|
39
39
|
it 'sets visibility on subsequent child contexts' do
|
|
40
40
|
context.append_child_context first_child
|
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
|
2
2
|
require_lib 'reek/context/root_context'
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::Context::RootContext do
|
|
5
|
-
|
|
5
|
+
describe '#full_name' do
|
|
6
6
|
it 'reports full context' do
|
|
7
7
|
ast = Reek::Source::SourceCode.from('foo = 1').syntax_tree
|
|
8
8
|
root = described_class.new(ast)
|
|
@@ -220,6 +220,26 @@ RSpec.describe Reek::ContextBuilder do
|
|
|
220
220
|
described_class.new(syntax_tree(code)).context_tree
|
|
221
221
|
end
|
|
222
222
|
|
|
223
|
+
it 'marks instance methods when using a def modifier' do
|
|
224
|
+
code = <<-EOS
|
|
225
|
+
class Foo
|
|
226
|
+
private def bar
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def baz
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
EOS
|
|
233
|
+
|
|
234
|
+
root = context_tree_for(code)
|
|
235
|
+
module_context = root.children.first
|
|
236
|
+
method_contexts = module_context.children
|
|
237
|
+
aggregate_failures do
|
|
238
|
+
expect(method_contexts[0].visibility).to eq :private
|
|
239
|
+
expect(method_contexts[1].visibility).to eq :public
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
223
243
|
it 'does not mark class methods with instance visibility' do
|
|
224
244
|
code = <<-EOS
|
|
225
245
|
class Foo
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Reek::DocumentationLink do
|
|
4
|
+
describe '.build' do
|
|
5
|
+
it 'returns the correct link for a smell type' do
|
|
6
|
+
expect(described_class.build('FeatureEnvy')).
|
|
7
|
+
to eq "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Feature-Envy.md"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'returns the correct link for general documentation' do
|
|
11
|
+
expect(described_class.build('Rake Task')).
|
|
12
|
+
to eq "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Rake-Task.md"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'returns the correct link for subjects with abbreviations' do
|
|
16
|
+
expect(described_class.build('YAML Report')).
|
|
17
|
+
to eq "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/YAML-Report.md"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
|
|
3
|
+
require_lib 'reek/errors/base_error'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Reek::Errors::BaseError do
|
|
6
|
+
let(:error) { described_class.new }
|
|
7
|
+
|
|
8
|
+
describe '#long_message' do
|
|
9
|
+
it 'returns the message' do
|
|
10
|
+
expect(error.long_message).to eq error.message
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/spec/reek/examiner_spec.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative '../spec_helper'
|
|
2
2
|
require_lib 'reek/examiner'
|
|
3
|
+
require_lib 'reek/logging_error_handler'
|
|
3
4
|
|
|
4
5
|
RSpec.shared_examples_for 'no smells found' do
|
|
5
6
|
it 'is not smelly' do
|
|
@@ -45,7 +46,7 @@ RSpec.describe Reek::Examiner do
|
|
|
45
46
|
filter_by_smells: [],
|
|
46
47
|
configuration: configuration)
|
|
47
48
|
end
|
|
48
|
-
let(:path) {
|
|
49
|
+
let(:path) { CONFIGURATION_DIR.join('partial_mask.reek') }
|
|
49
50
|
let(:expected_first_smell) { 'UncommunicativeVariableName' }
|
|
50
51
|
|
|
51
52
|
it_behaves_like 'one smell found'
|
|
@@ -57,27 +58,12 @@ RSpec.describe Reek::Examiner do
|
|
|
57
58
|
it_behaves_like 'no smells found'
|
|
58
59
|
end
|
|
59
60
|
|
|
60
|
-
describe '
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let(:examiner) do
|
|
64
|
-
described_class.new(source)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'has been run on the given source' do
|
|
68
|
-
expect(examiner.origin).to eq('string')
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it 'has the right smells' do
|
|
72
|
-
smells = examiner.smells
|
|
73
|
-
expect(smells[0].message).to eq('has no descriptive comment')
|
|
74
|
-
expect(smells[1].message).to eq("has the name 'f'")
|
|
75
|
-
expect(smells[2].message).to eq("has the name 'C'")
|
|
76
|
-
end
|
|
61
|
+
describe '#origin' do
|
|
62
|
+
let(:source) { 'class C; def f; end; end' }
|
|
63
|
+
let(:examiner) { described_class.new(source) }
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
65
|
+
it 'returns "string" for a string source' do
|
|
66
|
+
expect(examiner.origin).to eq('string')
|
|
81
67
|
end
|
|
82
68
|
end
|
|
83
69
|
|
|
@@ -91,7 +77,20 @@ RSpec.describe Reek::Examiner do
|
|
|
91
77
|
expect(smell.message).to eq("calls 'bar.call_me()' 2 times")
|
|
92
78
|
end
|
|
93
79
|
|
|
94
|
-
context 'source
|
|
80
|
+
context 'with a source with three smells' do
|
|
81
|
+
let(:source) { 'class C; def f; end; end' }
|
|
82
|
+
let(:examiner) { described_class.new(source) }
|
|
83
|
+
|
|
84
|
+
it 'has the right smells' do
|
|
85
|
+
smells = examiner.smells
|
|
86
|
+
expect(smells.map(&:message)).
|
|
87
|
+
to eq ['has no descriptive comment',
|
|
88
|
+
"has the name 'f'",
|
|
89
|
+
"has the name 'C'"]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'when source only contains comments' do
|
|
95
94
|
let(:source) do
|
|
96
95
|
<<-EOS
|
|
97
96
|
# Just a comment
|
|
@@ -107,7 +106,7 @@ RSpec.describe Reek::Examiner do
|
|
|
107
106
|
end
|
|
108
107
|
end
|
|
109
108
|
|
|
110
|
-
context 'with an incomprehensible source that causes
|
|
109
|
+
context 'with an incomprehensible source that causes the detectors to crash' do
|
|
111
110
|
let(:source) { 'class C; def does_crash_reek; end; end' }
|
|
112
111
|
|
|
113
112
|
let(:examiner) do
|
|
@@ -128,24 +127,133 @@ RSpec.describe Reek::Examiner do
|
|
|
128
127
|
|
|
129
128
|
it 'explains the origin of the error' do
|
|
130
129
|
origin = 'string'
|
|
131
|
-
expect { examiner.smells }.
|
|
130
|
+
expect { examiner.smells }.
|
|
131
|
+
to raise_error.with_message("Source #{origin} cannot be processed by Reek.")
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
it 'explains what to do' do
|
|
135
|
-
explanation = '
|
|
136
|
-
expect { examiner.smells }.
|
|
135
|
+
explanation = 'It would be great if you could report this back to the Reek team'
|
|
136
|
+
expect { examiner.smells }.
|
|
137
|
+
to raise_error { |it| expect(it.long_message).to match(/#{explanation}/) }
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
it 'contains the original error message' do
|
|
140
141
|
original = 'Looks like bad source'
|
|
141
|
-
expect { examiner.smells }.
|
|
142
|
+
expect { examiner.smells }.
|
|
143
|
+
to raise_error { |it| expect(it.long_message).to match(/#{original}/) }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'shows the original exception class' do
|
|
147
|
+
expect { examiner.smells }.
|
|
148
|
+
to raise_error { |it| expect(it.long_message).to match(/ArgumentError/) }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe '#smells_count' do
|
|
154
|
+
let(:source) { 'class C; def f; end; end' }
|
|
155
|
+
let(:examiner) { described_class.new(source) }
|
|
156
|
+
|
|
157
|
+
it 'has the right smell count' do
|
|
158
|
+
expect(examiner.smells_count).to eq(3)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context 'when the source causes the source buffer to crash' do
|
|
163
|
+
let(:source) { 'I make the buffer crash' }
|
|
164
|
+
|
|
165
|
+
before do
|
|
166
|
+
buffer = double
|
|
167
|
+
allow(buffer).to receive(:source=) { raise RuntimeError }
|
|
168
|
+
allow(Parser::Source::Buffer).to receive(:new).and_return(buffer)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context 'when the error handler does not handle the error' do
|
|
172
|
+
let(:examiner) { described_class.new(source) }
|
|
173
|
+
|
|
174
|
+
it 'does not raise an error during initialization' do
|
|
175
|
+
expect { examiner }.not_to raise_error
|
|
142
176
|
end
|
|
177
|
+
|
|
178
|
+
it 'raises an incomprehensible source error when asked for smells' do
|
|
179
|
+
expect { examiner.smells }.to raise_error Reek::Errors::IncomprehensibleSourceError
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context 'when the error handler handles the error' do
|
|
184
|
+
let(:handler) { instance_double(Reek::LoggingErrorHandler, handle: true) }
|
|
185
|
+
let(:examiner) { described_class.new(source, error_handler: handler) }
|
|
186
|
+
|
|
187
|
+
it 'does not raise an error when asked for smells' do
|
|
188
|
+
expect { examiner.smells }.not_to raise_error
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it 'passes the wrapped error to the handler' do
|
|
192
|
+
examiner.smells
|
|
193
|
+
expect(handler).to have_received(:handle).with(Reek::Errors::IncomprehensibleSourceError)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context 'with a source that triggers a syntax error' do
|
|
199
|
+
let(:examiner) { described_class.new(source) }
|
|
200
|
+
let(:source) do
|
|
201
|
+
<<-SRC.strip_heredoc
|
|
202
|
+
1 2 3
|
|
203
|
+
SRC
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it 'does not raise an error during initialization' do
|
|
207
|
+
expect { examiner }.not_to raise_error
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'raises an encoding error when asked for smells' do
|
|
211
|
+
expect { examiner.smells }.to raise_error Reek::Errors::SyntaxError
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'explains the origin of the error' do
|
|
215
|
+
message = "Source 'string' cannot be processed by Reek due to a syntax error in the source file."
|
|
216
|
+
expect { examiner.smells }.to raise_error.with_message(/#{message}/)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it 'shows the original exception class' do
|
|
220
|
+
expect { examiner.smells }.
|
|
221
|
+
to raise_error { |it| expect(it.long_message).to match(/Parser::SyntaxError/) }
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
context 'with a source that triggers an encoding error' do
|
|
226
|
+
let(:examiner) { described_class.new(source) }
|
|
227
|
+
let(:source) do
|
|
228
|
+
<<-SRC.strip_heredoc
|
|
229
|
+
# encoding: US-ASCII
|
|
230
|
+
puts 'こんにちは世界'
|
|
231
|
+
SRC
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it 'does not raise an error during initialization' do
|
|
235
|
+
expect { examiner }.not_to raise_error
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it 'raises an encoding error when asked for smells' do
|
|
239
|
+
expect { examiner.smells }.to raise_error Reek::Errors::EncodingError
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'explains the origin of the error' do
|
|
243
|
+
message = "Source 'string' cannot be processed by Reek due to an encoding error in the source file."
|
|
244
|
+
expect { examiner.smells }.to raise_error.with_message(/#{message}/)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it 'shows the original exception class' do
|
|
248
|
+
expect { examiner.smells }.
|
|
249
|
+
to raise_error { |it| expect(it.long_message).to match(/InvalidByteSequenceError/) }
|
|
143
250
|
end
|
|
144
251
|
end
|
|
145
252
|
|
|
146
253
|
describe 'bad comment config' do
|
|
147
254
|
let(:examiner) { described_class.new(source) }
|
|
148
|
-
|
|
255
|
+
|
|
256
|
+
context 'with an unknown smell detector' do
|
|
149
257
|
let(:source) do
|
|
150
258
|
<<-EOS
|
|
151
259
|
# :reek:DoesNotExist
|
|
@@ -171,7 +279,7 @@ RSpec.describe Reek::Examiner do
|
|
|
171
279
|
end
|
|
172
280
|
end
|
|
173
281
|
|
|
174
|
-
context 'garbage in detector config' do
|
|
282
|
+
context 'with garbage in detector config' do
|
|
175
283
|
let(:source) do
|
|
176
284
|
<<-EOS
|
|
177
285
|
# :reek:UncommunicativeMethodName { thats: a: bad: config }
|