brasten-ci_reporter 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,143 @@
1
+ # Copyright (c) 2006-2010 Nick Sieger <nicksieger@gmail.com>
2
+ # See the file LICENSE.txt included with the distribution for
3
+ # software license details.
4
+
5
+ require 'ci/reporter/core'
6
+ require 'test/unit'
7
+ require 'test/unit/ui/console/testrunner'
8
+
9
+ module CI
10
+ module Reporter
11
+ # Factory for constructing either a CI::Reporter::TestUnitFailure or CI::Reporter::TestUnitError depending on the result
12
+ # of the test.
13
+ class Failure
14
+ def self.new(fault)
15
+ return TestUnitFailure.new(fault) if fault.kind_of?(Test::Unit::Failure)
16
+ return TestUnitSkipped.new(fault) if Test::Unit.constants.include?("Omission") && (fault.kind_of?(Test::Unit::Omission) || fault.kind_of?(Test::Unit::Pending))
17
+ return TestUnitNotification.new(fault) if Test::Unit.constants.include?("Notification") && fault.kind_of?(Test::Unit::Notification)
18
+ TestUnitError.new(fault)
19
+ end
20
+ end
21
+
22
+ # Wrapper around a <code>Test::Unit</code> error to be used by the test suite to interpret results.
23
+ class TestUnitError
24
+ def initialize(fault) @fault = fault end
25
+ def failure?() false end
26
+ def error?() true end
27
+ def name() @fault.exception.class.name end
28
+ def message() @fault.exception.message end
29
+ def location() @fault.exception.backtrace.join("\n") end
30
+ end
31
+
32
+ # Wrapper around a <code>Test::Unit</code> failure to be used by the test suite to interpret results.
33
+ class TestUnitFailure
34
+ def initialize(fault) @fault = fault end
35
+ def failure?() true end
36
+ def error?() false end
37
+ def name() Test::Unit::AssertionFailedError.name end
38
+ def message() @fault.message end
39
+ def location() @fault.location.join("\n") end
40
+ end
41
+
42
+ # Wrapper around a <code>Test::Unit</code> 2.0 omission.
43
+ class TestUnitSkipped
44
+ def initialize(fault) @fault = fault end
45
+ def failure?() false end
46
+ def error?() false end
47
+ def name() Test::Unit::Omission.name end
48
+ def message() @fault.message end
49
+ def location() @fault.location.join("\n") end
50
+ end
51
+
52
+ # Wrapper around a <code>Test::Unit</code> 2.0 notification.
53
+ class TestUnitNotification
54
+ def initialize(fault) @fault = fault end
55
+ def failure?() false end
56
+ def error?() false end
57
+ def name() Test::Unit::Notification.name end
58
+ def message() @fault.message end
59
+ def location() @fault.location.join("\n") end
60
+ end
61
+
62
+ # Replacement Mediator that adds listeners to capture the results of the <code>Test::Unit</code> runs.
63
+ class TestUnit < Test::Unit::UI::TestRunnerMediator
64
+ def initialize(suite, report_mgr = nil)
65
+ super(suite)
66
+ @report_manager = report_mgr || ReportManager.new("test")
67
+ add_listener(Test::Unit::UI::TestRunnerMediator::STARTED, &method(:started))
68
+ add_listener(Test::Unit::TestCase::STARTED, &method(:test_started))
69
+ add_listener(Test::Unit::TestCase::FINISHED, &method(:test_finished))
70
+ add_listener(Test::Unit::TestResult::FAULT, &method(:fault))
71
+ add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED, &method(:finished))
72
+ end
73
+
74
+ def started(result)
75
+ @suite_result = result
76
+ @last_assertion_count = 0
77
+ @current_suite = nil
78
+ @unknown_count = 0
79
+ @result_assertion_count = 0
80
+ end
81
+
82
+ def test_started(name)
83
+ test_name, suite_name = extract_names(name)
84
+ unless @current_suite && @current_suite.name == suite_name
85
+ finish_suite
86
+ start_suite(suite_name)
87
+ end
88
+ start_test(test_name)
89
+ end
90
+
91
+ def test_finished(name)
92
+ finish_test
93
+ end
94
+
95
+ def fault(fault)
96
+ tc = @current_suite.testcases.last
97
+ tc.failures << Failure.new(fault)
98
+ end
99
+
100
+ def finished(elapsed_time)
101
+ finish_suite
102
+ end
103
+
104
+ private
105
+ def extract_names(name)
106
+ match = name.match(/(.*)\(([^)]*)\)/)
107
+ if match
108
+ [match[1], match[2]]
109
+ else
110
+ @unknown_count += 1
111
+ [name, "unknown-#{@unknown_count}"]
112
+ end
113
+ end
114
+
115
+ def start_suite(suite_name)
116
+ @current_suite = TestSuite.new(suite_name)
117
+ @current_suite.start
118
+ end
119
+
120
+ def finish_suite
121
+ if @current_suite
122
+ @current_suite.finish
123
+ @current_suite.assertions = @suite_result.assertion_count - @last_assertion_count
124
+ @last_assertion_count = @suite_result.assertion_count
125
+ @report_manager.write_report(@current_suite)
126
+ end
127
+ end
128
+
129
+ def start_test(test_name)
130
+ tc = TestCase.new(test_name)
131
+ tc.start
132
+ @current_suite.testcases << tc
133
+ end
134
+
135
+ def finish_test
136
+ tc = @current_suite.testcases.last
137
+ tc.finish
138
+ tc.assertions = @suite_result.assertion_count - @result_assertion_count
139
+ @result_assertion_count = @suite_result.assertion_count
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,5 @@
1
+ module CI
2
+ module Reporter
3
+ VERSION = "1.6.4"
4
+ end
5
+ end
@@ -0,0 +1,230 @@
1
+ # Copyright (c) 2006-2010 Nick Sieger <nicksieger@gmail.com>
2
+ # See the file LICENSE.txt included with the distribution for
3
+ # software license details.
4
+
5
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
6
+ require 'ci/reporter/cucumber'
7
+
8
+ describe "The Cucumber reporter" do
9
+ describe CI::Reporter::CucumberFailure do
10
+ before(:each) do
11
+ @klass = mock("class")
12
+ @klass.stub!(:name).and_return("Exception name")
13
+
14
+ @exception = mock("exception")
15
+ @exception.stub!(:class).and_return(@klass)
16
+ @exception.stub!(:message).and_return("Exception message")
17
+ @exception.stub!(:backtrace).and_return(["First line", "Second line"])
18
+
19
+ @step = mock("step")
20
+ @step.stub!(:exception).and_return(@exception)
21
+
22
+ @cucumber_failure = CI::Reporter::CucumberFailure.new(@step)
23
+ end
24
+
25
+ it "should always return true for failure?" do
26
+ @cucumber_failure.should be_failure
27
+ end
28
+
29
+ it "should always return false for error?" do
30
+ @cucumber_failure.should_not be_error
31
+ end
32
+
33
+ it "should propagate the name as the underlying exception's class name" do
34
+ @step.should_receive(:exception)
35
+ @exception.should_receive(:class)
36
+ @klass.should_receive(:name)
37
+
38
+ @cucumber_failure.name.should == "Exception name"
39
+ end
40
+
41
+ it "should propagate the message as the underlying exception's message" do
42
+ @step.should_receive(:exception)
43
+ @exception.should_receive(:message)
44
+
45
+ @cucumber_failure.message.should == "Exception message"
46
+ end
47
+
48
+ it "should propagate and format the exception's backtrace" do
49
+ @step.should_receive(:exception)
50
+ @exception.should_receive(:backtrace)
51
+
52
+ @cucumber_failure.location.should == "First line\nSecond line"
53
+ end
54
+ end
55
+
56
+ describe CI::Reporter::Cucumber do
57
+ before(:each) do
58
+ @step_mother = mock("step_mother")
59
+ @io = mock("io")
60
+
61
+ @report_manager = mock("report_manager")
62
+ CI::Reporter::ReportManager.stub!(:new).and_return(@report_manager)
63
+ end
64
+
65
+ def new_instance
66
+ CI::Reporter::Cucumber.new(@step_mother, @io, {})
67
+ end
68
+
69
+ it "should create a new report manager to report on test success/failure" do
70
+ CI::Reporter::ReportManager.should_receive(:new)
71
+ new_instance
72
+ end
73
+
74
+ it "should record the feature name when a new feature is visited" do
75
+ cucumber = new_instance
76
+ cucumber.feature_name(nil, "Some feature name")
77
+ cucumber.name.should == "Some feature name"
78
+ end
79
+
80
+ it "should record only the first line of a feature name" do
81
+ cucumber = new_instance
82
+ cucumber.feature_name(nil, "Some feature name\nLonger description")
83
+ cucumber.name.should == "Some feature name"
84
+ end
85
+
86
+ context "applied to a feature" do
87
+ before(:each) do
88
+ @cucumber = new_instance
89
+ @cucumber.feature_name(nil, "Demo feature")
90
+
91
+ @test_suite = mock("test_suite", :start => nil, :finish => nil, :name= => nil)
92
+ CI::Reporter::TestSuite.stub!(:new).and_return(@test_suite)
93
+
94
+ @feature = mock("feature")
95
+
96
+ @report_manager.stub!(:write_report)
97
+ end
98
+
99
+ context "before" do
100
+ it "should create a new test suite" do
101
+ CI::Reporter::TestSuite.should_receive(:new).with(/Demo feature/)
102
+ @cucumber.before_feature(@feature)
103
+ end
104
+
105
+ it "should indicate that the test suite has started" do
106
+ @test_suite.should_receive(:start)
107
+ @cucumber.before_feature(@feature)
108
+ end
109
+ end
110
+
111
+ context "after" do
112
+ before :each do
113
+ @cucumber = new_instance
114
+ @cucumber.feature_name(nil, "Demo feature")
115
+
116
+ @test_suite = mock("test_suite", :start => nil, :finish => nil, :name= => nil)
117
+ CI::Reporter::TestSuite.stub!(:new).and_return(@test_suite)
118
+
119
+ @feature = mock("feature")
120
+
121
+ @report_manager.stub!(:write_report)
122
+
123
+ @cucumber.before_feature(@feature)
124
+ end
125
+
126
+ it "should indicate that the test suite has finished" do
127
+ @test_suite.should_receive(:finish)
128
+ @cucumber.after_feature(@feature)
129
+ end
130
+
131
+ it "should ask the report manager to write a report" do
132
+ @report_manager.should_receive(:write_report).with(@test_suite)
133
+ @cucumber.after_feature(@feature)
134
+ end
135
+ end
136
+ end
137
+
138
+ context "inside a scenario" do
139
+ before(:each) do
140
+ @testcases = []
141
+
142
+ @test_suite = mock("test_suite", :testcases => @testcases)
143
+
144
+ @cucumber = new_instance
145
+ @cucumber.stub!(:test_suite).and_return(@test_suite)
146
+
147
+ @test_case = mock("test_case", :start => nil, :finish => nil, :name => "Step Name")
148
+ CI::Reporter::TestCase.stub!(:new).and_return(@test_case)
149
+
150
+ @step = mock("step", :status => :passed)
151
+ @step.stub!(:name).and_return("Step Name")
152
+ end
153
+
154
+ context "before steps" do
155
+ it "should create a new test case" do
156
+ CI::Reporter::TestCase.should_receive(:new).with("Step Name")
157
+ @cucumber.scenario_name(nil, "Step Name")
158
+ @cucumber.before_steps(@step)
159
+ end
160
+
161
+ it "should indicate that the test case has started" do
162
+ @test_case.should_receive(:start)
163
+ @cucumber.before_steps(@step)
164
+ end
165
+ end
166
+
167
+ context "after steps" do
168
+ before :each do
169
+ @cucumber.before_steps(@step)
170
+ end
171
+
172
+ it "should indicate that the test case has finished" do
173
+ @test_case.should_receive(:finish)
174
+ @cucumber.after_steps(@step)
175
+ end
176
+
177
+ it "should add the test case to the suite's list of cases" do
178
+ @testcases.should be_empty
179
+ @cucumber.after_steps(@step)
180
+ @testcases.should_not be_empty
181
+ @testcases.first.should == @test_case
182
+ end
183
+
184
+ it "should alter the name of a test case that is pending to include '(PENDING)'" do
185
+ @step.stub!(:status).and_return(:pending)
186
+ @test_case.should_receive(:name=).with("Step Name (PENDING)")
187
+ @cucumber.after_steps(@step)
188
+ end
189
+
190
+ it "should alter the name of a test case that is undefined to include '(PENDING)'" do
191
+ @step.stub!(:status).and_return(:undefined)
192
+ @test_case.should_receive(:name=).with("Step Name (PENDING)")
193
+ @cucumber.after_steps(@step)
194
+ end
195
+
196
+ it "should alter the name of a test case that was skipped to include '(SKIPPED)'" do
197
+ @step.stub!(:status).and_return(:skipped)
198
+ @test_case.should_receive(:name=).with("Step Name (SKIPPED)")
199
+ @cucumber.after_steps(@step)
200
+ end
201
+ end
202
+
203
+ describe "that fails" do
204
+ before(:each) do
205
+ @step.stub!(:status).and_return(:failed)
206
+
207
+ @failures = []
208
+ @test_case.stub!(:failures).and_return(@failures)
209
+
210
+ @cucumber.before_steps(@step)
211
+
212
+ @cucumber_failure = mock("cucumber_failure")
213
+ CI::Reporter::CucumberFailure.stub!(:new).and_return(@cucumber_failure)
214
+ end
215
+
216
+ it "should create a new cucumber failure with that step" do
217
+ CI::Reporter::CucumberFailure.should_receive(:new).with(@step)
218
+ @cucumber.after_steps(@step)
219
+ end
220
+
221
+ it "should add the failure to the suite's list of failures" do
222
+ @failures.should be_empty
223
+ @cucumber.after_steps(@step)
224
+ @failures.should_not be_empty
225
+ @failures.first.should == @cucumber_failure
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2006-2010 Nick Sieger <nicksieger@gmail.com>
2
+ # See the file LICENSE.txt included with the distribution for
3
+ # software license details.
4
+
5
+ require File.dirname(__FILE__) + "/../../spec_helper.rb"
6
+ require 'rexml/document'
7
+
8
+ describe "Output capture" do
9
+ before(:each) do
10
+ @suite = CI::Reporter::TestSuite.new "test"
11
+ end
12
+
13
+ it "should save stdout and stderr messages written during the test run" do
14
+ @suite.start
15
+ puts "Hello"
16
+ $stderr.print "Hi"
17
+ @suite.finish
18
+ @suite.stdout.should == "Hello\n"
19
+ @suite.stderr.should == "Hi"
20
+ end
21
+
22
+ it "should include system-out and system-err elements in the xml output" do
23
+ @suite.start
24
+ puts "Hello"
25
+ $stderr.print "Hi"
26
+ @suite.finish
27
+
28
+ root = REXML::Document.new(@suite.to_xml).root
29
+ root.elements.to_a('//system-out').length.should == 1
30
+ root.elements.to_a('//system-err').length.should == 1
31
+ root.elements.to_a('//system-out').first.texts.first.to_s.strip.should == "Hello"
32
+ root.elements.to_a('//system-err').first.texts.first.to_s.strip.should == "Hi"
33
+ end
34
+
35
+ it "should return $stdout and $stderr to original value after finish" do
36
+ out, err = $stdout, $stderr
37
+ @suite.start
38
+ $stdout.object_id.should_not == out.object_id
39
+ $stderr.object_id.should_not == err.object_id
40
+ @suite.finish
41
+ $stdout.object_id.should == out.object_id
42
+ $stderr.object_id.should == err.object_id
43
+ end
44
+
45
+ it "should capture only during run of owner test suite" do
46
+ $stdout.print "A"
47
+ $stderr.print "A"
48
+ @suite.start
49
+ $stdout.print "B"
50
+ $stderr.print "B"
51
+ @suite.finish
52
+ $stdout.print "C"
53
+ $stderr.print "C"
54
+ @suite.stdout.should == "B"
55
+ @suite.stderr.should == "B"
56
+ end
57
+ end
@@ -0,0 +1,100 @@
1
+ # Copyright (c) 2006-2010 Nick Sieger <nicksieger@gmail.com>
2
+ # See the file LICENSE.txt included with the distribution for
3
+ # software license details.
4
+
5
+ require File.dirname(__FILE__) + "/../../../spec_helper.rb"
6
+ require 'rake'
7
+
8
+ def save_env(v)
9
+ ENV["PREV_#{v}"] = ENV[v]
10
+ end
11
+ def restore_env(v)
12
+ ENV[v] = ENV["PREV_#{v}"]
13
+ ENV.delete("PREV_#{v}")
14
+ end
15
+
16
+ describe "ci_reporter ci:setup:testunit task" do
17
+ before(:each) do
18
+ @rake = Rake::Application.new
19
+ Rake.application = @rake
20
+ load CI_REPORTER_LIB + '/ci/reporter/rake/test_unit.rb'
21
+ save_env "CI_REPORTS"
22
+ save_env "TESTOPTS"
23
+ ENV["CI_REPORTS"] = "some-bogus-nonexistent-directory-that-wont-fail-rm_rf"
24
+ end
25
+ after(:each) do
26
+ restore_env "TESTOPTS"
27
+ restore_env "CI_REPORTS"
28
+ Rake.application = nil
29
+ end
30
+
31
+ it "should set ENV['TESTOPTS'] to include test/unit setup file" do
32
+ @rake["ci:setup:testunit"].invoke
33
+ ENV["TESTOPTS"].should =~ /test_unit_loader/
34
+ end
35
+
36
+ it "should append to ENV['TESTOPTS'] if it already contains a value" do
37
+ ENV["TESTOPTS"] = "somevalue".freeze
38
+ @rake["ci:setup:testunit"].invoke
39
+ ENV["TESTOPTS"].should =~ /somevalue.*test_unit_loader/
40
+ end
41
+ end
42
+
43
+ describe "ci_reporter ci:setup:rspec task" do
44
+ before(:each) do
45
+ @rake = Rake::Application.new
46
+ Rake.application = @rake
47
+ load CI_REPORTER_LIB + '/ci/reporter/rake/rspec.rb'
48
+ save_env "CI_REPORTS"
49
+ save_env "SPEC_OPTS"
50
+ ENV["CI_REPORTS"] = "some-bogus-nonexistent-directory-that-wont-fail-rm_rf"
51
+ end
52
+ after(:each) do
53
+ restore_env "SPEC_OPTS"
54
+ restore_env "CI_REPORTS"
55
+ Rake.application = nil
56
+ end
57
+
58
+ it "should set ENV['SPEC_OPTS'] to include rspec formatter args" do
59
+ @rake["ci:setup:rspec"].invoke
60
+ ENV["SPEC_OPTS"].should =~ /--require.*rspec_loader.*--format.*CI::Reporter::RSpec/
61
+ end
62
+
63
+ it "should set ENV['SPEC_OPTS'] to include rspec doc formatter if task is ci:setup:rspecdoc" do
64
+ @rake["ci:setup:rspecdoc"].invoke
65
+ ENV["SPEC_OPTS"].should =~ /--require.*rspec_loader.*--format.*CI::Reporter::RSpecDoc/
66
+ end
67
+
68
+ it "should append to ENV['SPEC_OPTS'] if it already contains a value" do
69
+ ENV["SPEC_OPTS"] = "somevalue".freeze
70
+ @rake["ci:setup:rspec"].invoke
71
+ ENV["SPEC_OPTS"].should =~ /somevalue.*--require.*rspec_loader.*--format.*CI::Reporter::RSpec/
72
+ end
73
+ end
74
+
75
+ describe "ci_reporter ci:setup:cucumber task" do
76
+ before(:each) do
77
+ @rake = Rake::Application.new
78
+ Rake.application = @rake
79
+ load CI_REPORTER_LIB + '/ci/reporter/rake/cucumber.rb'
80
+ save_env "CI_REPORTS"
81
+ save_env "CUCUMBER_OPTS"
82
+ ENV["CI_REPORTS"] = "some-bogus-nonexistent-directory-that-wont-fail-rm_rf"
83
+ end
84
+ after(:each) do
85
+ restore_env "CUCUMBER_OPTS"
86
+ restore_env "CI_REPORTS"
87
+ Rake.application = nil
88
+ end
89
+
90
+ it "should set ENV['CUCUMBER_OPTS'] to include cucumber formatter args" do
91
+ @rake["ci:setup:cucumber"].invoke
92
+ ENV["CUCUMBER_OPTS"].should =~ /--require.*cucumber_loader.*--format.*CI::Reporter::Cucumber/
93
+ end
94
+
95
+ it "should append to ENV['CUCUMBER_OPTS'] if it already contains a value" do
96
+ ENV["CUCUMBER_OPTS"] = "somevalue".freeze
97
+ @rake["ci:setup:cucumber"].invoke
98
+ ENV["CUCUMBER_OPTS"].should =~ /somevalue.*--require.*cucumber_loader.*--format.*CI::Reporter::Cucumber/
99
+ end
100
+ end