Skip to content
This repository was archived by the owner on Feb 1, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Make sure bwoken is <a href="#installation">properly installed</a>. Then, build
<pre><code># will build and run all of your tests
$ rake

# will use xunit output formatter (default colorized)
$ rake formatter=xunit

# will run one file, relative to integration/coffeescript (note: no file extension)
$ RUN=iphone/focused_test rake
</code></pre>
Expand Down
8 changes: 7 additions & 1 deletion lib/bwoken.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'bwoken/build'
require 'bwoken/coffeescript'
require 'bwoken/formatters/colorful_formatter'
require 'bwoken/formatters/xunit_formatter'
require 'bwoken/script'
require 'bwoken/simulator'
require 'bwoken/device'
Expand All @@ -23,7 +24,12 @@ def app_name
end

def formatter
@formatter ||= Bwoken::ColorfulFormatter.new
formatter_type = ENV['formatter'] || 'color'
if formatter_type == 'xunit'
@formatter = Bwoken::XunitFormatter::Formatter.new(File.join(results_path, "#{app_name}.xml"))
else
@formatter = Bwoken::ColorfulFormatter.new
end
end

def project_path
Expand Down
2 changes: 1 addition & 1 deletion lib/bwoken/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def format_build stdout

def on name, &block
define_method "_on_#{name}_callback" do |*line|
block.call(*line)
self.instance_exec(*line, &block)
end
end

Expand Down
150 changes: 150 additions & 0 deletions lib/bwoken/formatters/xunit_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
require 'bwoken/formatter'
require 'date'

module Bwoken::XunitFormatter

##
# based on the code by @sebastianludwig as a part of tuneup.js
# https://github.com/alexvollmer/tuneup_js/blob/master/test_runner/xunit_output.rb
##
class TestSuite
attr_reader :name, :timestamp
attr_accessor :test_cases

def initialize(name)
@name = name
@test_cases = []
@timestamp = DateTime.now
end

def failures
@test_cases.count { |test| test.failed? }
end

def time
@test_cases.map { |test| test.time }.inject(:+)
end
end

class TestCase
attr_reader :name
attr_accessor :messages

def initialize(name)
@name = name
@messages = []
@failed = true
@start = Time.now
@finish = nil
end

def <<(message)
@messages << message
end

def pass!
@failed = false;
@finish = Time.now
end

def fail!
@finish = Time.now
end

def failed?
@failed
end

def time
return 0 if @finish.nil?
@finish - @start
end
end

class XunitOutput
attr_reader :suite

def initialize(filename)
@filename = filename
@suite = TestSuite.new(File.basename(filename, File.extname(filename)))
end

def add(line)
return if @suite.test_cases.empty?
@suite.test_cases.last << line
end

def add_status(status, msg)
case status
when :start
@suite.test_cases << TestCase.new(msg)
when :pass
@suite.test_cases.last.pass!
when :fail
@suite.test_cases.last.fail!
end
end

def close
File.open(@filename, 'w') { |f| f.write(serialize(@suite)) }
end

def xml_escape(input)
result = input.dup

result.gsub!("&", "&amp;")
result.gsub!("<", "&lt;")
result.gsub!(">", "&gt;")
result.gsub!("'", "&apos;")
result.gsub!("\"", "&quot;")

return result
end

def serialize(suite)
output = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" << "\n"
output << "<testsuite name=\"#{xml_escape(suite.name)}\" timestamp=\"#{suite.timestamp}\" time=\"#{suite.time}\" tests=\"#{suite.test_cases.count}\" failures=\"#{suite.failures}\">" << "\n"

suite.test_cases.each do |test|
output << " <testcase name=\"#{xml_escape(test.name)}\" time=\"#{test.time}\">" << "\n"
if test.failed?
output << " <failure>#{test.messages.map { |m| xml_escape(m) }.join("\n")}</failure>" << "\n"
end
output << " </testcase>" << "\n"
end

output << "</testsuite>" << "\n"
end
end

class Formatter < Bwoken::Formatter

def initialize(filename)
@output = XunitOutput.new(filename)
end

on :complete do |line|
@output.close
end

on :error do |line|
tokens = line.split(' ')
@output.add(tokens[4..-1].join(' ')) if line.include?('Exception')
end

on :fail do |line|
tokens = line.split(' ')
@output.add_status(:fail, tokens[4..-1].join(' '))
end

on :start do |line|
tokens = line.split(' ')
@output.add_status(:start, tokens[4..-1].join(' '))
end

on :pass do |line|
tokens = line.split(' ')
@output.add_status(:pass, tokens[4..-1].join(' '))
end
end
end
177 changes: 177 additions & 0 deletions spec/lib/bwoken/formatters/xunit_formatter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
require 'spec_helper'

require 'bwoken/formatters/xunit_formatter'

describe Bwoken::XunitFormatter::TestSuite do
subject { described_class.new('FakeProject') }

describe '.failures' do
context 'when contain failed test case' do
before { subject.test_cases << Bwoken::XunitFormatter::TestCase.new('foo') }
it 'returns number of failed cases' do
subject.failures.should == 1
end
end
end

describe '.time' do
before do
foo = Bwoken::XunitFormatter::TestCase.new('foo')
bar = Bwoken::XunitFormatter::TestCase.new('bar')
foo.stub(:time => 10)
bar.stub(:time => 1)
subject.test_cases << foo
subject.test_cases << bar
end

it 'returns number of seconds cosumed for all cases' do
subject.time.should == 11
end
end
end

describe Bwoken::XunitFormatter::TestCase do
subject { described_class.new('FakeTest') }

describe '.pass!' do
before do
time = Time.now
Time.stub(:now => time)
subject << 'Triggering creation'
Time.stub(:now => time + 2)
subject.pass!
end

it 'changes case status to passed' do
subject.failed?.should == false;
end

it 'saves finished time' do
subject.time.should == 2
end
end

describe '.fail!' do
before do
time = Time.now
Time.stub(:now => time)
subject << 'Triggering creation'
Time.stub(:now => time + 2)
subject.fail!
end

it 'saves finished time' do
subject.time.should == 2
end
end

describe '.failed?' do
context 'when test failed' do
it 'returns true' do
subject.failed?.should == true
end
end

context 'when test passed' do
before { subject.pass! }
it 'returns false' do
subject.failed?.should == false
end
end
end

describe '.time' do
context 'when test finished' do
before do
time = Time.now
Time.stub(:now => time)
subject << 'Triggering creation'
Time.stub(:now => time + 2)
subject.pass!
end

it 'returns number of seconds consumed by test case' do
subject.time.should == 2
end
end

context 'when test is not finished' do
it 'returns 0' do
subject.time.should == 0
end
end
end
end

describe Bwoken::XunitFormatter::XunitOutput do
subject { described_class.new('fake_file_path') }

describe '.add' do
before { subject.add_status(:start, '') }
it 'appends line to the last test case' do
subject.suite.test_cases.last.should_receive(:<<).with('foo')
subject.add('foo')
end
end

describe '.addStatus' do
context 'with :start' do
it 'creates new test case' do
subject.suite.test_cases.should_receive(:<<)
subject.add_status(:start, '')
end
end

context 'with :pass' do
before { subject.add_status(:start, '') }
it 'changes last test case status to passed' do
subject.suite.test_cases.last.should_receive(:pass!)
subject.add_status(:pass, '')
end
end

context 'with :fail' do
before { subject.add_status(:start, '') }
it 'changes last test case status to failed' do
subject.suite.test_cases.last.should_receive(:fail!)
subject.add_status(:fail, '')
end
end
end

describe '.close' do
it 'writes serialized test suite to the file' do
File.should_receive(:open).with('fake_file_path', 'w')
subject.close
end
end

describe '.serialize' do
before do
@datetime = DateTime.now
DateTime.stub(:now => @datetime)

@time = Time.now
Time.stub(:now => @time)

subject.add_status(:start, 'failed case')
subject.add('foo')
subject.add_status(:fail, '')
subject.add_status(:start, 'passed case')
subject.add_status(:pass, '')
end

it 'returns test suite as xml document' do
subject.serialize(subject.suite).should == <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<testsuite name="fake_file_path" timestamp="#{@datetime}" time="0.0" tests="2" failures="1">
<testcase name="failed case" time="0.0">
<failure>foo</failure>
</testcase>
<testcase name="passed case" time="0.0">
</testcase>
</testsuite>
XML
end
end
end
17 changes: 15 additions & 2 deletions spec/lib/bwoken_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,21 @@
end

describe '#formatter' do
it 'returns Bwoken::ColorfulFormatter' do
subject.formatter.should be_kind_of(Bwoken::ColorfulFormatter)
context 'without formatter env variable' do
it 'returns Bwoken::ColorfulFormatter' do
subject.formatter.should be_kind_of(Bwoken::ColorfulFormatter)
end
end

context "with ENV['formatter'] = 'xunit'" do
before do
ENV['formatter'] = 'xunit'
subject.stub(:app_name => 'FakeProject')
end

it 'returns Bwoken::XunitFormatter for ' do
subject.formatter.should be_kind_of(Bwoken::XunitFormatter::Formatter)
end
end
end

Expand Down