webspicy 0.20.4 → 0.20.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sandr +14 -0
  3. data/bin/search +2 -0
  4. data/bin/webspicy +2 -2
  5. data/lib/finitio/webspicy/shared.fio +10 -0
  6. data/lib/webspicy.rb +22 -53
  7. data/lib/webspicy/configuration.rb +2 -0
  8. data/lib/webspicy/configuration/scope.rb +2 -2
  9. data/lib/webspicy/configuration/single_url.rb +35 -25
  10. data/lib/webspicy/configuration/single_yml_file.rb +7 -2
  11. data/lib/webspicy/specification.rb +0 -55
  12. data/lib/webspicy/specification/service.rb +1 -5
  13. data/lib/webspicy/specification/test_case.rb +0 -49
  14. data/lib/webspicy/support/colorize.rb +1 -1
  15. data/lib/webspicy/tester.rb +1 -1
  16. data/lib/webspicy/tester/reporter/documentation.rb +4 -2
  17. data/lib/webspicy/version.rb +1 -1
  18. data/lib/webspicy/web.rb +46 -0
  19. data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
  20. data/lib/webspicy/web/specification.rb +68 -0
  21. data/lib/webspicy/web/specification/file_upload.rb +39 -0
  22. data/lib/webspicy/web/specification/service.rb +13 -0
  23. data/lib/webspicy/web/specification/test_case.rb +58 -0
  24. data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
  25. data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
  26. data/spec/unit/specification/service/test_dress_params.rb +2 -2
  27. data/spec/unit/test_configuration.rb +1 -0
  28. data/spec/unit/web/specification/test_instantiate_url.rb +36 -0
  29. data/spec/unit/web/specification/test_url_placeholders.rb +23 -0
  30. metadata +21 -16
  31. data/lib/webspicy/specification/file_upload.rb +0 -37
  32. data/spec/blackbox/commandline.yml +0 -24
  33. data/spec/blackbox/fixtures/passing/config.rb +0 -9
  34. data/spec/blackbox/fixtures/passing/formaldef/get.yml +0 -30
  35. data/spec/unit/specification/test_instantiate_url.rb +0 -34
  36. data/spec/unit/specification/test_url_placeholders.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9afe697a47ba4391d2e059f1bf3707c04f97f9d6fd50557104a59c6602dbd75c
4
- data.tar.gz: 66ec4036f8e76dad7af0f8b0cf83ea139a67a7b1020aa0a304c26fdc9402d593
3
+ metadata.gz: cf642b32d3e6abe3f90e53c047b8e1e973910041133ba4626d9ba7c2cb5ba333
4
+ data.tar.gz: 95860fd2e93a11f5dcecf7e175371eee6378e073ee60e22ea266c44e69265d19
5
5
  SHA512:
6
- metadata.gz: 79feb96443a47523b38f16e4cf7e7edfcd675f5a71c6b33aa452ad452aeacd5e64de1ce1ffa9ff3f5bf9cf428d59dc183e8f1455e1ce26126f2eddf9a14795fb
7
- data.tar.gz: 2761eb20d67f4c697dedf7c27496cfd36ceed4f988f1f54f17809358e570102f1e40c29c47e46f614671504dcf1c877ce2fe6ccb7a72b510994a9da95bb74de1
6
+ metadata.gz: 8415d763e56aec8f101d7140974e1ce959da7b1b0cc405c81c64976481a49b3042b442779973fe1eac76e20d9283e8aa6abb1c1363021c7c79d8f70fae59b482
7
+ data.tar.gz: 8bdfbf03a2c792fb1d772ec2260227ec24b0bfc87f4df5bf70e0baf2376818ed580f43e41d6ef1b4c753e5bc3cc620dcae1479501baea2a5cc84d65ad7370394
data/bin/sandr ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'path'
3
+
4
+ def sandr(file)
5
+ file.write file.read.gsub(ARGV[0], ARGV[1])
6
+ end
7
+
8
+ Path.dir.parent.glob("lib/**/*.rb") do |file|
9
+ sandr(file)
10
+ end
11
+
12
+ Path.dir.parent.glob("spec/**/*.rb") do |file|
13
+ sandr(file)
14
+ end
data/bin/search ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ grep -Rn --color $1 lib spec
data/bin/webspicy CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  #/
3
3
  #/ Document & test web services as black-box operations.
4
- #/ (c) Enspirit SRL. Distributed under MIT licence.
4
+ #/ Webspicy vVERSION, (c) Enspirit SRL. Distributed under MIT licence.
5
5
  #/
6
6
  #/ Usage: webspicy [options] URL # run default test againt url
7
7
  #/ Usage: webspicy [options] path/to/config.rb # run whole test suite
@@ -28,7 +28,7 @@ require 'optparse'
28
28
 
29
29
  def showhelp
30
30
  file = __FILE__
31
- exec "grep ^#/<'#{file}'|cut -c4-"
31
+ exec "grep ^#/<'#{file}'|cut -c4-|sed s/VERSION/#{Webspicy::VERSION}/g"
32
32
  end
33
33
 
34
34
  ARGV.options do |opts|
@@ -0,0 +1,10 @@
1
+ @import finitio/data
2
+
3
+ Tag = String( s | s.length > 0 )
4
+
5
+ Schema =
6
+ .Finitio::System <fio> String
7
+ \( s | ::Webspicy.schema(s) )
8
+ \( s | raise "Unsupported" )
9
+
10
+ Params = .Array|.Hash
data/lib/webspicy.rb CHANGED
@@ -7,7 +7,7 @@ require 'ostruct'
7
7
  require 'yaml'
8
8
  require 'rack/test'
9
9
  require 'mustermann'
10
- require 'colorized_string'
10
+ require 'paint'
11
11
  require 'securerandom'
12
12
  require 'forwardable'
13
13
  module Webspicy
@@ -21,22 +21,10 @@ module Webspicy
21
21
  require 'webspicy/specification'
22
22
  require 'webspicy/configuration'
23
23
  require 'webspicy/tester'
24
- require 'webspicy/web'
25
24
 
26
25
  class Error < StandardError; end
27
26
  class TimeoutError < Error; end
28
27
 
29
- ###
30
- ### Backward compatibility
31
- ###
32
- Client = Tester::Client
33
- HttpClient = Web::HttpClient
34
- RackTestClient = Web::RackTestClient
35
- Resource = Specification
36
- FileUpload = Specification::FileUpload
37
- Scope = Configuration::Scope
38
- Checker = Tester::FileChecker
39
-
40
28
  ###
41
29
  ### About folders
42
30
  ###
@@ -49,10 +37,11 @@ module Webspicy
49
37
  ### About formal doc and specifications defined there
50
38
  ###
51
39
  Finitio.stdlib_path(Path.dir/"finitio")
40
+
52
41
  DEFAULT_SYSTEM = Finitio.system(<<~FIO)
53
42
  @import webspicy/scalars
54
43
  FIO
55
- FORMALDOC = Finitio.system(Path.dir/("webspicy/formaldoc.fio"))
44
+
56
45
 
57
46
  ###
58
47
  ### Exceptions that we let pass during testing
@@ -66,45 +55,6 @@ module Webspicy
66
55
  end
67
56
  module_function :default_scope
68
57
 
69
- def specification(raw, file = nil, scope = default_scope)
70
- raw = YAML.load(raw) if raw.is_a?(String)
71
- with_scope(scope) do
72
- r = FORMALDOC["Specification"].dress(raw)
73
- r.config = scope.config
74
- r.located_at!(file) if file
75
- r
76
- end
77
- rescue Finitio::Error => ex
78
- handle_finitio_error(ex, scope)
79
- end
80
- module_function :specification
81
-
82
- def service(raw, scope = default_scope)
83
- with_scope(scope) do
84
- FORMALDOC["Service"].dress(raw)
85
- end
86
- rescue Finitio::Error => ex
87
- handle_finitio_error(ex)
88
- end
89
- module_function :service
90
-
91
- def test_case(raw, scope = default_scope)
92
- with_scope(scope) do
93
- FORMALDOC["TestCase"].dress(raw)
94
- end
95
- rescue Finitio::Error => ex
96
- handle_finitio_error(ex)
97
- end
98
- module_function :test_case
99
-
100
- def handle_finitio_error(ex, scope)
101
- # msg = "#{ex.message}:\n #{ex.root_cause.message}"
102
- # msg = Support::Colorize.colorize_error(msg, scope.config)
103
- # fatal(msg)
104
- raise
105
- end
106
- module_function :handle_finitio_error
107
-
108
58
  #
109
59
  # Yields the block after having installed `scope` globally.
110
60
  #
@@ -185,4 +135,23 @@ module Webspicy
185
135
  end
186
136
  module_function :fatal
187
137
 
138
+ require 'webspicy/web'
139
+
140
+ ###
141
+ ### Backward compatibility
142
+ ###
143
+ Client = Tester::Client
144
+ HttpClient = Web::HttpClient
145
+ RackTestClient = Web::RackTestClient
146
+ Resource = Specification
147
+ FileUpload = Web::Specification::FileUpload
148
+ Scope = Configuration::Scope
149
+ Checker = Tester::FileChecker
150
+
151
+ [:specification, :service, :test_case].each do |meth|
152
+ define_method(meth) do |*args, &bl|
153
+ Webspicy::Web.send(meth, *args, &bl)
154
+ end
155
+ module_function(meth)
156
+ end
188
157
  end
@@ -39,6 +39,7 @@ module Webspicy
39
39
  :success => :green
40
40
  }
41
41
  @colorize = true
42
+ @factory = Webspicy::Web
42
43
  @scope_factory = ->(config){ Scope.new(config) }
43
44
  @client = Web::HttpClient
44
45
  @reporter = default_reporter
@@ -109,6 +110,7 @@ module Webspicy
109
110
  end
110
111
  end
111
112
 
113
+ attr_accessor :factory
112
114
  attr_accessor :scope_factory
113
115
 
114
116
  def factor_scope
@@ -35,7 +35,7 @@ module Webspicy
35
35
  def each_specification(apply_filter = true, &bl)
36
36
  return enum_for(:each_specification, apply_filter) unless block_given?
37
37
  each_specification_file(apply_filter) do |file, folder|
38
- yield Webspicy.specification(file.load, file, self)
38
+ yield config.factory.specification(file.load, file, self)
39
39
  end
40
40
  end
41
41
 
@@ -138,7 +138,7 @@ module Webspicy
138
138
  return example unless service.default_example
139
139
  h1 = service.default_example.to_info
140
140
  h2 = example.to_info
141
- ex = Specification::TestCase.new(merge_maps(h1, h2))
141
+ ex = config.factory.test_case(merge_maps(h1, h2), self)
142
142
  ex.bind(service, example.counterexample?)
143
143
  end
144
144
 
@@ -10,37 +10,47 @@ module Webspicy
10
10
  end
11
11
  attr_reader :url
12
12
 
13
- def each_specification(&bl)
13
+ def each_specification_file(*args, &bl)
14
+ return enum_for(:each_specification_file) unless block_given?
15
+ yield Path.tempfile(["specification",".yml"]).tap{|f|
16
+ f.write(specification_src)
17
+ }
18
+ end
19
+
20
+ def each_specification(*args, &bl)
14
21
  return enum_for(:each_specification) unless block_given?
15
- spec = <<~YML
22
+ yield config.factory.specification(specification_src, nil, self)
23
+ end
24
+
25
+ def specification_src
26
+ <<~YML.tap{|s| Webspicy.debug(s) }
16
27
  ---
17
- name: |-
18
- Default specification
28
+ description: |-
29
+ Getting #{url}
30
+
19
31
  url: |-
20
32
  #{url}
21
33
 
22
- services:
23
- - method: |-
24
- GET
25
- description: |-
26
- Getting #{url}
27
-
28
- input_schema: |-
29
- Any
30
- output_schema: |-
31
- Any
32
- error_schema: |-
33
- Any
34
-
35
- examples:
36
- - description: |-
37
- it returns a 200
38
- params: {}
39
- expected:
40
- status: 200
34
+ method: |-
35
+ GET
36
+
37
+ input_schema: |-
38
+ Any
39
+
40
+ output_schema: |-
41
+ Any
42
+
43
+ error_schema: |-
44
+ Any
45
+
46
+ examples:
47
+
48
+ - description: |-
49
+ it returns a 200
50
+ params: {}
51
+ expected:
52
+ status: 200
41
53
  YML
42
- Webspicy.debug(spec)
43
- yield Webspicy.specification(spec, nil, self)
44
54
  end
45
55
 
46
56
  end # class SingleUrlScope
@@ -10,9 +10,14 @@ module Webspicy
10
10
  end
11
11
  attr_reader :file
12
12
 
13
- def each_specification(&bl)
13
+ def each_specification_file(*args, &bl)
14
+ return enum_for(:each_specification_file) unless block_given?
15
+ yield(file)
16
+ end
17
+
18
+ def each_specification(*args, &bl)
14
19
  return enum_for(:each_specification) unless block_given?
15
- yield Webspicy.specification(file.read, nil, self)
20
+ yield config.factory.specification(file.read, nil, self)
16
21
  end
17
22
 
18
23
  end # class SingleYmlFileScope
@@ -10,21 +10,6 @@ module Webspicy
10
10
  attr_accessor :config
11
11
  attr_reader :location
12
12
 
13
- def self.info(raw)
14
- new(raw)
15
- end
16
-
17
- def self.singleservice(raw)
18
- converted = {
19
- name: raw[:name] || "Unamed specification",
20
- url: raw[:url],
21
- services: [
22
- Webspicy.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
23
- ]
24
- }
25
- info(converted)
26
- end
27
-
28
13
  def located_at!(location)
29
14
  @location = Path(location)
30
15
  end
@@ -39,51 +24,12 @@ module Webspicy
39
24
  @raw[:name]
40
25
  end
41
26
 
42
- def url
43
- @raw[:url]
44
- end
45
-
46
- def url_pattern
47
- @url_pattern ||= Mustermann.new(url, type: :template)
48
- end
49
-
50
27
  def services
51
28
  @raw[:services] || []
52
29
  end
53
30
 
54
- def url_placeholders
55
- url.scan(/\{([a-zA-Z]+(\.[a-zA-Z]+)*)\}/).map{|x| x.first }
56
- end
57
-
58
- def instantiate_url(params)
59
- url, rest = self.url, params.dup
60
- url_placeholders.each do |placeholder|
61
- value, rest = extract_placeholder_value(rest, placeholder)
62
- url = url.gsub("{#{placeholder}}", value.to_s)
63
- end
64
- [ url, rest ]
65
- end
66
-
67
- def to_singleservice
68
- raise NotImplementedError
69
- end
70
-
71
31
  private
72
32
 
73
- def extract_placeholder_value(params, placeholder, split = nil)
74
- return extract_placeholder_value(params, placeholder, placeholder.split(".")) unless split
75
-
76
- key = [ split.first, split.first.to_sym ].find{|k| params.has_key?(k) }
77
- raise "Missing URL parameter `#{placeholder}`" unless key
78
-
79
- if split.size == 1
80
- [ params[key], params.dup.delete_if{|k| k == key } ]
81
- else
82
- value, rest = extract_placeholder_value(params[key], placeholder, split[1..-1])
83
- [ value, params.merge(key => rest) ]
84
- end
85
- end
86
-
87
33
  def bind_services
88
34
  services.each do |s|
89
35
  s.specification = self
@@ -99,4 +45,3 @@ require_relative 'specification/post'
99
45
  require_relative 'specification/err'
100
46
  require_relative 'specification/oldies'
101
47
  require_relative 'specification/test_case'
102
- require_relative 'specification/file_upload'
@@ -21,10 +21,6 @@ module Webspicy
21
21
  specification.config
22
22
  end
23
23
 
24
- def method
25
- @raw[:method]
26
- end
27
-
28
24
  def description
29
25
  @raw[:description]
30
26
  end
@@ -68,7 +64,7 @@ module Webspicy
68
64
  def generated_counterexamples
69
65
  preconditions.map{|pre|
70
66
  pre.counterexamples(self).map{|tc|
71
- tc = Webspicy.test_case(tc, Webspicy.current_scope)
67
+ tc = config.factory.test_case(tc, Webspicy.current_scope)
72
68
  tc.bind(self, true)
73
69
  }
74
70
  }.flatten
@@ -43,10 +43,6 @@ module Webspicy
43
43
  @raw[:seeds]
44
44
  end
45
45
 
46
- def headers
47
- @raw[:headers] ||= {}
48
- end
49
-
50
46
  def metadata
51
47
  @raw[:metadata] ||= {}
52
48
  end
@@ -55,47 +51,10 @@ module Webspicy
55
51
  @raw[:tags] ||= []
56
52
  end
57
53
 
58
- def dress_params
59
- @raw.fetch(:dress_params){ true }
60
- end
61
- alias :dress_params? :dress_params
62
-
63
- def params
64
- @raw[:params] || {}
65
- end
66
-
67
- def body
68
- @raw[:body]
69
- end
70
-
71
- def file_upload
72
- @raw[:file_upload]
73
- end
74
-
75
- def located_file_upload
76
- file_upload ? file_upload.locate(specification) : nil
77
- end
78
-
79
54
  def expected
80
55
  @raw[:expected] || {}
81
56
  end
82
57
 
83
- def expected_content_type
84
- expected[:content_type]
85
- end
86
-
87
- def expected_status
88
- expected[:status]
89
- end
90
-
91
- def is_expected_status?(status)
92
- expected_status === status
93
- end
94
-
95
- def has_expected_status?
96
- not expected[:status].nil?
97
- end
98
-
99
58
  def expected_error
100
59
  expected[:error]
101
60
  end
@@ -104,14 +63,6 @@ module Webspicy
104
63
  !expected_error.nil?
105
64
  end
106
65
 
107
- def expected_headers
108
- expected[:headers] || {}
109
- end
110
-
111
- def has_expected_headers?
112
- !expected_headers.empty?
113
- end
114
-
115
66
  def assert
116
67
  @raw[:assert] || []
117
68
  end
@@ -5,7 +5,7 @@ module Webspicy
5
5
  def colorize(str, kind, config = nil)
6
6
  return str if config && !config.colorize
7
7
  color = (config || self.config).colors[kind]
8
- ColorizedString[str].colorize(color)
8
+ Paint[str, color]
9
9
  end
10
10
  module_function :colorize
11
11
 
@@ -98,7 +98,7 @@ module Webspicy
98
98
  def load_specification(spec_file)
99
99
  @spec_file = spec_file
100
100
  reporter.before_spec_file
101
- Webspicy.specification(spec_file.load, spec_file, scope)
101
+ config.factory.specification(spec_file.load, spec_file, scope)
102
102
  rescue *PASSTHROUGH_EXCEPTIONS
103
103
  raise
104
104
  rescue Exception => e
@@ -7,8 +7,10 @@ module Webspicy
7
7
  INDENT = " ".freeze
8
8
 
9
9
  def spec_file_line(spec_file)
10
- relative_path = Path(spec_file).relative_to(config.folder)
11
- colorize_section(">> #{relative_path}", config)
10
+ path = Path(spec_file).expand_path
11
+ path = path.relative_to(config.folder)
12
+ path = spec_file if path.to_s.start_with?(".")
13
+ colorize_section(">> #{path}", config)
12
14
  end
13
15
 
14
16
  def spec_file_error_line(spec_file, ex)
@@ -2,7 +2,7 @@ module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 20
5
- TINY = 4
5
+ TINY = 5
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
data/lib/webspicy/web.rb CHANGED
@@ -1,3 +1,49 @@
1
+ module Webspicy
2
+ module Web
3
+
4
+ require_relative 'web/specification'
5
+
6
+ FORMALDOC = Finitio.system(Path.dir/("web/formaldoc.fio"))
7
+
8
+ def specification(raw, file = nil, scope = Webspicy.default_scope)
9
+ raw = YAML.load(raw) if raw.is_a?(String)
10
+ Webspicy.with_scope(scope) do
11
+ r = FORMALDOC["Specification"].dress(raw)
12
+ r.config = scope.config
13
+ r.located_at!(file) if file
14
+ r
15
+ end
16
+ rescue Finitio::Error => ex
17
+ handle_finitio_error(ex)
18
+ end
19
+ module_function :specification
20
+
21
+ def service(raw, scope = Webspicy.default_scope)
22
+ Webspicy.with_scope(scope) do
23
+ FORMALDOC["Service"].dress(raw)
24
+ end
25
+ rescue Finitio::Error => ex
26
+ handle_finitio_error(ex)
27
+ end
28
+ module_function :service
29
+
30
+ def test_case(raw, scope = Webspicy.default_scope)
31
+ Webspicy.with_scope(scope) do
32
+ FORMALDOC["TestCase"].dress(raw)
33
+ end
34
+ rescue Finitio::Error => ex
35
+ handle_finitio_error(ex)
36
+ end
37
+ module_function :test_case
38
+
39
+ def handle_finitio_error(ex)
40
+ puts ex.root_cause.message
41
+ raise ex
42
+ end
43
+ module_function :handle_finitio_error
44
+
45
+ end # module Web
46
+ end # module Webspicy
1
47
  require_relative 'web/client'
2
48
  require_relative 'web/invocation'
3
49
  require_relative 'web/mocker'
@@ -1,23 +1,17 @@
1
1
  @import finitio/data
2
+ @import webspicy/shared
2
3
 
3
4
  Method =
4
5
  String( s | s =~ /^(GET|POST|POST_FORM|PUT|DELETE|PATCH|PUT|OPTIONS)$/ )
5
6
 
6
- Tag = String( s | s.length > 0 )
7
-
8
- Schema =
9
- .Finitio::System <fio> String
10
- \( s | ::Webspicy.schema(s) )
11
- \( s | raise "Unsupported" )
12
-
13
7
  FileUpload =
14
- .Webspicy::FileUpload <info> {
8
+ .Webspicy::Web::Specification::FileUpload <info> {
15
9
  path : String
16
10
  content_type : String
17
11
  param_name :? String
18
12
  }
19
13
 
20
- Specification = .Webspicy::Specification
14
+ Specification = .Webspicy::Web::Specification
21
15
  <info> {
22
16
  name: String
23
17
  url: String
@@ -41,7 +35,7 @@ Specification = .Webspicy::Specification
41
35
  }
42
36
 
43
37
  Service =
44
- .Webspicy::Specification::Service <info> {
38
+ .Webspicy::Web::Specification::Service <info> {
45
39
  method : Method
46
40
  description : String
47
41
  preconditions :? [String]|String
@@ -57,7 +51,7 @@ Service =
57
51
  }
58
52
 
59
53
  TestCase =
60
- .Webspicy::Specification::TestCase <info> {
54
+ .Webspicy::Web::Specification::TestCase <info> {
61
55
  description :? String
62
56
  dress_params :? Boolean
63
57
  params :? Params
@@ -77,8 +71,6 @@ TestCase =
77
71
  tags :? [Tag]
78
72
  }
79
73
 
80
- Params = .Array|.Hash
81
-
82
74
  StatusRange = .Webspicy::Support::StatusRange
83
75
  <int> Integer
84
76
  <str> String(s | s =~ /^\dxx$/ )
@@ -0,0 +1,68 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification < Webspicy::Specification
4
+
5
+ class << self
6
+ def info(raw)
7
+ new(raw)
8
+ end
9
+
10
+ def singleservice(raw)
11
+ converted = {
12
+ name: raw[:name] || "Unamed specification",
13
+ url: raw[:url],
14
+ services: [
15
+ Webspicy::Web.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
16
+ ]
17
+ }
18
+ info(converted)
19
+ end
20
+ end
21
+
22
+ def url
23
+ @raw[:url]
24
+ end
25
+
26
+ def url_pattern
27
+ @url_pattern ||= Mustermann.new(url, type: :template)
28
+ end
29
+
30
+ def url_placeholders
31
+ url.scan(/\{([a-zA-Z]+(\.[a-zA-Z]+)*)\}/).map{|x| x.first }
32
+ end
33
+
34
+ def instantiate_url(params)
35
+ url, rest = self.url, params.dup
36
+ url_placeholders.each do |placeholder|
37
+ value, rest = extract_placeholder_value(rest, placeholder)
38
+ url = url.gsub("{#{placeholder}}", value.to_s)
39
+ end
40
+ [ url, rest ]
41
+ end
42
+
43
+ def to_singleservice
44
+ raise NotImplementedError
45
+ end
46
+
47
+ private
48
+
49
+ def extract_placeholder_value(params, placeholder, split = nil)
50
+ return extract_placeholder_value(params, placeholder, placeholder.split(".")) unless split
51
+
52
+ key = [ split.first, split.first.to_sym ].find{|k| params.has_key?(k) }
53
+ raise "Missing URL parameter `#{placeholder}`" unless key
54
+
55
+ if split.size == 1
56
+ [ params[key], params.dup.delete_if{|k| k == key } ]
57
+ else
58
+ value, rest = extract_placeholder_value(params[key], placeholder, split[1..-1])
59
+ [ value, params.merge(key => rest) ]
60
+ end
61
+ end
62
+
63
+ end # class Specification
64
+ end # module Web
65
+ end # module Webspicy
66
+ require_relative 'specification/service'
67
+ require_relative 'specification/test_case'
68
+ require_relative 'specification/file_upload'
@@ -0,0 +1,39 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class FileUpload
5
+
6
+ def initialize(raw)
7
+ @path = raw[:path]
8
+ @content_type = raw[:content_type]
9
+ @param_name = raw[:param_name] || "file"
10
+ end
11
+
12
+ attr_reader :path, :content_type, :param_name
13
+
14
+ def self.info(raw)
15
+ new(raw)
16
+ end
17
+
18
+ def locate(specification)
19
+ FileUpload.new({
20
+ path: specification.locate(path),
21
+ content_type: content_type
22
+ })
23
+ end
24
+
25
+ def to_info
26
+ { path: path.to_s,
27
+ content_type: content_type,
28
+ param_name: param_name }
29
+ end
30
+
31
+ def to_s
32
+ "FileUpload(#{to_info})"
33
+ end
34
+ alias :inspect :to_s
35
+
36
+ end # class FileUpload
37
+ end # class Specification
38
+ end # module Web
39
+ end # module Webspicy
@@ -0,0 +1,13 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class Service < Webspicy::Specification::Service
5
+
6
+ def method
7
+ @raw[:method]
8
+ end
9
+
10
+ end # class Service
11
+ end # class Specification
12
+ end # module Web
13
+ end # module Webspicy
@@ -0,0 +1,58 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class TestCase < Webspicy::Specification::TestCase
5
+
6
+ def headers
7
+ @raw[:headers] ||= {}
8
+ end
9
+
10
+ def dress_params
11
+ @raw.fetch(:dress_params){ true }
12
+ end
13
+ alias :dress_params? :dress_params
14
+
15
+ def params
16
+ @raw[:params] || {}
17
+ end
18
+
19
+ def body
20
+ @raw[:body]
21
+ end
22
+
23
+ def file_upload
24
+ @raw[:file_upload]
25
+ end
26
+
27
+ def located_file_upload
28
+ file_upload ? file_upload.locate(specification) : nil
29
+ end
30
+
31
+ def expected_content_type
32
+ expected[:content_type]
33
+ end
34
+
35
+ def expected_status
36
+ expected[:status]
37
+ end
38
+
39
+ def is_expected_status?(status)
40
+ expected_status === status
41
+ end
42
+
43
+ def has_expected_status?
44
+ not expected[:status].nil?
45
+ end
46
+
47
+ def expected_headers
48
+ expected[:headers] || {}
49
+ end
50
+
51
+ def has_expected_headers?
52
+ !expected_headers.empty?
53
+ end
54
+
55
+ end # class TestCase
56
+ end # class Specification
57
+ end # module Web
58
+ end # module Webspicy
@@ -3,11 +3,17 @@ module Webspicy
3
3
  class Configuration
4
4
  describe Scope, "expand_example" do
5
5
 
6
- subject{ Scope.new({}).send(:expand_example, service, example) }
6
+ let(:config){
7
+ Configuration.new(Path.dir)
8
+ }
9
+
10
+ subject{
11
+ Scope.new(config).send(:expand_example, service, example)
12
+ }
7
13
 
8
14
  context 'when the service has no default example' do
9
15
  let(:service) {
10
- Webspicy.service({
16
+ Webspicy::Web.service({
11
17
  method: "GET",
12
18
  description: "Test service",
13
19
  preconditions: "Foo",
@@ -18,7 +24,7 @@ module Webspicy
18
24
  }
19
25
 
20
26
  let(:example) {
21
- Webspicy.test_case({
27
+ Webspicy::Web.test_case({
22
28
  description: "Hello world"
23
29
  })
24
30
  }
@@ -30,7 +36,7 @@ module Webspicy
30
36
 
31
37
  context 'when the service has a default example' do
32
38
  let(:service) {
33
- Webspicy.service({
39
+ Webspicy::Web.service({
34
40
  method: "GET",
35
41
  description: "Test service",
36
42
  preconditions: "Foo",
@@ -44,7 +50,7 @@ module Webspicy
44
50
  }
45
51
 
46
52
  let(:example) {
47
- Webspicy.test_case({
53
+ Webspicy::Web.test_case({
48
54
  description: "Hello world",
49
55
  expected: { content_type: "application/json" }
50
56
  })
@@ -15,13 +15,13 @@ module Webspicy
15
15
 
16
16
  describe "instrument" do
17
17
  it 'injects the headers' do
18
- tc = TestCase.new({})
18
+ tc = Web::Specification::TestCase.new({})
19
19
  instrument(tc)
20
20
  expect(tc.headers['Accept']).to eql("application/json")
21
21
  end
22
22
 
23
23
  it 'keeps original headers unchanged' do
24
- tc = TestCase.new({
24
+ tc = Web::Specification::TestCase.new({
25
25
  headers: {
26
26
  'Content-Type' => 'text/plain'
27
27
  }
@@ -32,7 +32,7 @@ module Webspicy
32
32
  end
33
33
 
34
34
  it 'has low precedence' do
35
- tc = TestCase.new({
35
+ tc = Web::Specification::TestCase.new({
36
36
  headers: {
37
37
  'Accept' => 'text/plain'
38
38
  }
@@ -4,7 +4,7 @@ module Webspicy
4
4
  describe Service, "dress_params" do
5
5
 
6
6
  it 'symbolizes keys' do
7
- service = Webspicy.service({
7
+ service = Webspicy::Web.service({
8
8
  method: "GET",
9
9
  description: "Test service",
10
10
  preconditions: "Foo",
@@ -17,7 +17,7 @@ module Webspicy
17
17
  end
18
18
 
19
19
  it 'supports an array' do
20
- service = Webspicy.service({
20
+ service = Webspicy::Web.service({
21
21
  method: "GET",
22
22
  description: "Test service",
23
23
  preconditions: "Foo",
@@ -36,6 +36,7 @@ module Webspicy
36
36
  expect(c).to be_a(Configuration)
37
37
  expect(c.folder).to eq(Path.pwd)
38
38
  expect(c.each_scope.to_a.size).to eql(1)
39
+ expect(c.each_scope.to_a.first.each_specification_file.to_a.size).to eql(1)
39
40
  expect(c.each_scope.to_a.first.each_specification.to_a.size).to eql(1)
40
41
  end
41
42
 
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+ module Webspicy
3
+ module Web
4
+ describe Specification, "instantiate_url" do
5
+
6
+ it 'does nothing when the url has no placeholder' do
7
+ r = Specification.new(url: "/test/a/url")
8
+ url, params = r.instantiate_url(foo: "bar")
9
+ expect(url).to eq("/test/a/url")
10
+ expect(params).to eq(foo: "bar")
11
+ end
12
+
13
+ it 'instantiates placeholders and strips corresponding params' do
14
+ r = Specification.new(url: "/test/{foo}/url")
15
+ url, params = r.instantiate_url(foo: "bar", baz: "coz")
16
+ expect(url).to eq("/test/bar/url")
17
+ expect(params).to eq(baz: "coz")
18
+ end
19
+
20
+ it 'instantiates placeholders and strips corresponding params even when multiple' do
21
+ r = Specification.new(url: "/test/{foo}/url/{bar}")
22
+ url, params = r.instantiate_url(foo: "bar", bar: "baz", baz: "coz")
23
+ expect(url).to eq("/test/bar/url/baz")
24
+ expect(params).to eq(baz: "coz")
25
+ end
26
+
27
+ it 'supports placeholders corresponding to subentities' do
28
+ r = Specification.new(url: "/test/{foo.id}/url")
29
+ url, params = r.instantiate_url(foo: {id: "bar"}, baz: "coz")
30
+ expect(url).to eq("/test/bar/url")
31
+ expect(params).to eq(foo: {}, baz: "coz")
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+ module Webspicy
3
+ module Web
4
+ describe Specification, "url_placeholders" do
5
+
6
+ it 'returns an empty array on none' do
7
+ r = Specification.new(url: "/test/a/url")
8
+ expect(r.url_placeholders).to eq([])
9
+ end
10
+
11
+ it 'returns all placeholders' do
12
+ r = Specification.new(url: "/test/{foo}/url/{bar}")
13
+ expect(r.url_placeholders).to eq(["foo", "bar"])
14
+ end
15
+
16
+ it 'returns all placeholders expr' do
17
+ r = Specification.new(url: "/test/{foo.id}/url/{bar}")
18
+ expect(r.url_placeholders).to eq(["foo.id", "bar"])
19
+ end
20
+
21
+ end
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webspicy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.4
4
+ version: 0.20.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-13 00:00:00.000000000 Z
11
+ date: 2021-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -171,19 +171,19 @@ dependencies:
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0'
173
173
  - !ruby/object:Gem::Dependency
174
- name: colorize
174
+ name: paint
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - "~>"
178
178
  - !ruby/object:Gem::Version
179
- version: 0.8.1
179
+ version: '2.2'
180
180
  type: :runtime
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: 0.8.1
186
+ version: '2.2'
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: openapi3_parser
189
189
  requirement: !ruby/object:Gem::Requirement
@@ -201,6 +201,8 @@ dependencies:
201
201
  description: Webspicy helps testing web services as software operation black boxes
202
202
  email: blambeau@gmail.com
203
203
  executables:
204
+ - sandr
205
+ - search
204
206
  - webspicy
205
207
  extensions: []
206
208
  extra_rdoc_files: []
@@ -208,22 +210,23 @@ files:
208
210
  - Gemfile
209
211
  - README.md
210
212
  - Rakefile
213
+ - bin/sandr
214
+ - bin/search
211
215
  - bin/webspicy
212
216
  - doc/1-black-box-scene.md
213
217
  - doc/2-black-box-testing.md
214
218
  - doc/3-specification-importance.md
215
219
  - doc/4-sequence-diagram.md
216
220
  - lib/finitio/webspicy/scalars.fio
221
+ - lib/finitio/webspicy/shared.fio
217
222
  - lib/webspicy.rb
218
223
  - lib/webspicy/configuration.rb
219
224
  - lib/webspicy/configuration/scope.rb
220
225
  - lib/webspicy/configuration/single_url.rb
221
226
  - lib/webspicy/configuration/single_yml_file.rb
222
- - lib/webspicy/formaldoc.fio
223
227
  - lib/webspicy/specification.rb
224
228
  - lib/webspicy/specification/condition.rb
225
229
  - lib/webspicy/specification/err.rb
226
- - lib/webspicy/specification/file_upload.rb
227
230
  - lib/webspicy/specification/oldies.rb
228
231
  - lib/webspicy/specification/oldies/bridge.rb
229
232
  - lib/webspicy/specification/oldies/errcondition.rb
@@ -279,14 +282,16 @@ files:
279
282
  - lib/webspicy/web/client/http_client.rb
280
283
  - lib/webspicy/web/client/rack_test_client.rb
281
284
  - lib/webspicy/web/client/support.rb
285
+ - lib/webspicy/web/formaldoc.fio
282
286
  - lib/webspicy/web/invocation.rb
283
287
  - lib/webspicy/web/mocker.rb
284
288
  - lib/webspicy/web/mocker/config.ru
285
289
  - lib/webspicy/web/openapi.rb
286
290
  - lib/webspicy/web/openapi/generator.rb
287
- - spec/blackbox/commandline.yml
288
- - spec/blackbox/fixtures/passing/config.rb
289
- - spec/blackbox/fixtures/passing/formaldef/get.yml
291
+ - lib/webspicy/web/specification.rb
292
+ - lib/webspicy/web/specification/file_upload.rb
293
+ - lib/webspicy/web/specification/service.rb
294
+ - lib/webspicy/web/specification/test_case.rb
290
295
  - spec/spec_helper.rb
291
296
  - spec/unit/configuration/config.rb
292
297
  - spec/unit/configuration/scope/test_each_service.rb
@@ -297,8 +302,6 @@ files:
297
302
  - spec/unit/specification/service/test_dress_params.rb
298
303
  - spec/unit/specification/test_case/test_mutate.rb
299
304
  - spec/unit/specification/test_condition.rb
300
- - spec/unit/specification/test_instantiate_url.rb
301
- - spec/unit/specification/test_url_placeholders.rb
302
305
  - spec/unit/support/hooks/test_fire_after_each.rb
303
306
  - spec/unit/support/hooks/test_fire_around.rb
304
307
  - spec/unit/support/hooks/test_fire_before_each.rb
@@ -314,13 +317,15 @@ files:
314
317
  - spec/unit/tester/test_assertions.rb
315
318
  - spec/unit/web/mocker/test_mocker.rb
316
319
  - spec/unit/web/openapi/test_generator.rb
320
+ - spec/unit/web/specification/test_instantiate_url.rb
321
+ - spec/unit/web/specification/test_url_placeholders.rb
317
322
  - tasks/gem.rake
318
323
  - tasks/test.rake
319
324
  homepage: http://github.com/enspirit/webspicy
320
325
  licenses:
321
326
  - MIT
322
327
  metadata: {}
323
- post_install_message:
328
+ post_install_message:
324
329
  rdoc_options: []
325
330
  require_paths:
326
331
  - lib
@@ -335,8 +340,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
335
340
  - !ruby/object:Gem::Version
336
341
  version: '0'
337
342
  requirements: []
338
- rubygems_version: 3.1.4
339
- signing_key:
343
+ rubygems_version: 3.2.1
344
+ signing_key:
340
345
  specification_version: 4
341
346
  summary: Webspicy helps testing web services as software operation black boxes!
342
347
  test_files: []
@@ -1,37 +0,0 @@
1
- module Webspicy
2
- class Specification
3
- class FileUpload
4
-
5
- def initialize(raw)
6
- @path = raw[:path]
7
- @content_type = raw[:content_type]
8
- @param_name = raw[:param_name] || "file"
9
- end
10
-
11
- attr_reader :path, :content_type, :param_name
12
-
13
- def self.info(raw)
14
- new(raw)
15
- end
16
-
17
- def locate(specification)
18
- FileUpload.new({
19
- path: specification.locate(path),
20
- content_type: content_type
21
- })
22
- end
23
-
24
- def to_info
25
- { path: path.to_s,
26
- content_type: content_type,
27
- param_name: param_name }
28
- end
29
-
30
- def to_s
31
- "FileUpload(#{to_info})"
32
- end
33
- alias :inspect :to_s
34
-
35
- end # class FileUpload
36
- end # class Specification
37
- end # module Webspicy
@@ -1,24 +0,0 @@
1
- ---
2
- command:
3
- webspicy {options} {args}
4
-
5
- examples:
6
-
7
- - description: |-
8
- when called on a passing path
9
- args:
10
- - ./fixtures/passing/config.rb
11
- assert:
12
- exit_code:
13
- 0
14
- stdout: |-
15
- GET /, when requested
16
- v It has a 200 response status
17
- v It has a `Content-Type: application/json` response header
18
- v Its output meets the expected data schema
19
- v Assert notEmpty
20
- v Assert pathFD('', :hello => "World" )
21
-
22
-
23
- 1 spec file, 1 example, 0 counterexample
24
- 5 assertions, 0 error, 0 failure
@@ -1,9 +0,0 @@
1
- Webspicy::Configuration.new(Path.dir) do |c|
2
- app = ->(env){
3
- [ 200,
4
- {"Content-Type" => "application/json"},
5
- [ {hello: "World"}.to_json ]
6
- ]
7
- }
8
- c.client = Webspicy::Tester::RackTestClient.for(app)
9
- end
@@ -1,30 +0,0 @@
1
- ---
2
- url: |-
3
- /
4
-
5
- method: |-
6
- GET
7
-
8
- description: |-
9
- Returns hello world
10
-
11
- input_schema: |-
12
- { }
13
-
14
- output_schema: |-
15
- { hello: String }
16
-
17
- error_schema: |-
18
- .
19
-
20
- examples:
21
-
22
- - description: |-
23
- when requested
24
- params: {}
25
- expected:
26
- content_type: application/json
27
- status: 200
28
- assert:
29
- - notEmpty
30
- - pathFD('', :hello => "World" )
@@ -1,34 +0,0 @@
1
- require "spec_helper"
2
- module Webspicy
3
- describe Specification, "instantiate_url" do
4
-
5
- it 'does nothing when the url has no placeholder' do
6
- r = Specification.new(url: "/test/a/url")
7
- url, params = r.instantiate_url(foo: "bar")
8
- expect(url).to eq("/test/a/url")
9
- expect(params).to eq(foo: "bar")
10
- end
11
-
12
- it 'instantiates placeholders and strips corresponding params' do
13
- r = Specification.new(url: "/test/{foo}/url")
14
- url, params = r.instantiate_url(foo: "bar", baz: "coz")
15
- expect(url).to eq("/test/bar/url")
16
- expect(params).to eq(baz: "coz")
17
- end
18
-
19
- it 'instantiates placeholders and strips corresponding params even when multiple' do
20
- r = Specification.new(url: "/test/{foo}/url/{bar}")
21
- url, params = r.instantiate_url(foo: "bar", bar: "baz", baz: "coz")
22
- expect(url).to eq("/test/bar/url/baz")
23
- expect(params).to eq(baz: "coz")
24
- end
25
-
26
- it 'supports placeholders corresponding to subentities' do
27
- r = Specification.new(url: "/test/{foo.id}/url")
28
- url, params = r.instantiate_url(foo: {id: "bar"}, baz: "coz")
29
- expect(url).to eq("/test/bar/url")
30
- expect(params).to eq(foo: {}, baz: "coz")
31
- end
32
-
33
- end
34
- end
@@ -1,21 +0,0 @@
1
- require "spec_helper"
2
- module Webspicy
3
- describe Specification, "url_placeholders" do
4
-
5
- it 'returns an empty array on none' do
6
- r = Specification.new(url: "/test/a/url")
7
- expect(r.url_placeholders).to eq([])
8
- end
9
-
10
- it 'returns all placeholders' do
11
- r = Specification.new(url: "/test/{foo}/url/{bar}")
12
- expect(r.url_placeholders).to eq(["foo", "bar"])
13
- end
14
-
15
- it 'returns all placeholders expr' do
16
- r = Specification.new(url: "/test/{foo.id}/url/{bar}")
17
- expect(r.url_placeholders).to eq(["foo.id", "bar"])
18
- end
19
-
20
- end
21
- end