webspicy 0.16.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -5
- data/examples/restful/webspicy/config.rb +1 -0
- data/examples/restful/webspicy/{todo/deleteTodo.yml → formaldef/todo/_one/delete.yml} +3 -0
- data/examples/restful/webspicy/{todo/getTodoSingleServiceFormat.yml → formaldef/todo/_one/get.simpler.yml} +0 -0
- data/examples/restful/webspicy/{todo/getTodo.yml → formaldef/todo/_one/get.yml} +0 -0
- data/examples/restful/webspicy/{todo/patchTodo.yml → formaldef/todo/_one/patch.yml} +0 -0
- data/examples/restful/webspicy/{todo/putTodo.yml → formaldef/todo/_one/put.yml} +0 -0
- data/examples/restful/webspicy/{todo/getTodos.yml → formaldef/todo/get.yml} +0 -0
- data/examples/restful/webspicy/{todo → formaldef/todo}/options.yml +0 -0
- data/examples/restful/webspicy/{todo/postCsv.yml → formaldef/todo/post.csv.yml} +0 -0
- data/examples/restful/webspicy/{todo/postFile.yml → formaldef/todo/post.file.yml} +0 -0
- data/examples/restful/webspicy/{todo/postTodos.yml → formaldef/todo/post.yml} +0 -0
- data/examples/restful/webspicy/{todo → formaldef/todo}/todos.csv +0 -0
- data/examples/restful/webspicy/support/todo_not_removed.rb +21 -0
- data/examples/restful/webspicy/support/todo_removed.rb +5 -3
- data/examples/website/specification/get-http.yml +20 -24
- data/examples/website/specification/get-https.yml +20 -24
- data/lib/webspicy.rb +4 -3
- data/lib/webspicy/checker.rb +5 -20
- data/lib/webspicy/configuration.rb +9 -0
- data/lib/webspicy/configuration/scope.rb +0 -8
- data/lib/webspicy/formaldoc.fio +8 -6
- data/lib/webspicy/mocker/config.ru +5 -0
- data/lib/webspicy/rspec/checker.rb +2 -0
- data/lib/webspicy/rspec/checker/rspec_checker.rb +24 -0
- data/lib/webspicy/rspec/support/rspec_runnable.rb +27 -0
- data/lib/webspicy/rspec/tester.rb +4 -0
- data/lib/webspicy/{tester → rspec/tester}/rspec_asserter.rb +24 -11
- data/lib/webspicy/{tester → rspec/tester}/rspec_matchers.rb +10 -0
- data/lib/webspicy/rspec/tester/rspec_tester.rb +63 -0
- data/lib/webspicy/specification.rb +10 -10
- data/lib/webspicy/specification/errcondition.rb +16 -0
- data/lib/webspicy/specification/precondition/robust_to_invalid_input.rb +1 -1
- data/lib/webspicy/specification/service.rb +27 -19
- data/lib/webspicy/specification/test_case.rb +3 -9
- data/lib/webspicy/support.rb +1 -0
- data/lib/webspicy/support/data_object.rb +25 -0
- data/lib/webspicy/tester.rb +4 -78
- data/lib/webspicy/tester/asserter.rb +9 -4
- data/lib/webspicy/tester/assertions.rb +8 -9
- data/lib/webspicy/tester/failure.rb +6 -0
- data/lib/webspicy/tester/invocation.rb +8 -156
- data/lib/webspicy/version.rb +1 -1
- data/spec/unit/configuration/scope/test_each_service.rb +2 -2
- data/spec/unit/configuration/scope/test_each_specification.rb +7 -7
- data/spec/unit/test_configuration.rb +1 -1
- data/spec/unit/tester/test_asserter.rb +198 -3
- data/spec/unit/tester/test_assertions.rb +8 -6
- metadata +33 -25
- data/LICENSE.md +0 -22
- data/examples/restful/Gemfile.lock +0 -105
@@ -8,6 +8,10 @@ module Webspicy
|
|
8
8
|
end
|
9
9
|
attr_reader :rspec, :invocation
|
10
10
|
|
11
|
+
def self.call(rspec, invocation)
|
12
|
+
new(rspec, invocation).send(:assert!)
|
13
|
+
end
|
14
|
+
|
11
15
|
def response
|
12
16
|
invocation.response
|
13
17
|
end
|
@@ -20,15 +24,20 @@ module Webspicy
|
|
20
24
|
test_case.service
|
21
25
|
end
|
22
26
|
|
27
|
+
protected
|
28
|
+
|
23
29
|
def assert!
|
24
|
-
|
25
|
-
|
26
|
-
|
30
|
+
rspec.aggregate_failures do
|
31
|
+
assert_status_met
|
32
|
+
assert_content_type_met
|
33
|
+
assert_expected_headers
|
34
|
+
end
|
27
35
|
assert_output_schema_met
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
rspec.aggregate_failures do
|
37
|
+
assert_assertions_met
|
38
|
+
assert_postconditions_met
|
39
|
+
assert_errconditions_met
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
43
|
def assert_status_met
|
@@ -45,7 +54,7 @@ module Webspicy
|
|
45
54
|
if ect.nil?
|
46
55
|
rspec.expect(ect).to rspec.have_no_response_type
|
47
56
|
else
|
48
|
-
rspec.expect(
|
57
|
+
rspec.expect(got).to rspec.match_content_type(ect)
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
@@ -98,9 +107,13 @@ module Webspicy
|
|
98
107
|
end
|
99
108
|
end
|
100
109
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
110
|
+
def assert_errconditions_met
|
111
|
+
return unless service.has_errconditions?
|
112
|
+
return unless test_case.counterexample?
|
113
|
+
service.errconditions.each do |post|
|
114
|
+
msg = post.check(invocation)
|
115
|
+
rspec.expect(msg).to rspec.meet_errcondition(post)
|
116
|
+
end
|
104
117
|
end
|
105
118
|
|
106
119
|
end # class RSpecAsserter
|
@@ -94,6 +94,16 @@ RSpec::Matchers.define :meet_postcondition do |post|
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
RSpec::Matchers.define :meet_errcondition do |post|
|
98
|
+
match do |actual|
|
99
|
+
actual.nil?
|
100
|
+
end
|
101
|
+
failure_message_for_should do |actual|
|
102
|
+
"expected errcondition `#{post.class.name}` to be met, got following error:\n" + \
|
103
|
+
" #{actual}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
97
107
|
RSpec::Matchers.define :be_an_empty_errors_array do
|
98
108
|
match do |actual|
|
99
109
|
actual.empty?
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class Tester
|
3
|
+
class RSpecTester
|
4
|
+
include Webspicy::Support::RSpecRunnable
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def load_rspec_examples
|
9
|
+
tester = self
|
10
|
+
RSpec.describe "Webspicy test suite" do
|
11
|
+
before(:all) do
|
12
|
+
tester.config.listeners(:before_all).each do |l|
|
13
|
+
l.call(tester.config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
after(:all) do
|
17
|
+
tester.config.listeners(:after_all).each do |l|
|
18
|
+
l.call(tester.config)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
tester.config.each_scope do |scope|
|
22
|
+
client = scope.get_client
|
23
|
+
scope.each_specification do |specification|
|
24
|
+
scope.each_service(specification) do |service|
|
25
|
+
scope.each_testcase(service) do |test_case|
|
26
|
+
str = "#{service} #{test_case}"
|
27
|
+
str = Webspicy::Support::Colorize.colorize_highlight(str, tester.config)
|
28
|
+
describe(str) do
|
29
|
+
|
30
|
+
around(:each) do |example|
|
31
|
+
client.around(test_case) do
|
32
|
+
client.before(test_case)
|
33
|
+
test_case.instrument(client)
|
34
|
+
client.instrument(test_case)
|
35
|
+
@response = client.call(test_case)
|
36
|
+
@invocation = Tester::Invocation.new(test_case, @response, client)
|
37
|
+
example.run
|
38
|
+
client.after(test_case, @invocation)
|
39
|
+
@invocation
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:invocation) do
|
44
|
+
@invocation
|
45
|
+
end
|
46
|
+
|
47
|
+
it "meets its specification" do
|
48
|
+
raise "Test not ran" unless invocation.done?
|
49
|
+
RSpecAsserter.call(self, invocation)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
end # class RSpecTester
|
62
|
+
end # class Tester
|
63
|
+
end # module Webspicy
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module Webspicy
|
2
2
|
class Specification
|
3
|
+
include Support::DataObject
|
3
4
|
|
4
5
|
def initialize(raw, location = nil)
|
5
|
-
|
6
|
+
super(raw)
|
6
7
|
@location = location
|
7
8
|
bind_services
|
8
9
|
end
|
10
|
+
attr_accessor :config
|
9
11
|
attr_reader :location
|
10
12
|
|
11
13
|
def self.info(raw)
|
@@ -14,11 +16,13 @@ module Webspicy
|
|
14
16
|
|
15
17
|
def self.singleservice(raw)
|
16
18
|
converted = {
|
17
|
-
name: raw
|
19
|
+
name: raw[:name] || "Unamed specification",
|
18
20
|
url: raw[:url],
|
19
|
-
services: [
|
21
|
+
services: [
|
22
|
+
Webspicy.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
|
23
|
+
]
|
20
24
|
}
|
21
|
-
|
25
|
+
info(converted)
|
22
26
|
end
|
23
27
|
|
24
28
|
def located_at!(location)
|
@@ -44,7 +48,7 @@ module Webspicy
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def services
|
47
|
-
@raw[:services]
|
51
|
+
@raw[:services] || []
|
48
52
|
end
|
49
53
|
|
50
54
|
def url_placeholders
|
@@ -60,10 +64,6 @@ module Webspicy
|
|
60
64
|
[ url, rest ]
|
61
65
|
end
|
62
66
|
|
63
|
-
def to_info
|
64
|
-
@raw
|
65
|
-
end
|
66
|
-
|
67
67
|
def to_singleservice
|
68
68
|
raise NotImplementedError
|
69
69
|
end
|
@@ -85,7 +85,7 @@ module Webspicy
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def bind_services
|
88
|
-
|
88
|
+
services.each do |s|
|
89
89
|
s.specification = self
|
90
90
|
end
|
91
91
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class Specification
|
3
|
+
module Errcondition
|
4
|
+
|
5
|
+
def self.match(service, descr)
|
6
|
+
end
|
7
|
+
|
8
|
+
def instrument(test_case, client)
|
9
|
+
end
|
10
|
+
|
11
|
+
def check(invocation)
|
12
|
+
end
|
13
|
+
|
14
|
+
end # module Errcondition
|
15
|
+
end # module Specification
|
16
|
+
end # module Webspicy
|
@@ -40,7 +40,7 @@ module Webspicy
|
|
40
40
|
def empty_input_counterexamples(service, first)
|
41
41
|
placeholders = service.specification.url_placeholders
|
42
42
|
empty_input = first.params.reject{|k| !placeholders.include?(k) }
|
43
|
-
if
|
43
|
+
if invalid_input?(service, empty_input)
|
44
44
|
[first.mutate({
|
45
45
|
:description => "it is robust to an invalid empty input (RobustToInvalidInput)",
|
46
46
|
:dress_params => false,
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Webspicy
|
2
2
|
class Specification
|
3
3
|
class Service
|
4
|
+
include Support::DataObject
|
4
5
|
|
5
6
|
def initialize(raw)
|
6
|
-
|
7
|
+
super(raw)
|
7
8
|
bind_examples
|
8
9
|
bind_counterexamples
|
9
|
-
@preconditions = compile_preconditions
|
10
|
-
@postconditions = compile_postconditions
|
11
10
|
end
|
12
11
|
attr_accessor :specification
|
13
12
|
|
@@ -15,6 +14,10 @@ module Webspicy
|
|
15
14
|
new(raw)
|
16
15
|
end
|
17
16
|
|
17
|
+
def config
|
18
|
+
specification.config
|
19
|
+
end
|
20
|
+
|
18
21
|
def method
|
19
22
|
@raw[:method]
|
20
23
|
end
|
@@ -24,7 +27,7 @@ module Webspicy
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def preconditions
|
27
|
-
@preconditions
|
30
|
+
@preconditions ||= compile_preconditions
|
28
31
|
end
|
29
32
|
|
30
33
|
def has_preconditions?
|
@@ -32,23 +35,31 @@ module Webspicy
|
|
32
35
|
end
|
33
36
|
|
34
37
|
def postconditions
|
35
|
-
@postconditions
|
38
|
+
@postconditions ||= compile_postconditions
|
36
39
|
end
|
37
40
|
|
38
41
|
def has_postconditions?
|
39
42
|
!postconditions.empty?
|
40
43
|
end
|
41
44
|
|
45
|
+
def errconditions
|
46
|
+
@errconditions ||= compile_errconditions
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_errconditions?
|
50
|
+
!errconditions.empty?
|
51
|
+
end
|
52
|
+
|
42
53
|
def default_example
|
43
54
|
@raw[:default_example]
|
44
55
|
end
|
45
56
|
|
46
57
|
def examples
|
47
|
-
@raw[:examples]
|
58
|
+
@raw[:examples] || []
|
48
59
|
end
|
49
60
|
|
50
61
|
def counterexamples
|
51
|
-
@raw[:counterexamples]
|
62
|
+
@raw[:counterexamples] || []
|
52
63
|
end
|
53
64
|
|
54
65
|
def generated_counterexamples
|
@@ -76,28 +87,25 @@ module Webspicy
|
|
76
87
|
input_schema.dress(params)
|
77
88
|
end
|
78
89
|
|
79
|
-
def to_info
|
80
|
-
@raw
|
81
|
-
end
|
82
|
-
|
83
90
|
def to_s
|
84
91
|
"#{method} #{specification.url}"
|
85
92
|
end
|
86
93
|
|
87
94
|
private
|
88
95
|
|
89
|
-
def scope
|
90
|
-
Webspicy.current_scope
|
91
|
-
end
|
92
|
-
|
93
96
|
def compile_preconditions
|
94
97
|
@raw[:preconditions] = [@raw[:preconditions]] if @raw[:preconditions].is_a?(String)
|
95
|
-
compile_conditions(@raw[:preconditions] ||= [],
|
98
|
+
compile_conditions(@raw[:preconditions] ||= [], config.preconditions)
|
96
99
|
end
|
97
100
|
|
98
101
|
def compile_postconditions
|
99
102
|
@raw[:postconditions] = [@raw[:postconditions]] if @raw[:postconditions].is_a?(String)
|
100
|
-
compile_conditions(@raw[:postconditions] ||= [],
|
103
|
+
compile_conditions(@raw[:postconditions] ||= [], config.postconditions)
|
104
|
+
end
|
105
|
+
|
106
|
+
def compile_errconditions
|
107
|
+
@raw[:errconditions] = [@raw[:errconditions]] if @raw[:errconditions].is_a?(String)
|
108
|
+
compile_conditions(@raw[:errconditions] ||= [], config.errconditions)
|
101
109
|
end
|
102
110
|
|
103
111
|
def compile_conditions(descriptions, conditions)
|
@@ -112,13 +120,13 @@ module Webspicy
|
|
112
120
|
end
|
113
121
|
|
114
122
|
def bind_examples
|
115
|
-
|
123
|
+
examples.each do |ex|
|
116
124
|
ex.bind(self, false)
|
117
125
|
end
|
118
126
|
end
|
119
127
|
|
120
128
|
def bind_counterexamples
|
121
|
-
|
129
|
+
counterexamples.each do |ex|
|
122
130
|
ex.bind(self, true)
|
123
131
|
end
|
124
132
|
end
|
@@ -1,17 +1,15 @@
|
|
1
1
|
module Webspicy
|
2
2
|
class Specification
|
3
3
|
class TestCase
|
4
|
+
include Support::DataObject
|
4
5
|
|
5
6
|
def initialize(raw)
|
6
|
-
|
7
|
+
super(raw)
|
7
8
|
@counterexample = nil
|
8
9
|
end
|
9
10
|
attr_reader :service
|
10
11
|
attr_reader :counterexample
|
11
12
|
|
12
|
-
attr_accessor :raw
|
13
|
-
protected :raw, :raw=
|
14
|
-
|
15
13
|
def bind(service, counterexample)
|
16
14
|
@service = service
|
17
15
|
@counterexample = counterexample
|
@@ -111,13 +109,9 @@ module Webspicy
|
|
111
109
|
!assert.empty?
|
112
110
|
end
|
113
111
|
|
114
|
-
def to_info
|
115
|
-
@raw
|
116
|
-
end
|
117
|
-
|
118
112
|
def instrument(client)
|
119
113
|
service.preconditions.each do |pre|
|
120
|
-
pre.instrument(self, client)
|
114
|
+
pre.instrument(self, client) if pre.respond_to?(:instrument)
|
121
115
|
end
|
122
116
|
service.postconditions.each do |post|
|
123
117
|
post.instrument(self, client) if post.respond_to?(:instrument)
|
data/lib/webspicy/support.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Webspicy
|
2
|
+
module Support
|
3
|
+
module DataObject
|
4
|
+
|
5
|
+
def initialize(raw)
|
6
|
+
@raw = raw
|
7
|
+
end
|
8
|
+
attr_accessor :raw
|
9
|
+
protected :raw, :raw=
|
10
|
+
|
11
|
+
def method_missing(name, *args, &bl)
|
12
|
+
if @raw.has_key?(name) && args.empty? && bl.nil?
|
13
|
+
@raw[name]
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_info
|
20
|
+
@raw
|
21
|
+
end
|
22
|
+
|
23
|
+
end # module DataObject
|
24
|
+
end # module Support
|
25
|
+
end # module Webspicy
|
data/lib/webspicy/tester.rb
CHANGED
@@ -1,89 +1,15 @@
|
|
1
1
|
module Webspicy
|
2
2
|
class Tester
|
3
|
-
include Webspicy::Support::Colorize
|
4
3
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
attr_reader :config
|
10
|
-
|
11
|
-
def call(err=$stderr, out=$stdout)
|
12
|
-
$_rspec_core_load_started_at = nil
|
13
|
-
options = RSpec::Core::ConfigurationOptions.new(config.rspec_options)
|
14
|
-
conf = RSpec::Core::Configuration.new
|
15
|
-
RSpec::Core::Runner.new(options, conf).run(err, out)
|
16
|
-
end
|
17
|
-
|
18
|
-
# protected
|
19
|
-
|
20
|
-
def load
|
21
|
-
tester = self
|
22
|
-
RSpec.reset
|
23
|
-
rspec_config!
|
24
|
-
RSpec.describe "" do
|
25
|
-
before(:all) do
|
26
|
-
tester.config.listeners(:before_all).each do |l|
|
27
|
-
l.call(tester.config)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
after(:all) do
|
31
|
-
tester.config.listeners(:after_all).each do |l|
|
32
|
-
l.call(tester.config)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
tester.config.each_scope do |scope|
|
36
|
-
client = scope.get_client
|
37
|
-
scope.each_specification do |specification|
|
38
|
-
scope.each_service(specification) do |service|
|
39
|
-
tester.rspec_service!(self, service, client, scope)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
def rspec_service!(on, service, client, scope)
|
48
|
-
scope.each_testcase(service) do |test_case|
|
49
|
-
str = "#{service} #{test_case}"
|
50
|
-
str = colorize_highlight(str)
|
51
|
-
on.describe(str) do
|
52
|
-
include_examples 'a successful test case invocation', client, test_case
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def rspec_config!
|
58
|
-
RSpec.shared_examples "a successful test case invocation" do |client, test_case|
|
59
|
-
|
60
|
-
around(:each) do |example|
|
61
|
-
client.around(test_case) do
|
62
|
-
client.before(test_case)
|
63
|
-
test_case.instrument(client)
|
64
|
-
client.instrument(test_case)
|
65
|
-
@response = client.call(test_case)
|
66
|
-
@invocation = Tester::Invocation.new(test_case, @response, client)
|
67
|
-
example.run
|
68
|
-
client.after(test_case, @invocation)
|
69
|
-
@invocation
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
let(:invocation) do
|
74
|
-
@invocation
|
75
|
-
end
|
76
|
-
|
77
|
-
it "meets its specification" do
|
78
|
-
raise "Test not ran" unless invocation.done?
|
79
|
-
invocation.rspec_assert!(self)
|
80
|
-
end
|
81
|
-
end
|
4
|
+
def self.new(*args, &bl)
|
5
|
+
require_relative 'rspec/tester'
|
6
|
+
RSpecTester.new(*args, &bl)
|
82
7
|
end
|
83
8
|
|
84
9
|
end # class Tester
|
85
10
|
end # module Webspicy
|
86
11
|
require_relative 'tester/client'
|
87
12
|
require_relative 'tester/invocation'
|
13
|
+
require_relative 'tester/failure'
|
88
14
|
require_relative 'tester/assertions'
|
89
15
|
require_relative 'tester/asserter'
|