xcodebuild-rb 0.1.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,276 @@
1
+ require 'spec_helper'
2
+
3
+ describe XcodeBuild::Reporting::CleanReporting do
4
+ let(:reporter) { XcodeBuild::Reporter.new }
5
+
6
+ shared_examples_for "any clean" do
7
+ it "reports the clean target" do
8
+ reporter.clean.target.should == "ExampleProject"
9
+ end
10
+
11
+ it "reports the project name" do
12
+ reporter.clean.project_name.should == "ExampleProject"
13
+ end
14
+
15
+ it "reports the clean configuration" do
16
+ reporter.clean.configuration.should == "Release"
17
+ end
18
+
19
+ it "reports if the clean configuration was the default" do
20
+ reporter.clean.should be_default_configuration
21
+ end
22
+ end
23
+
24
+ context "when receiving events" do
25
+ let(:delegate) { mock('reporter delegate').as_null_object }
26
+
27
+ before do
28
+ reporter.delegate = delegate
29
+
30
+ # let's assume it responds to all delegate methods
31
+ delegate.stub(:respond_to?).with(anything).and_return(true)
32
+ end
33
+
34
+ it "notifies it's delegate that a clean has started" do
35
+ delegate.should_receive(:clean_started).with instance_of(XcodeBuild::Reporting::CleanReporting::Clean)
36
+
37
+ event({:clean_started=>
38
+ {:target=>"ExampleProject",
39
+ :project=>"ExampleProject",
40
+ :configuration=>"Release",
41
+ :default=>true}})
42
+ end
43
+
44
+ it "notifies it's delegate when a clean step begins" do
45
+ assume_clean_started
46
+
47
+ delegate.should_receive(:clean_step_started).with instance_of(XcodeBuild::BuildStep)
48
+
49
+ event({:clean_step=>
50
+ {:type=>"Clean.Remove",
51
+ :arguments=>
52
+ ["clean",
53
+ "build/Release-iphoneos/ExampleProject.app"]}})
54
+ end
55
+
56
+ it "notifies it's delegate when a previous clean step finishes" do
57
+ assume_clean_started
58
+
59
+ event({:clean_step=>
60
+ {:type=>"Clean.Remove",
61
+ :arguments=>
62
+ ["clean",
63
+ "build/Release-iphoneos/ExampleProject.app"]}})
64
+
65
+ delegate.should_receive(:clean_step_finished).with reporter.clean.last_step
66
+
67
+ event({:clean_step=>
68
+ {:type=>"Clean.Remove",
69
+ :arguments=>
70
+ ["clean",
71
+ "build/Release-iphoneos/ExampleProject.app"]}})
72
+ end
73
+
74
+ it "notifies it's delegate when the last clean step finishes and the clean is successful" do
75
+ assume_clean_started
76
+
77
+ event({:clean_step=>
78
+ {:type=>"Clean.Remove",
79
+ :arguments=>
80
+ ["clean",
81
+ "build/Release-iphoneos/ExampleProject.app"]}})
82
+
83
+ delegate.should_receive(:clean_step_finished).with reporter.clean.last_step
84
+
85
+ event({:clean_succeeded=>{}})
86
+ end
87
+
88
+ it "notifies it's delegate when the last clean step finishes and the clean fails" do
89
+ assume_clean_started
90
+
91
+ event({:clean_step=>
92
+ {:type=>"Clean.Remove",
93
+ :arguments=>
94
+ ["clean",
95
+ "build/Release-iphoneos/ExampleProject.app"]}})
96
+
97
+ delegate.should_receive(:clean_step_finished).with reporter.clean.last_step
98
+
99
+ event({:clean_failed=>{}})
100
+ end
101
+
102
+ it "notifies it's delegate that the clean has finished when it is successful" do
103
+ assume_clean_started
104
+ delegate.should_receive(:clean_finished).with(reporter.clean)
105
+ event({:clean_succeeded=>{}})
106
+ end
107
+
108
+ it "notifies it's delegate that the clean has finished when it fails" do
109
+ assume_clean_started
110
+ delegate.should_receive(:clean_finished).with(reporter.clean)
111
+ event({:clean_failed=>{}})
112
+ end
113
+
114
+ it "tracks the time a clean takes" do
115
+ Timecop.travel(Chronic.parse("10 seconds ago")) do
116
+ event({:clean_started=>
117
+ {:target=>"ExampleProject",
118
+ :project=>"ExampleProject",
119
+ :configuration=>"Release",
120
+ :default=>true}})
121
+
122
+ Timecop.travel(Chronic.parse("5 seconds from now")) do
123
+ event({:clean_succeeded=>{}})
124
+ end
125
+ end
126
+
127
+ reporter.clean.duration.should be_within(0.01).of(5)
128
+ end
129
+ end
130
+
131
+ context "once a clean has started" do
132
+ before do
133
+ event({:clean_started=>
134
+ {:target=>"ExampleProject",
135
+ :project=>"ExampleProject",
136
+ :configuration=>"Release",
137
+ :default=>true}})
138
+ end
139
+
140
+ it "reports that the clean is running" do
141
+ reporter.clean.should be_running
142
+ end
143
+
144
+ it "reports that the clean is not finished" do
145
+ reporter.clean.should_not be_finished
146
+ end
147
+ end
148
+
149
+ context "once a simple, successful clean has finished" do
150
+ before do
151
+ event({:clean_started=>
152
+ {:target=>"ExampleProject",
153
+ :project=>"ExampleProject",
154
+ :configuration=>"Release",
155
+ :default=>true}})
156
+
157
+ event({:clean_step=>
158
+ {:type=>"Clean.Remove",
159
+ :arguments=>
160
+ ["clean",
161
+ "build/Release-iphoneos/FileOne"]}})
162
+
163
+ event({:clean_step=>
164
+ {:type=>"Clean.Remove",
165
+ :arguments=>
166
+ ["clean",
167
+ "build/Release-iphoneos/FileTwo"]}})
168
+
169
+ event({:clean_succeeded=>{}})
170
+ end
171
+
172
+ it_behaves_like "any clean"
173
+
174
+ it "reports that the clean was successful" do
175
+ reporter.clean.should be_successful
176
+ end
177
+
178
+ it "reports the total number of completed clean steps" do
179
+ reporter.clean.should have(2).steps_completed
180
+ end
181
+
182
+ it "reports that the clean is not running" do
183
+ reporter.clean.should_not be_running
184
+ end
185
+
186
+ it "reports that the clean is finished" do
187
+ reporter.clean.should be_finished
188
+ end
189
+ end
190
+
191
+ context "once a simple, failed build has finished" do
192
+ before do
193
+ event({:clean_started=>
194
+ {:target=>"ExampleProject",
195
+ :project=>"ExampleProject",
196
+ :configuration=>"Release",
197
+ :default=>true}})
198
+
199
+ event({:clean_step=>
200
+ {:type=>"Clean.Remove",
201
+ :arguments=>
202
+ ["clean",
203
+ "build/Release-iphoneos/FileOne"]}})
204
+
205
+ event({:clean_error_detected=>
206
+ {:message=>"Error Domain=NSCocoaErrorDomain Code=513 ExampleProject couldn't be removed"}})
207
+
208
+ event({:clean_step=>
209
+ {:type=>"Clean.Remove",
210
+ :arguments=>
211
+ ["clean",
212
+ "build/Release-iphoneos/FileTwo"]}})
213
+
214
+ event({:clean_failed=>{}})
215
+
216
+ event({:clean_step_failed=>
217
+ {:type=>"Clean.Remove",
218
+ :arguments=>
219
+ ["clean",
220
+ "build/Release-iphoneos/FileOne"]}})
221
+ end
222
+
223
+ it_behaves_like "any clean"
224
+
225
+ it "reports that the clean was a failure" do
226
+ reporter.clean.should be_failed
227
+ end
228
+
229
+ it "reports the total number of completed clean steps" do
230
+ reporter.clean.should have(2).steps_completed
231
+ end
232
+
233
+ it "reports the total number of failed clean steps" do
234
+ reporter.clean.should have(1).failed_steps
235
+ reporter.clean.failed_steps.first.tap do |step|
236
+ step.type.should == "Clean.Remove"
237
+ end
238
+ end
239
+
240
+ it "reports the errors for each failed clean step" do
241
+ reporter.clean.failed_steps.first.should have(1).errors
242
+ reporter.clean.failed_steps.first.errors.first.tap do |error|
243
+ error.message.should == "Error Domain=NSCocoaErrorDomain Code=513 ExampleProject couldn't be removed"
244
+ end
245
+ end
246
+
247
+ it "reports that the clean is not running" do
248
+ reporter.clean.should_not be_running
249
+ end
250
+
251
+ it "reports that the clean is finished" do
252
+ reporter.clean.should be_finished
253
+ end
254
+ end
255
+
256
+ private
257
+
258
+ def event(event_data)
259
+ message = event_data.keys.first
260
+ params = event_data.values.first
261
+
262
+ if params.any?
263
+ reporter.send(message, params)
264
+ else
265
+ reporter.send(message)
266
+ end
267
+ end
268
+
269
+ def assume_clean_started
270
+ event({:clean_started=>
271
+ {:target=>"ExampleProject",
272
+ :project=>"ExampleProject",
273
+ :configuration=>"Release",
274
+ :default=>true}})
275
+ end
276
+ end
@@ -0,0 +1,31 @@
1
+ ENV["LC_CTYPE"] = "en_US.UTF-8"
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
6
+ # loaded once.
7
+ #
8
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+ end
14
+
15
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
16
+
17
+ require 'xcodebuild'
18
+ require 'chronic'
19
+ require 'timecop'
20
+
21
+ def delegate_should_respond_to(method)
22
+ mock_should_respond?(delegate, method, true)
23
+ end
24
+
25
+ def delegate_should_not_respond_to(method)
26
+ mock_should_respond?(delegate, method, false)
27
+ end
28
+
29
+ def mock_should_respond?(mock, method, should_respond)
30
+ mock.stub(:respond_to?).with(method).and_return(should_respond)
31
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe XcodeBuild::Translations::Building do
4
+ let(:delegate) { mock('delegate', :respond_to? => true) }
5
+ let(:translator) { XcodeBuild::OutputTranslator.new(delegate, ignore_global_translations: true) }
6
+ let(:translation) { translator.translations[0] }
7
+
8
+ before do
9
+ translator.use_translation XcodeBuild::Translations::Building
10
+
11
+ delegate_should_respond_to(:beginning_translation_of_line)
12
+ delegate.stub(:beginning_translation_of_line).and_return(true)
13
+
14
+ translator.should have(1).translations
15
+ end
16
+
17
+ context "before it detects that a build has started" do
18
+ it "reports that it is not building" do
19
+ translation.should_not be_building
20
+ end
21
+
22
+ it "notifies the delegate of the start of a build with the default configuration" do
23
+ delegate.stub(:beginning_translation_of_line)
24
+ delegate.should_receive(:build_started).with(
25
+ target: "ExampleProject",
26
+ project: "ExampleProject",
27
+ configuration: "Release",
28
+ default: true
29
+ )
30
+ translator << "=== BUILD NATIVE TARGET ExampleProject OF PROJECT ExampleProject WITH THE DEFAULT CONFIGURATION (Release) ==="
31
+ end
32
+
33
+ it "notifies the delegate of the start of a build with a non-default configuration" do
34
+ delegate.stub(:beginning_translation_of_line)
35
+ delegate.should_receive(:build_started).with(
36
+ target: "ExampleProject",
37
+ project: "ExampleProject",
38
+ configuration: "Debug",
39
+ default: false
40
+ )
41
+ translator << "=== BUILD NATIVE TARGET ExampleProject OF PROJECT ExampleProject WITH THE CONFIGURATION Debug ==="
42
+ end
43
+
44
+ it "treats :build_started as a required delegate message and raise if it doesn't respond" do
45
+ delegate_should_not_respond_to(:build_started)
46
+ -> {
47
+ translator << "=== BUILD NATIVE TARGET ExampleProject OF PROJECT ExampleProject WITH THE CONFIGURATION Debug ==="
48
+
49
+ }.should raise_error(XcodeBuild::OutputTranslator::MissingDelegateMethodError)
50
+ end
51
+ end
52
+
53
+ context "once a build start has been detected" do
54
+ before do
55
+ translation.stub(:building?).and_return(true)
56
+ end
57
+
58
+ it "notifies the delegate of a single build step" do
59
+ delegate.stub(:beginning_translation_of_line)
60
+ delegate.should_receive(:build_step).with(
61
+ type: "CodeSign",
62
+ arguments: ["build/Debug-iphoneos/ExampleProject.app"]
63
+ )
64
+ translator << "\n"
65
+ translator << "CodeSign build/Debug-iphoneos/ExampleProject.app"
66
+ end
67
+
68
+ it "treats :beginning_translation_of_line as an optional delegate message" do
69
+ delegate_should_not_respond_to(:build_step)
70
+ delegate.should_not_receive(:build_step)
71
+ translator << "\n"
72
+ translator << "CodeSign build/Debug-iphoneos/ExampleProject.app"
73
+ end
74
+
75
+ it "notifies the delegate when the build failed" do
76
+ delegate.stub(:beginning_translation_of_line)
77
+ delegate.should_receive(:build_failed)
78
+ translator << "\n\n\n"
79
+ translator << "** BUILD FAILED **"
80
+ end
81
+
82
+ it "treats :build_failed as a required delegate message and raise if it doesn't respond" do
83
+ delegate_should_not_respond_to(:build_failed)
84
+ -> {
85
+ translator << "** BUILD FAILED **"
86
+
87
+ }.should raise_error(XcodeBuild::OutputTranslator::MissingDelegateMethodError)
88
+ end
89
+
90
+ it "notifies the delegate when the build succeeded" do
91
+ delegate.stub(:beginning_translation_of_line)
92
+ delegate.should_receive(:build_succeeded)
93
+ translator << "\n\n\n"
94
+ translator << "** BUILD SUCCEEDED **"
95
+ end
96
+
97
+ it "treats :build_succeeded as a required delegate message and raise if it doesn't respond" do
98
+ delegate_should_not_respond_to(:build_succeeded)
99
+ -> {
100
+ translator << "** BUILD SUCCEEDED **"
101
+
102
+ }.should raise_error(XcodeBuild::OutputTranslator::MissingDelegateMethodError)
103
+ end
104
+
105
+ it "notifies the delegate of build step failures" do
106
+ delegate.should_receive(:build_step_failed).with(
107
+ type: "CodeSign",
108
+ arguments: ["build/Debug-iphoneos/ExampleProject.app"]
109
+ )
110
+ translator << "The following build commands failed:"
111
+ translator << "\tCodeSign build/Debug-iphoneos/ExampleProject.app"
112
+ translator << "(2 failures)"
113
+ end
114
+
115
+ it "treats :build_step_failed as an optional delegate message" do
116
+ delegate_should_not_respond_to(:build_step_failed)
117
+ delegate.should_not_receive(:build_step_failed)
118
+ translator << "The following build commands failed:"
119
+ translator << "\tCodeSign build/Debug-iphoneos/ExampleProject.app"
120
+ end
121
+
122
+ it "notifies the delegate of errors that occur throughout the build" do
123
+ delegate.should_receive(:build_error_detected).with(
124
+ file: "/ExampleProject/main.m",
125
+ line: 16,
126
+ char: 42,
127
+ message: "expected ';' after expression [1]"
128
+ )
129
+ translator << "/ExampleProject/main.m:16:42: error: expected ';' after expression [1]"
130
+ end
131
+
132
+ it "notifies the delegate of errors for different build steps" do
133
+ delegate.should_receive(:build_error_detected).with(
134
+ file: "/ExampleProject/main.m",
135
+ line: 16,
136
+ char: 42,
137
+ message: "expected ';' after expression [1]"
138
+ )
139
+
140
+ translator << "CompileC ExampleProject/main.m normal"
141
+ translator << "/ExampleProject/main.m:16:42: error: expected ';' after expression [1]"
142
+ translator << "1 error generated."
143
+ end
144
+
145
+ it "notifies the delegate of multiple errors for the same build step" do
146
+ delegate.should_receive(:build_error_detected).with(
147
+ file: "/ExampleProject/main.m",
148
+ line: 16,
149
+ char: 42,
150
+ message: "expected ';' after expression [1]"
151
+ ).twice
152
+
153
+ translator << "CompileC ExampleProject/main.m normal"
154
+ translator << "/ExampleProject/main.m:16:42: error: expected ';' after expression [1]"
155
+ translator << ""
156
+ translator << "/ExampleProject/main.m:16:42: error: expected ';' after expression [1]"
157
+ translator << ""
158
+ translator << "2 errors generated."
159
+ end
160
+
161
+ it "treats :build_error_detected as an optional delegate message" do
162
+ delegate_should_not_respond_to(:build_error_detected)
163
+ delegate.should_not_receive(:build_error_detected)
164
+ translator << "/ExampleProject/main.m:16:42: error: expected ';' after expression [1]"
165
+ end
166
+ end
167
+ end