github 0.1.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +37 -0
- data/Manifest +33 -12
- data/README.md +187 -0
- data/Rakefile +44 -0
- data/bin/gh +8 -0
- data/bin/github +4 -1
- data/github.gemspec +29 -34
- data/lib/commands/commands.rb +249 -0
- data/lib/commands/helpers.rb +486 -0
- data/lib/commands/issues.rb +17 -0
- data/lib/commands/network.rb +110 -0
- data/lib/github.rb +117 -29
- data/lib/github/command.rb +69 -14
- data/lib/github/extensions.rb +39 -0
- data/lib/github/ui.rb +19 -0
- data/setup.rb +1551 -0
- data/spec/command_spec.rb +82 -0
- data/spec/commands/command_browse_spec.rb +36 -0
- data/spec/commands/command_clone_spec.rb +87 -0
- data/spec/commands/command_create-from-local_spec.rb +7 -0
- data/spec/commands/command_fetch_spec.rb +56 -0
- data/spec/commands/command_fork_spec.rb +44 -0
- data/spec/commands/command_helper.rb +170 -0
- data/spec/commands/command_home_spec.rb +20 -0
- data/spec/commands/command_info_spec.rb +23 -0
- data/spec/commands/command_issues_spec.rb +97 -0
- data/spec/commands/command_network_spec.rb +30 -0
- data/spec/commands/command_pull-request_spec.rb +51 -0
- data/spec/commands/command_pull_spec.rb +82 -0
- data/spec/commands/command_search_spec.rb +34 -0
- data/spec/commands/command_track_spec.rb +82 -0
- data/spec/commands_spec.rb +49 -0
- data/spec/extensions_spec.rb +36 -0
- data/spec/github_spec.rb +85 -0
- data/spec/helper_spec.rb +368 -0
- data/spec/spec_helper.rb +160 -4
- data/spec/windoze_spec.rb +38 -0
- metadata +114 -47
- data/README +0 -49
- data/commands/commands.rb +0 -54
- data/commands/helpers.rb +0 -79
- data/spec/helpers/owner_spec.rb +0 -12
- data/spec/helpers/project_spec.rb +0 -12
- data/spec/helpers/public_url_for_spec.rb +0 -12
- data/spec/helpers/repo_for_spec.rb +0 -12
- data/spec/helpers/user_and_repo_from_spec.rb +0 -15
- data/spec/helpers/user_for_spec.rb +0 -12
data/spec/command_spec.rb
CHANGED
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe GitHub::Command do
|
4
|
+
before(:each) do
|
5
|
+
@command = GitHub::Command.new(proc { |x| puts x })
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return a GitHub::Helper" do
|
9
|
+
@command.helper.should be_instance_of(GitHub::Helper)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should call successfully" do
|
13
|
+
@command.should_receive(:puts).with("test").once
|
14
|
+
@command.call("test")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return options" do
|
18
|
+
GitHub.should_receive(:options).with().once.and_return({:ssh => true})
|
19
|
+
@command.options.should == {:ssh => true}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should successfully call out to the shell" do
|
23
|
+
unguard(Kernel, :fork)
|
24
|
+
unguard(Kernel, :exec)
|
25
|
+
hi = @command.sh("echo hi")
|
26
|
+
hi.should == "hi"
|
27
|
+
hi.out.should == "hi"
|
28
|
+
hi.out?.should be(true)
|
29
|
+
hi.error.should be_nil
|
30
|
+
hi.error?.should be(false)
|
31
|
+
hi.command.should == "echo hi"
|
32
|
+
if RUBY_PLATFORM =~ /mingw|mswin/
|
33
|
+
command = "cmd /c echo bye >&2"
|
34
|
+
else
|
35
|
+
command = "echo bye >&2"
|
36
|
+
end
|
37
|
+
bye = @command.sh(command)
|
38
|
+
bye.should == "bye"
|
39
|
+
bye.out.should be_nil
|
40
|
+
bye.out?.should be(false)
|
41
|
+
bye.error.should == "bye"
|
42
|
+
bye.error?.should be(true)
|
43
|
+
bye.command.should == command
|
44
|
+
hi_and_bye = @command.sh("echo hi; echo bye >&2")
|
45
|
+
hi_and_bye.should == "hi"
|
46
|
+
hi_and_bye.out.should == "hi"
|
47
|
+
hi_and_bye.out?.should be(true)
|
48
|
+
hi_and_bye.error.should == "bye"
|
49
|
+
hi_and_bye.error?.should be(true)
|
50
|
+
hi_and_bye.command.should == "echo hi; echo bye >&2"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return the results of a git operation" do
|
54
|
+
GitHub::Command::Shell.should_receive(:new).with("git rev-parse master").once.and_return do |*cmds|
|
55
|
+
s = mock("GitHub::Commands::Shell")
|
56
|
+
s.should_receive(:run).once.and_return("sha1")
|
57
|
+
s
|
58
|
+
end
|
59
|
+
@command.git("rev-parse master").should == "sha1"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should print the results of a git operation" do
|
63
|
+
@command.should_receive(:puts).with("sha1").once
|
64
|
+
GitHub::Command::Shell.should_receive(:new).with("git rev-parse master").once.and_return do |*cmds|
|
65
|
+
s = mock("GitHub::Commands::Shell")
|
66
|
+
s.should_receive(:run).once.and_return("sha1")
|
67
|
+
s
|
68
|
+
end
|
69
|
+
@command.pgit("rev-parse master")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should exec a git command" do
|
73
|
+
@command.should_receive(:exec).with("git rev-parse master").once
|
74
|
+
@command.git_exec "rev-parse master"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should die" do
|
78
|
+
@command.should_receive(:puts).once.with("=> message")
|
79
|
+
@command.should_receive(:exit!).once
|
80
|
+
@command.die "message"
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require File.dirname(__FILE__) + '/command_helper'
|
3
|
+
|
4
|
+
describe "github browse" do
|
5
|
+
include CommandHelper
|
6
|
+
|
7
|
+
specify "browse should open the project home page with the current branch" do
|
8
|
+
running :browse do
|
9
|
+
setup_url_for
|
10
|
+
setup_user_and_branch("user", "test-branch")
|
11
|
+
@helper.should_receive(:open).once.with("https://github.com/user/project/tree/test-branch")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "browse pending should open the project home page with the 'pending' branch" do
|
16
|
+
running :browse, "pending" do
|
17
|
+
setup_url_for
|
18
|
+
setup_user_and_branch("user", "test-branch")
|
19
|
+
@helper.should_receive(:open).once.with("https://github.com/user/project/tree/pending")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "browse defunkt pending should open the home page of defunkt's fork with the 'pending' branch" do
|
24
|
+
running :browse, "defunkt", "pending" do
|
25
|
+
setup_url_for
|
26
|
+
@helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "browse defunkt/pending should open the home page of defunkt's fork with the 'pending' branch" do
|
31
|
+
running :browse, "defunkt/pending" do
|
32
|
+
setup_url_for
|
33
|
+
@helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require File.dirname(__FILE__) + '/command_helper'
|
3
|
+
|
4
|
+
describe "github clone" do
|
5
|
+
include CommandHelper
|
6
|
+
|
7
|
+
# -- clone --
|
8
|
+
specify "clone should die with no args" do
|
9
|
+
running :clone do
|
10
|
+
@command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died" }
|
11
|
+
self.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "clone should fall through with just one arg" do
|
16
|
+
running :clone, "git://git.kernel.org/linux.git" do
|
17
|
+
@command.should_receive(:git_exec).with("clone git://git.kernel.org/linux.git")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "clone defunkt github-gem should clone the repo" do
|
22
|
+
running :clone, "defunkt", "github-gem" do
|
23
|
+
@command.should_receive(:current_user?).and_return(nil)
|
24
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "clone defunkt/github-gem should clone the repo" do
|
29
|
+
running :clone, "defunkt/github-gem" do
|
30
|
+
@command.should_receive(:current_user?).and_return(nil)
|
31
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "clone --ssh defunkt github-gem should clone the repo using the private URL" do
|
36
|
+
running :clone, "--ssh", "defunkt", "github-gem" do
|
37
|
+
@command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "clone defunkt github-gem repo should clone the repo into the dir 'repo'" do
|
42
|
+
running :clone, "defunkt", "github-gem", "repo" do
|
43
|
+
@command.should_receive(:current_user?).and_return(nil)
|
44
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
|
49
|
+
running :clone, "defunkt/github-gem", "repo" do
|
50
|
+
@command.should_receive(:current_user?).and_return(nil)
|
51
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "clone --ssh defunkt github-gem repo should clone the repo using the private URL into the dir 'repo'" do
|
56
|
+
running :clone, "--ssh", "defunkt", "github-gem", "repo" do
|
57
|
+
@command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git repo")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
|
62
|
+
running :clone, "defunkt/github-gem", "repo" do
|
63
|
+
@command.should_receive(:current_user?).and_return(nil)
|
64
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "clone a selected repo after showing search results" do
|
69
|
+
running :clone, "--search", "github-gem" do
|
70
|
+
json = StringIO.new '{"repositories":[' +
|
71
|
+
'{"name":"github-gem","size":300,"followers":499,"username":"defunkt","language":"Ruby","fork":false,"id":"repo-1653","type":"repo","pushed":"2008-12-04T03:14:00Z","forks":59,"description":"The official `github` command line helper for simplifying your GitHub experience.","score":3.4152448,"created":"2008-02-28T09:35:34Z"},' +
|
72
|
+
'{"name":"github-gem-builder","size":76,"followers":26,"username":"pjhyett","language":"Ruby","fork":false,"id":"repo-67489","type":"repo","pushed":"2008-11-04T04:54:57Z","forks":3,"description":"The scripts used to build RubyGems on GitHub","score":3.4152448,"created":"2008-10-24T22:29:32Z"}' +
|
73
|
+
']}'
|
74
|
+
json.rewind
|
75
|
+
question_list = <<-LIST.gsub(/^ /, '').split("\n").compact
|
76
|
+
defunkt/github-gem # The official `github` command line helper for simplifying your GitHub experience.
|
77
|
+
pjhyett/github-gem-builder # The scripts used to build RubyGems on GitHub
|
78
|
+
LIST
|
79
|
+
@command.should_receive(:open).with("http://github.com/api/v1/json/search/github-gem").and_return(json)
|
80
|
+
GitHub::UI.should_receive(:display_select_list).with(question_list).
|
81
|
+
and_return("defunkt/github-gem")
|
82
|
+
@command.should_receive(:current_user?).and_return(nil)
|
83
|
+
@command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require File.dirname(__FILE__) + '/command_helper'
|
3
|
+
|
4
|
+
describe "github fetch" do
|
5
|
+
include CommandHelper
|
6
|
+
|
7
|
+
specify "fetch should die with no args" do
|
8
|
+
running :fetch do
|
9
|
+
@command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died" }
|
10
|
+
self.should raise_error(RuntimeError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "fetch defunkt should start tracking defunkt if they're not already tracked" do
|
15
|
+
running :fetch, "defunkt" do
|
16
|
+
setup_remote(:origin, :user => "user", :ssh => true)
|
17
|
+
setup_remote(:external, :url => "home:/path/to/project.git")
|
18
|
+
GitHub.should_receive(:invoke).with(:track, "defunkt").and_return { raise "Tracked" }
|
19
|
+
self.should raise_error("Tracked")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "fetch defunkt should create defunkt/master and fetch from the defunkt remote" do
|
24
|
+
running :fetch, "defunkt" do
|
25
|
+
setup_remote(:defunkt)
|
26
|
+
@helper.should_receive(:branch_dirty?).and_return false
|
27
|
+
@command.should_receive(:git).with("fetch defunkt master:refs/remotes/defunkt/master").ordered
|
28
|
+
@command.should_receive(:git).with("update-ref refs/heads/defunkt/master refs/remotes/defunkt/master").ordered
|
29
|
+
@command.should_receive(:git_exec).with("checkout defunkt/master").ordered
|
30
|
+
stdout.should == "Fetching defunkt/master\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "fetch defunkt/wip should create defunkt/wip and fetch from wip branch on defunkt remote" do
|
35
|
+
running :fetch, "defunkt/wip" do
|
36
|
+
setup_remote(:defunkt, :remote_branches => ["master", "wip"])
|
37
|
+
@helper.should_receive(:branch_dirty?).and_return false
|
38
|
+
@command.should_receive(:git).with("fetch defunkt wip:refs/remotes/defunkt/wip").ordered
|
39
|
+
@command.should_receive(:git).with("update-ref refs/heads/defunkt/wip refs/remotes/defunkt/wip").ordered
|
40
|
+
@command.should_receive(:git_exec).with("checkout defunkt/wip").ordered
|
41
|
+
stdout.should == "Fetching defunkt/wip\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "fetch --merge defunkt should fetch from defunkt remote into current branch" do
|
46
|
+
running :fetch, "--merge", "defunkt" do
|
47
|
+
setup_remote(:defunkt)
|
48
|
+
@helper.should_receive(:branch_dirty?).and_return false
|
49
|
+
@command.should_receive(:git).with("fetch defunkt master:refs/remotes/defunkt/master").ordered
|
50
|
+
@command.should_receive(:git).with("update-ref refs/heads/defunkt/master refs/remotes/defunkt/master").ordered
|
51
|
+
@command.should_receive(:git_exec).with("checkout defunkt/master").ordered
|
52
|
+
stdout.should == "Fetching defunkt/master\n"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require File.dirname(__FILE__) + '/command_helper'
|
3
|
+
|
4
|
+
describe "github fork" do
|
5
|
+
include CommandHelper
|
6
|
+
|
7
|
+
specify "fork should print out help" do
|
8
|
+
running :fork do
|
9
|
+
@helper.should_receive(:remotes).and_return({})
|
10
|
+
@command.should_receive(:die).with("Specify a user/project to fork, or run from within a repo").and_return { raise "Died" }
|
11
|
+
self.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "fork this repo should create github fork and replace origin remote" do
|
16
|
+
running :fork do
|
17
|
+
setup_github_token
|
18
|
+
setup_url_for "origin", "defunkt", "github-gem"
|
19
|
+
setup_remote "origin", :user => "defunkt", :project => "github-gem"
|
20
|
+
setup_user_and_branch
|
21
|
+
@command.should_receive(:sh).with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
|
22
|
+
@command.should_receive(:git, "config remote.origin.url git@github.com/drnic/github-gem.git")
|
23
|
+
stdout.should == "defunkt/github-gem forked\n"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "fork a user/project repo" do
|
28
|
+
running :fork, "defunkt/github-gem" do
|
29
|
+
setup_github_token
|
30
|
+
@command.should_receive(:sh).with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
|
31
|
+
@command.should_receive(:git_exec, "clone git://github.com/defunkt/github-gem.git")
|
32
|
+
stdout.should == "Giving GitHub a moment to create the fork...\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "fork a user project repo" do
|
37
|
+
running :fork, "defunkt", "github-gem" do
|
38
|
+
setup_github_token
|
39
|
+
@command.should_receive("sh").with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
|
40
|
+
@command.should_receive(:git_exec, "clone git://github.com/defunkt/github-gem.git")
|
41
|
+
stdout.should == "Giving GitHub a moment to create the fork...\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module CommandHelper
|
2
|
+
def running(cmd, *args, &block)
|
3
|
+
Runner.new(self, cmd, *args, &block).run
|
4
|
+
end
|
5
|
+
|
6
|
+
class Runner
|
7
|
+
include SetupMethods
|
8
|
+
|
9
|
+
def initialize(parent, cmd, *args, &block)
|
10
|
+
@cmd_name = cmd.to_s
|
11
|
+
@command = GitHub.find_command(cmd)
|
12
|
+
@helper = @command.helper
|
13
|
+
@args = args
|
14
|
+
@block = block
|
15
|
+
@parent = parent
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
self.instance_eval &@block
|
20
|
+
mock_remotes unless @remotes.nil?
|
21
|
+
GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/commands.rb")
|
22
|
+
GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/helpers.rb")
|
23
|
+
GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/network.rb")
|
24
|
+
GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/issues.rb")
|
25
|
+
args = @args.clone
|
26
|
+
GitHub.parse_options(args) # strip out the flags
|
27
|
+
GitHub.should_receive(:invoke).with(@cmd_name, *args).and_return do
|
28
|
+
GitHub.send(GitHub.send(:__mock_proxy).send(:munge, :invoke), @cmd_name, *args)
|
29
|
+
end
|
30
|
+
invoke = lambda { GitHub.activate([@cmd_name, *@args]) }
|
31
|
+
if @expected_result
|
32
|
+
expectation, result = @expected_result
|
33
|
+
case result
|
34
|
+
when Spec::Matchers::RaiseError, Spec::Matchers::Change, Spec::Matchers::ThrowSymbol
|
35
|
+
invoke.send expectation, result
|
36
|
+
else
|
37
|
+
invoke.call.send expectation, result
|
38
|
+
end
|
39
|
+
else
|
40
|
+
invoke.call
|
41
|
+
end
|
42
|
+
@stdout_mock.invoke unless @stdout_mock.nil?
|
43
|
+
@stderr_mock.invoke unless @stderr_mock.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup_remote(remote, options = {:user => nil, :project => "project", :remote_branches => nil})
|
47
|
+
@remotes ||= {}
|
48
|
+
@remote_branches ||= {}
|
49
|
+
user = options[:user] || remote
|
50
|
+
project = options[:project]
|
51
|
+
ssh = options[:ssh]
|
52
|
+
url = options[:url]
|
53
|
+
remote_branches = options[:remote_branches] || ["master"]
|
54
|
+
if url
|
55
|
+
@remotes[remote] = url
|
56
|
+
elsif ssh
|
57
|
+
@remotes[remote] = "git@github.com:#{user}/#{project}.git"
|
58
|
+
else
|
59
|
+
@remotes[remote] = "git://github.com/#{user}/#{project}.git"
|
60
|
+
end
|
61
|
+
|
62
|
+
@remote_branches[remote] = (@remote_branches[remote] || Array.new) | remote_branches
|
63
|
+
@helper.should_receive(:remote_branch?).any_number_of_times.and_return do |remote, branch|
|
64
|
+
@remote_branches.fetch(remote.to_sym,[]).include?(branch)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def mock_remotes()
|
69
|
+
@helper.should_receive(:remotes).any_number_of_times.and_return(@remotes)
|
70
|
+
end
|
71
|
+
|
72
|
+
def mock_members(members)
|
73
|
+
@helper.should_receive(:network_members).any_number_of_times.and_return(members)
|
74
|
+
end
|
75
|
+
|
76
|
+
def should(result)
|
77
|
+
@expected_result = [:should, result]
|
78
|
+
end
|
79
|
+
|
80
|
+
def should_not(result)
|
81
|
+
@expected_result = [:should_not, result]
|
82
|
+
end
|
83
|
+
|
84
|
+
def stdout
|
85
|
+
if @stdout_mock.nil?
|
86
|
+
output = ""
|
87
|
+
@stdout_mock = DeferredMock.new(output)
|
88
|
+
$stdout.should_receive(:write).any_number_of_times do |str|
|
89
|
+
output << str
|
90
|
+
end
|
91
|
+
end
|
92
|
+
@stdout_mock
|
93
|
+
end
|
94
|
+
|
95
|
+
def stderr
|
96
|
+
if @stderr_mock.nil?
|
97
|
+
output = ""
|
98
|
+
@stderr_mock = DeferredMock.new(output)
|
99
|
+
$stderr.should_receive(:write).any_number_of_times do |str|
|
100
|
+
output << str
|
101
|
+
end
|
102
|
+
end
|
103
|
+
@stderr_mock
|
104
|
+
end
|
105
|
+
|
106
|
+
class DeferredMock
|
107
|
+
def initialize(obj = nil)
|
108
|
+
@obj = obj
|
109
|
+
@calls = []
|
110
|
+
@expectations = []
|
111
|
+
end
|
112
|
+
|
113
|
+
attr_reader :obj
|
114
|
+
|
115
|
+
def invoke(obj = nil)
|
116
|
+
obj ||= @obj
|
117
|
+
@calls.each do |sym, args|
|
118
|
+
obj.send sym, *args
|
119
|
+
end
|
120
|
+
@expectations.each do |exp|
|
121
|
+
exp.invoke
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def should(*args)
|
126
|
+
if args.empty?
|
127
|
+
exp = Expectation.new(self, :should)
|
128
|
+
@expectations << exp
|
129
|
+
exp
|
130
|
+
else
|
131
|
+
@calls << [:should, args]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def should_not(*args)
|
136
|
+
if args.empty?
|
137
|
+
exp = Expectation.new(self, :should_not)
|
138
|
+
@expectations << exp
|
139
|
+
exp
|
140
|
+
else
|
141
|
+
@calls << [:should_not, args]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class Expectation
|
146
|
+
def initialize(mock, call)
|
147
|
+
@mock = mock
|
148
|
+
@call = call
|
149
|
+
@calls = []
|
150
|
+
end
|
151
|
+
|
152
|
+
undef_method *(instance_methods.map { |x| x.to_sym } - [:__id__, :__send__])
|
153
|
+
|
154
|
+
def invoke
|
155
|
+
@calls.each do |sym, args|
|
156
|
+
(@mock.obj.send @call).send sym, *args
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def method_missing(sym, *args)
|
161
|
+
@calls << [sym, args]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def method_missing(sym, *args)
|
167
|
+
@parent.send sym, *args
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|