startapp 0.1.6

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,575 @@
1
+ require 'coverage_helper'
2
+ require 'webmock/rspec'
3
+ require 'fakefs/safe'
4
+ require 'rbconfig'
5
+
6
+ require 'pry' if ENV['PRY']
7
+
8
+ # Environment reset
9
+ ENV['http_proxy'] = nil
10
+ ENV['HTTP_PROXY'] = nil
11
+ ENV['OPENSHIFT_CONFIG'] = nil
12
+
13
+ class FakeFS::Mode
14
+ def initialize(mode_s)
15
+ @s = mode_s
16
+ end
17
+ def to_s(*args)
18
+ @s
19
+ end
20
+ end
21
+ class FakeFS::Stat
22
+ attr_reader :mode
23
+ def initialize(mode_s)
24
+ @mode = FakeFS::Mode.new(mode_s)
25
+ end
26
+ end
27
+
28
+ # chmod isn't implemented in the released fakefs gem
29
+ # but is in git. Once the git version is released we
30
+ # should remove this and actively check permissions
31
+ class FakeFS::File
32
+ def self.chmod(*args)
33
+ # noop
34
+ end
35
+
36
+ def self.stat(path)
37
+ FakeFS::Stat.new(mode(path))
38
+ end
39
+
40
+ def self.mode(path)
41
+ @modes && @modes[path] || '664'
42
+ end
43
+ def self.expect_mode(path, mode)
44
+ (@modes ||= {})[path] = mode
45
+ end
46
+
47
+ # FakeFS incorrectly assigns this to '/'
48
+ remove_const(:PATH_SEPARATOR) rescue nil
49
+ const_set(:PATH_SEPARATOR, ":")
50
+ const_set(:ALT_SEPARATOR, '') rescue nil
51
+
52
+ def self.executable?(path)
53
+ # if the file exists we will assume it is executable
54
+ # for testing purposes
55
+ self.exists?(path)
56
+ end
57
+ end
58
+
59
+ IO.instance_eval{ alias :read_orig :read }
60
+
61
+ module FakeFS
62
+ class << self
63
+ alias_method :activate_orig, :activate!
64
+ alias_method :deactivate_orig, :deactivate!
65
+
66
+ def activate!
67
+ IO.instance_eval{ def self.read(path); FakeFS::File.read(path); end }
68
+ activate_orig
69
+ end
70
+ def deactivate!
71
+ IO.instance_eval{ alias :read :read_orig }
72
+ deactivate_orig
73
+ end
74
+ end
75
+ end
76
+
77
+ require 'rhc/cli'
78
+
79
+ class MockHighLineTerminal < HighLineExtension
80
+ def self.use_color?
81
+ true
82
+ end
83
+
84
+ def initialize(input=StringIO.new, output=StringIO.new)
85
+ super
86
+ @last_read_pos = 0
87
+ end
88
+
89
+ ##
90
+ # read
91
+ #
92
+ # seeks to the last read in the IO stream and reads
93
+ # the data from that position so we don't repeat
94
+ # reads or get empty data due to writes moving
95
+ # the caret to the end of the stream
96
+ def read
97
+ @output.seek(@last_read_pos)
98
+ result = @output.read
99
+ @last_read_pos = @output.pos
100
+ result
101
+ end
102
+
103
+ ##
104
+ # write_line
105
+ #
106
+ # writes a line of data to the end of the
107
+ # input stream appending a newline so
108
+ # highline knows to stop processing and then
109
+ # resets the caret position to the last read
110
+ def write_line(str)
111
+ reset_pos = @input.pos
112
+ # seek end so we don't overwrite anything
113
+ @input.seek(0, IO::SEEK_END)
114
+ result = @input.write "#{str}\n"
115
+ @input.seek(reset_pos)
116
+ result
117
+ end
118
+ def close_write
119
+ @input.close_write
120
+ end
121
+ end
122
+
123
+ include WebMock::API
124
+
125
+ require 'httpclient'
126
+ require 'webmock/http_lib_adapters/httpclient_adapter'
127
+ #
128
+ # Patched from WebMock 1.11, needs to be upstreamed
129
+ #
130
+ class WebMockHTTPClient
131
+ def do_get(req, proxy, conn, stream = false, &block)
132
+ request_signature = build_request_signature(req, :reuse_existing)
133
+
134
+ WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
135
+
136
+ if webmock_responses[request_signature]
137
+ webmock_response = webmock_responses.delete(request_signature)
138
+ response = build_httpclient_response(webmock_response, stream, &block)
139
+ @request_filter.each do |filter|
140
+ # CHANGED
141
+ r = filter.filter_response(req, response)
142
+ res = do_get(req, proxy, conn, stream, &block) if r == :retry
143
+ # END CHANGES
144
+ end
145
+ res = conn.push(response)
146
+ WebMock::CallbackRegistry.invoke_callbacks(
147
+ {:lib => :httpclient}, request_signature, webmock_response)
148
+ res
149
+ elsif WebMock.net_connect_allowed?(request_signature.uri)
150
+ # in case there is a nil entry in the hash...
151
+ webmock_responses.delete(request_signature)
152
+
153
+ res = if stream
154
+ do_get_stream_without_webmock(req, proxy, conn, &block)
155
+ else
156
+ do_get_block_without_webmock(req, proxy, conn, &block)
157
+ end
158
+ res = conn.pop
159
+ conn.push(res)
160
+ if WebMock::CallbackRegistry.any_callbacks?
161
+ webmock_response = build_webmock_response(res)
162
+ WebMock::CallbackRegistry.invoke_callbacks(
163
+ {:lib => :httpclient, :real_request => true}, request_signature,
164
+ webmock_response)
165
+ end
166
+ res
167
+ else
168
+ raise WebMock::NetConnectNotAllowedError.new(request_signature)
169
+ end
170
+ end
171
+ end
172
+
173
+ def stderr
174
+ $stderr.rewind
175
+ # some systems might redirect warnings to stderr
176
+ [$stderr,$terminal].map(&:read).delete_if{|x| x.strip.empty?}.join(' ')
177
+ end
178
+
179
+ module Commander::UI
180
+ alias :enable_paging_old :enable_paging
181
+ def enable_paging
182
+ end
183
+ end
184
+
185
+
186
+ module CommandExampleHelpers
187
+ #
188
+ # Allow this example to stub command methods
189
+ # by guaranteeing the instance exists prior
190
+ # to command execution. Use with methods on
191
+ # CommandHelpers
192
+ #
193
+ def using_command_instance
194
+ subject{ described_class }
195
+ let(:instance) { described_class.new }
196
+ end
197
+ end
198
+ #
199
+ # Helper methods for executing commands and
200
+ # stubbing/mocking methods
201
+ #
202
+ module CommandHelpers
203
+ def command_runner(*args)
204
+ mock_terminal
205
+ new_command_runner *args do
206
+ instance #ensure instance is created before subject :new is mocked
207
+ subject.stub(:new).and_return(instance)
208
+ RHC::Commands.to_commander
209
+ end
210
+ end
211
+ def run!(*args)
212
+ command_runner(*args).run!
213
+ end
214
+ def expects_running(*args, &block)
215
+ r = command_runner(*args)
216
+ lambda { r.run! }
217
+ end
218
+ def command_for(*args)
219
+ command = nil
220
+ RHC::Commands.stub(:execute){ |cmd, method, args| command = cmd; 0 }
221
+ command_runner(*args).run!
222
+ command
223
+ end
224
+
225
+ #
226
+ # These methods assume the example has declared
227
+ # let(:arguments){ [<arguments>] }
228
+ #
229
+
230
+ def run_command(args=arguments)
231
+ mock_terminal
232
+ input.each { |i| $terminal.write_line(i) } if respond_to?(:input)
233
+ $terminal.close_write
234
+ run!(*args)
235
+ end
236
+ def command_output(args=arguments)
237
+ run_command(args)
238
+ rescue SystemExit => e
239
+ "#{@output.string}\n#{$stderr.string}#{e}"
240
+ else
241
+ "#{@output.string}\n#{$stderr.string}"
242
+ end
243
+
244
+ #
245
+ # These methods bypass normal command stubbing.
246
+ # Should really be used when stubbing the whole
247
+ # path. Most specs should use run_instance.
248
+ #
249
+ def run(input=[])
250
+ mock_terminal
251
+ input.each { |i| $terminal.write_line(i) }
252
+ $terminal.close_write
253
+ RHC::CLI.start(arguments)
254
+ end
255
+
256
+ def run_output(input=[])
257
+ run(input)
258
+ rescue SystemExit => e
259
+ "#{@output.string}\n#{$stderr.string}#{e}"
260
+ else
261
+ "#{@output.string}\n#{$stderr.string}"
262
+ end
263
+
264
+ end
265
+
266
+ module ClassSpecHelpers
267
+
268
+ include Commander::Delegates
269
+
270
+ def const_for(obj=nil)
271
+ if obj
272
+ Object.const_set(const_for, obj)
273
+ else
274
+ "#{example.full_description}".split(" ").map{|word| word.capitalize}.join.gsub(/[^\w]/, '')
275
+ end
276
+ end
277
+
278
+ def with_constants(constants, base=Object, &block)
279
+ constants.each do |constant, val|
280
+ base.const_set(constant, val)
281
+ end
282
+
283
+ block.call
284
+ ensure
285
+ constants.each do |constant, val|
286
+ base.send(:remove_const, constant)
287
+ end
288
+ end
289
+
290
+ def new_command_runner *args, &block
291
+ Commander::Runner.instance_variable_set :"@singleton", RHC::CommandRunner.new(args)
292
+ program :name, 'test'
293
+ program :version, '1.2.3'
294
+ program :description, 'something'
295
+ program :help_formatter, RHC::HelpFormatter
296
+
297
+ #create_test_command
298
+ yield if block
299
+ Commander::Runner.instance
300
+ end
301
+
302
+ def mock_terminal
303
+ @input = StringIO.new
304
+ @output = StringIO.new
305
+ $stdout = @output
306
+ $stderr = (@error = StringIO.new)
307
+ $terminal = MockHighLineTerminal.new @input, @output
308
+ end
309
+ def input_line(s)
310
+ $terminal.write_line s
311
+ end
312
+ def last_output(&block)
313
+ if block_given?
314
+ yield $terminal.read
315
+ else
316
+ $terminal.read
317
+ end
318
+ end
319
+
320
+ def capture(&block)
321
+ old_stdout = $stdout
322
+ old_stderr = $stderr
323
+ old_terminal = $terminal
324
+ @input = StringIO.new
325
+ @output = StringIO.new
326
+ $stdout = @output
327
+ $stderr = (@error = StringIO.new)
328
+ $terminal = MockHighLineTerminal.new @input, @output
329
+ yield
330
+ @output.string
331
+ ensure
332
+ $stdout = old_stdout
333
+ $stderr = old_stderr
334
+ $terminal = old_terminal
335
+ end
336
+
337
+ def capture_all(&block)
338
+ old_stdout = $stdout
339
+ old_stderr = $stderr
340
+ old_terminal = $terminal
341
+ @input = StringIO.new
342
+ @output = StringIO.new
343
+ $stdout = @output
344
+ $stderr = @output
345
+ $terminal = MockHighLineTerminal.new @input, @output
346
+ yield
347
+ @output.string
348
+ ensure
349
+ $stdout = old_stdout
350
+ $stderr = old_stderr
351
+ $terminal = old_terminal
352
+ end
353
+
354
+ #
355
+ # usage: stub_request(...).with(&user_agent_header)
356
+ #
357
+ def user_agent_header
358
+ lambda do |request|
359
+ #User-Agent is not sent to mock by httpclient
360
+ #request.headers['User-Agent'] =~ %r{\Arhc/\d+\.\d+.\d+ \(.*?ruby.*?\)}
361
+ true
362
+ end
363
+ end
364
+
365
+ def base_config(&block)
366
+ config = RHC::Config.new
367
+ config.stub(:load_config_files)
368
+ defaults = config.instance_variable_get(:@defaults)
369
+ yield config, defaults if block_given?
370
+ RHC::Config.stub(:default).and_return(config)
371
+ RHC::Config.stub(:new).and_return(config)
372
+ config
373
+ end
374
+
375
+ def user_config
376
+ user = respond_to?(:username) ? self.username : 'test_user'
377
+ password = respond_to?(:password) ? self.password : 'test pass'
378
+ server = respond_to?(:server) ? self.server : nil
379
+
380
+ base_config do |config, defaults|
381
+ defaults.add 'default_rhlogin', user
382
+ defaults.add 'password', password
383
+ defaults.add 'libra_server', server if server
384
+ end.tap do |c|
385
+ opts = c.to_options
386
+ opts[:rhlogin].should == user
387
+ opts[:password].should == password
388
+ opts[:server].should == server if server
389
+ end
390
+ end
391
+
392
+ def expect_multi_ssh(command, hosts, check_error=false)
393
+ require 'net/ssh/multi'
394
+
395
+ session = double('Multi::SSH::Session')
396
+ described_class.any_instance.stub(:requires_ssh_multi!)
397
+ channels = hosts.inject({}) do |h, (k,v)|
398
+ c = double(:properties => {}, :connection => double(:properties => {}))
399
+ h[k] = c
400
+ h
401
+ end
402
+ session.should_receive(:use).exactly(hosts.count).times.with do |host, opts|
403
+ opts[:properties].should_not be_nil
404
+ opts[:properties][:gear].should_not be_nil
405
+ hosts.should have_key(host)
406
+ channels[host].connection.properties.merge!(opts[:properties])
407
+ true
408
+ end
409
+ session.stub(:_command).and_return(command)
410
+ session.stub(:_hosts).and_return(hosts)
411
+ session.stub(:_channels).and_return(channels)
412
+ session.instance_eval do
413
+ def exec(arg1, *args, &block)
414
+ arg1.should == _command
415
+ _hosts.to_a.sort{ |a,b| a[0] <=> b[0] }.each do |(k,v)|
416
+ block.call(_channels[k], :stdout, v)
417
+ end
418
+ end
419
+ end
420
+ session.should_receive(:loop) unless hosts.empty?
421
+ Net::SSH::Multi.should_receive(:start).and_yield(session).with do |opts|
422
+ opts.should have_key(:on_error)
423
+ capture_all{ opts[:on_error].call('test') }.should =~ /Unable to connect to gear test/ if check_error
424
+ true
425
+ end
426
+ session
427
+ end
428
+ end
429
+
430
+ module ExitCodeMatchers
431
+ RSpec::Matchers.define :exit_with_code do |code|
432
+ actual = nil
433
+ match do |block|
434
+ begin
435
+ actual = block.call
436
+ rescue SystemExit => e
437
+ actual = e.status
438
+ end
439
+ actual and actual == code
440
+ end
441
+ failure_message_for_should do |block|
442
+ "expected block to call exit(#{code}) but exit" +
443
+ (actual.nil? ? " not called" : "(#{actual}) was called")
444
+ end
445
+ failure_message_for_should_not do |block|
446
+ "expected block not to call exit(#{code})"
447
+ end
448
+ description do
449
+ "expect block to call exit(#{code})"
450
+ end
451
+ end
452
+ end
453
+
454
+ module CommanderInvocationMatchers
455
+ InvocationMatch = Class.new(RuntimeError)
456
+
457
+ RSpec::Matchers.define :call do |method|
458
+ chain :on do |object|
459
+ @object = object
460
+ end
461
+ chain :with do |*args|
462
+ @args = args
463
+ end
464
+ chain :and_stop do
465
+ @stop = true
466
+ end
467
+
468
+ match do |block|
469
+ e = @object.should_receive(method)
470
+ e.and_raise(InvocationMatch) if @stop
471
+ e.with(*@args) if @args
472
+ begin
473
+ block.call
474
+ true
475
+ rescue InvocationMatch => e
476
+ true
477
+ rescue SystemExit => e
478
+ false
479
+ end
480
+ end
481
+ description do
482
+ "expect block to invoke '#{method}' on #{@object} with #{@args}"
483
+ end
484
+ end
485
+
486
+ RSpec::Matchers.define :not_call do |method|
487
+ chain :on do |object|
488
+ @object = object
489
+ end
490
+ chain :with do |*args|
491
+ @args = args
492
+ end
493
+
494
+ match do |block|
495
+ e = @object.should_not_receive(method)
496
+ e.with(*@args) if @args
497
+ begin
498
+ block.call
499
+ true
500
+ rescue SystemExit => e
501
+ false
502
+ end
503
+ end
504
+ description do
505
+ "expect block to invoke '#{method}' on #{@object} with #{@args}"
506
+ end
507
+ end
508
+ end
509
+
510
+ module ColorMatchers
511
+ COLORS = {
512
+ :green => 32,
513
+ :yellow => 33,
514
+ :cyan => 36,
515
+ :red => 31,
516
+ :clear => 0
517
+ }
518
+
519
+ RSpec::Matchers.define :be_colorized do |msg,color|
520
+ match do |actual|
521
+ actual == colorized_message(msg,color)
522
+ end
523
+
524
+ failure_message_for_should do |actual|
525
+ failure_message(actual,msg,color)
526
+ end
527
+
528
+ failure_message_for_should_not do |actual|
529
+ failure_message(actual,msg,color)
530
+ end
531
+
532
+ def failure_message(actual,msg,color)
533
+ "expected: #{colorized_message(msg,color).inspect}\n" +
534
+ " got: #{actual.inspect}"
535
+ end
536
+
537
+ def ansi_code(color)
538
+ "\e[#{ColorMatchers::COLORS[color]}m"
539
+ end
540
+
541
+ def colorized_message(msg,color)
542
+ [
543
+ ansi_code(color),
544
+ msg,
545
+ ansi_code(:clear),
546
+ "\n"
547
+ ].join('')
548
+ end
549
+ end
550
+ end
551
+
552
+ def mac?
553
+ RbConfig::CONFIG['host_os'] =~ /^darwin/
554
+ end
555
+
556
+ RSpec.configure do |config|
557
+ config.include(ExitCodeMatchers)
558
+ config.include(CommanderInvocationMatchers)
559
+ config.include(ColorMatchers)
560
+ config.include(ClassSpecHelpers)
561
+ config.include(CommandHelpers)
562
+ config.extend(CommandExampleHelpers)
563
+ config.backtrace_clean_patterns = [] if ENV['FULL_BACKTRACE']
564
+ end
565
+
566
+ module TestEnv
567
+ extend ClassSpecHelpers
568
+ class << self
569
+ attr_accessor :instance, :subject
570
+ def instance=(i)
571
+ self.subject = i.class
572
+ @instance = i
573
+ end
574
+ end
575
+ end