require 'rubygems' require 'sinatra/base' require 'syntax/convertors/html' module Cuukie class Server < Sinatra::Base set :features, [] set :build_status, 'undefined' set :start_time, nil set :duration, nil set :stats, Hash.new('') get '/' do @features = settings.features @build_status = settings.build_status @stats = settings.stats erb :index end post '/before_features' do settings.features.clear settings.build_status = 'undefined' settings.start_time = Time.now settings.duration = nil settings.stats = Hash.new('') end post '/before_feature' do feature = read_from_request feature[:keyword] = '...' feature[:description] = feature[:description].split("\n") feature[:scenarios] = [] feature[:id] = settings.features.size + 1 settings.features << feature 'OK' end post '/feature_name' do current_feature.merge! read_from_request 'OK' end post '/scenario_name' do scenario = read_from_request scenario[:steps] = [] scenario[:id] = "scenario_#{current_feature[:id]}_#{current_feature[:scenarios].size + 1}" scenario[:status] = 'undefined' current_feature[:scenarios] << scenario 'OK' end post '/before_step' do step = read_from_request step[:table] = [] step[:status] = 'undefined' current_scenario[:steps] << step 'OK' end post '/before_table_row' do current_step[:table] << [] 'OK' end post '/table_cell_value' do data = read_from_request current_step[:table].last << data[:value] 'OK' end post '/doc_string' do data = read_from_request current_step[:multiline_string] = data[:multiline_string] 'OK' end post '/exception' do current_step[:exception] = read_from_request 'OK' end post '/after_step_result' do current_step.merge! read_from_request if current_step[:status] == 'failed' current_scenario[:status] = settings.build_status = 'failed' elsif current_step[:status] == 'pending' current_scenario[:status] = 'pending' settings.build_status = 'pending' if settings.build_status == 'undefined' end 'OK' end post '/after_steps' do if current_scenario[:steps].all? {|step| step[:status] == 'skipped' } current_scenario[:status] = 'skipped' end current_scenario[:status] = 'passed' if current_scenario[:status] == 'undefined' 'OK' end post '/after_features' do settings.duration = read_from_request[:duration] settings.build_status = 'passed' if settings.build_status == 'undefined' settings.stats = stats 'OK' end get('/ping') { 'pong!' } delete('/') { exit! } helpers do def code_snippet_for(exception) return '' unless exception[:raw_lines] result = '
'
linenum = exception[:first_line].to_i
html_lines = htmlize(exception[:raw_lines]).split "\n"
html_lines.each do |html_line|
line = "#{linenum}#{html_line}"
line = "#{line}" if linenum.to_s == exception[:marked_line]
result << "#{line}
"
linenum += 1
end
result << '
'
end
def time_label
settings.duration ? "Duration" : "Running time"
end
def format_time
min, sec = time.to_i.divmod(60)
"#{min}':#{sec}''"
end
end
def current_feature
settings.features.last
end
def current_scenario
# return a "nil scenario" (that includes a "nil step") if we
# don't have a scenario yet. this is useful to eliminate steps
# coming from backgrounds (which will be re-sent during the
# following scenarios anyway)
return { :steps => [{}] } if current_feature[:scenarios].empty?
current_feature[:scenarios].last
end
def current_step
current_scenario[:steps].last
end
def time
return settings.duration if settings.duration
return 0 unless settings.start_time
return Time.now - settings.start_time
end
def stats
scenarios = []
settings.features.each {|feature| scenarios.concat feature[:scenarios] }
result = {:scenarios => String.new, :steps => String.new}
result[:scenarios] << pluralize(scenarios.size, "scenario")
result[:scenarios] << counts(scenarios)
steps = []
scenarios.each {|scenario| steps.concat scenario[:steps] }
result[:steps] << pluralize(steps.size, "step")
step_count = counts steps
result[:steps] << step_count if step_count
result
end
def pluralize(count, what)
"#{count} #{what}#{count == 1 ? '' : 's'}"
end
def counts(elements)
counts = ['failed', 'skipped', 'undefined', 'pending', 'passed'].map do |status|
selected = elements.find_all {|element| element[:status] == status }
selected.any? ? "#{selected.size} #{status}" : nil
end.compact
counts.any? ? " (#{counts.join(', ')})" : ''
end
def htmlize(ruby)
convertor = Syntax::Convertors::HTML.for_syntax("ruby")
convertor.convert(ruby, false)
end
def read_from_request
result = {}
request.params.each do |k, v|
result[k.to_sym] = (k =~ /^raw_/) ? v : Rack::Utils.escape_html(v)
end
result
end
end
end
if __FILE__ == $0
Cuukie::Server.set :port, ARGV[0] if ARGV[0]
Cuukie::Server.run!
end