-
Notifications
You must be signed in to change notification settings - Fork 32
/
command_spec.rb
308 lines (253 loc) · 10.1 KB
/
command_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# encoding: utf-8
require File.expand_path('../spec_helper', __FILE__)
module CLAide
describe Command do
before do
@subject = Fixture::Command
end
describe 'in general' do
it 'registers the subcommand classes' do
@subject.subcommands.map(&:command).should ==
%w(spec-file)
@subject::SpecFile.subcommands.map(&:command).should ==
%w(common-invisible-command)
@subject::SpecFile::Create.subcommands.map(&:command).should ==
[]
@subject::SpecFile::Lint.subcommands.map(&:command).should ==
%w(repo)
end
it 'returns subcommands for look up' do
subcommands = @subject::SpecFile.subcommands_for_command_lookup
subcommands.map(&:command).should == %w(lint create)
end
it 'returns whether it is the root command' do
@subject.should.be.root_command?
@subject::SpecFile.should.not.be.root_command?
end
it 'tries to match a subclass for each of the subcommands' do
parsed = @subject.parse(%w(spec-file --verbose lint))
parsed.should.be.instance_of @subject::SpecFile::Lint
end
it 'returns the signature arguments' do
@subject::SpecFile::Lint.arguments.should == [
CLAide::Argument.new('NAME', false),
]
end
end
#-------------------------------------------------------------------------#
describe 'class methods' do
it 'returns that ANSI output should be used if a TTY is present' do
@subject.ansi_output = nil
STDOUT.expects(:tty?).returns(true)
@subject.ansi_output.should.be.true
end
it 'returns that ANSI output should be used if a TTY is not present' do
@subject.ansi_output = nil
STDOUT.expects(:tty?).returns(false)
@subject.ansi_output.should.be.false
end
it 'invokes a command with the convenience method and args list' do
@subject::SpecFile.any_instance.expects(:validate!)
@subject::SpecFile.any_instance.expects(:run).once
@subject::SpecFile.invoke('arg1', 'arg2')
argv = @subject::SpecFile.latest_instance.instance_eval { @argv }
argv.should.be.an.instance_of? CLAide::ARGV
argv.arguments.should == %w(arg1 arg2)
end
it 'invokes a command with the convenience method and array args' do
@subject::SpecFile.any_instance.expects(:validate!)
@subject::SpecFile.any_instance.expects(:run).once
@subject::SpecFile.invoke %w(arg1 arg2)
argv = @subject::SpecFile.latest_instance.instance_eval { @argv }
argv.should.be.an.instance_of? CLAide::ARGV
argv.arguments.should == %w(arg1 arg2)
end
it 'raise when invoking a bad command with the convenience method' do
error = Fixture::Error.new('validate! did raise')
@subject::SpecFile.any_instance.stubs(:validate!).raises(error)
should.raise Fixture::Error do
@subject::SpecFile.invoke('arg1', 'arg2')
end.message.should.match /validate! did raise/
end
end
#-------------------------------------------------------------------------#
describe 'plugins' do
describe 'when the plugin is at <command-prefix>_plugin.rb' do
before do
path = ROOT + 'spec/fixture/command/plugin_fixture.rb'
Gem.stubs(:find_latest_files).returns([path])
end
it 'loads the plugin' do
Fixture::CommandPluginable.subcommands.find do |cmd|
cmd.command == 'demo-plugin'
end.should.be.nil
prefix = Fixture::CommandPluginable.plugin_prefix
Command::PluginsHelper.load_plugins(prefix)
plugin_command = Fixture::CommandPluginable.subcommands.find do |cmd|
cmd.command == 'demo-plugin'
end
plugin_command.should.not.be.nil
plugin_command.ancestors.should.include Fixture::CommandPluginable
plugin_command.description.should =~ /plugins/
end
it 'is available for help' do
prefix = Fixture::CommandPluginable.plugin_prefix
Command::PluginsHelper.load_plugins(prefix)
banner = CLAide::Command::Banner.new(Fixture::CommandPluginable)
banner.formatted_banner.should =~ /demo-plugin/
end
end
it 'fails normally if there is no plugin' do
Command::PluginsHelper.load_plugins(@subject.plugin_prefix)
@subject.subcommands.find do
|cmd| cmd.name == 'demo-plugin'
end.should.be.nil
end
describe 'failing plugins' do
it 'rescues exceptions raised during the load of the plugin' do
path = ROOT + 'spec/fixture/command/load_error_plugin_fixture.rb'
should.raise LoadError do
require path
end
Gem.stubs(:find_latest_files).returns([path])
should.not.raise do
Command::PluginsHelper.load_plugins(@subject.plugin_prefix)
end
end
end
end
#-------------------------------------------------------------------------#
describe 'validation' do
it 'does not raise if one of the subcommands consumes arguments' do
subcommand = @subject.parse(%w(spec-file create AFNetworking))
subcommand.spec.should == 'AFNetworking'
end
it 'raises a Help exception when created with an invalid subcommand' do
message = "Unknown command: `unknown`\nDid you mean: spec-file"
should_raise_help message do
@subject.parse(%w(unknown)).validate!
end
should_raise_help "Unknown command: `unknown`\nDid you mean: lint" do
@subject.parse(%w(spec-file unknown)).validate!
end
end
it 'raises an empty Help exception when called on an abstract command' do
should_raise_help nil do
@subject.parse(%w(spec-file)).validate!
end
end
end
#-------------------------------------------------------------------------#
describe 'default options' do
before do
@subject.stubs(:puts)
end
it 'raises a Help exception, without error message' do
should.raise SystemExit do
@subject.parse(%w(--help)).validate!
end
end
it 'configures whether ANSI output is enabled' do
ANSI.expects(:disabled=).with(true)
@subject.any_instance.expects(:validate!)
@subject.any_instance.expects(:run)
@subject.run(%w(--help --no-ansi))
end
it 'sets the verbose flag' do
command = @subject.parse([])
command.should.not.be.verbose
command = @subject.parse(%w(--verbose))
command.should.be.verbose
end
it 'does not runs the instance if root options have been specified' do
Command::Options.expects(:handle_root_option).returns(true)
@subject.any_instance.expects(:run).never
@subject.run(%w(--version))
end
end
#-------------------------------------------------------------------------#
describe 'when running' do
before do
@subject.stubs(:puts)
end
it 'invokes an instance of the parsed subcommand' do
@subject::SpecFile.any_instance.stubs(:validate!)
@subject::SpecFile.any_instance.expects(:run)
@subject.run(%w(spec-file))
end
it 'does not print the backtrace of an InformativeError by default' do
::CLAide::ANSI.disabled = true
expected = Help.new(@subject.banner).message
@subject.expects(:puts).with(expected)
should.raise SystemExit do
@subject.run(%w(--help))
end
end
it 'does not print the backtrace if help and verbose are set' do
::CLAide::ANSI.disabled = true
expected = Help.new(@subject.banner).message
@subject.expects(:puts).with(expected)
should.raise SystemExit do
@subject.run(%w(--help --verbose))
end
end
it 'prints the backtrace of an InformativeError, if set to verbose' do
error = Fixture::Error.new
@subject.any_instance.stubs(:validate!).raises(error)
error.stubs(:message).returns('the message')
error.stubs(:backtrace).returns(%w(the backtrace))
printed = states('printed').starts_as(:nothing)
@subject.expects(:puts).with('the message').
when(printed.is(:nothing)).then(printed.is(:message))
@subject.expects(:puts).with('the', 'backtrace').
when(printed.is(:message)).then(printed.is(:done))
should.raise SystemExit do
@subject.run(%w(--verbose))
end
end
it 'exits with a failure status when an InformativeError occurs' do
@subject.expects(:exit).with(1)
@subject.any_instance.stubs(:validate!).
raises(Fixture::Error.new)
@subject.run([])
end
it 'exits with a failure status when a Help exception occurs' do
@subject.expects(:exit).with(1)
@subject.run(%w(unknown))
end
it 'exits with a success status when an empty Help exception occurs' do
@subject.expects(:exit).with(0)
@subject.any_instance.stubs(:run) # by mocking exit, we reach run
@subject.run(%w(--help))
end
it 'allows clients to customize how to report exceptions' do
exception = Exception.new('message')
@subject.any_instance.expects(:run).raises(exception)
@subject.expects(:report_error).with(exception)
@subject.run
end
it 'raises by default' do
should.raise do
@subject.run
end.message.should.match /subclass should override/
end
end
#-------------------------------------------------------------------------#
describe 'help' do
before do
@command_class = @subject::SpecFile.dup
@command_class.default_subcommand = 'lint'
end
it 'shows the help of the parent if a command was invoked by default' do
cmd = @command_class.parse([])
cmd.class.superclass.expects(:help!)
cmd.send(:help!)
end
it "doesn't show the help of the parent by default" do
cmd = @command_class.parse(%w(create))
cmd.class.expects(:help!)
cmd.send(:help!)
end
end
end
end