transpec 0.2.6 → 1.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +10 -0
  5. data/README.md +111 -56
  6. data/README.md.erb +117 -62
  7. data/lib/transpec/ast/node.rb +41 -0
  8. data/lib/transpec/base_rewriter.rb +55 -0
  9. data/lib/transpec/cli.rb +43 -153
  10. data/lib/transpec/configuration.rb +13 -9
  11. data/lib/transpec/{rewriter.rb → converter.rb} +44 -71
  12. data/lib/transpec/dynamic_analyzer/rewriter.rb +94 -0
  13. data/lib/transpec/dynamic_analyzer/runtime_data.rb +27 -0
  14. data/lib/transpec/dynamic_analyzer.rb +166 -0
  15. data/lib/transpec/file_finder.rb +53 -0
  16. data/lib/transpec/option_parser.rb +166 -0
  17. data/lib/transpec/{context.rb → static_context_inspector.rb} +2 -2
  18. data/lib/transpec/syntax/be_close.rb +7 -9
  19. data/lib/transpec/syntax/double.rb +6 -10
  20. data/lib/transpec/syntax/expect.rb +35 -0
  21. data/lib/transpec/syntax/have.rb +195 -0
  22. data/lib/transpec/syntax/method_stub.rb +22 -27
  23. data/lib/transpec/syntax/mixin/allow_no_message.rb +73 -0
  24. data/lib/transpec/syntax/mixin/any_instance.rb +22 -0
  25. data/lib/transpec/syntax/mixin/expectizable.rb +26 -0
  26. data/lib/transpec/syntax/mixin/have_matcher.rb +23 -0
  27. data/lib/transpec/syntax/mixin/monkey_patch.rb +37 -0
  28. data/lib/transpec/syntax/mixin/send.rb +109 -0
  29. data/lib/transpec/syntax/{matcher.rb → operator_matcher.rb} +27 -14
  30. data/lib/transpec/syntax/raise_error.rb +6 -10
  31. data/lib/transpec/syntax/rspec_configure.rb +29 -28
  32. data/lib/transpec/syntax/should.rb +45 -15
  33. data/lib/transpec/syntax/should_receive.rb +44 -16
  34. data/lib/transpec/syntax.rb +29 -21
  35. data/lib/transpec/util.rb +12 -2
  36. data/lib/transpec/version.rb +3 -3
  37. data/spec/spec_helper.rb +8 -6
  38. data/spec/support/cache_helper.rb +50 -0
  39. data/spec/support/shared_context.rb +49 -1
  40. data/spec/transpec/ast/node_spec.rb +65 -0
  41. data/spec/transpec/cli_spec.rb +33 -242
  42. data/spec/transpec/commit_message_spec.rb +2 -2
  43. data/spec/transpec/configuration_spec.rb +12 -8
  44. data/spec/transpec/{rewriter_spec.rb → converter_spec.rb} +198 -148
  45. data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +183 -0
  46. data/spec/transpec/dynamic_analyzer_spec.rb +164 -0
  47. data/spec/transpec/file_finder_spec.rb +118 -0
  48. data/spec/transpec/option_parser_spec.rb +185 -0
  49. data/spec/transpec/{context_spec.rb → static_context_inspector_spec.rb} +27 -12
  50. data/spec/transpec/syntax/be_close_spec.rb +8 -4
  51. data/spec/transpec/syntax/double_spec.rb +105 -12
  52. data/spec/transpec/syntax/expect_spec.rb +83 -0
  53. data/spec/transpec/syntax/have_spec.rb +599 -0
  54. data/spec/transpec/syntax/method_stub_spec.rb +276 -115
  55. data/spec/transpec/syntax/{matcher_spec.rb → operator_matcher_spec.rb} +277 -98
  56. data/spec/transpec/syntax/raise_error_spec.rb +92 -46
  57. data/spec/transpec/syntax/should_receive_spec.rb +298 -92
  58. data/spec/transpec/syntax/should_spec.rb +230 -44
  59. data/spec/transpec/util_spec.rb +2 -9
  60. data/tasks/lib/transpec_demo.rb +1 -1
  61. data/tasks/lib/transpec_test.rb +5 -7
  62. data/tasks/test.rake +5 -1
  63. data/transpec.gemspec +1 -1
  64. metadata +46 -22
  65. data/lib/transpec/syntax/able_to_allow_no_message.rb +0 -73
  66. data/lib/transpec/syntax/able_to_target_any_instance.rb +0 -24
  67. data/lib/transpec/syntax/expectizable.rb +0 -27
  68. data/lib/transpec/syntax/send_node_syntax.rb +0 -57
@@ -0,0 +1,183 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/dynamic_analyzer/rewriter'
5
+
6
+ module Transpec
7
+ class DynamicAnalyzer
8
+ describe Rewriter do
9
+ include ::AST::Sexp
10
+
11
+ subject(:rewriter) { Rewriter.new }
12
+
13
+ describe '#rewrite' do
14
+ subject { rewriter.rewrite(source) }
15
+
16
+ let(:source) do
17
+ <<-END
18
+ describe 'example' do
19
+ it 'is foo' do
20
+ subject.should be(foo)
21
+ end
22
+ end
23
+ END
24
+ end
25
+
26
+ # rubocop:disable LineLength
27
+ let(:expected_source) do
28
+ <<-END
29
+ describe 'example' do
30
+ it 'is foo' do
31
+ transpec_analysis((transpec_analysis((subject), self, { :should_source_location => [:object, "method(:should).source_location"] }, __FILE__, 79, 86).should be(foo)), self, { :expect_available? => [:context, "self.class.name.start_with?('RSpec::') && respond_to?(:expect)"] }, __FILE__, 79, 101)
32
+ end
33
+ end
34
+ END
35
+ end
36
+ # rubocop:enable LineLength
37
+
38
+ it 'wraps target object with analysis helper method' do
39
+ should == expected_source
40
+ end
41
+
42
+ context 'when the target includes here document' do
43
+ let(:source) do
44
+ <<-END
45
+ describe 'example' do
46
+ it 'matches to foo' do
47
+ subject.should =~ <<-HEREDOC.gsub('foo', 'bar')
48
+ foo
49
+ HEREDOC
50
+ end
51
+ end
52
+ END
53
+ end
54
+
55
+ # rubocop:disable LineLength
56
+ let(:expected_source) do
57
+ <<-END
58
+ describe 'example' do
59
+ it 'matches to foo' do
60
+ transpec_analysis((transpec_analysis((subject), self, { :should_source_location => [:object, "method(:should).source_location"] }, __FILE__, 93, 100).should), self, { :expect_available? => [:context, "self.class.name.start_with?('RSpec::') && respond_to?(:expect)"] }, __FILE__, 93, 107) =~ transpec_analysis((<<-HEREDOC.gsub('foo', 'bar')
61
+ foo
62
+ HEREDOC
63
+ ), self, { :arg_is_enumerable? => [:object, "is_a?(Enumerable)"] }, __FILE__, 111, 188)
64
+ end
65
+ end
66
+ END
67
+ end
68
+ # rubocop:enable LineLength
69
+
70
+ it 'wraps the here document properly' do
71
+ should == expected_source
72
+ end
73
+ end
74
+
75
+ context 'when the target takes block' do
76
+ let(:source) do
77
+ <<-END
78
+ describe 'example' do
79
+ it 'raises error' do
80
+ expect { do_something }.to throw_symbol
81
+ end
82
+ end
83
+ END
84
+ end
85
+
86
+ # rubocop:disable LineLength
87
+ let(:expected_source) do
88
+ <<-END
89
+ describe 'example' do
90
+ it 'raises error' do
91
+ transpec_analysis((expect { do_something }), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 91, 97).to throw_symbol
92
+ end
93
+ end
94
+ END
95
+ end
96
+ # rubocop:enable LineLength
97
+
98
+ it 'wraps the block properly' do
99
+ should == expected_source
100
+ end
101
+ end
102
+
103
+ context 'when the target is only the expression in a block' do
104
+ let(:source) do
105
+ <<-END
106
+ describe 'example' do
107
+ it 'raises error' do
108
+ expect
109
+ end
110
+ end
111
+ END
112
+ end
113
+
114
+ # rubocop:disable LineLength
115
+ let(:expected_source) do
116
+ <<-END
117
+ describe 'example' do
118
+ it 'raises error' do
119
+ transpec_analysis((expect), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 91, 97)
120
+ end
121
+ end
122
+ END
123
+ end
124
+ # rubocop:enable LineLength
125
+
126
+ it 'wraps the target properly' do
127
+ should == expected_source
128
+ end
129
+ end
130
+
131
+ context 'when the target is method invocation without parentheses' do
132
+ let(:source) do
133
+ <<-END
134
+ describe 'example' do
135
+ it 'raises error' do
136
+ expect subject
137
+ end
138
+ end
139
+ END
140
+ end
141
+
142
+ # rubocop:disable LineLength
143
+ let(:expected_source) do
144
+ <<-END
145
+ describe 'example' do
146
+ it 'raises error' do
147
+ transpec_analysis((expect subject), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 91, 105)
148
+ end
149
+ end
150
+ END
151
+ end
152
+ # rubocop:enable LineLength
153
+
154
+ it 'wraps the target properly' do
155
+ should == expected_source
156
+ end
157
+ end
158
+ end
159
+
160
+ describe '#register_request' do
161
+ let(:some_node) { s(:int, 1) }
162
+ let(:another_node) { s(:int, 2) }
163
+
164
+ it 'stores requests for each node' do
165
+ rewriter.register_request(some_node, :odd, 'odd?', :object)
166
+ rewriter.register_request(another_node, :even, 'even?', :object)
167
+ rewriter.requests.should == {
168
+ some_node => { odd: [:object, 'odd?'] },
169
+ another_node => { even: [:object, 'even?'] }
170
+ }
171
+ end
172
+
173
+ it 'merges multiple requests for same node' do
174
+ rewriter.register_request(some_node, :odd, 'odd?', :object)
175
+ rewriter.register_request(some_node, :even, 'even?', :object)
176
+ rewriter.requests.should == {
177
+ some_node => { odd: [:object, 'odd?'], even: [:object, 'even?'] }
178
+ }
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,164 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/dynamic_analyzer'
5
+
6
+ module Transpec
7
+ describe DynamicAnalyzer do
8
+ include FileHelper
9
+ include ::AST::Sexp
10
+ include_context 'isolated environment'
11
+
12
+ subject(:dynamic_analyzer) { DynamicAnalyzer.new(rspec_command: rspec_command, silent: true) }
13
+ let(:rspec_command) { nil }
14
+
15
+ describe '.new' do
16
+ context 'when when block is passed' do
17
+ it 'yields instance' do
18
+ yielded = false
19
+
20
+ DynamicAnalyzer.new(silent: true) do |analyzer|
21
+ yielded = true
22
+ analyzer.should be_a(DynamicAnalyzer)
23
+ end
24
+
25
+ yielded.should be_true
26
+ end
27
+
28
+ it 'changes working directory to copied project directory' do
29
+ initial_directory = Dir.pwd
30
+ DynamicAnalyzer.new(silent: true) do |analyzer|
31
+ Dir.pwd.should_not == initial_directory
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#rspec_command' do
38
+ subject { dynamic_analyzer.rspec_command }
39
+
40
+ context 'when command is specified' do
41
+ let(:rspec_command) { 'rspec some_argument' }
42
+
43
+ it 'returns the specified command' do
44
+ should == rspec_command
45
+ end
46
+ end
47
+
48
+ context 'when command is not specified' do
49
+ context 'and there is a Gemfile' do
50
+ before do
51
+ create_file('Gemfile', '')
52
+ end
53
+
54
+ it 'returns "bundle exec rspec"' do
55
+ should == 'bundle exec rspec'
56
+ end
57
+ end
58
+
59
+ context 'and there is no Gemfile' do
60
+ it 'returns "rspec"' do
61
+ should == 'rspec'
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#analyze' do
68
+ let(:source) do
69
+ <<-END
70
+ describe [1, 2] do
71
+ it 'has 2 items' do
72
+ expect(subject).to have(2).items
73
+ end
74
+ end
75
+ END
76
+ end
77
+
78
+ let(:file_path) { 'spec/example_spec.rb' }
79
+
80
+ before do
81
+ create_file(file_path, source)
82
+ end
83
+
84
+ context 'when already in copied project directory' do
85
+ it 'does not change working directory' do
86
+ DynamicAnalyzer.new(silent: true) do |analyzer|
87
+ Dir.should_not_receive(:chdir)
88
+ analyzer.analyze
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'when no path is passed' do
94
+ it 'rewrites all files in the "spec" directory' do
95
+ DynamicAnalyzer::Rewriter.any_instance.should_receive(:rewrite_file!).with(file_path)
96
+ dynamic_analyzer.analyze
97
+ end
98
+ end
99
+
100
+ context 'when some paths are passed' do
101
+ before do
102
+ create_file('spec/another_spec.rb', '')
103
+ end
104
+
105
+ it 'rewrites only files in the passed paths' do
106
+ DynamicAnalyzer::Rewriter.any_instance.should_receive(:rewrite_file!).with(file_path)
107
+ dynamic_analyzer.analyze([file_path])
108
+ end
109
+ end
110
+
111
+ context 'when there is invalid syntax source file' do
112
+ before do
113
+ create_file('spec/fixtures/invalid.rb', 'This is invalid syntax <')
114
+ end
115
+
116
+ it 'does not raise error' do
117
+ -> { dynamic_analyzer.analyze }.should_not raise_error
118
+ end
119
+ end
120
+
121
+ runtime_data_cache = {}
122
+
123
+ subject(:runtime_data) do
124
+ if runtime_data_cache[source]
125
+ runtime_data_cache[source]
126
+ else
127
+ runtime_data_cache[source] = dynamic_analyzer.analyze
128
+ end
129
+ end
130
+
131
+ it 'returns an instance of DynamicAnalyzer::RuntimeData' do
132
+ runtime_data.should be_an(DynamicAnalyzer::RuntimeData)
133
+ end
134
+
135
+ describe 'its element' do
136
+ let(:ast) do
137
+ source_buffer = Parser::Source::Buffer.new(file_path)
138
+ source_buffer.source = source
139
+
140
+ builder = AST::Builder.new
141
+
142
+ parser = Parser::CurrentRuby.new(builder)
143
+ parser.parse(source_buffer)
144
+ end
145
+
146
+ let(:target_node) do
147
+ ast.each_descendent_node do |node|
148
+ return node if node == s(:send, nil, :subject)
149
+ end
150
+ end
151
+
152
+ subject(:element) { runtime_data[target_node] }
153
+
154
+ it 'is a hash' do
155
+ should be_a(Hash)
156
+ end
157
+
158
+ it 'has result of requested analysis' do
159
+ element[:available_query_methods].result.should =~ [:size, :count, :length]
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,118 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/file_finder'
5
+
6
+ module Transpec
7
+ describe FileFinder do
8
+ include FileHelper
9
+
10
+ describe '.find' do
11
+ include_context 'isolated environment'
12
+
13
+ before do
14
+ ['file', 'file.rb', 'dir/file', 'dir/file.rb'].each do |path|
15
+ create_file(path, '')
16
+ end
17
+ end
18
+
19
+ subject { FileFinder.find(paths) }
20
+
21
+ context 'when no path is passed' do
22
+ let(:paths) { [] }
23
+
24
+ context 'and there is "spec" directory' do
25
+ before do
26
+ create_file('spec/file.rb', '')
27
+ end
28
+
29
+ it 'returns file paths with .rb extension in the "spec" directory recursively' do
30
+ should == ['spec/file.rb']
31
+ end
32
+ end
33
+
34
+ context 'and there is not "spec" directory' do
35
+ it 'raises error' do
36
+ -> { FileFinder.find(paths) }.should raise_error(ArgumentError)
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'when a file path with .rb extension is passed' do
42
+ let(:paths) { ['file.rb'] }
43
+
44
+ it 'returns the path' do
45
+ should == ['file.rb']
46
+ end
47
+ end
48
+
49
+ context 'when a file path without extension is passed' do
50
+ let(:paths) { ['file'] }
51
+
52
+ it 'returns the path' do
53
+ should == ['file']
54
+ end
55
+ end
56
+
57
+ context 'when a non-existent path is passed' do
58
+ let(:paths) { ['non-existent-file'] }
59
+
60
+ it 'raises error' do
61
+ -> { FileFinder.find(paths) }.should raise_error(ArgumentError) { |error|
62
+ error.message.should == 'No such file or directory "non-existent-file"'
63
+ }
64
+ end
65
+ end
66
+
67
+ context 'when a directory path is passed' do
68
+ let(:paths) { ['dir'] }
69
+
70
+ it 'returns file paths with .rb extension in the directory recursively' do
71
+ should == ['dir/file.rb']
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '.base_paths' do
77
+ include_context 'isolated environment'
78
+
79
+ subject { FileFinder.base_paths(paths) }
80
+
81
+ context 'when target paths are specified' do
82
+ let(:paths) { ['foo_spec.rb', 'spec/bar_spec.rb'] }
83
+
84
+ it 'returns the passed paths' do
85
+ should == paths
86
+ end
87
+ end
88
+
89
+ context 'when paths outside of the current working directory are specified' do
90
+ let(:paths) { ['../foo_spec.rb', 'spec/bar_spec.rb'] }
91
+
92
+ it 'raises error' do
93
+ -> { FileFinder.base_paths(paths) }.should raise_error(ArgumentError)
94
+ end
95
+ end
96
+
97
+ context 'when no target paths are specified' do
98
+ let(:paths) { [] }
99
+
100
+ context 'and there is "spec" directory' do
101
+ before do
102
+ Dir.mkdir('spec')
103
+ end
104
+
105
+ it 'returns ["spec"]' do
106
+ should == ['spec']
107
+ end
108
+ end
109
+
110
+ context 'and there is not "spec" directory' do
111
+ it 'raises error' do
112
+ -> { FileFinder.base_paths(paths) }.should raise_error(ArgumentError)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,185 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/option_parser'
5
+
6
+ module Transpec
7
+ describe OptionParser do
8
+ subject(:parser) { OptionParser.new(configuration) }
9
+ let(:configuration) { Configuration.new }
10
+
11
+ describe '#parse' do
12
+ subject { parser.parse(args) }
13
+ let(:args) { ['some_file', '--negative-form', 'to_not', 'some_dir'] }
14
+
15
+ it 'return non-option arguments' do
16
+ should == ['some_file', 'some_dir']
17
+ end
18
+
19
+ it 'does not mutate the passed array' do
20
+ parser.parse(args)
21
+ args.should == ['some_file', '--negative-form', 'to_not', 'some_dir']
22
+ end
23
+
24
+ describe '-f/--force option' do
25
+ let(:args) { ['--force'] }
26
+
27
+ it 'sets Configuration#forced? true' do
28
+ parser.parse(args)
29
+ configuration.forced?.should be_true
30
+ end
31
+ end
32
+
33
+ describe '-s/--skip-dynamic-analysis option' do
34
+ let(:args) { ['--skip-dynamic-analysis'] }
35
+
36
+ it 'sets Configuration#skip_dynamic_analysis? true' do
37
+ parser.parse(args)
38
+ configuration.skip_dynamic_analysis?.should be_true
39
+ end
40
+ end
41
+
42
+ describe '-m/--generate-commit-message option' do
43
+ include_context 'isolated environment'
44
+
45
+ let(:args) { ['--generate-commit-message'] }
46
+
47
+ context 'when inside of git repository' do
48
+ include_context 'inside of git repository'
49
+
50
+ it 'sets Configuration#generate_commit_message? true' do
51
+ parser.parse(args)
52
+ configuration.generate_commit_message?.should be_true
53
+ end
54
+ end
55
+
56
+ context 'when not inside of git repository' do
57
+ it 'raises error' do
58
+ -> { parser.parse(args) }.should raise_error(/not in a Git repository/)
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '-k/--keep option' do
64
+ [
65
+ ['should', :convert_should?],
66
+ ['should_receive', :convert_should_receive?],
67
+ ['stub', :convert_stub?],
68
+ ['have_items', :convert_have_items],
69
+ ['deprecated', :convert_deprecated_method?]
70
+ ].each do |cli_type, config_attr|
71
+ context "when #{cli_type.inspect} is specified" do
72
+ let(:args) { ['--keep', cli_type] }
73
+
74
+ it "sets Configuration##{config_attr} false" do
75
+ parser.parse(args)
76
+ configuration.send(config_attr).should be_false
77
+ end
78
+ end
79
+ end
80
+
81
+ context 'when multiple types are specified with comma' do
82
+ let(:args) { ['--keep', 'should_receive,deprecated'] }
83
+
84
+ it 'handles all of them' do
85
+ parser.parse(args)
86
+ configuration.convert_should_receive?.should be_false
87
+ configuration.convert_deprecated_method?.should be_false
88
+ end
89
+ end
90
+
91
+ context 'when unknown type is specified' do
92
+ let(:args) { ['--keep', 'unknown'] }
93
+
94
+ it 'raises error' do
95
+ -> { parser.parse(args) }.should raise_error(ArgumentError) { |error|
96
+ error.message.should == 'Unknown syntax type "unknown"'
97
+ }
98
+ end
99
+ end
100
+ end
101
+
102
+ describe '-n/--negative-form option' do
103
+ ['not_to', 'to_not'].each do |form|
104
+ context "when #{form.inspect} is specified" do
105
+ let(:args) { ['--negative-form', form] }
106
+
107
+ it "sets Configuration#negative_form_of_to? #{form.inspect}" do
108
+ parser.parse(args)
109
+ configuration.negative_form_of_to.should == form
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ describe '-p/--no-parentheses-matcher-arg option' do
116
+ let(:args) { ['--no-parentheses-matcher-arg'] }
117
+
118
+ it 'sets Configuration#parenthesize_matcher_arg? false' do
119
+ parser.parse(args)
120
+ configuration.parenthesize_matcher_arg.should be_false
121
+ end
122
+ end
123
+
124
+ describe '--no-color option' do
125
+ before do
126
+ Sickill::Rainbow.enabled = true
127
+ end
128
+
129
+ let(:args) { ['--no-color'] }
130
+
131
+ it 'disables color in the output' do
132
+ parser.parse(args)
133
+ Sickill::Rainbow.enabled.should be_false
134
+ end
135
+ end
136
+
137
+ describe '--version option' do
138
+ before do
139
+ parser.stub(:puts)
140
+ parser.stub(:exit)
141
+ end
142
+
143
+ let(:args) { ['--version'] }
144
+
145
+ it 'shows version' do
146
+ parser.should_receive(:puts).with(Version.to_s)
147
+ parser.parse(args)
148
+ end
149
+
150
+ it 'exits' do
151
+ parser.should_receive(:exit)
152
+ parser.parse(args)
153
+ end
154
+ end
155
+ end
156
+
157
+ describe 'help text' do
158
+ subject(:help_text) do
159
+ parser.help
160
+ end
161
+
162
+ it 'does not exceed 80 characters in each line' do
163
+ help_text.each_line do |line|
164
+ line.chomp.length.should <= 80
165
+ end
166
+ end
167
+
168
+ it 'describes all conversion types for -k/--keep option' do
169
+ option_sections = help_text.lines.slice_before(/^\s*-/)
170
+
171
+ keep_section = option_sections.find do |lines|
172
+ lines.first =~ /^\s*-k/
173
+ end
174
+
175
+ conversion_types = keep_section.reduce([]) do |types, line|
176
+ match = line.match(/^[ ]{37}([a-z_]+)/)
177
+ next types unless match
178
+ types << match.captures.first
179
+ end
180
+
181
+ conversion_types.should =~ OptionParser.available_conversion_types.map(&:to_s)
182
+ end
183
+ end
184
+ end
185
+ end