webspicy 0.16.0 → 0.18.0
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.
- 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'
|