webspicy 0.16.3 → 0.17.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 +8 -3
- data/examples/restful/Gemfile.lock +14 -13
- 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/lib/webspicy.rb +1 -0
- 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 +2 -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 +23 -10
- 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 +5 -7
- data/lib/webspicy/specification/errcondition.rb +16 -0
- 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 +2 -2
- 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 +27 -18
@@ -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)
|
@@ -46,7 +48,7 @@ module Webspicy
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def services
|
49
|
-
@raw[:services]
|
51
|
+
@raw[:services] || []
|
50
52
|
end
|
51
53
|
|
52
54
|
def url_placeholders
|
@@ -62,10 +64,6 @@ module Webspicy
|
|
62
64
|
[ url, rest ]
|
63
65
|
end
|
64
66
|
|
65
|
-
def to_info
|
66
|
-
@raw
|
67
|
-
end
|
68
|
-
|
69
67
|
def to_singleservice
|
70
68
|
raise NotImplementedError
|
71
69
|
end
|
@@ -87,7 +85,7 @@ module Webspicy
|
|
87
85
|
end
|
88
86
|
|
89
87
|
def bind_services
|
90
|
-
|
88
|
+
services.each do |s|
|
91
89
|
s.specification = self
|
92
90
|
end
|
93
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
|
@@ -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'
|
@@ -78,14 +78,19 @@ module Webspicy
|
|
78
78
|
expected = id
|
79
79
|
id, path = path, ''
|
80
80
|
end
|
81
|
-
|
82
|
-
|
81
|
+
element = @assertions.element_with_id(@target, path, id)
|
82
|
+
unless element
|
83
|
+
_! "Expected an element with id #{id} to contain the key(s) and value(s) #{expected}, but there is no element with that id"
|
84
|
+
end
|
85
|
+
|
86
|
+
unless @assertions.idFD(element, expected)
|
87
|
+
_! "Expected #{_s(@target, path)} to contain the key(s) and value(s) #{expected}"
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
86
91
|
def pathFD(path, expected)
|
87
92
|
unless @assertions.pathFD(@target, path, expected)
|
88
|
-
_! "
|
93
|
+
_! "Expected #{_s(@target, path)} to contain the key(s) and value(s) #{expected}"
|
89
94
|
end
|
90
95
|
end
|
91
96
|
|
@@ -121,7 +126,7 @@ module Webspicy
|
|
121
126
|
end
|
122
127
|
|
123
128
|
def _!(msg)
|
124
|
-
raise msg
|
129
|
+
raise Failure, msg
|
125
130
|
end
|
126
131
|
|
127
132
|
end # class Asserter
|
@@ -63,16 +63,15 @@ module Webspicy
|
|
63
63
|
(ids.to_set & expected.to_set).empty?
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
67
|
-
if expected == NO_ARG
|
68
|
-
expected = id
|
69
|
-
id, path = path, ''
|
70
|
-
end
|
66
|
+
def element_with_id(target, path, id)
|
71
67
|
target = extract_path(target, path)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
an_array(target).find { |t| t[:id] == id }
|
69
|
+
end
|
70
|
+
|
71
|
+
def idFD(element, expected)
|
72
|
+
expected.keys.all? do |k|
|
73
|
+
value_equal(expected[k], element[k])
|
74
|
+
end
|
76
75
|
end
|
77
76
|
|
78
77
|
def pathFD(target, path, expected)
|