git_reflow 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitHelpers do
4
+ let(:origin_url) { 'git@github.com:reenhanced.spectacular/this-is-the.shit.git' }
5
+
6
+ before do
7
+ stub_with_fallback(GitReflow::Config, :get).with('remote.origin.url').and_return(origin_url)
8
+
9
+ module Gitacular
10
+ include GitReflow::GitHelpers
11
+ extend self
12
+ end
13
+
14
+ stub_run_for Gitacular
15
+ end
16
+
17
+ describe ".remote_user" do
18
+ subject { Gitacular.remote_user }
19
+
20
+ it { should == 'reenhanced.spectacular' }
21
+
22
+ context "remote origin url isn't set" do
23
+ let(:origin_url) { nil }
24
+ it { should == '' }
25
+ end
26
+ end
27
+
28
+ describe ".remote_repo_name" do
29
+ subject { Gitacular.remote_repo_name }
30
+
31
+ it { should == 'this-is-the.shit' }
32
+
33
+ context "remote origin url isn't set" do
34
+ let(:origin_url) { nil }
35
+ it { should == '' }
36
+ end
37
+ end
38
+
39
+ describe ".current_branch" do
40
+ subject { Gitacular.current_branch }
41
+ it { expect{ subject }.to have_run_command_silently "git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'" }
42
+ end
43
+
44
+ describe ".get_first_commit_message" do
45
+ subject { Gitacular.get_first_commit_message }
46
+ it { expect{ subject }.to have_run_command_silently 'git log --pretty=format:"%s" --no-merges -n 1' }
47
+ end
48
+
49
+ describe ".push_current_branch" do
50
+ subject { Gitacular.push_current_branch }
51
+ before { Gitacular.stub(:current_branch).and_return('bingo') }
52
+ it { expect{ subject }.to have_run_command "git push origin bingo" }
53
+ end
54
+
55
+ describe ".fetch_destination(destination_branch)" do
56
+ subject { Gitacular.fetch_destination('new-feature') }
57
+ it { expect{ subject }.to have_run_command "git fetch origin new-feature" }
58
+ end
59
+
60
+ describe ".update_destination(destination_branch)" do
61
+ let(:current_branch) { 'bananas' }
62
+ let(:destination_branch) { 'monkey-business' }
63
+
64
+ before { Gitacular.stub(:current_branch).and_return(current_branch) }
65
+ subject { Gitacular.update_destination(destination_branch) }
66
+
67
+ it "updates the destination branch with the latest code from the remote repo" do
68
+ expect { subject }.to have_run_commands_in_order [
69
+ "git checkout #{destination_branch}",
70
+ "git pull origin #{destination_branch}",
71
+ "git checkout #{current_branch}"
72
+ ]
73
+ end
74
+ end
75
+
76
+ describe ".merge_feature_branch(options)" do
77
+ let(:destination_branch) { 'monkey-business' }
78
+ let(:feature_branch) { 'bananas' }
79
+ let(:merge_options) { {} }
80
+
81
+ subject { Gitacular.merge_feature_branch(feature_branch, merge_options) }
82
+
83
+ it 'checks out master as the default destination branch and squash merges the feature branch' do
84
+ expect { subject }.to have_run_commands_in_order [
85
+ 'git checkout master',
86
+ "git merge --squash #{feature_branch}"
87
+ ]
88
+ end
89
+
90
+ context "providing a destination branch" do
91
+ let(:merge_options) {{ destination_branch: destination_branch }}
92
+ it { expect{ subject }.to have_run_command "git checkout #{destination_branch}" }
93
+ end
94
+
95
+ context "with a message" do
96
+ let(:merge_options) {{ message: "don't throw doo doo" }}
97
+ it "appends the message to the squashed commit message" do
98
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("don't throw doo doo")
99
+ subject
100
+ end
101
+
102
+ context 'and a pull reuqest number' do
103
+ before { merge_options.merge!(pull_request_number: 3) }
104
+ it "appends the message to the squashed commit message" do
105
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("don't throw doo doo\nCloses #3\n")
106
+ subject
107
+ end
108
+ end
109
+ end
110
+
111
+ context "with a pull request number" do
112
+ let(:merge_options) {{ pull_request_number: 3 }}
113
+ it "appends the message to the squashed commit message" do
114
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nCloses #3\n")
115
+ subject
116
+ end
117
+ end
118
+
119
+ context "with one LGTM author" do
120
+ let(:merge_options) {{ lgtm_authors: 'codenamev' }}
121
+ it "appends the message to the squashed commit message" do
122
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nLGTM given by: @#{merge_options[:lgtm_authors]}\n")
123
+ subject
124
+ end
125
+ end
126
+
127
+ context "with LGTM authors" do
128
+ let(:merge_options) {{ lgtm_authors: ['codenamev', 'nhance'] }}
129
+ it "appends the message to the squashed commit message" do
130
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nLGTM given by: @#{merge_options[:lgtm_authors].join(', @')}\n")
131
+ subject
132
+ end
133
+ end
134
+ end
135
+
136
+ describe ".append_to_squashed_commit_message(message)" do
137
+ let(:message) { "do do the voodoo that you do" }
138
+ subject { Gitacular.append_to_squashed_commit_message(message) }
139
+ it "appends the message to git's SQUASH_MSG temp file" do
140
+ expect{ subject }.to have_run_commands_in_order [
141
+ "echo \"#{message}\" | cat - .git/SQUASH_MSG > ./tmp_squash_msg",
142
+ 'mv ./tmp_squash_msg .git/SQUASH_MSG'
143
+ ]
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitServer do
4
+ let(:connection_options) { nil }
5
+
6
+ subject { GitReflow::GitServer.connect connection_options }
7
+
8
+ before do
9
+ GitReflow::GitServer::GitHub.stub(:new)
10
+
11
+ module GitReflow::GitServer
12
+ class DummyHub < Base
13
+ def initialize(options)
14
+ "Initialized with #{options}"
15
+ end
16
+
17
+ def authenticate(options={})
18
+ end
19
+
20
+ def connection
21
+ 'Connected!'
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '.connect(options)' do
28
+ it 'initializes a new GitHub server provider by default' do
29
+ stubbed_github = Class.new
30
+ stubbed_github.stub(:authenticate)
31
+ GitReflow::GitServer::GitHub.should_receive(:new).and_return(stubbed_github)
32
+ subject
33
+ end
34
+
35
+ context 'provider is specified' do
36
+ let(:connection_options) { {provider: 'DummyHub'}.merge(expected_server_options) }
37
+ let(:expected_server_options) {{ basic_auth: 'user:pass', end_point: 'https://api.example.com' }}
38
+
39
+ it 'initializes any server provider that has been implemented' do
40
+ dummy_hub = GitReflow::GitServer::DummyHub.new({})
41
+ GitReflow::GitServer::DummyHub.should_receive(:new).with(expected_server_options).and_return(dummy_hub)
42
+ subject.should == dummy_hub
43
+ $output.should_not include 'GitServer not setup for: DummyHub'
44
+ end
45
+ end
46
+
47
+ context 'provider not yet implemented' do
48
+ let(:connection_options) {{ provider: 'GitLab' }}
49
+ it { expect{ subject }.to have_output "Error connecting to GitLab: GitServer not setup for \"GitLab\"" }
50
+ end
51
+ end
52
+
53
+ describe '.current_provider' do
54
+ subject { GitReflow::GitServer.current_provider }
55
+
56
+ context 'Reflow setup to use GitHub' do
57
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GitHub') }
58
+ it { should == GitReflow::GitServer::GitHub }
59
+ end
60
+
61
+ context 'Reflow has not yet been setup' do
62
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('') }
63
+ it { should be_nil }
64
+ it { expect{ subject }.to have_output "[notice] Reflow hasn't been setup yet. Run 'git reflow setup' to continue" }
65
+ end
66
+
67
+ context 'an unknown server provider is stored in the git config' do
68
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GittyUp') }
69
+
70
+ it { should be_nil }
71
+ it { expect{ subject }.to have_output "GitServer not setup for \"GittyUp\"" }
72
+ end
73
+ end
74
+
75
+ describe '.connection' do
76
+ subject { GitReflow::GitServer.connection }
77
+
78
+ it { should be_nil }
79
+
80
+ context "with a valid provider" do
81
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GitHub') }
82
+ it 'calls connection on the provider' do
83
+ GitReflow::GitServer::GitHub.should_receive(:connection)
84
+ subject
85
+ end
86
+ end
87
+
88
+ context "with an invalid provider" do
89
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GittyUp') }
90
+ it { should be_nil }
91
+ it { expect{ subject }.to have_output "GitServer not setup for \"GittyUp\"" }
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,236 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitServer::GitHub do
4
+ let(:user) { 'reenhanced' }
5
+ let(:password) { 'shazam' }
6
+ let(:repo) { 'repo' }
7
+ let(:oauth_token_hash) { Hashie::Mash.new({ token: 'a1b2c3d4e5f6g7h8i9j0'}) }
8
+ let(:hostname) { 'hostname.local' }
9
+ let(:github_site) { 'https://github.com' }
10
+ let(:github_api_endpoint) { 'https://api.github.com' }
11
+ let(:enterprise_site) { 'https://github.gittyup.com' }
12
+ let(:enterprise_api) { 'https://github.gittyup.com/api/v3' }
13
+ let(:github) { stub_github_with(pull: existing_pull_request) }
14
+ let!(:github_api) { github.connection }
15
+ let(:existing_pull_request) { Hashie::Mash.new JSON.parse(fixture('pull_requests/pull_request.json').read) }
16
+ let(:existing_pull_requests) { JSON.parse(fixture('pull_requests/pull_requests.json').read).collect {|pull| Hashie::Mash.new pull } }
17
+
18
+ before do
19
+ HighLine.any_instance.stub(:ask) do |terminal, question|
20
+ values = {
21
+ "Please enter your GitHub username: " => user,
22
+ "Please enter your GitHub password (we do NOT store this): " => password,
23
+ "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
24
+ "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api
25
+ }
26
+ return_value = values[question]
27
+ question = ""
28
+ return_value
29
+ end
30
+
31
+ github.stub(:remote_user).and_return(user)
32
+ github.stub(:remote_repo_name).and_return(repo)
33
+ github.stub(:run).with('hostname', loud: false).and_return(hostname)
34
+ end
35
+
36
+ describe '#initialize(options)' do
37
+ subject { GitReflow::GitServer::GitHub.new({}) }
38
+
39
+ it 'sets the reflow git server provider to GitHub in the git config' do
40
+ GitReflow::Config.should_receive(:set).once.with('github.site', github_site, local: false)
41
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', github_api_endpoint, local: false)
42
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub')
43
+ subject
44
+ end
45
+
46
+ context 'using enterprise' do
47
+ subject { GitReflow::GitServer::GitHub.new(enterprise: true) }
48
+
49
+ it 'sets the enterprise site and api as the site and api endpoints for the GitHub provider in the git config' do
50
+ GitReflow::Config.should_receive(:set).once.with('github.site', enterprise_site, local: false)
51
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', enterprise_api, local: false)
52
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub')
53
+ subject
54
+ end
55
+
56
+ end
57
+
58
+ context 'storing git config settings only for this project' do
59
+ subject { GitReflow::GitServer::GitHub.new(project_only: true) }
60
+
61
+ it 'sets the enterprise site and api as the site and api endpoints for the GitHub provider in the git config' do
62
+ GitReflow::Config.should_receive(:set).once.with('github.site', github_site, local: true).and_call_original
63
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', github_api_endpoint, local: true)
64
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub', local: true)
65
+ subject
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ describe '#authenticate' do
72
+ let(:github) { GitReflow::GitServer::GitHub.new({}) }
73
+ let!(:github_api) { Github.new }
74
+ let(:github_authorizations) { Github::Client::Authorizations.new }
75
+ subject { github.authenticate }
76
+
77
+ before do
78
+ GitReflow::GitServer::GitHub.stub(:user).and_return('reenhanced')
79
+ github_api.stub(:oauth).and_return(github_authorizations)
80
+ github_api.stub_chain(:oauth, :all).and_return([])
81
+ github.stub(:run).with('hostname', loud: false).and_return(hostname)
82
+ end
83
+
84
+ context 'not yet authenticated' do
85
+ context 'with valid GitHub credentials' do
86
+
87
+ before do
88
+ Github.stub(:new).and_return(github_api)
89
+ github_authorizations.stub(:authenticated?).and_return(true)
90
+ github_api.oauth.stub(:create).with({ scopes: ['repo'], note: "git-reflow (#{hostname})" }).and_return(oauth_token_hash)
91
+ end
92
+
93
+ it "notifies the user of successful setup" do
94
+ expect { subject }.to have_output "\nYour GitHub account was successfully setup!"
95
+ end
96
+
97
+ it "creates a new GitHub oauth token" do
98
+ github_api.oauth.should_receive(:create).and_return(oauth_token_hash)
99
+ subject
100
+ end
101
+
102
+ it "creates git config keys for github connections" do
103
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
104
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
105
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
106
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
107
+ end
108
+
109
+ context "exclusive to project" do
110
+ let(:github) { GitReflow::GitServer::GitHub.new(project_only: true) }
111
+ before { GitReflow::GitServer::GitHub.stub(:@project_only).and_return(true) }
112
+
113
+ it "creates _local_ git config keys for github connections" do
114
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
115
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
116
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
117
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
118
+
119
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
120
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
121
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
122
+ expect{ subject }.to have_run_command_silently "git config --replace-all reflow.git-server \"GitHub\""
123
+ end
124
+ end
125
+
126
+ context "use GitHub enterprise account" do
127
+ let(:github) { GitReflow::GitServer::GitHub.new(enterprise: true) }
128
+ before { GitReflow::GitServer::GitHub.stub(:@using_enterprise).and_return(true) }
129
+ it "creates git config keys for github connections" do
130
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.site \"#{enterprise_site}\""
131
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.endpoint \"#{enterprise_api}\""
132
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
133
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
134
+ end
135
+ end
136
+ end
137
+
138
+ context "with invalid GitHub credentials" do
139
+ let(:unauthorized_error_response) {{
140
+ response_headers: {'content-type' => 'application/json; charset=utf-8', status: 'Unauthorized'},
141
+ method: 'GET',
142
+ status: '401',
143
+ body: { error: "GET https://api.github.com/authorizations: 401 Bad credentials" }
144
+ }}
145
+
146
+ before do
147
+ Github.should_receive(:new).and_raise Github::Error::Unauthorized.new(unauthorized_error_response)
148
+ end
149
+
150
+ it "notifies user of invalid login details" do
151
+ expect { subject }.to have_output "\nInvalid username or password: #{Github::Error::Unauthorized.new(unauthorized_error_response).inspect}"
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ describe '#create_pull_request(options)' do
158
+ let(:title) { 'Fresh title' }
159
+ let(:body) { 'Funky body' }
160
+ let(:current_branch) { 'new-feature' }
161
+
162
+ before { github.stub(:current_branch).and_return(current_branch) }
163
+
164
+ it 'creates a pull request using the remote user and repo' do
165
+ github_api.stub(:pull_requests)
166
+ github_api.pull_requests.should_receive(:create).with(user, repo, title: title, body: body, head: "#{user}:#{current_branch}", base: 'master')
167
+ github.create_pull_request({ title: title, body: body, base: 'master' })
168
+ end
169
+ end
170
+
171
+ describe '#find_pull_request(from, to)' do
172
+ subject { github.find_pull_request({ from: 'new-feature', to: 'master'}) }
173
+
174
+ it 'looks for an open pull request matching the remote user/repo' do
175
+ subject.should == existing_pull_requests.first
176
+ end
177
+
178
+ context 'no pull request exists' do
179
+ before { github.stub(:find_pull_request).and_return([]) }
180
+ it { should == [] }
181
+ end
182
+ end
183
+
184
+ describe '#pull_request_comments(pull_request)' do
185
+ let(:pull_request_comments) { JSON.parse(fixture('pull_requests/comments.json').read).collect {|c| Hashie::Mash.new(c) } }
186
+
187
+ subject { github.pull_request_comments(existing_pull_request) }
188
+
189
+ before do
190
+ github_api.stub_chain(:issues, :comments)
191
+ github_api.stub_chain(:pull_requests, :comments)
192
+ end
193
+
194
+ it 'includes both issue comments and pull request comments' do
195
+ github_api.issues.comments.should_receive(:all).with(user, repo, number: existing_pull_request.number).and_return([pull_request_comments.first])
196
+ github_api.pull_requests.comments.should_receive(:all).with(user, repo, number: existing_pull_request.number).and_return([pull_request_comments.first])
197
+ subject.count.should == 2
198
+ end
199
+ end
200
+
201
+ describe '#has_pull_request_comments?(pull_request)' do
202
+ let(:existing_pull_request) { Hashie::Mash.new JSON.parse(fixture('pull_requests/pull_request.json').read) }
203
+ let(:pull_request_comments) { JSON.parse(fixture('pull_requests/comments.json').read).collect {|c| Hashie::Mash.new(c) } }
204
+
205
+ before { github.stub(:pull_request_comments).and_return([pull_request_comments]) }
206
+ subject { github.has_pull_request_comments?(existing_pull_request) }
207
+
208
+ it { should == true }
209
+
210
+ context 'no comments exist for the given pull request' do
211
+ before { github.stub(:pull_request_comments).and_return([]) }
212
+ it { should == false }
213
+ end
214
+ end
215
+
216
+ describe '#get_build_status(sha)' do
217
+ let(:sha) { '6dcb09b5b57875f334f61aebed695e2e4193db5e' }
218
+ subject { github.get_build_status(sha) }
219
+ before { github_api.stub_chain(:repos, :statuses) }
220
+
221
+ it 'gets the latest build status for the given commit hash' do
222
+ github_api.repos.statuses.should_receive(:all).with(user, repo, sha).and_return([{ state: 'success'}])
223
+ subject
224
+ end
225
+ end
226
+
227
+ describe '#find_authors_of_open_pull_request_comments(pull_request)' do
228
+ end
229
+
230
+ describe '#comment_authors_for_pull_request(pull_request, options = {})' do
231
+ end
232
+
233
+ describe '#get_commited_time(commit_sha)' do
234
+ end
235
+
236
+ end
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'multi_json'
4
+ require 'webmock/rspec'
5
+ require 'pry'
6
+
7
+ $LOAD_PATH << 'lib'
8
+ require 'git_reflow'
9
+
10
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.include GithubHelpers
14
+ config.include WebMock::API
15
+ config.include CommandLineHelpers
16
+ config.include GithubHelpers
17
+ config.include RspecStubHelpers
18
+
19
+ config.expect_with :rspec do |c|
20
+ c.syntax = [:should, :expect]
21
+ end
22
+
23
+ config.mock_with :rspec do |c|
24
+ c.syntax = [:should, :expect]
25
+ end
26
+
27
+ config.before(:each) do
28
+ WebMock.reset!
29
+ stub_command_line
30
+ allow_message_expectations_on_nil
31
+ end
32
+
33
+ config.after(:each) do
34
+ WebMock.reset!
35
+ reset_stubbed_command_line
36
+ end
37
+ end
@@ -0,0 +1,99 @@
1
+ module CommandLineHelpers
2
+ def stub_command_line
3
+ $commands_ran = []
4
+ $output = []
5
+
6
+ stub_run_for GitReflow
7
+ stub_run_for GitReflow::Sandbox
8
+
9
+ STDOUT.stub(:puts) do |output|
10
+ $output << output
11
+ output = ''
12
+ end
13
+ end
14
+
15
+ def stub_run_for(module_to_stub)
16
+ module_to_stub.stub(:run) do |command, options|
17
+ options ||= {}
18
+ $commands_ran << Hashie::Mash.new(command: command, options: options)
19
+ command = "" # we need this due to a bug in rspec that will keep this assignment on subsequent runs of the stub
20
+ end
21
+ end
22
+
23
+ def reset_stubbed_command_line
24
+ $commands_ran = []
25
+ end
26
+
27
+ def stub_command(command, return_value)
28
+ GitReflow::Sandbox.stub(:run).with(command).and_return(return_value)
29
+ end
30
+ end
31
+
32
+ RSpec::Matchers.define :have_run_command do |command|
33
+ match do |block|
34
+ block.call
35
+ (
36
+ $commands_ran.include? Hashie::Mash.new(command: command, options: {}) or
37
+ $commands_ran.include? Hashie::Mash.new(command: command, options: {with_system: true})
38
+ )
39
+ end
40
+
41
+ supports_block_expectations
42
+
43
+ failure_message do |block|
44
+ "expected to have run the command \`#{command}\` but instead ran:\n\t#{$commands_ran.inspect}"
45
+ end
46
+ end
47
+
48
+ RSpec::Matchers.define :have_run_command_silently do |command|
49
+ match do |block|
50
+ block.call
51
+ $commands_ran.include? Hashie::Mash.new(command: command, options: { loud: false })
52
+ end
53
+
54
+ supports_block_expectations
55
+
56
+ failure_message do |block|
57
+ "expected to have run the command \`#{command}\` silently but instead ran:\n\t#{$commands_ran.inspect}"
58
+ end
59
+ end
60
+
61
+ RSpec::Matchers.define :have_run_commands_in_order do |commands|
62
+ match do |block|
63
+ block.call
64
+ command_count = commands.count
65
+ command_start_index = $commands_ran.reverse.find_index {|c| c.command == commands.first }
66
+ return false unless command_start_index
67
+
68
+ $commands_ran.reverse.each_with_index do |command_ran, index|
69
+ next unless command_start_index
70
+ if command_count >= 1
71
+ current_command = commands[command_count - 1]
72
+ current_command.should == command_ran.command
73
+ command_count -= 1
74
+ end
75
+ end
76
+
77
+ return command_count == 0
78
+ end
79
+
80
+ supports_block_expectations
81
+
82
+ failure_message do |block|
83
+ "expected to have run these commands in order:\n\t\t#{commands.inspect}\n\tgot:\n\t\t#{$commands_ran.inspect}"
84
+ end
85
+ end
86
+
87
+ RSpec::Matchers.define :have_output do |expected_output|
88
+ match do |block|
89
+ block.call
90
+ $output.include? expected_output
91
+ end
92
+
93
+ supports_block_expectations
94
+
95
+ failure_message do |block|
96
+ "expected STDOUT to include #{expected_output} but didn't: \n\t#{$output.inspect}"
97
+ end
98
+ end
99
+
@@ -0,0 +1,8 @@
1
+ def fixture_path
2
+ File.expand_path("../../fixtures", __FILE__)
3
+ end
4
+
5
+ def fixture(file)
6
+ File.new(File.join(fixture_path, '/', file))
7
+ end
8
+