webspicy 0.16.3 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -3
  3. data/examples/restful/Gemfile.lock +14 -13
  4. data/examples/restful/webspicy/config.rb +1 -0
  5. data/examples/restful/webspicy/{todo/deleteTodo.yml → formaldef/todo/_one/delete.yml} +3 -0
  6. data/examples/restful/webspicy/{todo/getTodoSingleServiceFormat.yml → formaldef/todo/_one/get.simpler.yml} +0 -0
  7. data/examples/restful/webspicy/{todo/getTodo.yml → formaldef/todo/_one/get.yml} +0 -0
  8. data/examples/restful/webspicy/{todo/patchTodo.yml → formaldef/todo/_one/patch.yml} +0 -0
  9. data/examples/restful/webspicy/{todo/putTodo.yml → formaldef/todo/_one/put.yml} +0 -0
  10. data/examples/restful/webspicy/{todo/getTodos.yml → formaldef/todo/get.yml} +0 -0
  11. data/examples/restful/webspicy/{todo → formaldef/todo}/options.yml +0 -0
  12. data/examples/restful/webspicy/{todo/postCsv.yml → formaldef/todo/post.csv.yml} +0 -0
  13. data/examples/restful/webspicy/{todo/postFile.yml → formaldef/todo/post.file.yml} +0 -0
  14. data/examples/restful/webspicy/{todo/postTodos.yml → formaldef/todo/post.yml} +0 -0
  15. data/examples/restful/webspicy/{todo → formaldef/todo}/todos.csv +0 -0
  16. data/examples/restful/webspicy/support/todo_not_removed.rb +21 -0
  17. data/examples/restful/webspicy/support/todo_removed.rb +5 -3
  18. data/lib/webspicy.rb +1 -0
  19. data/lib/webspicy/checker.rb +5 -20
  20. data/lib/webspicy/configuration.rb +9 -0
  21. data/lib/webspicy/configuration/scope.rb +0 -8
  22. data/lib/webspicy/formaldoc.fio +2 -0
  23. data/lib/webspicy/rspec/checker.rb +2 -0
  24. data/lib/webspicy/rspec/checker/rspec_checker.rb +24 -0
  25. data/lib/webspicy/rspec/support/rspec_runnable.rb +27 -0
  26. data/lib/webspicy/rspec/tester.rb +4 -0
  27. data/lib/webspicy/{tester → rspec/tester}/rspec_asserter.rb +23 -10
  28. data/lib/webspicy/{tester → rspec/tester}/rspec_matchers.rb +10 -0
  29. data/lib/webspicy/rspec/tester/rspec_tester.rb +63 -0
  30. data/lib/webspicy/specification.rb +5 -7
  31. data/lib/webspicy/specification/errcondition.rb +16 -0
  32. data/lib/webspicy/specification/service.rb +27 -19
  33. data/lib/webspicy/specification/test_case.rb +3 -9
  34. data/lib/webspicy/support.rb +1 -0
  35. data/lib/webspicy/support/data_object.rb +25 -0
  36. data/lib/webspicy/tester.rb +4 -78
  37. data/lib/webspicy/tester/asserter.rb +9 -4
  38. data/lib/webspicy/tester/assertions.rb +8 -9
  39. data/lib/webspicy/tester/failure.rb +6 -0
  40. data/lib/webspicy/tester/invocation.rb +8 -156
  41. data/lib/webspicy/version.rb +2 -2
  42. data/spec/unit/configuration/scope/test_each_service.rb +2 -2
  43. data/spec/unit/configuration/scope/test_each_specification.rb +7 -7
  44. data/spec/unit/test_configuration.rb +1 -1
  45. data/spec/unit/tester/test_asserter.rb +198 -3
  46. data/spec/unit/tester/test_assertions.rb +8 -6
  47. metadata +27 -18
@@ -0,0 +1,6 @@
1
+ module Webspicy
2
+ class Tester
3
+ class Failure < Exception
4
+ end # class Failure
5
+ end # class Tester
6
+ end # module Webspicy
@@ -14,36 +14,6 @@ module Webspicy
14
14
  test_case.service
15
15
  end
16
16
 
17
- def rspec_assert!(rspec)
18
- RSpecAsserter.new(rspec, self).assert!
19
- end
20
-
21
- def errors
22
- @errors ||= begin
23
- errs = [
24
- [:expected_status_unmet, true],
25
- [:expected_content_type_unmet, !test_case.is_expected_status?(204)],
26
- [:expected_headers_unmet, test_case.has_expected_headers?],
27
- [:expected_schema_unmet, !test_case.is_expected_status?(204)],
28
- [:assertions_unmet, test_case.has_assertions?],
29
- [:postconditions_unmet, test_case.service.has_postconditions? && !test_case.counterexample?],
30
- [:expected_error_unmet, test_case.has_expected_error?]
31
- ].map do |(expectation,only_if)|
32
- next unless only_if
33
- begin
34
- self.send(expectation)
35
- rescue => ex
36
- ex.message
37
- end
38
- end
39
- errs.compact
40
- end
41
- end
42
-
43
- def has_error?
44
- !errors.empty?
45
- end
46
-
47
17
  ### Getters on response
48
18
 
49
19
  def response_code
@@ -74,121 +44,10 @@ module Webspicy
74
44
  response_code >= 300 && response_code < 400
75
45
  end
76
46
 
77
- ### Check of HTTP status
78
-
79
- def expected_status_unmet
80
- expected = test_case.expected_status
81
- got = response.status
82
- expected === got ? nil : "[status] #{expected} !== #{got}"
83
- end
84
-
85
- def meets_expected_status?
86
- expected_status_unmet.nil?
87
- end
88
-
89
- ### Check of the expected output type
90
-
91
- def expected_content_type_unmet
92
- ect = test_case.expected_content_type
93
- return nil unless ect
94
- got = response.content_type
95
- got = got.mime_type if got.respond_to?(:mime_type)
96
- if ect.nil?
97
- got.nil? ? nil : "[content type] #{ect} != #{got}"
98
- else
99
- got.to_s.start_with?(ect.to_s) ? nil : "[content type] #{ect} != #{got}"
100
- end
101
- end
102
-
103
- def meets_expected_content_type?
104
- expected_content_type_unmet.nil?
105
- end
106
-
107
- ### Check of output schema
108
-
109
- def expected_schema_unmet
110
- if is_empty_response?
111
- body = response.body.to_s.strip
112
- body.empty? ? nil : "[body] empty vs. #{body}"
113
- elsif is_redirect?
114
- else
115
- case dressed_body
116
- when Finitio::TypeError
117
- rc = dressed_body.root_cause
118
- "#{rc.message} (#{rc.location ? rc.location : 'unknown location'})"
119
- when StandardError
120
- dressed_body.message
121
- else nil
122
- end
123
- end
124
- end
125
-
126
- def meets_expected_schema?
127
- expected_schema_unmet.nil?
128
- end
129
-
130
- ### Check of assertions
131
-
132
- def assertions_unmet
133
- unmet = []
134
- asserter = Tester::Asserter.new(dressed_body)
135
- test_case.assert.each do |assert|
136
- begin
137
- asserter.instance_eval(assert)
138
- rescue => ex
139
- unmet << ex.message
140
- end
141
- end
142
- unmet.empty? ? nil : unmet.join("\n")
143
- end
144
-
145
- def value_equal(exp, got)
146
- case exp
147
- when Hash
148
- exp.all?{|(k,v)|
149
- got[k] == v
150
- }
151
- else
152
- exp == got
153
- end
154
- end
155
-
156
- ### Check of expected error message
157
-
158
- def expected_error_unmet
159
- expected = test_case.expected_error
160
- case test_case.expected_content_type
161
- when %r{json}
162
- got = meets_expected_schema? ? dressed_body[:description] : response.body
163
- expected == got ? nil : "[error message] `#{expected}` vs. `#{got}`"
164
- else
165
- dressed_body.include?(expected) ? nil : "[error message] `#{expected}` not found" unless expected.nil?
166
- end
167
- end
168
-
169
- ### Check of expected headers
170
-
171
- def expected_headers_unmet
172
- unmet = []
173
- expected = test_case.expected_headers
174
- expected.each_pair do |k,v|
175
- got = response.headers[k]
176
- unmet << "[headers] #{v} expected for #{k}, got #{got}" unless (got == v)
177
- end
178
- unmet.empty? ? nil : unmet.join("\n")
179
- end
180
-
181
- ### Check of postconditions
182
-
183
- def postconditions_unmet
184
- failures = service.postconditions.map{|post|
185
- post.check(self)
186
- }.compact
187
- failures.empty? ? nil : failures.join("\n")
188
- end
189
-
190
47
  def loaded_body
191
- case test_case.expected_content_type
48
+ ct = response.content_type || test_case.expected_content_type
49
+ ct = ct.mime_type if ct.respond_to?(:mime_type)
50
+ case ct
192
51
  when %r{json}
193
52
  raise "Body empty while expected" if response.body.to_s.empty?
194
53
  @loaded_body ||= ::JSON.parse(response.body)
@@ -198,21 +57,14 @@ module Webspicy
198
57
  end
199
58
 
200
59
  def dressed_body
201
- @dressed_body ||= case test_case.expected_content_type
202
- when %r{json}
203
- schema = is_expected_success? ? service.output_schema : service.error_schema
204
- begin
205
- schema.dress(loaded_body)
206
- rescue Finitio::TypeError => ex
207
- ex
208
- end
209
- else
210
- loaded_body
60
+ schema = is_expected_success? ? service.output_schema : service.error_schema
61
+ begin
62
+ schema.dress(loaded_body)
63
+ rescue Finitio::TypeError => ex
64
+ ex
211
65
  end
212
66
  end
213
67
 
214
68
  end # class Invocation
215
69
  end # class Tester
216
70
  end # module Webspicy
217
- require_relative 'rspec_matchers'
218
- require_relative 'rspec_asserter'
@@ -1,8 +1,8 @@
1
1
  module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 16
5
- TINY = 3
4
+ MINOR = 17
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -19,7 +19,7 @@ module Webspicy
19
19
 
20
20
  let(:configuration) {
21
21
  Configuration.new(restful_folder){|c|
22
- c.file_filter = /getTodo.yml/
22
+ c.file_filter = /get.yml/
23
23
  }
24
24
  }
25
25
 
@@ -32,7 +32,7 @@ module Webspicy
32
32
 
33
33
  let(:configuration) {
34
34
  Configuration.new(restful_folder){|c|
35
- c.file_filter = /getTodo.yml/
35
+ c.file_filter = /get.yml/
36
36
  c.service_filter = ->(s) {
37
37
  s.method == "POST"
38
38
  }
@@ -27,13 +27,13 @@ module Webspicy
27
27
  let(:configuration) {
28
28
  Configuration.new(restful_folder){|c|
29
29
  c.file_filter = ->(f) {
30
- f.basename.to_s == "getTodo.yml"
30
+ f.basename.to_s == "get.yml"
31
31
  }
32
32
  }
33
33
  }
34
34
 
35
- it 'returns only that file' do
36
- expect(subject.size).to eql(1)
35
+ it 'returns only that files' do
36
+ expect(subject.size).to eql(2)
37
37
  end
38
38
  end
39
39
 
@@ -41,12 +41,12 @@ module Webspicy
41
41
 
42
42
  let(:configuration) {
43
43
  Configuration.new(restful_folder){|c|
44
- c.file_filter = /getTodo.yml/
44
+ c.file_filter = /get.yml/
45
45
  }
46
46
  }
47
47
 
48
- it 'returns only that file' do
49
- expect(subject.size).to eql(1)
48
+ it 'returns only that files' do
49
+ expect(subject.size).to eql(2)
50
50
  end
51
51
  end
52
52
 
@@ -54,7 +54,7 @@ module Webspicy
54
54
 
55
55
  let(:configuration) {
56
56
  Configuration.new(restful_folder) do |c|
57
- c.folder 'todo'
57
+ c.folder 'formaldef/todo'
58
58
  end
59
59
  }
60
60
 
@@ -40,7 +40,7 @@ module Webspicy
40
40
  end
41
41
 
42
42
  it 'supports a single .yml file and returns a specific configuration instance' do
43
- file = restful_folder/"todo/getTodo.yml"
43
+ file = restful_folder/"formaldef/todo/get.yml"
44
44
  c = Configuration.dress(file)
45
45
  expect(c).to be_a(Configuration)
46
46
  expect(c.folder).to eq(restful_folder)
@@ -3,10 +3,75 @@ require 'spec_helper'
3
3
  module Webspicy
4
4
  class Tester
5
5
  describe Asserter do
6
- let(:asserter) { Asserter.new(target) }
6
+ describe '#includes' do
7
+ it 'returns nil when the value is found in an array' do
8
+ expect(Asserter.new([:a, 'foo', 99]).includes('', 'foo'))
9
+ .to eq nil
10
+ end
11
+
12
+ it 'returns nil when the assertion is identical to a non-array' do
13
+ expect(Asserter.new({ foo: Time.at(0) }).includes('', { foo: Time.at(0) }))
14
+ .to eq nil
15
+ end
16
+
17
+ it 'raises an exception with a descriptive message when the assertion is false' do
18
+ expect { Asserter.new([:a, 'foo', 99]).includes('', 42) }
19
+ .to raise_exception Failure,
20
+ 'Expected ["a","foo",99] to include 42'
21
+
22
+ end
23
+ end
24
+
25
+ describe '#notIncludes' do
26
+ it 'returns nil when the value is not found in an array' do
27
+ expect(Asserter.new([:a, 'foo', 99]).notIncludes('', 'boom'))
28
+ .to eq nil
29
+ end
30
+
31
+ it 'returns nil when the assertion and target are not identical' do
32
+ expect(Asserter.new({ foo: Time.at(0) }).notIncludes('', 'LOL'))
33
+ .to eq nil
34
+ end
35
+
36
+ it 'raises an exception with a descriptive message when the assertion is false' do
37
+ expect { Asserter.new([:a, 'foo', 99]).notIncludes('', 'foo') }
38
+ .to raise_exception Failure,
39
+ 'Expected ["a","foo",99] not to include foo'
40
+ end
41
+ end
42
+
43
+ describe '#empty' do
44
+ it 'returns nil when the target is empty' do
45
+ expect(Asserter.new([]).empty).to eq nil
46
+ expect(Asserter.new({}).empty).to eq nil
47
+ end
48
+
49
+ it 'raises an exception with a descriptive message when the assertion is false' do
50
+ expect { Asserter.new(['foo']).empty }
51
+ .to raise_exception Failure,
52
+ 'Expected ["foo"] to be empty'
53
+ end
54
+ end
55
+
56
+ describe '#notEmpty' do
57
+ it 'returns nil when the target is not empty' do
58
+ expect(Asserter.new(['foo']).notEmpty).to eq nil
59
+ expect(Asserter.new({ foo: 'bar' }).notEmpty).to eq nil
60
+ end
61
+
62
+ it 'raises an exception with a descriptive message when the assertion is false' do
63
+ expect { Asserter.new([]).notEmpty }
64
+ .to raise_exception Failure,
65
+ 'Expected [] to be non empty'
66
+ expect { Asserter.new({}).notEmpty }
67
+ .to raise_exception Failure,
68
+ 'Expected {} to be non empty'
69
+ end
70
+ end
7
71
 
8
72
  describe '#size' do
9
73
  let(:target) { [1, 2, 3, 4] }
74
+ let(:asserter) { Asserter.new(target) }
10
75
 
11
76
  it 'returns nil when the assertion is true for a plain array' do
12
77
  expect(asserter.size('', 4)).to eq nil
@@ -14,7 +79,7 @@ module Webspicy
14
79
 
15
80
  it 'raises an exception with a descriptive message when the assertion is false' do
16
81
  expect { asserter.size('', 3) }
17
- .to raise_exception RuntimeError, 'Expected [1,2,3,4] to have a size of 3, actual size is: 4'
82
+ .to raise_exception Failure, 'Expected [1,2,3,4] to have a size of 3, actual size is: 4'
18
83
  end
19
84
 
20
85
  context 'with a string' do
@@ -34,7 +99,7 @@ module Webspicy
34
99
 
35
100
  it 'raises an exception with a descriptive message when the assertion is false' do
36
101
  expect { asserter.size('foo/2/bar', 99) }
37
- .to raise_exception RuntimeError,
102
+ .to raise_exception Failure,
38
103
  'Expected [10,11,12] to have a size of 99, actual size is: 3'
39
104
  end
40
105
 
@@ -45,6 +110,136 @@ module Webspicy
45
110
  end
46
111
  end
47
112
  end
113
+
114
+ describe '#idIn' do
115
+ it 'returns nil when the specified ids match exactly' do
116
+ expect(Asserter.new([{ id: 1 }, { id: 2 }]).idIn('', 1, 2)).to eq nil
117
+ expect(Asserter.new({ id: 123 }).idIn('', 123)).to eq nil
118
+
119
+ os = OpenStruct.new(id: 'foo')
120
+ expect(Asserter.new(os).idIn('', 'foo')).to eq nil
121
+ end
122
+
123
+ it 'raises an exception with a descriptive message when the assertion is false' do
124
+ expect { Asserter.new([{ id: 1}, { id: 2}]).idIn('', 123, 125) }
125
+ .to raise_exception Failure,
126
+ 'Expected [{"id":1},{"id":2}] to have ids 123,125'
127
+ expect { Asserter.new([{ id: 1}, { id: 2}]).idIn('', 1, 2, 3) }
128
+ .to raise_exception Failure,
129
+ 'Expected [{"id":1},{"id":2}] to have ids 1,2,3'
130
+ expect { Asserter.new([{ id: 1}, { id: 2}]).idIn('', 1) }
131
+ .to raise_exception Failure,
132
+ 'Expected [{"id":1},{"id":2}] to have ids 1'
133
+ end
134
+ end
135
+
136
+ describe '#idNotIn' do
137
+ it 'returns nil when the specified ids do not match exactly' do
138
+ expect(Asserter.new([{ id: 1 }, { id: 2 }]).idNotIn('', 123, 125)).to eq nil
139
+ expect(Asserter.new({ id: 123 }).idNotIn('', 1, 2, 3)).to eq nil
140
+ expect(Asserter.new({ id: 123 }).idNotIn('', 1)).to eq nil
141
+ end
142
+
143
+ it 'raises an exception with a descriptive message when the assertion is false' do
144
+ expect { Asserter.new([{ id: 1}, { id: 2}]).idNotIn('', 1, 2) }
145
+ .to raise_exception Failure,
146
+ 'Expected [{"id":1},{"id":2}] to not have ids 1,2'
147
+ expect { Asserter.new({ id: 1}).idNotIn('', 1) }
148
+ .to raise_exception Failure,
149
+ 'Expected {"id":1} to not have ids 1'
150
+
151
+ os = OpenStruct.new(id: 'foo')
152
+ expect { Asserter.new(os).idNotIn('', 'foo') }
153
+ .to raise_exception Failure,
154
+ 'Expected "#<OpenStruct id=\"foo\">"... to not have ids foo'
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '#idFD' do
160
+ let(:target) do
161
+ [
162
+ { id: 1, a: 'a1', b: 'b1' },
163
+ { id: 2, a: 'a2', b: 'b2' }
164
+ ]
165
+ end
166
+
167
+ it 'returns nil when the element with specified id matches the expected keys-value pairs' do
168
+ expect(Asserter.new(target).idFD('', 2, { b: 'b2' })).to eq nil
169
+ expect(Asserter.new(target).idFD('', 2, { a: 'a2', b: 'b2' })).to eq nil
170
+ end
171
+
172
+ it 'raises an exception when the assertion is false' do
173
+ expect { Asserter.new(target).idFD('', 2, { c: 'c2' }) }
174
+ .to raise_exception Failure,
175
+ 'Expected [{"id":1,"a":"a1","b":"b1"... ' \
176
+ 'to contain the key(s) and value(s) {:c=>"c2"}'
177
+ expect { Asserter.new(target).idFD('', 2, { b: 'b1' }) }
178
+ .to raise_exception Failure,
179
+ 'Expected [{"id":1,"a":"a1","b":"b1"... ' \
180
+ 'to contain the key(s) and value(s) {:b=>"b1"}'
181
+ end
182
+
183
+ it 'raises an exception with a descriptive message when no element with the specified id is present in target' do
184
+ expect { Asserter.new(target).idFD('', 3, { a: 'a3' }) }
185
+ .to raise_exception Failure,
186
+ 'Expected an element with id 3 to contain ' \
187
+ 'the key(s) and value(s) {:a=>"a3"}, '\
188
+ 'but there is no element with that id'
189
+ end
190
+ end
191
+
192
+ describe '#pathFD' do
193
+ let(:target) do
194
+ [
195
+ { a: 'a1', b: 'b1' },
196
+ { a: 'a2', b: 'b2' }
197
+ ]
198
+ end
199
+
200
+ it 'returns nil when the target matches the expected keys-value pairs' do
201
+ expect(Asserter.new(target).pathFD('0', { b: 'b1' })).to eq nil
202
+ expect(Asserter.new(target).pathFD('0', { a: 'a1', b: 'b1' })).to eq nil
203
+ expect(Asserter.new(target).pathFD('1', { b: 'b2' })).to eq nil
204
+ expect(Asserter.new(target).pathFD('1', { a: 'a2', b: 'b2' })).to eq nil
205
+ end
206
+
207
+ it 'raises an exception when the assertion is false' do
208
+ expect { Asserter.new(target).pathFD('0', { c: 'c2' }) }
209
+ .to raise_exception Failure,
210
+ 'Expected {"a":"a1","b":"b1"} ' \
211
+ 'to contain the key(s) and value(s) {:c=>"c2"}'
212
+ expect { Asserter.new(target).pathFD('0', { b: 'b2' }) }
213
+ .to raise_exception Failure,
214
+ 'Expected {"a":"a1","b":"b1"} ' \
215
+ 'to contain the key(s) and value(s) {:b=>"b2"}'
216
+ end
217
+ end
218
+
219
+ describe '#match' do
220
+ it 'returns nil when the target matches the specified regexp' do
221
+ expect(Asserter.new('Empathise').match('', /path/)).to eq nil
222
+ expect(Asserter.new('Empathise').match('', /.mp/)).to eq nil
223
+ end
224
+
225
+ it 'raises an exception when the assertion is false' do
226
+ expect { Asserter.new('Empathise').match('', /ize/) }
227
+ .to raise_exception Failure,
228
+ 'Expected "Empathise" to match /ize/'
229
+ end
230
+ end
231
+
232
+ describe '#notMatch' do
233
+ it 'returns nil when the target does not matche the specified regexp' do
234
+ expect(Asserter.new('Empathise').notMatch('', /ize/)).to eq nil
235
+ expect(Asserter.new('Empathise').notMatch('', /^path/)).to eq nil
236
+ end
237
+
238
+ it 'raises an exception when the assertion is false' do
239
+ expect { Asserter.new('Empathise').notMatch('', /path/) }
240
+ .to raise_exception Failure,
241
+ 'Expected "Empathise" not to match /path/'
242
+ end
48
243
  end
49
244
  end
50
245
  end