schacon-github 0.3.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.
@@ -0,0 +1,138 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/github'
5
+
6
+ class Module
7
+ def metaclass
8
+ class << self;self;end
9
+ end
10
+ end
11
+
12
+ class Spec::NextInstanceProxy
13
+ def initialize
14
+ @deferred = []
15
+ end
16
+
17
+ def method_missing(sym, *args)
18
+ proxy = Spec::NextInstanceProxy.new
19
+ @deferred << [sym, args, proxy]
20
+ proxy
21
+ end
22
+
23
+ def should_receive(*args)
24
+ method_missing(:should_receive, *args)
25
+ end
26
+ alias stub! should_receive
27
+
28
+ def invoke(obj)
29
+ @deferred.each do |(sym, args, proxy)|
30
+ result = obj.send(sym, *args)
31
+ proxy.invoke(result)
32
+ end
33
+ end
34
+ end
35
+
36
+ class Class
37
+ def next_instance
38
+ meth = metaclass.instance_method(:new)
39
+ proxy = Spec::NextInstanceProxy.new
40
+ metaclass.send :define_method, :new do |*args|
41
+ instance = meth.bind(self).call(*args)
42
+ proxy.invoke(instance)
43
+ metaclass.send :define_method, :new, meth
44
+ instance
45
+ end
46
+ proxy
47
+ end
48
+ end
49
+
50
+ module Spec::Example::ExampleGroupSubclassMethods
51
+ def add_guard(klass, name, is_class = false)
52
+ guarded = nil # define variable now for scoping
53
+ target = (is_class ? klass.metaclass : klass)
54
+ sep = (is_class ? "." : "#")
55
+ target.class_eval do
56
+ guarded = instance_method(name)
57
+ define_method name do |*args|
58
+ raise "Testing guards violated: Cannot call #{klass}#{sep}#{name}"
59
+ end
60
+ end
61
+ @guards ||= []
62
+ @guards << [klass, name, is_class, guarded]
63
+ end
64
+
65
+ def add_class_guard(klass, name)
66
+ add_guard(klass, name, true)
67
+ end
68
+
69
+ def unguard(klass, name, is_class = false)
70
+ row = @guards.find { |(k,n,i)| k == klass and n == name and i == is_class }
71
+ raise "#{klass}#{is_class ? "." : "#"}#{name} is not guarded" if row.nil?
72
+ (is_class ? klass.metaclass : klass).class_eval do
73
+ define_method name, row.last
74
+ end
75
+ @guards.delete row
76
+ end
77
+
78
+ def class_unguard(klass, name)
79
+ unguard(klass, name, true)
80
+ end
81
+
82
+ def unguard_all
83
+ @guards ||= []
84
+ @guards.each do |klass, name, is_class, guarded|
85
+ (is_class ? klass.metaclass : klass).class_eval do
86
+ define_method name, guarded
87
+ end
88
+ end
89
+ @guards.clear
90
+ end
91
+ end
92
+
93
+ # prevent the use of `` in tests
94
+ Spec::Runner.configure do |configuration|
95
+ # load this here so it's covered by the `` guard
96
+ configuration.prepend_before(:all) do
97
+ module GitHub
98
+ load 'helpers.rb'
99
+ load 'commands.rb'
100
+ end
101
+ end
102
+
103
+ configuration.prepend_after(:each) do
104
+ GitHub.instance_variable_set :'@options', nil
105
+ GitHub.instance_variable_set :'@debug', nil
106
+ end
107
+
108
+ configuration.prepend_before(:all) do
109
+ self.class.send :include, Spec::Example::ExampleGroupSubclassMethods
110
+ end
111
+
112
+ configuration.prepend_before(:each) do
113
+ add_guard Kernel, :`
114
+ add_guard Kernel, :system
115
+ add_guard Kernel, :fork
116
+ add_guard Kernel, :exec
117
+ add_class_guard Process, :fork
118
+ end
119
+
120
+ configuration.append_after(:each) do
121
+ unguard_all
122
+ end
123
+ end
124
+
125
+ # include this in any example group that defines @helper
126
+ module SetupMethods
127
+ def setup_user_and_branch(user = :user, branch = :master)
128
+ @helper.should_receive(:user_and_branch).any_number_of_times.and_return([user, branch])
129
+ end
130
+
131
+ def setup_url_for(remote = :origin, user = nil, project = :project)
132
+ if user.nil?
133
+ user = remote
134
+ user = "user" if remote == :origin
135
+ end
136
+ @helper.should_receive(:url_for).any_number_of_times.with(remote).and_return("git://github.com/#{user}/#{project}.git")
137
+ end
138
+ end
@@ -0,0 +1,604 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "github" do
4
+ # -- home --
5
+ specify "home should open the project home page" do
6
+ running :home do
7
+ setup_url_for
8
+ @helper.should_receive(:open).once.with("https://github.com/user/project/tree/master")
9
+ end
10
+ end
11
+
12
+ specify "home defunkt should open the home page of defunkt's fork" do
13
+ running :home, "defunkt" do
14
+ setup_url_for
15
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/master")
16
+ end
17
+ end
18
+
19
+ # -- browse --
20
+ specify "browse should open the project home page with the current branch" do
21
+ running :browse do
22
+ setup_url_for
23
+ setup_user_and_branch("user", "test-branch")
24
+ @helper.should_receive(:open).once.with("https://github.com/user/project/tree/test-branch")
25
+ end
26
+ end
27
+
28
+ specify "browse pending should open the project home page with the 'pending' branch" do
29
+ running :browse, "pending" do
30
+ setup_url_for
31
+ setup_user_and_branch("user", "test-branch")
32
+ @helper.should_receive(:open).once.with("https://github.com/user/project/tree/pending")
33
+ end
34
+ end
35
+
36
+ specify "browse defunkt pending should open the home page of defunkt's fork with the 'pending' branch" do
37
+ running :browse, "defunkt", "pending" do
38
+ setup_url_for
39
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
40
+ end
41
+ end
42
+
43
+ specify "browse defunkt/pending should open the home page of defunkt's fork with the 'pending' branch" do
44
+ running :browse, "defunkt/pending" do
45
+ setup_url_for
46
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
47
+ end
48
+ end
49
+
50
+ # -- network --
51
+ specify "network should open the network page for this repo" do
52
+ running :network, 'web' do
53
+ setup_url_for
54
+ @helper.should_receive(:open).once.with("https://github.com/user/project/network")
55
+ end
56
+ end
57
+
58
+ specify "network defunkt should open the network page for defunkt's fork" do
59
+ running :network, 'web', "defunkt" do
60
+ setup_url_for
61
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/network")
62
+ end
63
+ end
64
+
65
+ # -- info --
66
+ specify "info should show info for this project" do
67
+ running :info do
68
+ setup_url_for
69
+ setup_remote(:origin, :user => "user", :ssh => true)
70
+ setup_remote(:defunkt)
71
+ setup_remote(:external, :url => "home:/path/to/project.git")
72
+ stdout.should == <<-EOF
73
+ == Info for project
74
+ You are user
75
+ Currently tracking:
76
+ - user (as origin)
77
+ - defunkt (as defunkt)
78
+ - home:/path/to/project.git (as external)
79
+ EOF
80
+ end
81
+ end
82
+
83
+ # -- track --
84
+ specify "track defunkt should track a new remote for defunkt" do
85
+ running :track, "defunkt" do
86
+ setup_url_for
87
+ @helper.should_receive(:tracking?).with("defunkt").once.and_return(false)
88
+ @command.should_receive(:git).with("remote add defunkt git://github.com/defunkt/project.git").once
89
+ end
90
+ end
91
+
92
+ specify "track --private defunkt should track a new remote for defunkt using ssh" do
93
+ running :track, "--private", "defunkt" do
94
+ setup_url_for
95
+ @helper.should_receive(:tracking?).with("defunkt").and_return(false)
96
+ @command.should_receive(:git).with("remote add defunkt git@github.com:defunkt/project.git")
97
+ end
98
+ end
99
+
100
+ specify "track --ssh defunkt should be equivalent to track --private defunkt" do
101
+ running :track, "--ssh", "defunkt" do
102
+ setup_url_for
103
+ @helper.should_receive(:tracking?).with("defunkt").and_return(false)
104
+ @command.should_receive(:git).with("remote add defunkt git@github.com:defunkt/project.git")
105
+ end
106
+ end
107
+
108
+ specify "track defunkt should die if the defunkt remote exists" do
109
+ running :track, "defunkt" do
110
+ setup_url_for
111
+ @helper.should_receive(:tracking?).with("defunkt").once.and_return(true)
112
+ @command.should_receive(:die).with("Already tracking defunkt").and_return { raise "Died" }
113
+ self.should raise_error("Died")
114
+ end
115
+ end
116
+
117
+ specify "track should die with no args" do
118
+ running :track do
119
+ @command.should_receive(:die).with("Specify a user to track").and_return { raise "Died" }
120
+ self.should raise_error("Died")
121
+ end
122
+ end
123
+
124
+ specify "track should accept user/project syntax" do
125
+ running :track, "defunkt/github-gem.git" do
126
+ setup_url_for
127
+ @helper.should_receive(:tracking?).with("defunkt").and_return false
128
+ @command.should_receive(:git).with("remote add defunkt git://github.com/defunkt/github-gem.git")
129
+ end
130
+ end
131
+
132
+ specify "track defunkt/github-gem.git should function with no origin remote" do
133
+ running :track, "defunkt/github-gem.git" do
134
+ @helper.stub!(:url_for).with(:origin).and_return ""
135
+ @helper.stub!(:tracking?).and_return false
136
+ @command.should_receive(:git).with("remote add defunkt git://github.com/defunkt/github-gem.git")
137
+ self.should_not raise_error(SystemExit)
138
+ stderr.should_not =~ /^Error/
139
+ end
140
+ end
141
+
142
+ specify "track origin defunkt/github-gem should track defunkt/github-gem as the origin remote" do
143
+ running :track, "origin", "defunkt/github-gem" do
144
+ @helper.stub!(:url_for).with(:origin).and_return ""
145
+ @helper.stub!(:tracking?).and_return false
146
+ @command.should_receive(:git).with("remote add origin git://github.com/defunkt/github-gem.git")
147
+ stderr.should_not =~ /^Error/
148
+ end
149
+ end
150
+
151
+ specify "track --private origin defunkt/github-gem should track defunkt/github-gem as the origin remote using ssh" do
152
+ running :track, "--private", "origin", "defunkt/github-gem" do
153
+ @helper.stub!(:url_for).with(:origin).and_return ""
154
+ @helper.stub!(:tracking?).and_return false
155
+ @command.should_receive(:git).with("remote add origin git@github.com:defunkt/github-gem.git")
156
+ stderr.should_not =~ /^Error/
157
+ end
158
+ end
159
+
160
+ # -- fetch --
161
+ specify "fetch should die with no args" do
162
+ running :fetch do
163
+ @command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died "}
164
+ self.should raise_error("Died")
165
+ end
166
+ end
167
+
168
+ specify "pull defunkt should start tracking defunkt if they're not already tracked" do
169
+ running :pull, "defunkt" do
170
+ mock_members 'defunkt'
171
+ setup_remote(:origin, :user => "user", :ssh => true)
172
+ setup_remote(:external, :url => "home:/path/to/project.git")
173
+ GitHub.should_receive(:invoke).with(:track, "defunkt").and_return { raise "Tracked" }
174
+ self.should raise_error("Tracked")
175
+ end
176
+ end
177
+
178
+ specify "pull defunkt should create defunkt/master and pull from the defunkt remote" do
179
+ running :pull, "defunkt" do
180
+ mock_members 'defunkt'
181
+ setup_remote(:defunkt)
182
+ @helper.should_receive(:branch_dirty?).and_return false
183
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/master HEAD").ordered
184
+ @command.should_receive(:git).with("checkout defunkt/master").ordered
185
+ @command.should_receive(:git_exec).with("fetch defunkt master").ordered
186
+ stdout.should == "Switching to defunkt/master\n"
187
+ end
188
+ end
189
+
190
+ specify "pull defunkt should switch to pre-existing defunkt/master and pull from the defunkt remote" do
191
+ running :pull, "defunkt" do
192
+ mock_members 'defunkt'
193
+ setup_remote(:defunkt)
194
+ @helper.should_receive(:branch_dirty?).and_return true
195
+ @command.should_receive(:die).with("Unable to switch branches, your current branch has uncommitted changes").and_return { raise "Died" }
196
+ self.should raise_error("Died")
197
+ end
198
+ end
199
+
200
+ specify "fetch defunkt/wip should create defunkt/wip and fetch from wip branch on defunkt remote" do
201
+ running :fetch, "defunkt/wip" do
202
+ setup_remote(:defunkt, :remote_branches => ["master", "wip"])
203
+ @helper.should_receive(:branch_dirty?).and_return false
204
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/wip HEAD").ordered
205
+ @command.should_receive(:git).with("checkout defunkt/wip").ordered
206
+ @command.should_receive(:git_exec).with("fetch defunkt wip").ordered
207
+ stdout.should == "Switching to defunkt/wip\n"
208
+ end
209
+ end
210
+
211
+ specify "fetch --merge defunkt should fetch from defunkt remote into current branch" do
212
+ running :fetch, "--merge", "defunkt" do
213
+ setup_remote(:defunkt)
214
+ @helper.should_receive(:branch_dirty?).and_return false
215
+ @command.should_receive(:git_exec).with("fetch defunkt master")
216
+ end
217
+ end
218
+
219
+ # -- fetch --
220
+ specify "fetch should die with no args" do
221
+ running :fetch do
222
+ @command.should_receive(:die).with("Specify a user to fetch from").and_return { raise "Died" }
223
+ self.should raise_error("Died")
224
+ end
225
+ end
226
+
227
+ specify "fetch defunkt should start tracking defunkt if they're not already tracked" do
228
+ running :fetch, "defunkt" do
229
+ setup_remote(:origin, :user => "user", :ssh => true)
230
+ setup_remote(:external, :url => "home:/path/to/project.git")
231
+ GitHub.should_receive(:invoke).with(:track, "defunkt").and_return { raise "Tracked" }
232
+ self.should raise_error("Tracked")
233
+ end
234
+ end
235
+
236
+ specify "fetch defunkt should create defunkt/master and fetch from the defunkt remote" do
237
+ running :fetch, "defunkt" do
238
+ setup_remote(:defunkt)
239
+ @helper.should_receive(:branch_dirty?).and_return false
240
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/master HEAD").ordered
241
+ @command.should_receive(:git).with("checkout defunkt/master").ordered
242
+ @command.should_receive(:git_exec).with("fetch defunkt master").ordered
243
+ stdout.should == "Switching to defunkt/master\n"
244
+ end
245
+ end
246
+
247
+ specify "pull defunkt wip should create defunkt/wip and pull from wip branch on defunkt remote" do
248
+ running :pull, "defunkt", "wip" do
249
+ mock_members 'defunkt'
250
+ setup_remote(:defunkt)
251
+ @helper.should_receive(:branch_dirty?).and_return true
252
+ @command.should_receive(:die).with("Unable to switch branches, your current branch has uncommitted changes").and_return { raise "Died" }
253
+ self.should raise_error("Died")
254
+ end
255
+ end
256
+
257
+ specify "pull defunkt/wip should switch to pre-existing defunkt/wip and pull from wip branch on defunkt remote" do
258
+ running :pull, "defunkt/wip" do
259
+ mock_members 'defunkt'
260
+ setup_remote(:defunkt)
261
+ @command.should_receive(:git).with("checkout -b defunkt/wip").ordered.and_return do
262
+ mock("checkout -b defunkt/wip").tap { |m| m.should_receive(:error?) { true } }
263
+ end
264
+ @command.should_receive(:git).with("checkout defunkt/wip").ordered
265
+ @command.should_receive(:git_exec).with("fetch defunkt wip").ordered
266
+ stdout.should == "Switching to defunkt/wip\n"
267
+ end
268
+ end
269
+
270
+ specify "pull --merge defunkt should pull from defunkt remote into current branch" do
271
+ running :pull, "--merge", "defunkt" do
272
+ mock_members 'defunkt'
273
+ setup_remote(:defunkt)
274
+ @helper.should_receive(:branch_dirty?).and_return false
275
+ @command.should_receive(:git_exec).with("fetch defunkt master")
276
+ end
277
+ end
278
+
279
+ specify "pull falls through for non-recognized commands" do
280
+ running :pull, 'remote' do
281
+ mock_members 'defunkt'
282
+ @command.should_receive(:git_exec).with("pull remote")
283
+ end
284
+ end
285
+
286
+ specify "pull passes along args when falling through" do
287
+ running :pull, 'remote', '--stat' do
288
+ mock_members 'defunkt'
289
+ @command.should_receive(:git_exec).with("pull remote --stat")
290
+ end
291
+ end
292
+
293
+ # -- clone --
294
+ specify "clone should die with no args" do
295
+ running :clone do
296
+ @command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died" }
297
+ self.should raise_error("Died")
298
+ end
299
+ end
300
+
301
+ specify "clone should fall through with just one arg" do
302
+ running :clone, "git://git.kernel.org/linux.git" do
303
+ @command.should_receive(:git_exec).with("clone git://git.kernel.org/linux.git")
304
+ end
305
+ end
306
+
307
+ specify "clone defunkt github-gem should clone the repo" do
308
+ running :clone, "defunkt", "github-gem" do
309
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
310
+ end
311
+ end
312
+
313
+ specify "clone defunkt/github-gem should clone the repo" do
314
+ running :clone, "defunkt/github-gem" do
315
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
316
+ end
317
+ end
318
+
319
+ specify "clone --ssh defunkt github-gem should clone the repo using the private URL" do
320
+ running :clone, "--ssh", "defunkt", "github-gem" do
321
+ @command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git")
322
+ end
323
+ end
324
+
325
+ specify "clone defunkt github-gem repo should clone the repo into the dir 'repo'" do
326
+ running :clone, "defunkt", "github-gem", "repo" do
327
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
328
+ end
329
+ end
330
+
331
+ specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
332
+ running :clone, "defunkt/github-gem", "repo" do
333
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
334
+ end
335
+ end
336
+
337
+ specify "clone --ssh defunkt github-gem repo should clone the repo using the private URL into the dir 'repo'" do
338
+ running :clone, "--ssh", "defunkt", "github-gem", "repo" do
339
+ @command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git repo")
340
+ end
341
+ end
342
+
343
+ specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
344
+ running :clone, "defunkt/github-gem", "repo" do
345
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
346
+ end
347
+ end
348
+
349
+ # -- pull-request --
350
+ specify "pull-request should die with no args" do
351
+ running :'pull-request' do
352
+ setup_url_for
353
+ @command.should_receive(:die).with("Specify a user for the pull request").and_return { raise "Died" }
354
+ self.should raise_error("Died")
355
+ end
356
+ end
357
+
358
+ specify "pull-request user should track user if untracked" do
359
+ running :'pull-request', "user" do
360
+ setup_url_for
361
+ setup_remote :origin, :user => "kballard"
362
+ setup_remote :defunkt
363
+ GitHub.should_receive(:invoke).with(:track, "user").and_return { raise "Tracked" }
364
+ self.should raise_error("Tracked")
365
+ end
366
+ end
367
+
368
+ specify "pull-request user/branch should generate a pull request" do
369
+ running :'pull-request', "user/branch" do
370
+ setup_url_for
371
+ setup_remote :origin, :user => "kballard"
372
+ setup_remote :user
373
+ @command.should_receive(:git_exec).with("request-pull user/branch origin")
374
+ end
375
+ end
376
+
377
+ specify "pull-request user should generate a pull request with branch master" do
378
+ running :'pull-request', "user" do
379
+ setup_url_for
380
+ setup_remote :origin, :user => "kballard"
381
+ setup_remote :user
382
+ @command.should_receive(:git_exec).with("request-pull user/master origin")
383
+ end
384
+ end
385
+
386
+ specify "pull-request user branch should generate a pull request" do
387
+ running:'pull-request', "user", "branch" do
388
+ setup_url_for
389
+ setup_remote :origin, :user => "kballard"
390
+ setup_remote :user
391
+ @command.should_receive(:git_exec).with("request-pull user/branch origin")
392
+ end
393
+ end
394
+
395
+ # -- fallthrough --
396
+ specify "should fall through to actual git commands" do
397
+ running :commit do
398
+ @command.should_receive(:git_exec).with("commit")
399
+ end
400
+ end
401
+
402
+ specify "should pass along arguments when falling through" do
403
+ running :commit, '-a', '-m', 'yo mama' do
404
+ @command.should_receive(:git_exec).with("commit -a -m 'yo mama'")
405
+ end
406
+ end
407
+
408
+ # -- default --
409
+ specify "should print the default message" do
410
+ running :default do
411
+ GitHub.should_receive(:descriptions).any_number_of_times.and_return({
412
+ "home" => "Open the home page",
413
+ "track" => "Track a new repo",
414
+ "browse" => "Browse the github page for this branch",
415
+ "command" => "description"
416
+ })
417
+ GitHub.should_receive(:flag_descriptions).any_number_of_times.and_return({
418
+ "home" => {:flag => "Flag description"},
419
+ "track" => {:flag1 => "Flag one", :flag2 => "Flag two"},
420
+ "browse" => {},
421
+ "command" => {}
422
+ })
423
+ @command.should_receive(:puts).with("Usage: github command <space separated arguments>", '').ordered
424
+ @command.should_receive(:puts).with("Available commands:", '').ordered
425
+ @command.should_receive(:puts).with(" home => Open the home page")
426
+ @command.should_receive(:puts).with(" --flag: Flag description")
427
+ @command.should_receive(:puts).with(" track => Track a new repo")
428
+ @command.should_receive(:puts).with(" --flag1: Flag one")
429
+ @command.should_receive(:puts).with(" --flag2: Flag two")
430
+ @command.should_receive(:puts).with(" browse => Browse the github page for this branch")
431
+ @command.should_receive(:puts).with(" command => description")
432
+ @command.should_receive(:puts).with()
433
+ end
434
+ end
435
+
436
+ # -----------------
437
+
438
+ def running(cmd, *args, &block)
439
+ Runner.new(self, cmd, *args, &block).run
440
+ end
441
+
442
+ class Runner
443
+ include SetupMethods
444
+
445
+ def initialize(parent, cmd, *args, &block)
446
+ @cmd_name = cmd.to_s
447
+ @command = GitHub.find_command(cmd)
448
+ @helper = @command.helper
449
+ @args = args
450
+ @block = block
451
+ @parent = parent
452
+ end
453
+
454
+ def run
455
+ self.instance_eval &@block
456
+ mock_remotes unless @remotes.nil?
457
+ GitHub.should_receive(:load).with("commands.rb")
458
+ GitHub.should_receive(:load).with("helpers.rb")
459
+ args = @args.clone
460
+ GitHub.parse_options(args) # strip out the flags
461
+ GitHub.should_receive(:invoke).with(@cmd_name, *args).and_return do
462
+ GitHub.send(GitHub.send(:__mock_proxy).send(:munge, :invoke), @cmd_name, *args)
463
+ end
464
+ invoke = lambda { GitHub.activate([@cmd_name, *@args]) }
465
+ if @expected_result
466
+ expectation, result = @expected_result
467
+ case result
468
+ when Spec::Matchers::RaiseError, Spec::Matchers::Change, Spec::Matchers::ThrowSymbol
469
+ invoke.send expectation, result
470
+ else
471
+ invoke.call.send expectation, result
472
+ end
473
+ else
474
+ invoke.call
475
+ end
476
+ @stdout_mock.invoke unless @stdout_mock.nil?
477
+ @stderr_mock.invoke unless @stderr_mock.nil?
478
+ end
479
+
480
+ def setup_remote(remote, options = {:user => nil, :project => "project", :remote_branches => nil})
481
+ @remotes ||= {}
482
+ @remote_branches ||= {}
483
+ user = options[:user] || remote
484
+ project = options[:project]
485
+ ssh = options[:ssh]
486
+ url = options[:url]
487
+ remote_branches = options[:remote_branches] || ["master"]
488
+ if url
489
+ @remotes[remote.to_sym] = url
490
+ elsif ssh
491
+ @remotes[remote.to_sym] = "git@github.com:#{user}/#{project}.git"
492
+ else
493
+ @remotes[remote.to_sym] = "git://github.com/#{user}/#{project}.git"
494
+ end
495
+
496
+ @remote_branches[remote.to_sym] = (@remote_branches[remote.to_sym] || Array.new) | remote_branches
497
+ @helper.should_receive(:remote_branch?).any_number_of_times.and_return do |remote, branch|
498
+ @remote_branches.fetch(remote.to_sym,[]).include?(branch)
499
+ end
500
+ end
501
+
502
+ def mock_remotes()
503
+ @helper.should_receive(:remotes).any_number_of_times.and_return(@remotes)
504
+ end
505
+
506
+ def mock_members(members)
507
+ @helper.should_receive(:network_members).any_number_of_times.and_return(members)
508
+ end
509
+
510
+ def should(result)
511
+ @expected_result = [:should, result]
512
+ end
513
+
514
+ def should_not(result)
515
+ @expected_result = [:should_not, result]
516
+ end
517
+
518
+ def stdout
519
+ if @stdout_mock.nil?
520
+ output = ""
521
+ @stdout_mock = DeferredMock.new(output)
522
+ $stdout.should_receive(:write).any_number_of_times do |str|
523
+ output << str
524
+ end
525
+ end
526
+ @stdout_mock
527
+ end
528
+
529
+ def stderr
530
+ if @stderr_mock.nil?
531
+ output = ""
532
+ @stderr_mock = DeferredMock.new(output)
533
+ $stderr.should_receive(:write).any_number_of_times do |str|
534
+ output << str
535
+ end
536
+ end
537
+ @stderr_mock
538
+ end
539
+
540
+ class DeferredMock
541
+ def initialize(obj = nil)
542
+ @obj = obj
543
+ @calls = []
544
+ @expectations = []
545
+ end
546
+
547
+ attr_reader :obj
548
+
549
+ def invoke(obj = nil)
550
+ obj ||= @obj
551
+ @calls.each do |sym, args|
552
+ obj.send sym, *args
553
+ end
554
+ @expectations.each do |exp|
555
+ exp.invoke
556
+ end
557
+ end
558
+
559
+ def should(*args)
560
+ if args.empty?
561
+ exp = Expectation.new(self, :should)
562
+ @expectations << exp
563
+ exp
564
+ else
565
+ @calls << [:should, args]
566
+ end
567
+ end
568
+
569
+ def should_not(*args)
570
+ if args.empty?
571
+ exp = Expectation.new(self, :should_not)
572
+ @expectations << exp
573
+ exp
574
+ else
575
+ @calls << [:should_not, args]
576
+ end
577
+ end
578
+
579
+ class Expectation
580
+ def initialize(mock, call)
581
+ @mock = mock
582
+ @call = call
583
+ @calls = []
584
+ end
585
+
586
+ undef_method *(instance_methods.map { |x| x.to_sym } - [:__id__, :__send__])
587
+
588
+ def invoke
589
+ @calls.each do |sym, args|
590
+ (@mock.obj.send @call).send sym, *args
591
+ end
592
+ end
593
+
594
+ def method_missing(sym, *args)
595
+ @calls << [sym, args]
596
+ end
597
+ end
598
+ end
599
+
600
+ def method_missing(sym, *args)
601
+ @parent.send sym, *args
602
+ end
603
+ end
604
+ end