snowblink-github 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
data/spec/ui_spec.rb ADDED
@@ -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