Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TAP formatter to spec suite #6286

Merged
merged 3 commits into from Aug 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 85 additions & 0 deletions spec/std/spec/tap_formatter_spec.cr
@@ -0,0 +1,85 @@
require "spec"
require "xml"

private def build_report
String.build do |io|
formatter = Spec::TAPFormatter.new(io)
yield formatter
formatter.finish
end
end

private def exception_with_backtrace(msg)
begin
raise Exception.new(msg)
rescue e
e
end
end

describe Spec::TAPFormatter do
it "reports successful results" do
output = build_report do |f|
f.report Spec::Result.new(:success, "should do something", "spec/some_spec.cr", 33, nil, nil)
f.report Spec::Result.new(:success, "should do something else", "spec/some_spec.cr", 50, nil, nil)
end

output.chomp.should eq <<-TAP
ok 1 - should do something
ok 2 - should do something else
1..2
TAP
end

it "reports failures" do
output = build_report do |f|
f.report Spec::Result.new(:fail, "should do something", "spec/some_spec.cr", 33, nil, nil)
end

output.chomp.should eq <<-TAP
not ok 1 - should do something
1..1
TAP
end

it "reports errors" do
output = build_report do |f|
f.report Spec::Result.new(:error, "should do something", "spec/some_spec.cr", 33, nil, nil)
end

output.chomp.should eq <<-TAP
not ok 1 - should do something
1..1
TAP
end

it "reports pending" do
output = build_report do |f|
f.report Spec::Result.new(:pending, "should do something", "spec/some_spec.cr", 33, nil, nil)
end

output.chomp.should eq <<-TAP
ok 1 - # SKIP should do something
1..1
TAP
end

it "reports mixed results" do
output = build_report do |f|
f.report Spec::Result.new(:success, "should do something1", "spec/some_spec.cr", 33, 2.seconds, nil)
f.report Spec::Result.new(:fail, "should do something2", "spec/some_spec.cr", 50, 0.5.seconds, nil)
f.report Spec::Result.new(:error, "should do something3", "spec/some_spec.cr", 65, nil, nil)
f.report Spec::Result.new(:error, "should do something4", "spec/some_spec.cr", 80, nil, nil)
f.report Spec::Result.new(:pending, "should do something5", "spec/some_spec.cr", 33, nil, nil)
end

output.chomp.should eq <<-TAP
ok 1 - should do something1
not ok 2 - should do something2
not ok 3 - should do something3
not ok 4 - should do something4
ok 5 - # SKIP should do something5
1..5
TAP
end
end
3 changes: 3 additions & 0 deletions src/spec.cr
Expand Up @@ -99,6 +99,9 @@ OptionParser.parse! do |opts|
opts.on("-v", "--verbose", "verbose output") do
Spec.override_default_formatter(Spec::VerboseFormatter.new)
end
opts.on("--tap", "Generate TAP output (Test Anything Protocol)") do
Spec.override_default_formatter(Spec::TAPFormatter.new)
end
opts.on("--no-color", "Disable colored output") do
Spec.use_colors = false
end
Expand Down
9 changes: 8 additions & 1 deletion src/spec/context.cr
Expand Up @@ -50,9 +50,16 @@ module Spec
@@instance.succeeded
end

def print_results(elapsed_time, aborted = false)
def self.finish(elapsed_time, aborted = false)
@@instance.finish(elapsed_time, aborted)
end

def finish(elapsed_time, aborted = false)
Spec.formatters.each(&.finish)
Spec.formatters.each(&.print_results(elapsed_time, aborted))
end

def print_results(elapsed_time, aborted = false)
pendings = @results[:pending]
unless pendings.empty?
puts
Expand Down
2 changes: 1 addition & 1 deletion src/spec/dsl.cr
Expand Up @@ -170,7 +170,7 @@ module Spec
start_time = Time.monotonic
at_exit do
elapsed_time = Time.monotonic - start_time
Spec::RootContext.print_results(elapsed_time, @@aborted)
Spec::RootContext.finish(elapsed_time, @@aborted)
exit 1 unless Spec::RootContext.succeeded && !@@aborted
end
end
Expand Down
46 changes: 29 additions & 17 deletions src/spec/formatter.cr
@@ -1,6 +1,9 @@
module Spec
# :nodoc:
abstract class Formatter
def initialize(@io : IO = STDOUT)
end

def push(context)
end

Expand All @@ -15,16 +18,23 @@ module Spec

def finish
end

def print_results(elapsed_time : Time::Span, aborted : Bool)
end
end

# :nodoc:
class DotFormatter < Formatter
def report(result)
print Spec.color(LETTERS[result.kind], result.kind)
@io << Spec.color(LETTERS[result.kind], result.kind)
end

def finish
puts
@io.puts
end

def print_results(elapsed_time : Time::Span, aborted : Bool)
Spec::RootContext.print_results(elapsed_time, aborted)
end
end

Expand All @@ -35,20 +45,18 @@ module Spec
@printed = false
end

def print
def print(io)
return if @printed
@printed = true

VerboseFormatter.print_indent(@indent)
puts @description
VerboseFormatter.print_indent(io, @indent)
io.puts @description
end
end

def initialize
@indent = 0
@last_description = ""
@items = [] of Item
end
@indent = 0
@last_description = ""
@items = [] of Item

def push(context)
@items << Item.new(@indent, context.description)
Expand All @@ -61,24 +69,28 @@ module Spec
end

def print_indent
self.class.print_indent(@indent)
self.class.print_indent(@io, @indent)
end

def self.print_indent(indent)
indent.times { print " " }
def self.print_indent(io, indent)
indent.times { io << " " }
end

def before_example(description)
@items.each &.print
@items.each &.print(@io)
print_indent
print description
@io << description
@last_description = description
end

def report(result)
print '\r'
@io << '\r'
print_indent
puts Spec.color(@last_description, result.kind)
@io.puts Spec.color(@last_description, result.kind)
end

def print_results(elapsed_time : Time::Span, aborted : Bool)
Spec::RootContext.print_results(elapsed_time, aborted)
end
end

Expand Down
6 changes: 1 addition & 5 deletions src/spec/junit_formatter.cr
Expand Up @@ -3,21 +3,17 @@ require "html"
module Spec
# :nodoc:
class JUnitFormatter < Formatter
@output : IO
@results = [] of Spec::Result
@summary = {} of Symbol => Int32

def initialize(@output)
end

def report(result)
current = @summary[result.kind]? || 0
@summary[result.kind] = current + 1
@results << result
end

def finish
io = @output
io = @io
io.puts %(<?xml version="1.0"?>)
io << %(<testsuite tests=") << @results.size
io << %(" errors=") << (@summary[:error]? || 0)
Expand Down
30 changes: 30 additions & 0 deletions src/spec/tap_formatter.cr
@@ -0,0 +1,30 @@
# :nodoc:
class Spec::TAPFormatter < Spec::Formatter
@counter = 0

def report(result)
case result.kind
when :success
Copy link
Contributor

@wooster0 wooster0 Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be when :success, :pending. And the when :pending should be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, that would reduce visibility. Separate entries makes it obvious what we're looking at.

@io << "ok"
when :fail, :error
@io << "not ok"
when :pending
@io << "ok"
end

@counter += 1

@io << ' ' << @counter << " -"
if result.kind == :pending
@io << " # SKIP"
end
@io << ' ' << result.description

@io.puts
end

def finish
@io << "1.." << @counter
@io.puts
end
end