aspec 0.1
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.
- data/README.md +16 -0
- data/bin/aspec +14 -0
- data/lib/aspec.rb +55 -0
- data/lib/aspec/cli.rb +45 -0
- data/lib/aspec/formatters/junit.rb +92 -0
- data/lib/aspec/formatters/terminal.rb +80 -0
- data/lib/aspec/parser.rb +50 -0
- data/lib/aspec/runner.rb +76 -0
- data/lib/aspec/test.rb +140 -0
- data/spec/aspec_spec.rb +9 -0
- data/spec/cli_spec.rb +14 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/test_app/aspec/aspec_helper.rb +8 -0
- data/spec/test_app/test_app.rb +27 -0
- metadata +100 -0
data/README.md
ADDED
data/bin/aspec
ADDED
data/lib/aspec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'rack/test'
|
4
|
+
require 'rspec/mocks/standalone'
|
5
|
+
require 'term/ansicolor'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
require 'aspec/cli'
|
9
|
+
require 'aspec/formatters/terminal'
|
10
|
+
require 'aspec/formatters/junit'
|
11
|
+
require 'aspec/runner'
|
12
|
+
require 'aspec/parser'
|
13
|
+
require 'aspec/test'
|
14
|
+
|
15
|
+
module Aspec
|
16
|
+
def self.configuration
|
17
|
+
@configuration ||= Configure.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield configuration
|
22
|
+
end
|
23
|
+
|
24
|
+
class Configure
|
25
|
+
attr_accessor :verbose, :slow, :formatter
|
26
|
+
|
27
|
+
def verbose?; verbose; end
|
28
|
+
def slow?; slow; end
|
29
|
+
|
30
|
+
def app_under_test(&block)
|
31
|
+
@app_under_test = block
|
32
|
+
end
|
33
|
+
|
34
|
+
def before(&block)
|
35
|
+
@before = block
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_app_under_test
|
39
|
+
@app_under_test
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_before
|
43
|
+
@before
|
44
|
+
end
|
45
|
+
|
46
|
+
def after_suite(&block)
|
47
|
+
@after_suite = block
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_after_suite
|
51
|
+
@after_suite
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/lib/aspec/cli.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module Aspec
|
3
|
+
class CLI
|
4
|
+
attr_reader :args, :working_dir
|
5
|
+
|
6
|
+
def initialize(working_dir, args)
|
7
|
+
@working_dir = working_dir
|
8
|
+
@args = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def aspec_files
|
12
|
+
files = []
|
13
|
+
@args.each do |arg|
|
14
|
+
arg = File.expand_path(arg, working_dir)
|
15
|
+
if File.exist?(arg)
|
16
|
+
if File.directory?(arg)
|
17
|
+
files += Dir[arg + "**/*.aspec"]
|
18
|
+
elsif arg =~ /.*\.aspec/
|
19
|
+
files << arg
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
files
|
24
|
+
end
|
25
|
+
|
26
|
+
def aspec_helper_path
|
27
|
+
File.expand_path("aspec/aspec_helper.rb")
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
bits = args[0].split(":")
|
32
|
+
|
33
|
+
load aspec_helper_path if File.exist?(aspec_helper_path)
|
34
|
+
|
35
|
+
@lines = bits[1..-1].map(&:to_i)
|
36
|
+
is_verbose = args.include?("-v")
|
37
|
+
Aspec.configure do |c|
|
38
|
+
c.verbose = is_verbose
|
39
|
+
c.slow = args.include?("--slow")
|
40
|
+
c.formatter = args.include?("--junit") ? Formatter::JUnit.new(@file) : Formatter::Terminal.new(is_verbose)
|
41
|
+
end
|
42
|
+
TestRunner.new(Aspec.configuration, aspec_files).run(@lines)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
module Aspec
|
3
|
+
module Formatter
|
4
|
+
class JUnit
|
5
|
+
def initialize(test_file_name, verbose = false, out_file_name = '.junit_aspecs')
|
6
|
+
@test_results = { :failures => [], :successes => [] }
|
7
|
+
@out = File.open(out_file_name, 'w')
|
8
|
+
@test_file_name = test_file_name
|
9
|
+
@exceptions = []
|
10
|
+
at_exit do
|
11
|
+
unless @out.closed?
|
12
|
+
@out.flush
|
13
|
+
@out.close
|
14
|
+
puts "Output junit results to .junit_aspecs"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def comment(comment_string)
|
23
|
+
end
|
24
|
+
|
25
|
+
def step_error(step)
|
26
|
+
@test_results[:failures] << [step_line(step), @exceptions]
|
27
|
+
@exceptions = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def exception(error_string)
|
31
|
+
@exceptions << error_string
|
32
|
+
end
|
33
|
+
|
34
|
+
def step_error_title(step)
|
35
|
+
end
|
36
|
+
|
37
|
+
def step_pass(step)
|
38
|
+
@test_results[:successes] << step_line(step)
|
39
|
+
end
|
40
|
+
|
41
|
+
def debug
|
42
|
+
end
|
43
|
+
|
44
|
+
def dump_summary(summary)
|
45
|
+
@out.puts("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
|
46
|
+
@out.puts("<testsuite errors=\"0\" failures=\"#{failure_count}\" tests=\"#{example_count}\" time=\"#{duration=0}\" timestamp=\"#{Time.now.iso8601}\">")
|
47
|
+
@out.puts(" <properties />")
|
48
|
+
|
49
|
+
@test_results[:successes].each do |success_string|
|
50
|
+
#TODO: Add timings
|
51
|
+
runtime = 0
|
52
|
+
@out.puts(" <testcase classname=\"#{@test_file_name}\" name=\"#{test_name(success_string)}\" time=\"#{runtime}\" />")
|
53
|
+
end
|
54
|
+
@test_results[:failures].each do |(failure_string, exceptions)|
|
55
|
+
runtime = 0
|
56
|
+
@out.puts(" <testcase classname=\"#{@test_file_name}\" name=\"#{failure_string}\" time=\"#{runtime}\">")
|
57
|
+
|
58
|
+
@out.puts(" <failure message=\"failure\" type=\"failure\">")
|
59
|
+
@out.puts("<![CDATA[ #{exceptions} ]]>")
|
60
|
+
@out.puts(" </failure>")
|
61
|
+
@out.puts(" </testcase>")
|
62
|
+
end
|
63
|
+
@out.puts("</testsuite>")
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def step_line(step)
|
68
|
+
"#{step[:method]} #{step[:url]} line: #{step[:line_num]}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_name(string)
|
72
|
+
xml_encode(string.split("\n")[0].strip)
|
73
|
+
end
|
74
|
+
|
75
|
+
def example_count
|
76
|
+
@test_results[:successes].count + failure_count
|
77
|
+
end
|
78
|
+
|
79
|
+
def failure_count
|
80
|
+
@test_results[:failures].count
|
81
|
+
end
|
82
|
+
|
83
|
+
def xml_encode(string)
|
84
|
+
#TODO: Use builder to do this
|
85
|
+
string.gsub!('&', '&')
|
86
|
+
string.gsub!('>', '')
|
87
|
+
string.gsub!('"','"')
|
88
|
+
string
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module Aspec
|
3
|
+
module Formatter
|
4
|
+
class Terminal
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
def initialize(verbose, out = STDOUT)
|
8
|
+
@out = out
|
9
|
+
@verbose = verbose
|
10
|
+
@line_buffer ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear
|
14
|
+
@line_buffer.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
def comment(comment_string)
|
18
|
+
line(comment_string)
|
19
|
+
end
|
20
|
+
|
21
|
+
def exception(error_string)
|
22
|
+
line(error_string)
|
23
|
+
end
|
24
|
+
|
25
|
+
def step_error_title(step)
|
26
|
+
step_line(step)
|
27
|
+
end
|
28
|
+
|
29
|
+
def step_error(step)
|
30
|
+
line(red + step_line(step) + reset)
|
31
|
+
print_error unless @verbose
|
32
|
+
end
|
33
|
+
|
34
|
+
def step_pass(step)
|
35
|
+
line(green + step_line(step) + reset)
|
36
|
+
end
|
37
|
+
|
38
|
+
def debug(step)
|
39
|
+
@out.puts(step.inspect)
|
40
|
+
end
|
41
|
+
|
42
|
+
def dump_summary(summary)
|
43
|
+
@out.puts summary
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def step_line(step)
|
49
|
+
bits = [step[:method].rjust(7, " "), step[:url].ljust(50, " "), step[:exp_status], (step[:exp_content_type]||"")]
|
50
|
+
if step[:exp_content_type] == "application/json"
|
51
|
+
begin
|
52
|
+
json_string = JSON.parse(step[:exp_response]).to_json
|
53
|
+
if json_string.length > 20
|
54
|
+
json_string = "\n" + JSON.pretty_generate(JSON.parse(step[:exp_response])).split("\n").map {|l| " \\ #{l}"}.join("\n")
|
55
|
+
end
|
56
|
+
bits << json_string
|
57
|
+
rescue JSON::ParserError
|
58
|
+
bits << step[:exp_response]
|
59
|
+
end
|
60
|
+
else
|
61
|
+
bits << step[:exp_response]
|
62
|
+
end
|
63
|
+
bits.join("\t")
|
64
|
+
end
|
65
|
+
|
66
|
+
def line(line_string)
|
67
|
+
@out.puts(line_string) if @verbose
|
68
|
+
@line_buffer << line_string
|
69
|
+
end
|
70
|
+
|
71
|
+
def print_error
|
72
|
+
@line_buffer.each do |line|
|
73
|
+
@out.puts line
|
74
|
+
end
|
75
|
+
@line_buffer = []
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/aspec/parser.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Aspec
|
2
|
+
class Parser
|
3
|
+
def initialize(source)
|
4
|
+
@lines = source.split("\n").map {|l| l.strip}
|
5
|
+
end
|
6
|
+
|
7
|
+
def tests
|
8
|
+
@tests ||= begin
|
9
|
+
tests = [[]]
|
10
|
+
@lines.each_with_index do |line, line_num|
|
11
|
+
if line =~ /^\s*$/
|
12
|
+
if tests.last.length > 0
|
13
|
+
tests << []
|
14
|
+
end
|
15
|
+
elsif line =~ /^\s*\\(.*)$/
|
16
|
+
tests.last.last[:exp_response] = (tests.last.last[:exp_response] + $1)
|
17
|
+
else
|
18
|
+
tests.last << parse_line(line, line_num)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
tests.select {|tests| tests.any?}.map {|steps| Test.new(steps) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_line(line, line_num)
|
26
|
+
if line =~ /^\s*(#.*)$/
|
27
|
+
{:comment => $1, :line_num => line_num}
|
28
|
+
else
|
29
|
+
bits = line.split(" ")
|
30
|
+
method = bits[0]
|
31
|
+
url = bits[1]
|
32
|
+
url = URI.encode(url)
|
33
|
+
|
34
|
+
exp_status = bits[2]
|
35
|
+
exp_status = exp_status.strip if exp_status
|
36
|
+
exp_content_type = bits[3]
|
37
|
+
exp_content_type = exp_content_type.strip if exp_content_type
|
38
|
+
exp_response = (bits[4..-1]||[]).join(" ")
|
39
|
+
is_regex = exp_response[0] == '/' and exp_response[-1] == '/' and exp_response.size > 2
|
40
|
+
exp_response = exp_response[1 .. -2] if is_regex
|
41
|
+
|
42
|
+
{:method => method, :url => url,
|
43
|
+
:exp_status => exp_status, :exp_content_type => exp_content_type, :exp_response => exp_response,
|
44
|
+
:resp_is_regex => is_regex, :line_num => line_num
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/lib/aspec/runner.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
module Aspec
|
3
|
+
class TestRunner
|
4
|
+
include Term::ANSIColor
|
5
|
+
|
6
|
+
attr_reader :config, :source
|
7
|
+
|
8
|
+
def initialize(config, paths)
|
9
|
+
@paths = paths
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def verbose?
|
14
|
+
config.verbose?
|
15
|
+
end
|
16
|
+
|
17
|
+
def slow?
|
18
|
+
config.slow?
|
19
|
+
end
|
20
|
+
|
21
|
+
def formatter
|
22
|
+
config.formatter
|
23
|
+
end
|
24
|
+
|
25
|
+
def tests
|
26
|
+
@tests ||= begin
|
27
|
+
result = []
|
28
|
+
@paths.each do |path|
|
29
|
+
parser = Parser.new(File.read(path))
|
30
|
+
result += parser.tests
|
31
|
+
end
|
32
|
+
result.flatten
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def before_each
|
37
|
+
if before_block = config.get_before
|
38
|
+
before_block.call
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run(lines)
|
43
|
+
successes = 0
|
44
|
+
failures = 0
|
45
|
+
if lines.any?
|
46
|
+
run_tests = tests.select {|test| lines.any? {|line_num| test.contains_line?(line_num)}}
|
47
|
+
else
|
48
|
+
run_tests = tests
|
49
|
+
end
|
50
|
+
|
51
|
+
run_tests.each do |test|
|
52
|
+
before_each
|
53
|
+
if test.run(config)
|
54
|
+
successes += 1 unless test.comment_only?
|
55
|
+
puts if verbose?
|
56
|
+
else
|
57
|
+
failures += 1
|
58
|
+
puts
|
59
|
+
end
|
60
|
+
formatter.clear
|
61
|
+
end
|
62
|
+
color = send(failures > 0 ? :red : :green)
|
63
|
+
formatter.dump_summary color + "#{successes} passed, #{failures} failed." + reset
|
64
|
+
|
65
|
+
if after_suite_block = config.get_after_suite
|
66
|
+
after_suite_block.call
|
67
|
+
end
|
68
|
+
if failures > 0
|
69
|
+
exit(1)
|
70
|
+
else
|
71
|
+
exit(0)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
data/lib/aspec/test.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
module Aspec
|
3
|
+
class Test
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
def initialize(steps)
|
7
|
+
@steps = steps
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_method(method)
|
11
|
+
raise "unknown method #{method}" unless %W(GET POST DELETE PUT).include?(method)
|
12
|
+
end
|
13
|
+
|
14
|
+
def comment_only?
|
15
|
+
@steps.all? {|s| s[:comment]}
|
16
|
+
end
|
17
|
+
|
18
|
+
def contains_line?(line_num)
|
19
|
+
@steps.first[:line_num] <= line_num and @steps.last[:line_num] >= line_num
|
20
|
+
end
|
21
|
+
|
22
|
+
def app
|
23
|
+
@app
|
24
|
+
end
|
25
|
+
|
26
|
+
def run(config)
|
27
|
+
formatter = config.formatter
|
28
|
+
is_slow = config.slow?
|
29
|
+
@app = config.get_app_under_test.call
|
30
|
+
start_time = Time.at(0)
|
31
|
+
failed = false
|
32
|
+
@steps.each_with_index do |step, time_delta|
|
33
|
+
if is_slow
|
34
|
+
sleep 0.5
|
35
|
+
end
|
36
|
+
|
37
|
+
if ARGV.include?("--debug")
|
38
|
+
formatter.debug(step)
|
39
|
+
end
|
40
|
+
|
41
|
+
if failed
|
42
|
+
formatter.step_error_title(step)
|
43
|
+
next
|
44
|
+
end
|
45
|
+
|
46
|
+
if step[:comment]
|
47
|
+
formatter.comment(step[:comment])
|
48
|
+
else
|
49
|
+
Time.stub!(:now).and_return(start_time + 2*time_delta)
|
50
|
+
|
51
|
+
begin
|
52
|
+
if step[:method][0] == ">"
|
53
|
+
method = step[:method][1..-1]
|
54
|
+
validate_method(method)
|
55
|
+
url = "http://" + step[:url]
|
56
|
+
FakeWeb.register_uri(method.downcase.to_sym, url,
|
57
|
+
:body => step[:exp_response],
|
58
|
+
:content_type => step[:exp_content_type]
|
59
|
+
)
|
60
|
+
else
|
61
|
+
validate_method(step[:method])
|
62
|
+
send(step[:method].downcase, step[:url])
|
63
|
+
end
|
64
|
+
rescue Object => e
|
65
|
+
formatter.exception(" " + e.class.to_s + ": " + e.message)
|
66
|
+
e.backtrace.each do |backtrace_line|
|
67
|
+
formatter.exception(" " + backtrace_line) unless backtrace_line =~ /vendor\/bundle/ or backtrace_line =~ /test.rb/
|
68
|
+
end
|
69
|
+
failed = true
|
70
|
+
end
|
71
|
+
|
72
|
+
unless failed or step[:method][0] == ">"
|
73
|
+
if last_response.status.to_s != step[:exp_status]
|
74
|
+
formatter.exception(" * Expected status #{step[:exp_status]} got #{last_response.status}")
|
75
|
+
failed = true
|
76
|
+
end
|
77
|
+
|
78
|
+
if step[:exp_content_type] == "application/json" && !step[:resp_is_regex]
|
79
|
+
begin
|
80
|
+
expected_object = JSON.parse(step[:exp_response])
|
81
|
+
begin
|
82
|
+
response_object = JSON.parse(last_response.body)
|
83
|
+
if expected_object != response_object
|
84
|
+
formatter.exception(" * Expected response #{JSON.pretty_generate(expected_object)} got #{JSON.pretty_generate(response_object)}")
|
85
|
+
failed = true
|
86
|
+
end
|
87
|
+
rescue JSON::ParserError
|
88
|
+
formatter.exception(" * Response did not parse correctly as JSON: #{last_response.body.inspect}")
|
89
|
+
failed = true
|
90
|
+
end
|
91
|
+
rescue JSON::ParserError
|
92
|
+
formatter.exception(" * Expectation did not parse correctly as JSON: #{step[:exp_response].inspect}")
|
93
|
+
failed = true
|
94
|
+
end
|
95
|
+
|
96
|
+
else
|
97
|
+
|
98
|
+
if step[:resp_is_regex]
|
99
|
+
pattern = nil, body = nil
|
100
|
+
if !(step[:exp_content_type].start_with? 'text/')
|
101
|
+
pattern = Regexp.new(step[:exp_response].force_encoding("ASCII-8BIT"), Regexp::FIXEDENCODING)
|
102
|
+
body = last_response.body.to_s.force_encoding("ASCII-8BIT")
|
103
|
+
else
|
104
|
+
pattern = Regexp.new(step[:exp_response])
|
105
|
+
body = last_response.body.to_s
|
106
|
+
end
|
107
|
+
if !(body =~ pattern)
|
108
|
+
formatter.exception(" * Expected response pattern #{step[:exp_response].inspect} didn't match #{last_response.body.inspect}")
|
109
|
+
failed = true
|
110
|
+
end
|
111
|
+
elsif !step[:resp_is_regex] & (last_response.body.to_s != step[:exp_response])
|
112
|
+
formatter.exception(" * Expected response #{step[:exp_response].inspect} got #{last_response.body.inspect[0..50] + "..."}")
|
113
|
+
failed = true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
if step[:exp_content_type]
|
118
|
+
exp_content_type_header = "#{step[:exp_content_type]}"
|
119
|
+
exp_content_type_header << ";charset=utf-8" unless exp_content_type_header.start_with? "image/"
|
120
|
+
if last_response.headers["Content-Type"] != exp_content_type_header
|
121
|
+
formatter.exception(" * Expected content type #{exp_content_type_header} got #{last_response.headers["Content-Type"]}")
|
122
|
+
failed = true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
if failed
|
128
|
+
formatter.step_error(step)
|
129
|
+
else
|
130
|
+
formatter.step_pass(step)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
!failed
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
|
data/spec/aspec_spec.rb
ADDED
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aspec::CLI do
|
4
|
+
def test_app_dir
|
5
|
+
File.expand_path("../test_app", __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should list all files in a directory" do
|
9
|
+
cli = Aspec::CLI.new(test_app_dir, ["aspec/"])
|
10
|
+
cli.aspec_files.sort.should == [
|
11
|
+
File.expand_path("aspec/failing.aspec", test_app_dir),
|
12
|
+
File.expand_path("aspec/passing.aspec", test_app_dir)].sort
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
class TestApp < Sinatra::Application
|
5
|
+
get "/" do
|
6
|
+
end
|
7
|
+
|
8
|
+
get "/artists" do
|
9
|
+
status 200
|
10
|
+
content_type :json
|
11
|
+
@@artists.to_json
|
12
|
+
end
|
13
|
+
|
14
|
+
post "/artists" do
|
15
|
+
@@artists ||= []
|
16
|
+
@@artists << params[:name]
|
17
|
+
status 204
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
delete "/artists/:name" do
|
22
|
+
@@artists = @@artists.reject {|a| a == params[:name] }
|
23
|
+
status 204
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: "0.1"
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniel Lucraft
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-12-06 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: term-ansicolor
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rack-test
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
48
|
+
description:
|
49
|
+
email: dan@songkick.com
|
50
|
+
executables:
|
51
|
+
- aspec
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- README.md
|
56
|
+
files:
|
57
|
+
- README.md
|
58
|
+
- lib/aspec.rb
|
59
|
+
- lib/aspec/parser.rb
|
60
|
+
- lib/aspec/runner.rb
|
61
|
+
- lib/aspec/cli.rb
|
62
|
+
- lib/aspec/test.rb
|
63
|
+
- lib/aspec/formatters/terminal.rb
|
64
|
+
- lib/aspec/formatters/junit.rb
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
- spec/cli_spec.rb
|
67
|
+
- spec/test_app/aspec/aspec_helper.rb
|
68
|
+
- spec/test_app/test_app.rb
|
69
|
+
- spec/aspec_spec.rb
|
70
|
+
- bin/aspec
|
71
|
+
homepage: http://github.com/songkick/aspec
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --main
|
77
|
+
- README.md
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.8.12
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Testing for API external surfaces
|
99
|
+
test_files: []
|
100
|
+
|